@spaceflow/core 0.20.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +30 -30
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/__mocks__/c12.ts +3 -1
- package/src/cli-runtime/i18n/i18n.spec.ts +2 -1
- package/src/commands/build/build.service.ts +1 -1
- package/src/commands/install/install.service.ts +23 -23
- package/src/commands/list/list.service.ts +1 -1
- package/src/commands/update/update.service.ts +2 -2
- package/src/config/spaceflow.config.ts +3 -3
- package/src/shared/git-provider/detect-provider.ts +4 -4
- package/src/shared/logger/logger.spec.ts +3 -3
package/package.json
CHANGED
package/src/__mocks__/c12.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t, addLocaleResources, resetI18n } from "./i18n";
|
|
2
|
+
import { initCliI18n as initI18n } from "./init";
|
|
2
3
|
import zhCN from "../../locales/zh-cn/translation.json";
|
|
3
4
|
import en from "../../locales/en/translation.json";
|
|
4
5
|
|
|
@@ -117,7 +117,7 @@ export class BuildService {
|
|
|
117
117
|
private discoverExtensionDirs(): string[] {
|
|
118
118
|
const dependencies = getDependencies(this.projectRoot);
|
|
119
119
|
const parentDirs = new Set<string>();
|
|
120
|
-
for (const source of Object.values(dependencies)) {
|
|
120
|
+
for (const source of Object.values(dependencies) as string[]) {
|
|
121
121
|
if (!source.startsWith("link:")) continue;
|
|
122
122
|
const linkPath = source.slice(5);
|
|
123
123
|
const absolutePath = resolve(this.projectRoot, linkPath);
|
|
@@ -66,7 +66,7 @@ export interface McpExportItem {
|
|
|
66
66
|
* 插件配置类型
|
|
67
67
|
*/
|
|
68
68
|
export type PluginConfig = Record<
|
|
69
|
-
"flows" | "commands" | "
|
|
69
|
+
"flows" | "commands" | "skills",
|
|
70
70
|
Array<{ name: string; entry: string }>
|
|
71
71
|
> & {
|
|
72
72
|
mcps: McpExportItem[];
|
|
@@ -97,10 +97,10 @@ export class InstallService {
|
|
|
97
97
|
|
|
98
98
|
/**
|
|
99
99
|
* 将插件关联到各个编辑器的目录
|
|
100
|
-
* pluginConfig 包含 flows/commands/
|
|
100
|
+
* pluginConfig 包含 flows/commands/skills/mcps 四种类型
|
|
101
101
|
* - flows: CLI 子命令,不需要复制到编辑器目录
|
|
102
102
|
* - commands: 编辑器命令,复制到 .claude/commands/ 等目录
|
|
103
|
-
* -
|
|
103
|
+
* - skills: 技能文件,复制到 .claude/skills/ 等目录
|
|
104
104
|
* - mcps: MCP Server,注册到编辑器的 mcp.json 配置
|
|
105
105
|
*/
|
|
106
106
|
protected async linkPluginToEditors(options: {
|
|
@@ -120,19 +120,19 @@ export class InstallService {
|
|
|
120
120
|
const editorDirName = getEditorDirName(editor);
|
|
121
121
|
const editorRoot = isGlobal ? join(home, editorDirName) : join(workingDir, editorDirName);
|
|
122
122
|
|
|
123
|
-
// 处理
|
|
124
|
-
if (pluginConfig.
|
|
125
|
-
const
|
|
126
|
-
await this.ensureDir(
|
|
123
|
+
// 处理 skills
|
|
124
|
+
if (pluginConfig.skills.length > 0) {
|
|
125
|
+
const editorSkillsDir = join(editorRoot, "skills");
|
|
126
|
+
await this.ensureDir(editorSkillsDir, verbose);
|
|
127
127
|
|
|
128
|
-
for (const
|
|
129
|
-
const
|
|
130
|
-
const installName =
|
|
131
|
-
const targetPath = join(
|
|
128
|
+
for (const skill of pluginConfig.skills) {
|
|
129
|
+
const skillPath = skill.entry === "." ? depPath : join(depPath, skill.entry);
|
|
130
|
+
const installName = skill.name || name;
|
|
131
|
+
const targetPath = join(editorSkillsDir, installName);
|
|
132
132
|
|
|
133
|
-
await this.copyExtensionToTarget(
|
|
133
|
+
await this.copyExtensionToTarget(skillPath, targetPath, installName);
|
|
134
134
|
|
|
135
|
-
//
|
|
135
|
+
// 将生成的技能文件加入编辑器目录的 .gitignore
|
|
136
136
|
await ensureEditorGitignore(editorRoot, "skills", installName);
|
|
137
137
|
}
|
|
138
138
|
}
|
|
@@ -676,7 +676,7 @@ export class InstallService {
|
|
|
676
676
|
console.warn(t("install:pmInstallFailed", { pm }));
|
|
677
677
|
}
|
|
678
678
|
|
|
679
|
-
// 3. 处理每个依赖的
|
|
679
|
+
// 3. 处理每个依赖的 skills/commands 关联
|
|
680
680
|
for (const [name, config] of Object.entries(dependencies)) {
|
|
681
681
|
const { source } = this.parseExtensionConfig(config);
|
|
682
682
|
const sourceType = getSourceType(source);
|
|
@@ -1030,19 +1030,19 @@ export class InstallService {
|
|
|
1030
1030
|
|
|
1031
1031
|
/**
|
|
1032
1032
|
* 从 package.json 读取插件配置
|
|
1033
|
-
* 返回 { flows: [], commands: [],
|
|
1033
|
+
* 返回 { flows: [], commands: [], skills: [], mcps: [] } 格式的导出映射
|
|
1034
1034
|
*/
|
|
1035
1035
|
protected async getPluginConfigFromPackageJson(extPath: string): Promise<PluginConfig> {
|
|
1036
1036
|
const createEmptyConfig = (): PluginConfig => ({
|
|
1037
1037
|
flows: [],
|
|
1038
1038
|
commands: [],
|
|
1039
|
-
|
|
1039
|
+
skills: [],
|
|
1040
1040
|
mcps: [],
|
|
1041
1041
|
});
|
|
1042
|
-
const
|
|
1042
|
+
const createDefaultSkill = (name = ""): PluginConfig => ({
|
|
1043
1043
|
flows: [],
|
|
1044
1044
|
commands: [],
|
|
1045
|
-
|
|
1045
|
+
skills: [{ name, entry: "." }],
|
|
1046
1046
|
mcps: [],
|
|
1047
1047
|
});
|
|
1048
1048
|
|
|
@@ -1055,13 +1055,13 @@ export class InstallService {
|
|
|
1055
1055
|
) => {
|
|
1056
1056
|
if (type === "flow") config.flows.push({ name, entry });
|
|
1057
1057
|
else if (type === "command") config.commands.push({ name, entry });
|
|
1058
|
-
else if (type === "
|
|
1058
|
+
else if (type === "skill") config.skills.push({ name, entry });
|
|
1059
1059
|
else if (type === "mcp") config.mcps.push({ name, entry, mcp });
|
|
1060
1060
|
};
|
|
1061
1061
|
|
|
1062
1062
|
const pkgJsonPath = join(extPath, "package.json");
|
|
1063
1063
|
if (!existsSync(pkgJsonPath)) {
|
|
1064
|
-
return
|
|
1064
|
+
return createDefaultSkill();
|
|
1065
1065
|
}
|
|
1066
1066
|
|
|
1067
1067
|
try {
|
|
@@ -1070,7 +1070,7 @@ export class InstallService {
|
|
|
1070
1070
|
const spaceflowConfig = pkg.spaceflow;
|
|
1071
1071
|
|
|
1072
1072
|
if (!spaceflowConfig) {
|
|
1073
|
-
return
|
|
1073
|
+
return createDefaultSkill(pkg.name);
|
|
1074
1074
|
}
|
|
1075
1075
|
|
|
1076
1076
|
const config = createEmptyConfig();
|
|
@@ -1100,9 +1100,9 @@ export class InstallService {
|
|
|
1100
1100
|
return config;
|
|
1101
1101
|
}
|
|
1102
1102
|
|
|
1103
|
-
return
|
|
1103
|
+
return createDefaultSkill(pkg.name);
|
|
1104
1104
|
} catch {
|
|
1105
|
-
return
|
|
1105
|
+
return createDefaultSkill();
|
|
1106
1106
|
}
|
|
1107
1107
|
}
|
|
1108
1108
|
|
|
@@ -46,7 +46,7 @@ export class ListService {
|
|
|
46
46
|
const editors = getSupportedEditors(cwd);
|
|
47
47
|
// 收集所有外部扩展信息
|
|
48
48
|
const extensionInfos: ExtensionListInfo[] = [];
|
|
49
|
-
for (const [name, source] of Object.entries(dependencies)) {
|
|
49
|
+
for (const [name, source] of Object.entries(dependencies) as [string, string][]) {
|
|
50
50
|
const type = getSourceType(source);
|
|
51
51
|
const installed = await this.checkInstalled(name, source, type, editors);
|
|
52
52
|
extensionInfos.push({ name, source, type, installed, commands: [] });
|
|
@@ -312,7 +312,7 @@ export class UpdateService {
|
|
|
312
312
|
return false;
|
|
313
313
|
}
|
|
314
314
|
|
|
315
|
-
const { source } = this.parseExtensionConfig(dependencies[name]);
|
|
315
|
+
const { source } = this.parseExtensionConfig(dependencies[name] as ExtensionConfig);
|
|
316
316
|
const sourceType = this.getSourceType(source);
|
|
317
317
|
|
|
318
318
|
if (shouldLog(verbose, 1)) console.log(t("update:updating", { name }));
|
|
@@ -344,7 +344,7 @@ export class UpdateService {
|
|
|
344
344
|
let successCount = 0;
|
|
345
345
|
let failCount = 0;
|
|
346
346
|
|
|
347
|
-
for (const [name, config] of Object.entries(dependencies)) {
|
|
347
|
+
for (const [name, config] of Object.entries(dependencies) as [string, ExtensionConfig][]) {
|
|
348
348
|
const { source } = this.parseExtensionConfig(config);
|
|
349
349
|
const sourceType = this.getSourceType(source);
|
|
350
350
|
|
|
@@ -41,15 +41,15 @@ const GitProviderConfigSchema = z.object({
|
|
|
41
41
|
const CiConfigSchema = z.object({
|
|
42
42
|
repository: z
|
|
43
43
|
.string()
|
|
44
|
-
.default(process.env.GITHUB_REPOSITORY || "")
|
|
44
|
+
.default(process.env.GITHUB_REPOSITORY || process.env.GITEA_REPOSITORY || "")
|
|
45
45
|
.describe("仓库名称 (owner/repo 格式)"),
|
|
46
46
|
refName: z
|
|
47
47
|
.string()
|
|
48
|
-
.default(process.env.GITHUB_REF_NAME || "")
|
|
48
|
+
.default(process.env.GITHUB_REF_NAME || process.env.GITEA_REF_NAME || "")
|
|
49
49
|
.describe("当前分支名称"),
|
|
50
50
|
actor: z
|
|
51
51
|
.string()
|
|
52
|
-
.default(process.env.GITHUB_ACTOR || "")
|
|
52
|
+
.default(process.env.GITHUB_ACTOR || process.env.GITEA_ACTOR || "")
|
|
53
53
|
.describe("当前操作者"),
|
|
54
54
|
});
|
|
55
55
|
|
|
@@ -65,7 +65,7 @@ function buildResult(
|
|
|
65
65
|
* 解析服务器 URL
|
|
66
66
|
* - 优先使用 GIT_PROVIDER_URL
|
|
67
67
|
* - Gitea: GITEA_SERVER_URL > GITHUB_SERVER_URL
|
|
68
|
-
* - GitHub: GITHUB_API_URL > 默认 https://api.github.com
|
|
68
|
+
* - GitHub: GITHUB_API_URL > GITEA_API_URL > 默认 https://api.github.com
|
|
69
69
|
* - GitLab: CI_SERVER_URL > GITLAB_URL
|
|
70
70
|
*/
|
|
71
71
|
function resolveServerUrl(
|
|
@@ -76,7 +76,7 @@ function resolveServerUrl(
|
|
|
76
76
|
return env.GIT_PROVIDER_URL;
|
|
77
77
|
}
|
|
78
78
|
if (provider === "github") {
|
|
79
|
-
return env.GITHUB_API_URL || "https://api.github.com";
|
|
79
|
+
return env.GITHUB_API_URL || env.GITEA_API_URL || "https://api.github.com";
|
|
80
80
|
}
|
|
81
81
|
if (provider === "gitlab") {
|
|
82
82
|
return env.CI_SERVER_URL || env.GITLAB_URL || "https://gitlab.com";
|
|
@@ -95,7 +95,7 @@ function resolveServerUrl(
|
|
|
95
95
|
* 解析 API Token
|
|
96
96
|
* - 优先使用 GIT_PROVIDER_TOKEN
|
|
97
97
|
* - Gitea: GITEA_TOKEN > GITHUB_TOKEN
|
|
98
|
-
* - GitHub: GITHUB_TOKEN
|
|
98
|
+
* - GitHub: GITHUB_TOKEN > GITEA_TOKEN
|
|
99
99
|
* - GitLab: GITLAB_TOKEN > CI_JOB_TOKEN
|
|
100
100
|
*/
|
|
101
101
|
function resolveToken(provider: GitProviderType, env: Record<string, string | undefined>): string {
|
|
@@ -103,7 +103,7 @@ function resolveToken(provider: GitProviderType, env: Record<string, string | un
|
|
|
103
103
|
return env.GIT_PROVIDER_TOKEN;
|
|
104
104
|
}
|
|
105
105
|
if (provider === "github") {
|
|
106
|
-
return env.GITHUB_TOKEN || "";
|
|
106
|
+
return env.GITHUB_TOKEN || env.GITEA_TOKEN || "";
|
|
107
107
|
}
|
|
108
108
|
if (provider === "gitlab") {
|
|
109
109
|
return env.GITLAB_TOKEN || env.CI_JOB_TOKEN || "";
|
|
@@ -10,9 +10,9 @@ describe("Logger", () => {
|
|
|
10
10
|
|
|
11
11
|
beforeEach(() => {
|
|
12
12
|
consoleSpy = {
|
|
13
|
-
log: vi.spyOn(console, "log").mockImplementation(),
|
|
14
|
-
warn: vi.spyOn(console, "warn").mockImplementation(),
|
|
15
|
-
error: vi.spyOn(console, "error").mockImplementation(),
|
|
13
|
+
log: vi.spyOn(console, "log").mockImplementation(() => {}),
|
|
14
|
+
warn: vi.spyOn(console, "warn").mockImplementation(() => {}),
|
|
15
|
+
error: vi.spyOn(console, "error").mockImplementation(() => {}),
|
|
16
16
|
};
|
|
17
17
|
});
|
|
18
18
|
|