@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spaceflow/core",
3
- "version": "0.20.0",
3
+ "version": "0.22.0",
4
4
  "description": "Spaceflow 核心能力库",
5
5
  "license": "MIT",
6
6
  "author": "Lydanne",
@@ -1,3 +1,5 @@
1
- export const loadConfig = jest.fn().mockResolvedValue({
1
+ import { vi, type Mock } from "vitest";
2
+
3
+ export const loadConfig: Mock = vi.fn().mockResolvedValue({
2
4
  config: {},
3
5
  });
@@ -1,4 +1,5 @@
1
- import { initI18n, t, addLocaleResources, resetI18n } from "./i18n";
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" | "extensions",
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/extensions/mcps 四种类型
100
+ * pluginConfig 包含 flows/commands/skills/mcps 四种类型
101
101
  * - flows: CLI 子命令,不需要复制到编辑器目录
102
102
  * - commands: 编辑器命令,复制到 .claude/commands/ 等目录
103
- * - extensions: 扩展包,复制到 .claude/skills/ 等目录
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
- // 处理 extensions
124
- if (pluginConfig.extensions.length > 0) {
125
- const editorExtensionsDir = join(editorRoot, "skills");
126
- await this.ensureDir(editorExtensionsDir, verbose);
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 ext of pluginConfig.extensions) {
129
- const extPath = ext.entry === "." ? depPath : join(depPath, ext.entry);
130
- const installName = ext.name || name;
131
- const targetPath = join(editorExtensionsDir, installName);
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(extPath, targetPath, installName);
133
+ await this.copyExtensionToTarget(skillPath, targetPath, installName);
134
134
 
135
- // 将生成的扩展加入编辑器目录的 .gitignore
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. 处理每个依赖的 extensions/commands 关联
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: [], extensions: [], mcps: [] } 格式的导出映射
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
- extensions: [],
1039
+ skills: [],
1040
1040
  mcps: [],
1041
1041
  });
1042
- const createDefaultExtension = (name = ""): PluginConfig => ({
1042
+ const createDefaultSkill = (name = ""): PluginConfig => ({
1043
1043
  flows: [],
1044
1044
  commands: [],
1045
- extensions: [{ name, entry: "." }],
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 === "extension") config.extensions.push({ name, entry });
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 createDefaultExtension();
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 createDefaultExtension(pkg.name);
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 createDefaultExtension(pkg.name);
1103
+ return createDefaultSkill(pkg.name);
1104
1104
  } catch {
1105
- return createDefaultExtension();
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