Skip to content

Commit 4079d7e

Browse files
committed
feat(desktop): support git store branches and Kilo Code
1 parent 08f8ed3 commit 4079d7e

66 files changed

Lines changed: 1977 additions & 178 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
11
## [Unreleased]
22

3+
## [0.5.7-beta.2] - 2026-05-28
4+
5+
### 新功能 / Features
6+
7+
- 🌿 **Git 商店源支持 branch / directory**:自定义 Skill 商店源现在可以为 Git 仓库显式配置分支和子目录,支持 GitHub、SSH 仓库和远程分支建议列表
8+
- **Git Store Sources Now Support Branch / Directory**: Custom Skill store sources can now target a specific Git branch and subdirectory, with support for GitHub, SSH repositories, and remote branch suggestions
9+
- 🧩 **Kilo Code 内置平台接入**:Agent 管理和 Skill 一键安装现在内置支持 `Kilo Code`,并移除 `Roo Code`
10+
- **Built-in Kilo Code Platform Support**: Agent management and one-click Skill installation now include built-in `Kilo Code` support, replacing `Roo Code`
11+
12+
### 问题修复 / Fixes
13+
14+
- 📁 **项目 Skill 导入流程收口**`从我的技能导入到项目` 现在支持 `copy / symlink` 高级导入模式,并按项目记住目标目录和导入偏好;`导入到我的技能` 保持单按钮复制导入
15+
- **Project Skill Import Flow Refined**: `Import from My Skills` into a project now supports advanced `copy / symlink` modes and remembers per-project targets and import preferences, while `Import to My Skills` remains a single copy action
16+
- 🌍 **项目导入相关多语言补齐**:补全导入模式、目标目录与高级设置相关文案,修复项目页弹窗回退英文的问题
17+
- **Project Import Localization Completed**: Added missing localization for import mode, target folders, and advanced import settings, fixing English fallback in the project import dialog
18+
19+
### 优化 / Improvements
20+
21+
- 🔗 **Git 仓库导入兼容性增强**:Git Skill 仓库导入与自定义源现在统一支持 GitHub、Gitea、自部署 Git,以及 HTTPS / SSH 仓库地址
22+
- **Broader Git Repository Compatibility**: Git Skill repo import and custom sources now consistently support GitHub, Gitea, self-hosted Git servers, and both HTTPS / SSH repository URLs
23+
324
## [0.5.7-beta.1] - 2026-05-26
425

526
### 新功能 / Features

