@spaceflow/core 0.8.0 → 0.9.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 +5589 -970
- package/dist/index.js.map +1 -1
- package/package.json +9 -3
- package/src/cli-runtime/di/config.ts +157 -0
- package/src/cli-runtime/di/container.ts +120 -0
- package/src/cli-runtime/di/index.ts +3 -0
- package/src/cli-runtime/di/services.ts +53 -0
- package/src/cli-runtime/extension-loader.ts +74 -0
- package/src/{shared → cli-runtime}/i18n/index.ts +7 -1
- package/src/cli-runtime/i18n/init.ts +117 -0
- package/src/cli-runtime/index.ts +131 -0
- package/src/cli-runtime/internal-extensions.ts +33 -0
- package/src/commands/build/build.service.ts +323 -0
- package/src/commands/build/index.ts +49 -0
- package/src/commands/clear/clear.service.ts +159 -0
- package/src/commands/clear/index.ts +35 -0
- package/src/commands/commit/commit.config.ts +168 -0
- package/src/commands/commit/commit.service.ts +950 -0
- package/src/commands/commit/index.ts +58 -0
- package/src/commands/create/create.service.ts +318 -0
- package/src/commands/create/index.ts +42 -0
- package/src/commands/dev/index.ts +30 -0
- package/src/commands/install/index.ts +65 -0
- package/src/commands/install/install.service.ts +1539 -0
- package/src/commands/list/index.ts +33 -0
- package/src/commands/list/list.service.ts +127 -0
- package/src/commands/mcp/index.ts +37 -0
- package/src/commands/mcp/mcp.service.ts +246 -0
- package/src/commands/runx/index.ts +47 -0
- package/src/commands/runx/runx.service.ts +142 -0
- package/src/commands/runx/runx.utils.ts +83 -0
- package/src/commands/schema/index.ts +30 -0
- package/src/commands/setup/index.ts +34 -0
- package/src/commands/setup/setup.service.ts +234 -0
- package/src/commands/uninstall/index.ts +42 -0
- package/src/commands/uninstall/uninstall.service.ts +166 -0
- package/src/commands/update/index.ts +42 -0
- package/src/commands/update/update.service.ts +373 -0
- package/src/config/index.ts +1 -30
- package/src/config/spaceflow.config.ts +226 -278
- package/src/index.ts +11 -1
- package/src/locales/en/build.json +22 -0
- package/src/locales/en/clear.json +16 -0
- package/src/locales/en/commit.json +45 -0
- package/src/locales/en/create.json +27 -0
- package/src/locales/en/dev.json +5 -0
- package/src/locales/en/install.json +71 -0
- package/src/locales/en/list.json +8 -0
- package/src/locales/en/mcp.json +19 -0
- package/src/locales/en/runx.json +13 -0
- package/src/locales/en/schema.json +4 -0
- package/src/locales/en/setup.json +14 -0
- package/src/locales/en/uninstall.json +18 -0
- package/src/locales/en/update.json +28 -0
- package/src/locales/zh-cn/build.json +22 -0
- package/src/locales/zh-cn/clear.json +16 -0
- package/src/locales/zh-cn/commit.json +45 -0
- package/src/locales/zh-cn/create.json +27 -0
- package/src/locales/zh-cn/dev.json +5 -0
- package/src/locales/zh-cn/install.json +71 -0
- package/src/locales/zh-cn/list.json +8 -0
- package/src/locales/zh-cn/mcp.json +19 -0
- package/src/locales/zh-cn/runx.json +13 -0
- package/src/locales/zh-cn/schema.json +4 -0
- package/src/locales/zh-cn/setup.json +14 -0
- package/src/locales/zh-cn/uninstall.json +18 -0
- package/src/locales/zh-cn/update.json +28 -0
- package/src/shared/editor-config/index.ts +2 -21
- package/src/shared/llm-proxy/adapters/openai.adapter.ts +3 -1
- package/src/shared/package-manager/index.ts +5 -76
- package/src/shared/source-utils/index.ts +12 -130
- package/src/shared/spaceflow-dir/index.ts +13 -135
- package/src/shared/verbose/index.ts +10 -87
- package/dist/524.js +0 -9
- package/src/config/ci.config.ts +0 -29
- package/src/config/config-loader.ts +0 -100
- package/src/config/config-reader.service.ts +0 -128
- package/src/config/config-reader.ts +0 -75
- package/src/config/feishu.config.ts +0 -35
- package/src/config/git-provider.config.ts +0 -29
- package/src/config/llm.config.ts +0 -110
- package/src/config/load-env.ts +0 -15
- package/src/config/storage.config.ts +0 -33
- /package/src/{shared → cli-runtime}/i18n/i18n.spec.ts +0 -0
- /package/src/{shared → cli-runtime}/i18n/i18n.ts +0 -0
- /package/src/{shared → cli-runtime}/i18n/locale-detect.ts +0 -0
|
@@ -1,81 +1,11 @@
|
|
|
1
|
-
import { execSync } from "child_process";
|
|
2
|
-
import { existsSync } from "fs";
|
|
3
|
-
import { join } from "path";
|
|
4
|
-
|
|
5
1
|
/**
|
|
6
|
-
*
|
|
7
|
-
* 必须同时满足:命令可用 AND lock 文件存在
|
|
8
|
-
* @param cwd 工作目录,默认为 process.cwd()
|
|
2
|
+
* 从 @spaceflow/shared 重导出 package-manager 工具函数
|
|
9
3
|
*/
|
|
10
|
-
export
|
|
11
|
-
const workDir = cwd || process.cwd();
|
|
12
|
-
|
|
13
|
-
// pnpm: 命令可用 + pnpm-lock.yaml 存在
|
|
14
|
-
if (existsSync(join(workDir, "pnpm-lock.yaml"))) {
|
|
15
|
-
try {
|
|
16
|
-
execSync("pnpm --version", { stdio: "ignore" });
|
|
17
|
-
return "pnpm";
|
|
18
|
-
} catch {
|
|
19
|
-
// pnpm 命令不可用,继续检测其他
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// yarn: 命令可用 + yarn.lock 存在
|
|
24
|
-
if (existsSync(join(workDir, "yarn.lock"))) {
|
|
25
|
-
try {
|
|
26
|
-
execSync("yarn --version", { stdio: "ignore" });
|
|
27
|
-
return "yarn";
|
|
28
|
-
} catch {
|
|
29
|
-
// yarn 命令不可用,继续检测其他
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// npm: 命令可用 + package-lock.json 存在
|
|
34
|
-
if (existsSync(join(workDir, "package-lock.json"))) {
|
|
35
|
-
try {
|
|
36
|
-
execSync("npm --version", { stdio: "ignore" });
|
|
37
|
-
return "npm";
|
|
38
|
-
} catch {
|
|
39
|
-
// npm 命令不可用
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// 默认回退到 npm
|
|
44
|
-
return "npm";
|
|
45
|
-
}
|
|
4
|
+
export { getPackageManager, detectPackageManager, isPnpmWorkspace } from "@spaceflow/shared";
|
|
46
5
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
* @param dir 目标目录
|
|
51
|
-
*/
|
|
52
|
-
export function detectPackageManager(dir: string): string {
|
|
53
|
-
if (existsSync(join(dir, "pnpm-lock.yaml"))) {
|
|
54
|
-
return "pnpm";
|
|
55
|
-
}
|
|
56
|
-
if (existsSync(join(dir, "yarn.lock"))) {
|
|
57
|
-
return "yarn";
|
|
58
|
-
}
|
|
59
|
-
if (existsSync(join(dir, "package-lock.json"))) {
|
|
60
|
-
return "npm";
|
|
61
|
-
}
|
|
62
|
-
// 默认使用 pnpm(如果可用)
|
|
63
|
-
try {
|
|
64
|
-
execSync("pnpm --version", { stdio: "ignore" });
|
|
65
|
-
return "pnpm";
|
|
66
|
-
} catch {
|
|
67
|
-
return "npm";
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* 检测当前目录是否为 pnpm workspace
|
|
73
|
-
* @param cwd 工作目录,默认为 process.cwd()
|
|
74
|
-
*/
|
|
75
|
-
export function isPnpmWorkspace(cwd?: string): boolean {
|
|
76
|
-
const workDir = cwd || process.cwd();
|
|
77
|
-
return existsSync(join(workDir, "pnpm-workspace.yaml"));
|
|
78
|
-
}
|
|
6
|
+
// addSpaceflowToDevDependencies 是 core 独有的,保留在这里
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
8
|
+
import { join } from "path";
|
|
79
9
|
|
|
80
10
|
/**
|
|
81
11
|
* 将 .spaceflow 添加到根项目的 devDependencies 中
|
|
@@ -84,7 +14,6 @@ export function isPnpmWorkspace(cwd?: string): boolean {
|
|
|
84
14
|
* @returns 是否成功添加(如果已存在则返回 false)
|
|
85
15
|
*/
|
|
86
16
|
export function addSpaceflowToDevDependencies(cwd?: string): boolean {
|
|
87
|
-
const { readFileSync, writeFileSync } = require("fs");
|
|
88
17
|
const workDir = cwd || process.cwd();
|
|
89
18
|
const packageJsonPath = join(workDir, "package.json");
|
|
90
19
|
|
|
@@ -1,131 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*/
|
|
4
|
-
export type SourceType
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
(source.startsWith("https://") && source.endsWith(".git")) ||
|
|
15
|
-
source.endsWith(".git")
|
|
16
|
-
);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* 判断是否为本地路径
|
|
21
|
-
* 支持: ./path, ../path, /path, link:./path, skills/
|
|
22
|
-
*/
|
|
23
|
-
export function isLocalPath(source: string): boolean {
|
|
24
|
-
return (
|
|
25
|
-
source.startsWith("workspace:") ||
|
|
26
|
-
source.startsWith("link:") ||
|
|
27
|
-
source.startsWith("./") ||
|
|
28
|
-
source.startsWith("../") ||
|
|
29
|
-
source.startsWith("/") ||
|
|
30
|
-
source.startsWith("skills/")
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* 获取 source 类型
|
|
36
|
-
*/
|
|
37
|
-
export function getSourceType(source: string): SourceType {
|
|
38
|
-
if (isLocalPath(source)) return "local";
|
|
39
|
-
if (isGitUrl(source)) return "git";
|
|
40
|
-
return "npm";
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* 规范化 source(移除 link: 前缀等)
|
|
45
|
-
*/
|
|
46
|
-
export function normalizeSource(source: string): string {
|
|
47
|
-
if (source.startsWith("link:")) {
|
|
48
|
-
return source.substring(5); // 移除 "link:" 前缀
|
|
49
|
-
}
|
|
50
|
-
return source;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* 从 npm 包名中提取纯包名(去除版本号后缀)
|
|
55
|
-
* 例如: @spaceflow/review@0.10.0 → @spaceflow/review
|
|
56
|
-
* some-package@1.2.3 → some-package
|
|
57
|
-
*/
|
|
58
|
-
export function extractNpmPackageName(source: string): string {
|
|
59
|
-
// 处理 scoped 包: @scope/name@version
|
|
60
|
-
if (source.startsWith("@")) {
|
|
61
|
-
const slashIndex = source.indexOf("/");
|
|
62
|
-
if (slashIndex !== -1) {
|
|
63
|
-
const afterSlash = source.substring(slashIndex + 1);
|
|
64
|
-
const atIndex = afterSlash.indexOf("@");
|
|
65
|
-
if (atIndex !== -1) {
|
|
66
|
-
return source.substring(0, slashIndex + 1 + atIndex);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
return source;
|
|
70
|
-
}
|
|
71
|
-
// 处理普通包: name@version
|
|
72
|
-
const atIndex = source.indexOf("@");
|
|
73
|
-
if (atIndex !== -1) {
|
|
74
|
-
return source.substring(0, atIndex);
|
|
75
|
-
}
|
|
76
|
-
return source;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* 从 source 提取名称
|
|
81
|
-
* npm 包: @scope/package -> package
|
|
82
|
-
* git URL: git@git.example.com:org/repo.git -> repo
|
|
83
|
-
* 本地路径: ./skills/publish -> publish
|
|
84
|
-
*/
|
|
85
|
-
export function extractName(source: string): string {
|
|
86
|
-
if (isLocalPath(source)) {
|
|
87
|
-
// 本地路径:取最后一个目录名
|
|
88
|
-
const parts = source.replace(/\/$/, "").split("/").filter(Boolean);
|
|
89
|
-
return parts[parts.length - 1] || "unknown";
|
|
90
|
-
} else if (isGitUrl(source)) {
|
|
91
|
-
let path = source;
|
|
92
|
-
path = path.replace(/\.git$/, "");
|
|
93
|
-
path = path.replace(/^git@[^:]+:/, "");
|
|
94
|
-
path = path.replace(/^https?:\/\/[^/]+\//, "");
|
|
95
|
-
const parts = path.split("/").filter(Boolean);
|
|
96
|
-
return parts[parts.length - 1] || "unknown";
|
|
97
|
-
} else {
|
|
98
|
-
// npm 包名:先去除版本号后缀,再提取名称
|
|
99
|
-
// @spaceflow/review@0.10.0 → @spaceflow/review → review
|
|
100
|
-
const packageName = extractNpmPackageName(source);
|
|
101
|
-
const parts = packageName.split("/");
|
|
102
|
-
const lastPart = parts[parts.length - 1];
|
|
103
|
-
// 移除 spaceflow-plugin- 或 plugin- 前缀
|
|
104
|
-
return lastPart.replace(/^spaceflow-plugin-/, "").replace(/^plugin-/, "");
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* 构建 git 仓库的 package spec(用于 pnpm add)
|
|
110
|
-
* git@xxx.git -> git+ssh://git@xxx.git
|
|
111
|
-
* https://xxx.git -> git+https://xxx.git
|
|
112
|
-
*/
|
|
113
|
-
export function buildGitPackageSpec(source: string, ref?: string): string {
|
|
114
|
-
let spec: string;
|
|
115
|
-
if (source.startsWith("git@")) {
|
|
116
|
-
// SSH 格式: git@host:org/repo.git -> git+ssh://git@host/org/repo.git
|
|
117
|
-
const sshUrl = source.replace(":", "/").replace("git@", "git+ssh://git@");
|
|
118
|
-
spec = sshUrl;
|
|
119
|
-
} else if (source.startsWith("https://")) {
|
|
120
|
-
spec = `git+${source}`;
|
|
121
|
-
} else {
|
|
122
|
-
spec = source;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// 添加 ref(分支/tag/commit)
|
|
126
|
-
if (ref) {
|
|
127
|
-
spec += `#${ref}`;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return spec;
|
|
131
|
-
}
|
|
2
|
+
* 从 @spaceflow/shared 重导出 source-utils
|
|
3
|
+
*/
|
|
4
|
+
export type { SourceType } from "@spaceflow/shared";
|
|
5
|
+
export {
|
|
6
|
+
isGitUrl,
|
|
7
|
+
isLocalPath,
|
|
8
|
+
getSourceType,
|
|
9
|
+
normalizeSource,
|
|
10
|
+
extractNpmPackageName,
|
|
11
|
+
extractName,
|
|
12
|
+
buildGitPackageSpec,
|
|
13
|
+
} from "@spaceflow/shared";
|
|
@@ -1,136 +1,14 @@
|
|
|
1
|
-
import { existsSync, readFileSync, mkdirSync, writeFileSync } from "fs";
|
|
2
|
-
import { join } from "path";
|
|
3
|
-
import { homedir } from "os";
|
|
4
|
-
import { SPACEFLOW_DIR, PACKAGE_JSON } from "../../extension-system/extension.interface";
|
|
5
|
-
|
|
6
1
|
/**
|
|
7
|
-
*
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
* @param spaceflowDir .spaceflow 目录路径
|
|
21
|
-
*/
|
|
22
|
-
export function ensureSpaceflowDir(spaceflowDir: string): void {
|
|
23
|
-
if (!existsSync(spaceflowDir)) {
|
|
24
|
-
mkdirSync(spaceflowDir, { recursive: true });
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// 创建 .gitignore
|
|
28
|
-
const gitignorePath = join(spaceflowDir, ".gitignore");
|
|
29
|
-
if (!existsSync(gitignorePath)) {
|
|
30
|
-
const gitignoreContent = `# Spaceflow Extension dependencies
|
|
31
|
-
node_modules/
|
|
32
|
-
pnpm-lock.yaml
|
|
33
|
-
config-schema.json
|
|
34
|
-
`;
|
|
35
|
-
writeFileSync(gitignorePath, gitignoreContent);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* 获取 @spaceflow/core 的版本号
|
|
42
|
-
* 从 process.argv[1](cli 入口)向上找到 @spaceflow/cli 的 package.json
|
|
43
|
-
* 读取其中声明的 @spaceflow/core 依赖版本,保证 cli 和 core 版本一致
|
|
44
|
-
*/
|
|
45
|
-
export function getSpaceflowCoreVersion(): string {
|
|
46
|
-
const cliEntryPath = process.argv[1];
|
|
47
|
-
if (cliEntryPath) {
|
|
48
|
-
// cli 入口: .../node_modules/@spaceflow/cli/dist/cli.js → 往上两级是包根目录
|
|
49
|
-
const cliDir = join(cliEntryPath, "..", "..");
|
|
50
|
-
const cliPkgPath = join(cliDir, PACKAGE_JSON);
|
|
51
|
-
if (existsSync(cliPkgPath)) {
|
|
52
|
-
try {
|
|
53
|
-
const cliPkg = JSON.parse(readFileSync(cliPkgPath, "utf-8"));
|
|
54
|
-
if (cliPkg.name === "@spaceflow/cli") {
|
|
55
|
-
const coreVersion = cliPkg.dependencies?.["@spaceflow/core"];
|
|
56
|
-
if (coreVersion) {
|
|
57
|
-
return coreVersion;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
} catch {
|
|
61
|
-
// ignore
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return "latest";
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* 确保 .spaceflow 目录及 package.json 存在,并保持 @spaceflow/core 版本与 cli 一致
|
|
70
|
-
* @param spaceflowDir .spaceflow 目录路径
|
|
71
|
-
*/
|
|
72
|
-
export function ensureSpaceflowPackageJson(spaceflowDir: string): void {
|
|
73
|
-
ensureSpaceflowDir(spaceflowDir);
|
|
74
|
-
|
|
75
|
-
const packageJsonPath = join(spaceflowDir, PACKAGE_JSON);
|
|
76
|
-
const coreVersion = getSpaceflowCoreVersion();
|
|
77
|
-
|
|
78
|
-
if (existsSync(packageJsonPath)) {
|
|
79
|
-
// 已存在:检查并更新 @spaceflow/core 版本
|
|
80
|
-
try {
|
|
81
|
-
const pkg = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
82
|
-
if (pkg.dependencies?.["@spaceflow/core"] !== coreVersion) {
|
|
83
|
-
pkg.dependencies = pkg.dependencies || {};
|
|
84
|
-
pkg.dependencies["@spaceflow/core"] = coreVersion;
|
|
85
|
-
writeFileSync(packageJsonPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
86
|
-
}
|
|
87
|
-
} catch {
|
|
88
|
-
// ignore
|
|
89
|
-
}
|
|
90
|
-
} else {
|
|
91
|
-
// 不存在:创建
|
|
92
|
-
const packageJson = {
|
|
93
|
-
name: "spaceflow",
|
|
94
|
-
private: true,
|
|
95
|
-
dependencies: {
|
|
96
|
-
"@spaceflow/core": coreVersion,
|
|
97
|
-
},
|
|
98
|
-
};
|
|
99
|
-
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n");
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* 确保编辑器目录有 .gitignore 文件,并将生成的文件加入忽略列表
|
|
105
|
-
* @param editorRoot 编辑器根目录(如 .claude)
|
|
106
|
-
* @param itemType 项目类型 (skills 或 commands)
|
|
107
|
-
* @param itemName 项目名称
|
|
108
|
-
*/
|
|
109
|
-
export async function ensureEditorGitignore(
|
|
110
|
-
editorRoot: string,
|
|
111
|
-
itemType: "skills" | "commands",
|
|
112
|
-
itemName: string,
|
|
113
|
-
): Promise<void> {
|
|
114
|
-
const { readFile, writeFile } = await import("fs/promises");
|
|
115
|
-
const gitignorePath = join(editorRoot, ".gitignore");
|
|
116
|
-
const ignoreEntry = itemType === "skills" ? `skills/${itemName}` : `commands/${itemName}.md`;
|
|
117
|
-
|
|
118
|
-
let content = "";
|
|
119
|
-
if (existsSync(gitignorePath)) {
|
|
120
|
-
content = await readFile(gitignorePath, "utf-8");
|
|
121
|
-
// 检查是否已包含该条目
|
|
122
|
-
const lines = content.split("\n").map((l) => l.trim());
|
|
123
|
-
if (lines.includes(ignoreEntry)) {
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
// 确保末尾有换行
|
|
127
|
-
if (!content.endsWith("\n")) {
|
|
128
|
-
content += "\n";
|
|
129
|
-
}
|
|
130
|
-
} else {
|
|
131
|
-
content = "# 自动生成的 .gitignore - spaceflow 安装的 skills 和 commands\n";
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
content += `${ignoreEntry}\n`;
|
|
135
|
-
await writeFile(gitignorePath, content);
|
|
136
|
-
}
|
|
2
|
+
* 从 @spaceflow/shared 重导出 spaceflow-dir 工具函数
|
|
3
|
+
*/
|
|
4
|
+
export {
|
|
5
|
+
getSpaceflowDir,
|
|
6
|
+
ensureSpaceflowDir,
|
|
7
|
+
getSpaceflowCoreVersion,
|
|
8
|
+
ensureSpaceflowPackageJson,
|
|
9
|
+
ensureDependencies,
|
|
10
|
+
loadExtensionsFromDir,
|
|
11
|
+
ensureEditorGitignore,
|
|
12
|
+
SPACEFLOW_DIR,
|
|
13
|
+
PACKAGE_JSON,
|
|
14
|
+
} from "@spaceflow/shared";
|
|
@@ -1,88 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
* - 0 / false: 静默模式,只返回结果
|
|
13
|
-
* - 1 / true: 显示过程日志
|
|
14
|
-
* - 2: 显示详细日志
|
|
15
|
-
* - 3: 显示调试日志
|
|
16
|
-
*/
|
|
17
|
-
export type VerboseLevel = 0 | 1 | 2 | 3 | false | true;
|
|
18
|
-
|
|
19
|
-
/** 日志级别优先级映射 */
|
|
20
|
-
export const LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {
|
|
21
|
-
silent: 0,
|
|
22
|
-
info: 1,
|
|
23
|
-
verbose: 2,
|
|
24
|
-
debug: 3,
|
|
25
|
-
} as const;
|
|
26
|
-
|
|
27
|
-
/** VerboseLevel 数字到 LogLevel 字符串的映射 */
|
|
28
|
-
const VERBOSE_TO_LOG_LEVEL: Record<number, LogLevel> = {
|
|
29
|
-
0: "silent",
|
|
30
|
-
1: "info",
|
|
31
|
-
2: "verbose",
|
|
32
|
-
3: "debug",
|
|
33
|
-
} as const;
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* 将任意级别值统一转为 LogLevel 字符串
|
|
37
|
-
* @param level 日志级别(字符串、数字、布尔值)
|
|
38
|
-
* @returns LogLevel 字符串
|
|
39
|
-
*/
|
|
40
|
-
export const toLogLevel = (level: LogLevel | VerboseLevel | undefined): LogLevel => {
|
|
41
|
-
if (level === undefined) return "info";
|
|
42
|
-
if (typeof level === "string") return level;
|
|
43
|
-
if (level === true) return "info";
|
|
44
|
-
if (level === false) return "silent";
|
|
45
|
-
return VERBOSE_TO_LOG_LEVEL[level] ?? "info";
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* 将 verbose 值规范化为数字
|
|
50
|
-
* @param verbose verbose 值(支持字符串、数字、布尔值)
|
|
51
|
-
* @returns 规范化后的数字 (0, 1, 2, 3)
|
|
52
|
-
*/
|
|
53
|
-
export function normalizeVerbose(
|
|
54
|
-
verbose: LogLevel | VerboseLevel | boolean | undefined,
|
|
55
|
-
): 0 | 1 | 2 | 3 {
|
|
56
|
-
if (verbose === undefined || verbose === false || verbose === 0 || verbose === "silent") return 0;
|
|
57
|
-
if (verbose === true || verbose === 1 || verbose === "info") return 1;
|
|
58
|
-
if (verbose === 2 || verbose === "verbose") return 2;
|
|
59
|
-
return 3;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* 判断是否应该打印指定级别的日志
|
|
64
|
-
* @param verbose 当前 verbose 级别(支持字符串或数字)
|
|
65
|
-
* @param requiredLevel 需要的最低级别 (1, 2, 3)
|
|
66
|
-
* @returns 是否应该打印
|
|
67
|
-
*/
|
|
68
|
-
export function shouldLog(
|
|
69
|
-
verbose: LogLevel | VerboseLevel | undefined,
|
|
70
|
-
requiredLevel: 1 | 2 | 3,
|
|
71
|
-
): boolean {
|
|
72
|
-
return normalizeVerbose(verbose) >= requiredLevel;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* 解析命令行 verbose 参数
|
|
77
|
-
* 支持: -v, -v 2, -v 3, --verbose, --verbose 2, -vvv (计数模式)
|
|
78
|
-
* @param val 命令行参数值(字符串、布尔值、数字或 undefined)
|
|
79
|
-
* @returns 规范化后的 VerboseLevel
|
|
80
|
-
*/
|
|
81
|
-
export function parseVerbose(val: string | boolean | number | undefined): 0 | 1 | 2 | 3 {
|
|
82
|
-
if (val === undefined || val === 0) return 1;
|
|
83
|
-
if (val === true || val === "") return 1;
|
|
84
|
-
if (typeof val === "number") return normalizeVerbose(val as VerboseLevel);
|
|
85
|
-
const level = parseInt(val as string, 10);
|
|
86
|
-
if (isNaN(level)) return 1;
|
|
87
|
-
return normalizeVerbose(level as VerboseLevel);
|
|
88
|
-
}
|
|
2
|
+
* 从 @spaceflow/shared 重导出 verbose 工具
|
|
3
|
+
*/
|
|
4
|
+
export type { LogLevel, VerboseLevel } from "@spaceflow/shared";
|
|
5
|
+
export {
|
|
6
|
+
LOG_LEVEL_PRIORITY,
|
|
7
|
+
toLogLevel,
|
|
8
|
+
normalizeVerbose,
|
|
9
|
+
shouldLog,
|
|
10
|
+
parseVerbose,
|
|
11
|
+
} from "@spaceflow/shared";
|
package/dist/524.js
DELETED
package/src/config/ci.config.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { createEnvConfigLoader } from "./config-loader";
|
|
3
|
-
|
|
4
|
-
/** CI 配置 Schema */
|
|
5
|
-
const schemaFactory = () =>
|
|
6
|
-
z.object({
|
|
7
|
-
/** 仓库名称 (owner/repo 格式) */
|
|
8
|
-
repository: z
|
|
9
|
-
.string()
|
|
10
|
-
.default(process.env.GITHUB_REPOSITORY || "")
|
|
11
|
-
.describe("仓库名称 (owner/repo 格式)"),
|
|
12
|
-
/** 当前分支名称 */
|
|
13
|
-
refName: z
|
|
14
|
-
.string()
|
|
15
|
-
.default(process.env.GITHUB_REF_NAME || "")
|
|
16
|
-
.describe("当前分支名称"),
|
|
17
|
-
actor: z
|
|
18
|
-
.string()
|
|
19
|
-
.default(process.env.GITHUB_ACTOR || "")
|
|
20
|
-
.describe("当前操作者"),
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
/** CI 配置类型 */
|
|
24
|
-
export type CiConfig = z.infer<ReturnType<typeof schemaFactory>>;
|
|
25
|
-
|
|
26
|
-
export const ciConfig = createEnvConfigLoader({
|
|
27
|
-
configKey: "ci",
|
|
28
|
-
schemaFactory,
|
|
29
|
-
});
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { readConfigSync } from "./spaceflow.config";
|
|
3
|
-
import { registerPluginSchema } from "./schema-generator.service";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* 配置加载器选项
|
|
7
|
-
*/
|
|
8
|
-
export interface ConfigLoaderOptions<T extends z.ZodObject<z.ZodRawShape>> {
|
|
9
|
-
/** 配置 key(用于从 spaceflow.json 读取) */
|
|
10
|
-
configKey: string;
|
|
11
|
-
/** zod schema(应包含 .default() 设置默认值) */
|
|
12
|
-
schemaFactory: () => T;
|
|
13
|
-
/** 配置描述(用于生成 JSON Schema) */
|
|
14
|
-
description?: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* 创建配置加载器
|
|
19
|
-
* 统一使用 zod 进行配置验证和默认值填充
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* ```ts
|
|
23
|
-
* const GitProviderConfigSchema = z.object({
|
|
24
|
-
* serverUrl: z.string().default(process.env.GITHUB_SERVER_URL || ""),
|
|
25
|
-
* token: z.string().default(process.env.GITHUB_TOKEN || ""),
|
|
26
|
-
* });
|
|
27
|
-
*
|
|
28
|
-
* export type GitProviderConfig = z.infer<typeof GitProviderConfigSchema>;
|
|
29
|
-
*
|
|
30
|
-
* export const gitProviderConfig = createConfigLoader({
|
|
31
|
-
* configKey: "gitProvider",
|
|
32
|
-
* schemaFactory: GitProviderConfigSchema,
|
|
33
|
-
* description: "Git Provider 服务配置",
|
|
34
|
-
* });
|
|
35
|
-
* ```
|
|
36
|
-
*/
|
|
37
|
-
export function createConfigLoader<T extends z.ZodObject<z.ZodRawShape>>(
|
|
38
|
-
options: ConfigLoaderOptions<T>,
|
|
39
|
-
) {
|
|
40
|
-
const { configKey, schemaFactory, description } = options;
|
|
41
|
-
|
|
42
|
-
// 创建配置加载器
|
|
43
|
-
return (): z.infer<T> => {
|
|
44
|
-
const schema = schemaFactory();
|
|
45
|
-
// 注册 schema 用于 JSON Schema 生成
|
|
46
|
-
registerPluginSchema({
|
|
47
|
-
configKey,
|
|
48
|
-
schemaFactory: () => schema,
|
|
49
|
-
description,
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const fileConfig = readConfigSync();
|
|
53
|
-
const rawConfig = fileConfig[configKey] ?? {};
|
|
54
|
-
|
|
55
|
-
// 使用 zod 验证并填充默认值
|
|
56
|
-
const result = schema.safeParse(rawConfig);
|
|
57
|
-
|
|
58
|
-
if (!result.success) {
|
|
59
|
-
const errors = result.error.issues
|
|
60
|
-
.map((e) => ` - ${e.path.join(".")}: ${e.message}`)
|
|
61
|
-
.join("\n");
|
|
62
|
-
throw new Error(`配置 "${configKey}" 验证失败:\n${errors}`);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return result.data;
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* 创建简单配置加载器(仅从环境变量读取,不读取配置文件)
|
|
71
|
-
* 适用于 CI 等纯环境变量配置
|
|
72
|
-
*/
|
|
73
|
-
export function createEnvConfigLoader<T extends z.ZodObject<z.ZodRawShape>>(
|
|
74
|
-
options: Omit<ConfigLoaderOptions<T>, "description"> & { description?: string },
|
|
75
|
-
) {
|
|
76
|
-
const { configKey, schemaFactory, description } = options;
|
|
77
|
-
|
|
78
|
-
return (): z.infer<T> => {
|
|
79
|
-
const schema = schemaFactory();
|
|
80
|
-
// 注册 schema(如果有描述)
|
|
81
|
-
if (description) {
|
|
82
|
-
registerPluginSchema({
|
|
83
|
-
configKey,
|
|
84
|
-
schemaFactory: () => schema,
|
|
85
|
-
description,
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
// 直接使用空对象,让 schema 的 default 值生效
|
|
89
|
-
const result = schema.safeParse({});
|
|
90
|
-
|
|
91
|
-
if (!result.success) {
|
|
92
|
-
const errors = result.error.issues
|
|
93
|
-
.map((e) => ` - ${e.path.join(".")}: ${e.message}`)
|
|
94
|
-
.join("\n");
|
|
95
|
-
throw new Error(`配置 "${configKey}" 验证失败:\n${errors}`);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return result.data;
|
|
99
|
-
};
|
|
100
|
-
}
|