kcode-pi 0.1.13 → 0.1.14
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/README.md +20 -2
- package/dist/cli/kcode.d.ts +2 -1
- package/dist/cli/kcode.js +104 -7
- package/docs/DEVELOPMENT.md +2 -5
- package/package.json +2 -1
- package/src/cli/kcode.ts +101 -7
package/README.md
CHANGED
|
@@ -59,6 +59,13 @@ kcode context --refresh
|
|
|
59
59
|
|
|
60
60
|
```powershell
|
|
61
61
|
kcode doctor
|
|
62
|
+
kcode doctor --deep
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
修复项目级 KCode 配置:
|
|
66
|
+
|
|
67
|
+
```powershell
|
|
68
|
+
kcode repair
|
|
62
69
|
```
|
|
63
70
|
|
|
64
71
|
查看当前 KCode 版本:
|
|
@@ -240,6 +247,17 @@ kcode context --refresh
|
|
|
240
247
|
|
|
241
248
|
```powershell
|
|
242
249
|
kcode doctor
|
|
250
|
+
kcode doctor --deep
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
`--deep` 会额外检查 Node 版本、npm 全局目录、项目 `.pi/settings.json` 中的重复/旧 KCode package 路径、项目上下文和 active run。
|
|
254
|
+
|
|
255
|
+
### `kcode repair`
|
|
256
|
+
|
|
257
|
+
清理当前项目 `.pi/settings.json` 中旧 Node/nvm 版本下的 KCode package 路径,只保留当前安装路径,并刷新项目上下文。
|
|
258
|
+
|
|
259
|
+
```powershell
|
|
260
|
+
kcode repair
|
|
243
261
|
```
|
|
244
262
|
|
|
245
263
|
### `kcode version`
|
|
@@ -522,7 +540,7 @@ npm install -g kcode-pi@latest
|
|
|
522
540
|
|
|
523
541
|
```powershell
|
|
524
542
|
kcode init
|
|
525
|
-
kcode doctor
|
|
543
|
+
kcode doctor --deep
|
|
526
544
|
```
|
|
527
545
|
|
|
528
546
|
## nvm 与 Node 版本切换
|
|
@@ -646,7 +664,7 @@ type .pi\settings.json
|
|
|
646
664
|
如果 `packages` 中有多条 `kcode-pi` 路径,运行:
|
|
647
665
|
|
|
648
666
|
```powershell
|
|
649
|
-
kcode
|
|
667
|
+
kcode repair
|
|
650
668
|
```
|
|
651
669
|
|
|
652
670
|
如果使用的是 `0.1.1` 或更早版本,请手工删除旧路径,或升级到最新版。
|
package/dist/cli/kcode.d.ts
CHANGED
|
@@ -11,7 +11,8 @@ export interface PiCliCommand {
|
|
|
11
11
|
export declare function runKcodeCli(args: string[], cwd?: string): KcodeCliResult;
|
|
12
12
|
export declare function initProject(cwd: string): KcodeCliResult;
|
|
13
13
|
export declare function context(cwd: string, args: string[]): KcodeCliResult;
|
|
14
|
-
export declare function doctor(cwd: string): KcodeCliResult;
|
|
14
|
+
export declare function doctor(cwd: string, args?: string[]): KcodeCliResult;
|
|
15
|
+
export declare function repair(cwd: string): KcodeCliResult;
|
|
15
16
|
export declare function version(): KcodeCliResult;
|
|
16
17
|
export declare function start(cwd: string, piArgs: string[]): KcodeCliResult;
|
|
17
18
|
export declare function resolvePiCliCommand(piArgs?: string[]): PiCliCommand | undefined;
|
package/dist/cli/kcode.js
CHANGED
|
@@ -17,7 +17,9 @@ export function runKcodeCli(args, cwd = process.cwd()) {
|
|
|
17
17
|
case "context":
|
|
18
18
|
return context(cwd, args.slice(1));
|
|
19
19
|
case "doctor":
|
|
20
|
-
return doctor(cwd);
|
|
20
|
+
return doctor(cwd, args.slice(1));
|
|
21
|
+
case "repair":
|
|
22
|
+
return repair(cwd);
|
|
21
23
|
case "version":
|
|
22
24
|
case "--version":
|
|
23
25
|
case "-v":
|
|
@@ -55,28 +57,96 @@ export function context(cwd, args) {
|
|
|
55
57
|
output: [`项目上下文已${refresh ? "刷新" : "就绪"}:${projectContext.path}`, "", projectContext.content].join("\n"),
|
|
56
58
|
};
|
|
57
59
|
}
|
|
58
|
-
export function doctor(cwd) {
|
|
60
|
+
export function doctor(cwd, args = []) {
|
|
61
|
+
const deep = args.includes("--deep");
|
|
59
62
|
const lines = [];
|
|
60
63
|
const node = spawnSync("node", ["--version"], { encoding: "utf8" });
|
|
61
64
|
const piCli = resolvePiCliCommand(["--version"]);
|
|
62
65
|
const pi = piCli ? spawnSync(piCli.command, piCli.args, { encoding: "utf8" }) : undefined;
|
|
63
66
|
const settingsPath = projectSettingsPath(cwd);
|
|
67
|
+
const projectContextPath = join(cwd, ".pi", "kd", "PROJECT_CONTEXT.md");
|
|
68
|
+
let errors = 0;
|
|
69
|
+
let warnings = 0;
|
|
64
70
|
lines.push(`Node:${node.status === 0 ? node.stdout.trim() : "未找到"}`);
|
|
65
71
|
lines.push(`Pi CLI:${formatPiCliStatus(piCli, pi)}`);
|
|
66
72
|
lines.push(`KCode version:${packageName}@${packageVersion}`);
|
|
67
73
|
lines.push(`KCode package:${packageRoot}`);
|
|
68
74
|
lines.push(`项目配置:${existsSync(settingsPath) ? settingsPath : "未创建,请先运行 kcode init"}`);
|
|
69
|
-
lines.push(`项目上下文:${existsSync(
|
|
75
|
+
lines.push(`项目上下文:${existsSync(projectContextPath) ? projectContextPath : "未创建,请运行 kcode context"}`);
|
|
70
76
|
if (existsSync(settingsPath)) {
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
77
|
+
const settingsResult = readSettingsSafe(settingsPath);
|
|
78
|
+
if (!settingsResult.ok) {
|
|
79
|
+
errors++;
|
|
80
|
+
lines.push(`[ERROR] 项目配置无法解析:${settingsResult.error}`);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
const packages = settingsResult.settings.packages ?? [];
|
|
84
|
+
const hasKcode = packages.includes(normalizePath(packageRoot));
|
|
85
|
+
lines.push(`KCode package 已登记:${hasKcode ? "是" : "否"}`);
|
|
86
|
+
if (!hasKcode)
|
|
87
|
+
warnings++;
|
|
88
|
+
if (deep) {
|
|
89
|
+
const kcodePackages = packages.filter((pkg) => isSameKcodePackage(pkg, normalizePath(packageRoot)));
|
|
90
|
+
const stalePackages = kcodePackages.filter((pkg) => normalizePath(pkg) !== normalizePath(packageRoot));
|
|
91
|
+
lines.push(`KCode package 条目数:${kcodePackages.length}`);
|
|
92
|
+
if (stalePackages.length > 0) {
|
|
93
|
+
warnings++;
|
|
94
|
+
lines.push(`[WARN] 发现旧 KCode package 路径:${stalePackages.join(" | ")}`);
|
|
95
|
+
lines.push(" 运行 kcode repair 可清理旧路径并刷新项目上下文。");
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
74
99
|
}
|
|
100
|
+
else {
|
|
101
|
+
warnings++;
|
|
102
|
+
}
|
|
103
|
+
if (deep) {
|
|
104
|
+
if (!isSupportedNodeVersion(process.version)) {
|
|
105
|
+
errors++;
|
|
106
|
+
lines.push(`[ERROR] 当前 Node ${process.version} 不满足要求:>=22.19.0`);
|
|
107
|
+
}
|
|
108
|
+
if (!existsSync(projectContextPath)) {
|
|
109
|
+
warnings++;
|
|
110
|
+
lines.push("[WARN] 项目上下文不存在,运行 kcode context --refresh 或 kcode repair。");
|
|
111
|
+
}
|
|
112
|
+
const npmPrefix = spawnSync("npm", ["prefix", "-g"], { encoding: "utf8" });
|
|
113
|
+
const npmRoot = spawnSync("npm", ["root", "-g"], { encoding: "utf8" });
|
|
114
|
+
lines.push(`npm prefix -g:${npmPrefix.status === 0 ? npmPrefix.stdout.trim() : "不可用"}`);
|
|
115
|
+
lines.push(`npm root -g:${npmRoot.status === 0 ? npmRoot.stdout.trim() : "不可用"}`);
|
|
116
|
+
lines.push(`active run:${existsSync(join(cwd, ".pi", "kd", "active-run.json")) ? "存在" : "无"}`);
|
|
117
|
+
}
|
|
118
|
+
if (deep)
|
|
119
|
+
lines.push(`诊断汇总:errors=${errors} warnings=${warnings}`);
|
|
75
120
|
return {
|
|
76
|
-
exitCode: pi?.status === 0 ? 0 : 1,
|
|
121
|
+
exitCode: pi?.status === 0 && errors === 0 ? 0 : 1,
|
|
77
122
|
output: lines.join("\n"),
|
|
78
123
|
};
|
|
79
124
|
}
|
|
125
|
+
export function repair(cwd) {
|
|
126
|
+
const settingsPath = projectSettingsPath(cwd);
|
|
127
|
+
const settingsResult = readSettingsSafe(settingsPath);
|
|
128
|
+
if (!settingsResult.ok) {
|
|
129
|
+
return {
|
|
130
|
+
exitCode: 1,
|
|
131
|
+
output: `项目配置无法解析,未自动覆盖:${settingsPath}\n原因:${settingsResult.error}`,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
const currentPackage = normalizePath(packageRoot);
|
|
135
|
+
const packages = (settingsResult.settings.packages ?? []).filter((pkg) => !isSameKcodePackage(pkg, currentPackage));
|
|
136
|
+
packages.unshift(currentPackage);
|
|
137
|
+
settingsResult.settings.packages = packages;
|
|
138
|
+
mkdirSync(dirname(settingsPath), { recursive: true });
|
|
139
|
+
writeFileSync(settingsPath, `${JSON.stringify(settingsResult.settings, null, 2)}\n`, "utf8");
|
|
140
|
+
const projectContext = writeProjectContext(cwd);
|
|
141
|
+
return {
|
|
142
|
+
exitCode: 0,
|
|
143
|
+
output: [
|
|
144
|
+
`已修复项目级 Pi 配置:${settingsPath}`,
|
|
145
|
+
`已保留当前 KCode package:${currentPackage}`,
|
|
146
|
+
`已刷新项目上下文:${projectContext.path}`,
|
|
147
|
+
].join("\n"),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
80
150
|
export function version() {
|
|
81
151
|
const piCli = resolvePiCliCommand(["--version"]);
|
|
82
152
|
const pi = piCli ? spawnSync(piCli.command, piCli.args, { encoding: "utf8" }) : undefined;
|
|
@@ -136,6 +206,14 @@ function readSettings(path) {
|
|
|
136
206
|
return {};
|
|
137
207
|
return JSON.parse(readFileSync(path, "utf8"));
|
|
138
208
|
}
|
|
209
|
+
function readSettingsSafe(path) {
|
|
210
|
+
try {
|
|
211
|
+
return { ok: true, settings: readSettings(path) };
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
215
|
+
}
|
|
216
|
+
}
|
|
139
217
|
function normalizePath(path) {
|
|
140
218
|
return resolve(path);
|
|
141
219
|
}
|
|
@@ -184,6 +262,24 @@ function formatPiCliStatus(piCli, result) {
|
|
|
184
262
|
const source = piCli.source === "bundled" ? "随包" : "全局";
|
|
185
263
|
return `${version}(${source}:${piCli.displayPath})`;
|
|
186
264
|
}
|
|
265
|
+
function isSupportedNodeVersion(version) {
|
|
266
|
+
const match = /^v?(\d+)\.(\d+)\.(\d+)/.exec(version.trim());
|
|
267
|
+
if (!match)
|
|
268
|
+
return false;
|
|
269
|
+
const [, majorText, minorText, patchText] = match;
|
|
270
|
+
const major = Number(majorText);
|
|
271
|
+
const minor = Number(minorText);
|
|
272
|
+
const patch = Number(patchText);
|
|
273
|
+
if (major > 22)
|
|
274
|
+
return true;
|
|
275
|
+
if (major < 22)
|
|
276
|
+
return false;
|
|
277
|
+
if (minor > 19)
|
|
278
|
+
return true;
|
|
279
|
+
if (minor < 19)
|
|
280
|
+
return false;
|
|
281
|
+
return patch >= 0;
|
|
282
|
+
}
|
|
187
283
|
function piCliPackageVersion(piCli) {
|
|
188
284
|
if (piCli.source !== "bundled")
|
|
189
285
|
return undefined;
|
|
@@ -204,6 +300,7 @@ function helpText() {
|
|
|
204
300
|
" kcode init 初始化当前项目的 .pi/settings.json",
|
|
205
301
|
" kcode context 生成或刷新 .pi/kd/PROJECT_CONTEXT.md",
|
|
206
302
|
" kcode doctor 检查 Node、随包 Pi CLI、KCode package 和项目级配置",
|
|
303
|
+
" kcode repair 清理旧 KCode package 路径并刷新项目上下文",
|
|
207
304
|
" kcode version 显示 KCode、随包 Pi CLI 和 Node 版本",
|
|
208
305
|
" kcode start 初始化项目配置后启动 KCode 工作环境",
|
|
209
306
|
].join("\n");
|
package/docs/DEVELOPMENT.md
CHANGED
|
@@ -35,6 +35,7 @@ npm run smoke:build-debug
|
|
|
35
35
|
npm run smoke:sdk-signature
|
|
36
36
|
npm run smoke:package
|
|
37
37
|
npm run smoke:kcode-cli
|
|
38
|
+
npm run release:check
|
|
38
39
|
```
|
|
39
40
|
|
|
40
41
|
这些 smoke 分别验证:
|
|
@@ -107,11 +108,7 @@ npm run build:cli
|
|
|
107
108
|
发布检查:
|
|
108
109
|
|
|
109
110
|
```powershell
|
|
110
|
-
npm run check
|
|
111
|
-
npm run build:cli
|
|
112
|
-
npm run smoke:package
|
|
113
|
-
npm run smoke:kcode-cli
|
|
114
|
-
npm pack --dry-run
|
|
111
|
+
npm run release:check
|
|
115
112
|
```
|
|
116
113
|
|
|
117
114
|
发布:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kcode-pi",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"description": "Kingdee-specific package and harness for Pi Coding Agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
"smoke:sdk-signature": "tsx scripts/smoke-sdk-signature.ts",
|
|
65
65
|
"smoke:package": "tsx scripts/smoke-package.ts",
|
|
66
66
|
"smoke:kcode-cli": "tsx scripts/smoke-kcode-cli.ts",
|
|
67
|
+
"release:check": "tsx scripts/release-check.ts",
|
|
67
68
|
"kcode": "tsx scripts/kcode.ts",
|
|
68
69
|
"prepack": "npm run build:cli && npm run smoke:package"
|
|
69
70
|
},
|
package/src/cli/kcode.ts
CHANGED
|
@@ -37,7 +37,9 @@ export function runKcodeCli(args: string[], cwd = process.cwd()): KcodeCliResult
|
|
|
37
37
|
case "context":
|
|
38
38
|
return context(cwd, args.slice(1));
|
|
39
39
|
case "doctor":
|
|
40
|
-
return doctor(cwd);
|
|
40
|
+
return doctor(cwd, args.slice(1));
|
|
41
|
+
case "repair":
|
|
42
|
+
return repair(cwd);
|
|
41
43
|
case "version":
|
|
42
44
|
case "--version":
|
|
43
45
|
case "-v":
|
|
@@ -81,32 +83,101 @@ export function context(cwd: string, args: string[]): KcodeCliResult {
|
|
|
81
83
|
};
|
|
82
84
|
}
|
|
83
85
|
|
|
84
|
-
export function doctor(cwd: string): KcodeCliResult {
|
|
86
|
+
export function doctor(cwd: string, args: string[] = []): KcodeCliResult {
|
|
87
|
+
const deep = args.includes("--deep");
|
|
85
88
|
const lines: string[] = [];
|
|
86
89
|
const node = spawnSync("node", ["--version"], { encoding: "utf8" });
|
|
87
90
|
const piCli = resolvePiCliCommand(["--version"]);
|
|
88
91
|
const pi = piCli ? spawnSync(piCli.command, piCli.args, { encoding: "utf8" }) : undefined;
|
|
89
92
|
const settingsPath = projectSettingsPath(cwd);
|
|
93
|
+
const projectContextPath = join(cwd, ".pi", "kd", "PROJECT_CONTEXT.md");
|
|
94
|
+
let errors = 0;
|
|
95
|
+
let warnings = 0;
|
|
90
96
|
|
|
91
97
|
lines.push(`Node:${node.status === 0 ? node.stdout.trim() : "未找到"}`);
|
|
92
98
|
lines.push(`Pi CLI:${formatPiCliStatus(piCli, pi)}`);
|
|
93
99
|
lines.push(`KCode version:${packageName}@${packageVersion}`);
|
|
94
100
|
lines.push(`KCode package:${packageRoot}`);
|
|
95
101
|
lines.push(`项目配置:${existsSync(settingsPath) ? settingsPath : "未创建,请先运行 kcode init"}`);
|
|
96
|
-
lines.push(`项目上下文:${existsSync(
|
|
102
|
+
lines.push(`项目上下文:${existsSync(projectContextPath) ? projectContextPath : "未创建,请运行 kcode context"}`);
|
|
97
103
|
|
|
98
104
|
if (existsSync(settingsPath)) {
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
105
|
+
const settingsResult = readSettingsSafe(settingsPath);
|
|
106
|
+
if (!settingsResult.ok) {
|
|
107
|
+
errors++;
|
|
108
|
+
lines.push(`[ERROR] 项目配置无法解析:${settingsResult.error}`);
|
|
109
|
+
} else {
|
|
110
|
+
const packages = settingsResult.settings.packages ?? [];
|
|
111
|
+
const hasKcode = packages.includes(normalizePath(packageRoot));
|
|
112
|
+
lines.push(`KCode package 已登记:${hasKcode ? "是" : "否"}`);
|
|
113
|
+
if (!hasKcode) warnings++;
|
|
114
|
+
if (deep) {
|
|
115
|
+
const kcodePackages = packages.filter((pkg) => isSameKcodePackage(pkg, normalizePath(packageRoot)));
|
|
116
|
+
const stalePackages = kcodePackages.filter((pkg) => normalizePath(pkg) !== normalizePath(packageRoot));
|
|
117
|
+
lines.push(`KCode package 条目数:${kcodePackages.length}`);
|
|
118
|
+
if (stalePackages.length > 0) {
|
|
119
|
+
warnings++;
|
|
120
|
+
lines.push(`[WARN] 发现旧 KCode package 路径:${stalePackages.join(" | ")}`);
|
|
121
|
+
lines.push(" 运行 kcode repair 可清理旧路径并刷新项目上下文。");
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
warnings++;
|
|
102
127
|
}
|
|
103
128
|
|
|
129
|
+
if (deep) {
|
|
130
|
+
if (!isSupportedNodeVersion(process.version)) {
|
|
131
|
+
errors++;
|
|
132
|
+
lines.push(`[ERROR] 当前 Node ${process.version} 不满足要求:>=22.19.0`);
|
|
133
|
+
}
|
|
134
|
+
if (!existsSync(projectContextPath)) {
|
|
135
|
+
warnings++;
|
|
136
|
+
lines.push("[WARN] 项目上下文不存在,运行 kcode context --refresh 或 kcode repair。");
|
|
137
|
+
}
|
|
138
|
+
const npmPrefix = spawnSync("npm", ["prefix", "-g"], { encoding: "utf8" });
|
|
139
|
+
const npmRoot = spawnSync("npm", ["root", "-g"], { encoding: "utf8" });
|
|
140
|
+
lines.push(`npm prefix -g:${npmPrefix.status === 0 ? npmPrefix.stdout.trim() : "不可用"}`);
|
|
141
|
+
lines.push(`npm root -g:${npmRoot.status === 0 ? npmRoot.stdout.trim() : "不可用"}`);
|
|
142
|
+
lines.push(`active run:${existsSync(join(cwd, ".pi", "kd", "active-run.json")) ? "存在" : "无"}`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (deep) lines.push(`诊断汇总:errors=${errors} warnings=${warnings}`);
|
|
146
|
+
|
|
104
147
|
return {
|
|
105
|
-
exitCode: pi?.status === 0 ? 0 : 1,
|
|
148
|
+
exitCode: pi?.status === 0 && errors === 0 ? 0 : 1,
|
|
106
149
|
output: lines.join("\n"),
|
|
107
150
|
};
|
|
108
151
|
}
|
|
109
152
|
|
|
153
|
+
export function repair(cwd: string): KcodeCliResult {
|
|
154
|
+
const settingsPath = projectSettingsPath(cwd);
|
|
155
|
+
const settingsResult = readSettingsSafe(settingsPath);
|
|
156
|
+
if (!settingsResult.ok) {
|
|
157
|
+
return {
|
|
158
|
+
exitCode: 1,
|
|
159
|
+
output: `项目配置无法解析,未自动覆盖:${settingsPath}\n原因:${settingsResult.error}`,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const currentPackage = normalizePath(packageRoot);
|
|
164
|
+
const packages = (settingsResult.settings.packages ?? []).filter((pkg) => !isSameKcodePackage(pkg, currentPackage));
|
|
165
|
+
packages.unshift(currentPackage);
|
|
166
|
+
settingsResult.settings.packages = packages;
|
|
167
|
+
mkdirSync(dirname(settingsPath), { recursive: true });
|
|
168
|
+
writeFileSync(settingsPath, `${JSON.stringify(settingsResult.settings, null, 2)}\n`, "utf8");
|
|
169
|
+
const projectContext = writeProjectContext(cwd);
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
exitCode: 0,
|
|
173
|
+
output: [
|
|
174
|
+
`已修复项目级 Pi 配置:${settingsPath}`,
|
|
175
|
+
`已保留当前 KCode package:${currentPackage}`,
|
|
176
|
+
`已刷新项目上下文:${projectContext.path}`,
|
|
177
|
+
].join("\n"),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
110
181
|
export function version(): KcodeCliResult {
|
|
111
182
|
const piCli = resolvePiCliCommand(["--version"]);
|
|
112
183
|
const pi = piCli ? spawnSync(piCli.command, piCli.args, { encoding: "utf8" }) : undefined;
|
|
@@ -176,6 +247,14 @@ function readSettings(path: string): PiSettings {
|
|
|
176
247
|
return JSON.parse(readFileSync(path, "utf8")) as PiSettings;
|
|
177
248
|
}
|
|
178
249
|
|
|
250
|
+
function readSettingsSafe(path: string): { ok: true; settings: PiSettings } | { ok: false; error: string } {
|
|
251
|
+
try {
|
|
252
|
+
return { ok: true, settings: readSettings(path) };
|
|
253
|
+
} catch (error) {
|
|
254
|
+
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
179
258
|
function normalizePath(path: string): string {
|
|
180
259
|
return resolve(path);
|
|
181
260
|
}
|
|
@@ -233,6 +312,20 @@ function formatPiCliStatus(
|
|
|
233
312
|
return `${version}(${source}:${piCli.displayPath})`;
|
|
234
313
|
}
|
|
235
314
|
|
|
315
|
+
function isSupportedNodeVersion(version: string): boolean {
|
|
316
|
+
const match = /^v?(\d+)\.(\d+)\.(\d+)/.exec(version.trim());
|
|
317
|
+
if (!match) return false;
|
|
318
|
+
const [, majorText, minorText, patchText] = match;
|
|
319
|
+
const major = Number(majorText);
|
|
320
|
+
const minor = Number(minorText);
|
|
321
|
+
const patch = Number(patchText);
|
|
322
|
+
if (major > 22) return true;
|
|
323
|
+
if (major < 22) return false;
|
|
324
|
+
if (minor > 19) return true;
|
|
325
|
+
if (minor < 19) return false;
|
|
326
|
+
return patch >= 0;
|
|
327
|
+
}
|
|
328
|
+
|
|
236
329
|
function piCliPackageVersion(piCli: PiCliCommand): string | undefined {
|
|
237
330
|
if (piCli.source !== "bundled") return undefined;
|
|
238
331
|
|
|
@@ -253,6 +346,7 @@ function helpText(): string {
|
|
|
253
346
|
" kcode init 初始化当前项目的 .pi/settings.json",
|
|
254
347
|
" kcode context 生成或刷新 .pi/kd/PROJECT_CONTEXT.md",
|
|
255
348
|
" kcode doctor 检查 Node、随包 Pi CLI、KCode package 和项目级配置",
|
|
349
|
+
" kcode repair 清理旧 KCode package 路径并刷新项目上下文",
|
|
256
350
|
" kcode version 显示 KCode、随包 Pi CLI 和 Node 版本",
|
|
257
351
|
" kcode start 初始化项目配置后启动 KCode 工作环境",
|
|
258
352
|
].join("\n");
|