README.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ PromptHub 把你的 Prompt、SKILL.md 和项目级 AI 编程资产放进一个
7878
| Windows | [![Windows x64](https://img.shields.io/badge/Windows_x64-0078D6?style=for-the-badge&logo=windows&logoColor=white)](https://github.com/legeling/PromptHub/releases/latest/download/PromptHub-Setup-0.5.6-x64.exe) [![Windows arm64](https://img.shields.io/badge/Windows_arm64-0078D6?style=for-the-badge&logo=windows&logoColor=white)](https://github.com/legeling/PromptHub/releases/latest/download/PromptHub-Setup-0.5.6-arm64.exe) | [![Windows x64](https://img.shields.io/badge/Windows_x64-0078D6?style=for-the-badge&logo=windows&logoColor=white)](https://github.com/legeling/PromptHub/releases/latest/download/PromptHub-Setup-0.5.6-x64.exe) [![Windows arm64](https://img.shields.io/badge/Windows_arm64-0078D6?style=for-the-badge&logo=windows&logoColor=white)](https://github.com/legeling/PromptHub/releases/latest/download/PromptHub-Setup-0.5.6-arm64.exe) |
7979
| macOS | [![macOS Apple Silicon](https://img.shields.io/badge/macOS_Apple_Silicon-000000?style=for-the-badge&logo=apple&logoColor=white)](https://github.com/legeling/PromptHub/releases/latest/download/PromptHub-0.5.6-arm64.dmg) [![macOS Intel](https://img.shields.io/badge/macOS_Intel-000000?style=for-the-badge&logo=apple&logoColor=white)](https://github.com/legeling/PromptHub/releases/latest/download/PromptHub-0.5.6-x64.dmg) | [![macOS Apple Silicon](https://img.shields.io/badge/macOS_Apple_Silicon-000000?style=for-the-badge&logo=apple&logoColor=white)](https://github.com/legeling/PromptHub/releases/latest/download/PromptHub-0.5.6-arm64.dmg) [![macOS Intel](https://img.shields.io/badge/macOS_Intel-000000?style=for-the-badge&logo=apple&logoColor=white)](https://github.com/legeling/PromptHub/releases/latest/download/PromptHub-0.5.6-x64.dmg) |
8080
| Linux | [![Linux AppImage](https://img.shields.io/badge/Linux_AppImage-FCC624?style=for-the-badge&logo=linux&logoColor=black)](https://github.com/legeling/PromptHub/releases/latest/download/PromptHub-0.5.6-x64.AppImage) [![Linux deb](https://img.shields.io/badge/Linux_deb-FCC624?style=for-the-badge&logo=linux&logoColor=black)](https://github.com/legeling/PromptHub/releases/latest/download/PromptHub-0.5.6-amd64.deb) | [![Linux AppImage](https://img.shields.io/badge/Linux_AppImage-FCC624?style=for-the-badge&logo=linux&logoColor=black)](https://github.com/legeling/PromptHub/releases/latest/download/PromptHub-0.5.6-x64.AppImage) [![Linux deb](https://img.shields.io/badge/Linux_deb-FCC624?style=for-the-badge&logo=linux&logoColor=black)](https://github.com/legeling/PromptHub/releases/latest/download/PromptHub-0.5.6-amd64.deb) |
81-
| 预览版 | [![Preview v0.5.7-beta.1](https://img.shields.io/badge/Preview-v0.5.7--beta.1-8B5CF6?style=for-the-badge&logo=github&logoColor=white)](https://github.com/legeling/PromptHub/releases/tag/v0.5.7-beta.1) | 当前预览版:`v0.5.7-beta.1`。也可在应用内「设置 → 关于」打开「预览版通道」后自动检查并升级 |
81+
| 预览版 | [![Preview v0.5.7-beta.2](https://img.shields.io/badge/Preview-v0.5.7--beta.2-8B5CF6?style=for-the-badge&logo=github&logoColor=white)](https://github.com/legeling/PromptHub/releases/tag/v0.5.7-beta.2) | 当前预览版:`v0.5.7-beta.2`。也可在应用内「设置 → 关于」打开「预览版通道」后自动检查并升级 |
8282

8383
> **macOS 选哪个?** Apple Silicon(M1/M2/M3/M4)选 `arm64`,Intel Mac 选 `x64`
8484
> **Windows 选哪个?** 绝大多数选 `x64`,只有 Surface Pro X 这类 ARM 设备选 `arm64`
@@ -153,7 +153,7 @@ sudo xattr -rd com.apple.quarantine /Applications/PromptHub.app
153153
### 🧩 Skill 商店与一键分发
154154

155155
- **技能商店**:内置 20+ 精选技能(来自 Anthropic、OpenAI 等),可叠加自定义商店源(GitHub / skills.sh / 本地目录)
156-
- **一键安装到平台**:Claude Code、Cursor、Windsurf、Codex、Kiro、Gemini CLI、Cline、Qoder、QoderWork、CodeBuddy、Trae、Trae CN、OpenCode、Roo Code 等 15+ 平台
156+
- **一键安装到平台**:Claude Code、Cursor、Windsurf、Codex、Kiro、Kilo Code、Gemini CLI、Cline、Qoder、QoderWork、CodeBuddy、Trae、Trae CN、OpenCode 等 15+ 平台
157157
- **本地扫描**:自动发现本地已有 SKILL.md,预览选择后导入,避免在多个工具目录间复制粘贴
158158
- **Symlink / Copy 双模式**:选 symlink 共享编辑,选 copy 各平台保留独立副本
159159
- **平台目标目录可覆写**:为每个平台单独配置 Skills 目录,扫描和分发保持一致
@@ -304,6 +304,12 @@ workspace export / import
304304

305305
完整版本说明:**[CHANGELOG.md](./CHANGELOG.md)**
306306

307+
### v0.5.7-beta.2(2026-05-28,预览版)
308+
309+
- Git 商店源支持 `branch / directory` 配置、远程分支建议和 GitHub / SSH / 自部署 Git 仓库
310+
- 项目 Skill 导入支持 `copy / symlink` 高级模式,并按项目记住导入偏好与目标目录
311+
- Agent 管理与 Skill 平台安装内置接入 `Kilo Code`,移除 `Roo Code`
312+
307313
### v0.5.7-beta.1(2026-05-26,预览版)
308314

309315
- 统一 built-in / custom agent 完整配置模型,Skill Settings 可直接覆写 `root / skills / rules / agents / commands / config` 路径
@@ -341,11 +347,11 @@ workspace export / import
341347

342348
## 路线图
343349

344-
### v0.5.7-beta.1 ← 当前预览版
350+
### v0.5.7-beta.2 ← 当前预览版
345351

346-
- 统一 agent 配置模型,支持 built-in agent 完整路径覆盖
347-
- 项目级 Skill 直接部署到本地 agent 目录
348-
- Prompt 详情内联编辑体验进一步收口
352+
- Git 商店源支持 `branch / directory` 配置与远程分支建议
353+
- 项目级 Skill 导入支持 `copy / symlink` 高级模式与按项目偏好记忆
354+
- Agent 管理与 Skill 安装内置切换到 `Kilo Code`
349355

350356
### v0.5.6 ← 当前稳定版
351357

apps/cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@prompthub/cli",
3-
"version": "0.5.7-beta.1",
3+
"version": "0.5.7-beta.2",
44
"description": "PromptHub CLI - standalone command line product",
55
"license": "AGPL-3.0",
66
"type": "module",

apps/desktop/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@prompthub/desktop",
3-
"version": "0.5.7-beta.1",
3+
"version": "0.5.7-beta.2",
44
"private": true,
55
"description": "PromptHub Desktop - Electron application for AI prompt management",
66
"main": "out/main/index.js",

apps/desktop/src/main/ipc/skill/platform-handlers.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,4 +274,14 @@ export function registerSkillPlatformHandlers(context: SkillIPCContext): void {
274274
return SkillInstaller.scanRemoteGithub(repoUrl, registrySkills);
275275
},
276276
);
277+
278+
ipcMain.handle(
279+
IPC_CHANNELS.SKILL_LIST_REMOTE_BRANCHES,
280+
async (_, repoUrl: string) => {
281+
if (typeof repoUrl !== "string" || repoUrl.trim().length === 0) {
282+
throw new Error("skill:listRemoteBranches requires a non-empty repoUrl");
283+
}
284+
return SkillInstaller.listRemoteBranches(repoUrl);
285+
},
286+
);
277287
}

apps/desktop/src/main/services/skill-installer-utils.ts

Lines changed: 107 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { spawn } from "child_process";
1+
import * as childProcess from "child_process";
22
import * as os from "os";
33
import * as path from "path";
44
import { initDatabase } from "../database";
5+
import { parseGitRepo } from "@prompthub/shared/utils/git-repo";
56
import type { MCPServerConfig } from "@prompthub/shared/types/skill";
67
import {
78
getPlatformById,
@@ -90,6 +91,23 @@ export function validateMCPConfig(config: unknown, name: string): void {
9091
}
9192

9293
const GIT_CLONE_TIMEOUT_MS = 60_000; // 60 seconds
94+
const GIT_REMOTE_TIMEOUT_MS = 30_000; // 30 seconds
95+
96+
function normalizeRemoteGitUrl(url: string): string {
97+
const trimmed = url.trim();
98+
if (/^https?:\/\//i.test(trimmed)) {
99+
try {
100+
const parsedUrl = new URL(trimmed);
101+
if (parsedUrl.protocol !== "https:") {
102+
return trimmed;
103+
}
104+
} catch {
105+
return trimmed;
106+
}
107+
}
108+
const parsedRepo = parseGitRepo(trimmed);
109+
return parsedRepo?.cloneUrl ?? trimmed;
110+
}
93111

94112
export function gitClone(url: string, destDir: string): Promise<void> {
95113
if (!url.trim()) {
@@ -99,19 +117,21 @@ export function gitClone(url: string, destDir: string): Promise<void> {
99117
throw new Error("Git clone URL cannot start with '-'");
100118
}
101119

120+
const normalizedUrl = normalizeRemoteGitUrl(url);
121+
102122
const isSshGitUrl = /^git@[^:]+:[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+(?:\.git)?\/?$/.test(
103-
url,
123+
normalizedUrl,
104124
);
105125

106126
if (!isSshGitUrl) {
107-
const parsedUrl = new URL(url);
127+
const parsedUrl = new URL(normalizedUrl);
108128
if (parsedUrl.protocol !== "https:") {
109129
throw new Error("Only HTTPS or git@<host> SSH clone URLs are allowed");
110130
}
111131
}
112132

113133
return new Promise((resolve, reject) => {
114-
const proc = spawn("git", ["clone", "--depth", "1", "--", url, destDir], {
134+
const proc = childProcess.spawn("git", ["clone", "--depth", "1", "--", normalizedUrl, destDir], {
115135
stdio: ["ignore", "pipe", "pipe"],
116136
});
117137

@@ -154,6 +174,89 @@ export function gitClone(url: string, destDir: string): Promise<void> {
154174
});
155175
}
156176

177+
export function gitListRemoteBranches(url: string): Promise<string[]> {
178+
if (!url.trim()) {
179+
throw new Error("Git remote URL cannot be empty");
180+
}
181+
if (url.startsWith("-")) {
182+
throw new Error("Git remote URL cannot start with '-'");
183+
}
184+
185+
const normalizedUrl = normalizeRemoteGitUrl(url);
186+
187+
const isSshGitUrl = /^git@[^:]+:[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+(?:\.git)?\/?$/.test(
188+
normalizedUrl,
189+
);
190+
191+
if (!isSshGitUrl) {
192+
const parsedUrl = new URL(normalizedUrl);
193+
if (parsedUrl.protocol !== "https:") {
194+
throw new Error("Only HTTPS or git@<host> SSH remote URLs are allowed");
195+
}
196+
}
197+
198+
return new Promise((resolve, reject) => {
199+
const proc = childProcess.spawn(
200+
"git",
201+
["ls-remote", "--heads", "--", normalizedUrl],
202+
{ stdio: ["ignore", "pipe", "pipe"] },
203+
);
204+
205+
let stdout = "";
206+
let stderr = "";
207+
let settled = false;
208+
209+
const timeout = setTimeout(() => {
210+
if (!settled) {
211+
settled = true;
212+
proc.kill("SIGKILL");
213+
reject(
214+
new Error(
215+
`Git remote branch listing timed out after ${GIT_REMOTE_TIMEOUT_MS / 1000}s for URL: ${url}`,
216+
),
217+
);
218+
}
219+
}, GIT_REMOTE_TIMEOUT_MS);
220+
221+
proc.stdout?.on("data", (data) => {
222+
stdout += data.toString();
223+
});
224+
225+
proc.stderr?.on("data", (data) => {
226+
stderr += data.toString();
227+
});
228+
229+
proc.on("close", (code) => {
230+
if (settled) return;
231+
settled = true;
232+
clearTimeout(timeout);
233+
if (code !== 0) {
234+
reject(new Error(`Git remote branch listing failed with code ${code}: ${stderr}`));
235+
return;
236+
}
237+
238+
const branches = stdout
239+
.split(/\r?\n/u)
240+
.map((line) => line.trim())
241+
.filter(Boolean)
242+
.map((line) => line.split(/\s+/u)[1] ?? "")
243+
.filter((ref) => ref.startsWith("refs/heads/"))
244+
.map((ref) => ref.replace(/^refs\/heads\//u, ""))
245+
.filter(Boolean)
246+
.sort((a, b) => a.localeCompare(b));
247+
248+
resolve(branches);
249+
});
250+
251+
proc.on("error", (error) => {
252+
if (settled) return;
253+
settled = true;
254+
clearTimeout(timeout);
255+
reject(new Error(`Git remote branch listing error: ${error.message}`));
256+
});
257+
});
258+
}
259+
157260
export function resolvePlatformPath(template: string): string {
158261
const home = os.homedir();
159262
return template

apps/desktop/src/main/services/skill-installer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import { sanitizeImportedSkillDraft } from "./skill-import-sanitize";
3131
import {
3232
getPlatformSkillsDir,
3333
gitClone,
34+
gitListRemoteBranches,
3435
resolvePlatformPath,
3536
} from "./skill-installer-utils";
3637
import {
@@ -122,6 +123,7 @@ export class SkillInstaller {
122123
// ---- Remote / SSRF (re-exported for tests & callers) ----
123124
static fetchRemoteText = fetchRemoteText;
124125
static fetchRemoteBytes = fetchRemoteBytes;
126+
static listRemoteBranches = gitListRemoteBranches;
125127

126128
// ---- Repo CRUD (delegated) ----
127129
static isManagedRepoPath = isManagedRepoPath;

apps/desktop/src/preload/api/skill.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ export const skillApi = {
103103
ipcRenderer.invoke(IPC_CHANNELS.SKILL_FETCH_REMOTE_CONTENT_BYTES, url),
104104
scanRemoteGithub: (repoUrl: string, registrySkills: unknown[]) =>
105105
ipcRenderer.invoke(IPC_CHANNELS.SKILL_SCAN_REMOTE_GITHUB, repoUrl, registrySkills),
106+
listRemoteBranches: (repoUrl: string): Promise<string[]> =>
107+
ipcRenderer.invoke(IPC_CHANNELS.SKILL_LIST_REMOTE_BRANCHES, repoUrl),
106108
saveToRepo: (
107109
skillName: string,
108110
sourceDir: string,
Lines changed: 4 additions & 0 deletions
Loading
Lines changed: 4 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)