@house365/comate 0.10.3 → 1.0.2-next.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/LICENSE +21 -21
- package/README.md +104 -64
- package/bin/cli.mjs +197 -190
- package/bin/doctor.mjs +29 -41
- package/bin/init-run.mjs +310 -368
- package/bin/init.mjs +53 -71
- package/bin/postinstall.mjs +56 -56
- package/docs/CHANGELOG-fix-simplification.md +145 -0
- package/docs/COMATE_BETA.md +90 -0
- package/docs/COMATE_MANUAL.md +239 -665
- package/docs/superpowers/plans/2026-10-14-review-fixes.md +48 -0
- package/docs/superpowers/plans/2026-10-14-workflow-quality.md +48 -0
- package/package.json +54 -55
- package/skills/comate/SKILL.md +42 -325
- package/skills/comate/reference/archive.md +50 -0
- package/skills/comate/reference/build.md +67 -0
- package/skills/comate/reference/fix.md +150 -0
- package/skills/comate/reference/open.md +162 -0
- package/skills/comate/reference/verify.md +123 -0
- package/skills/comate/scaffold/comate/README.md +18 -0
- package/skills/{comate-gate/scaffold/docs → comate/scaffold/comate}/architecture/README.md +5 -6
- package/skills/comate/scaffold/comate/comate/config.json +10 -0
- package/skills/comate/scaffold/comate/knowledge-base/README.md +42 -0
- package/skills/{comate-gate/scaffold/docs → comate/scaffold/comate}/knowledge-base/integrations/_TEMPLATE/README.md +2 -2
- package/skills/{comate-gate/scaffold/docs → comate/scaffold/comate}/knowledge-base/integrations/_TEMPLATE/api-snapshot.md +47 -47
- package/skills/{comate-gate/scaffold/docs → comate/scaffold/comate}/knowledge-base/requirements/_templates/PRD.md +4 -4
- package/skills/comate/scripts/comate.mjs +147 -0
- package/skills/comate/scripts/lib/acceptance.mjs +112 -0
- package/skills/comate/scripts/lib/brief.mjs +50 -0
- package/skills/comate/scripts/lib/checks.mjs +178 -0
- package/skills/comate/scripts/lib/cmd-archive.mjs +152 -0
- package/skills/comate/scripts/lib/cmd-decide.mjs +116 -0
- package/skills/comate/scripts/lib/cmd-init.mjs +75 -0
- package/skills/comate/scripts/lib/cmd-loop.mjs +273 -0
- package/skills/comate/scripts/lib/cmd-open.mjs +161 -0
- package/skills/comate/scripts/lib/cmd-status.mjs +121 -0
- package/skills/comate/scripts/lib/common.mjs +85 -0
- package/skills/comate/scripts/lib/docs.mjs +45 -0
- package/skills/comate/scripts/lib/finish.mjs +108 -0
- package/skills/comate/scripts/lib/git.mjs +112 -0
- package/skills/comate/scripts/lib/md.mjs +85 -0
- package/skills/comate/scripts/lib/next.mjs +217 -0
- package/skills/comate/scripts/lib/paths.mjs +96 -0
- package/skills/comate/scripts/lib/render.mjs +46 -0
- package/skills/comate/scripts/lib/spec.mjs +106 -0
- package/skills/comate/scripts/lib/state.mjs +128 -0
- package/skills/comate/scripts/lib/tasks.mjs +53 -0
- package/skills/comate/scripts/lib/templates.mjs +58 -0
- package/skills/comate/scripts/lib/util.mjs +108 -0
- package/skills/comate-kb-integration/SKILL.md +128 -128
- package/skills/comate-kb-integration/scripts/fetch_rendered_doc.py +84 -84
- package/bin/cleanup-duplicate-superpowers.mjs +0 -119
- package/docs/COMATE_BEGINNER_GUIDE.md +0 -188
- package/docs/COMATE_INIT_DIRECTORY_GUIDE.md +0 -201
- package/docs/superpowers/plans/2026-09-13-fast-workflow.md +0 -62
- package/skills/comate/reference/decision-points.md +0 -103
- package/skills/comate/reference/dirty-worktree.md +0 -58
- package/skills/comate/reference/prerequisites.md +0 -89
- package/skills/comate/scripts/comate-lib.sh +0 -559
- package/skills/comate/scripts/comate.sh +0 -2147
- package/skills/comate/tests/comate.bats +0 -1019
- package/skills/comate/tests/run.sh +0 -101
- package/skills/comate-archive/SKILL.md +0 -63
- package/skills/comate-build/SKILL.md +0 -278
- package/skills/comate-design/SKILL.md +0 -178
- package/skills/comate-fix/SKILL.md +0 -195
- package/skills/comate-gate/SKILL.md +0 -319
- package/skills/comate-gate/scaffold/docs/README.md +0 -36
- package/skills/comate-gate/scaffold/docs/knowledge-base/README.md +0 -47
- package/skills/comate-grill/SKILL.md +0 -185
- package/skills/comate-open/SKILL.md +0 -240
- package/skills/comate-verify/SKILL.md +0 -212
- /package/skills/{comate-gate/scaffold/docs → comate/scaffold/comate}/knowledge-base/integrations/README.md +0 -0
package/bin/cli.mjs
CHANGED
|
@@ -1,191 +1,198 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// comate CLI.
|
|
3
|
-
// init
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
console.log('');
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
//
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
'
|
|
65
|
-
'
|
|
66
|
-
'
|
|
67
|
-
'
|
|
68
|
-
'
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
'-
|
|
80
|
-
'-
|
|
81
|
-
'--
|
|
82
|
-
'--
|
|
83
|
-
'--
|
|
84
|
-
'--
|
|
85
|
-
'--
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
comate
|
|
95
|
-
comate
|
|
96
|
-
comate
|
|
97
|
-
|
|
98
|
-
comate --
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
comate
|
|
102
|
-
comate
|
|
103
|
-
comate
|
|
104
|
-
comate
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
process.exit(0)
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
2
|
+
// comate CLI. Three jobs:
|
|
3
|
+
// init — install the comate skill and lay down the comate/ scaffold
|
|
4
|
+
// status / doctor / import-specs
|
|
5
|
+
// — forwarded to the installed skill's scripts/comate.mjs, so
|
|
6
|
+
// the CLI never carries a second copy of the state machine
|
|
7
|
+
// * — everything else is forwarded to the `skills` CLI, which
|
|
8
|
+
// handles agent detection, symlinking, update/remove.
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
import { dirname } from 'node:path';
|
|
11
|
+
import { readFileSync } from 'node:fs';
|
|
12
|
+
import { get } from 'node:https';
|
|
13
|
+
|
|
14
|
+
import { run, skillsInvocation, SKILLS_TIMEOUT_MS, atLeast } from './init.mjs';
|
|
15
|
+
|
|
16
|
+
// Check npm registry for the latest version and notify if an update is available.
|
|
17
|
+
async function checkForUpdates(currentVersion) {
|
|
18
|
+
// Escape hatch: skip the network round-trip entirely. Keeps `--version`
|
|
19
|
+
// deterministic and offline-safe in tests and CI.
|
|
20
|
+
if (process.env.COMATE_NO_UPDATE_CHECK) return;
|
|
21
|
+
return new Promise((resolve) => {
|
|
22
|
+
const req = get('https://registry.npmjs.org/@house365/comate/latest', { timeout: 3000 }, (res) => {
|
|
23
|
+
if (res.statusCode !== 200) {
|
|
24
|
+
resolve();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
let data = '';
|
|
28
|
+
res.on('data', (chunk) => { data += chunk; });
|
|
29
|
+
res.on('end', () => {
|
|
30
|
+
try {
|
|
31
|
+
const pkg = JSON.parse(data);
|
|
32
|
+
const latestVersion = pkg.version;
|
|
33
|
+
// Notify only when the registry is strictly newer. A plain `!==` also
|
|
34
|
+
// fired when local was ahead of the registry (e.g. mid-release, before
|
|
35
|
+
// publish lands), printing a bogus "update available" for an older
|
|
36
|
+
// version and polluting `--version` stdout.
|
|
37
|
+
if (latestVersion && atLeast(latestVersion, currentVersion) && latestVersion !== currentVersion) {
|
|
38
|
+
console.log('');
|
|
39
|
+
console.log(`\x1b[33m🔔 有新版本可用:${latestVersion} (当前版本:${currentVersion})\x1b[0m`);
|
|
40
|
+
console.log(`\x1b[36m更新命令:npm install -g @house365/comate@latest\x1b[0m`);
|
|
41
|
+
console.log('');
|
|
42
|
+
}
|
|
43
|
+
} catch {
|
|
44
|
+
// Ignore parse errors
|
|
45
|
+
}
|
|
46
|
+
resolve();
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
req.on('error', () => resolve());
|
|
50
|
+
req.on('timeout', () => {
|
|
51
|
+
req.destroy();
|
|
52
|
+
resolve();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// comate 自身的子命令(在下方被先取处理,不会透传给 skills CLI)。
|
|
58
|
+
const COMATE_COMMANDS = ['init', 'doctor', 'status', 'import-specs', 'update', 'usage'];
|
|
59
|
+
|
|
60
|
+
// 允许透传给 skills CLI 的子命令(含别名)。留在这里的都是 skills CLI 真实存在
|
|
61
|
+
// 的命令,未列入的一律视为未知命令并命中 --help。init/update 已被 comate 先取,
|
|
62
|
+
// 故不在此列。
|
|
63
|
+
const SKILLS_PASSTHROUGH = new Set([
|
|
64
|
+
'add', 'a',
|
|
65
|
+
'use',
|
|
66
|
+
'remove', 'rm',
|
|
67
|
+
'list', 'ls',
|
|
68
|
+
'find',
|
|
69
|
+
'upgrade',
|
|
70
|
+
'experimental_install',
|
|
71
|
+
'experimental_sync',
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
// Flags accepted on a bare `comate [flags]` invocation — these forward to the
|
|
75
|
+
// implicit `skills add`. Anything else starting with `-` is a typo (e.g.
|
|
76
|
+
// `--vasdasd`) and must hit help instead of silently installing everything.
|
|
77
|
+
// --version/-v and --help/-h are intercepted earlier, so they need not be here.
|
|
78
|
+
const ADD_FLAGS = new Set([
|
|
79
|
+
'-g', '--global',
|
|
80
|
+
'-a', '--agent',
|
|
81
|
+
'-s', '--skill',
|
|
82
|
+
'-l', '--list',
|
|
83
|
+
'-y', '--yes',
|
|
84
|
+
'--copy',
|
|
85
|
+
'--metadata',
|
|
86
|
+
'--subagent',
|
|
87
|
+
'--all',
|
|
88
|
+
'--full-depth',
|
|
89
|
+
]);
|
|
90
|
+
|
|
91
|
+
const HELP_TEXT = `comate — SDD (规约驱动开发) 的 AI 开发编排器
|
|
92
|
+
|
|
93
|
+
用法:
|
|
94
|
+
comate 安装/更新本包全部 comate skill 到当前 agent
|
|
95
|
+
comate init 安装 comate skill 到用户级,并在当前项目创建 comate/
|
|
96
|
+
comate init --migrate [--dry-run]
|
|
97
|
+
把 0.x 的 docs/knowledge-base、docs/architecture 移到 comate/
|
|
98
|
+
comate import-specs [--dry-run]
|
|
99
|
+
把 openspec/specs 主规格导入 comate/comate/specs
|
|
100
|
+
comate status [名] 查看当前项目的 change 与下一步
|
|
101
|
+
comate doctor 健康检查
|
|
102
|
+
comate update 更新 comate 到最新版本
|
|
103
|
+
comate usage 查看本项目 token 用量(--global 看全部;参数透传给 ccusage)
|
|
104
|
+
comate --help, -h 显示本帮助
|
|
105
|
+
comate --version, -v 显示版本号
|
|
106
|
+
|
|
107
|
+
管理 skill(透传给 skills CLI):
|
|
108
|
+
comate add <包> 添加 skill 包
|
|
109
|
+
comate remove [名] 移除已装 skill(别名 rm)
|
|
110
|
+
comate list 列出已装 skill(别名 ls)
|
|
111
|
+
comate find [关键词] 搜索 skill
|
|
112
|
+
|
|
113
|
+
装好后在 agent 中输入 /comate 开始使用。`;
|
|
114
|
+
|
|
115
|
+
function printHelp(stream = console.log) {
|
|
116
|
+
stream(HELP_TEXT);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const pkgRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
120
|
+
const args = process.argv.slice(2);
|
|
121
|
+
const packageVersion = JSON.parse(readFileSync(`${pkgRoot}/package.json`, 'utf8')).version;
|
|
122
|
+
|
|
123
|
+
if (args[0] === '--version' || args[0] === '-v') {
|
|
124
|
+
console.log(packageVersion);
|
|
125
|
+
// Await the check: without it, process.exit(0) fires synchronously and the
|
|
126
|
+
// process dies before the registry request resolves, so the update notice
|
|
127
|
+
// never prints. The check has its own 3s timeout, so a dead network stalls
|
|
128
|
+
// this by at most 3s.
|
|
129
|
+
await checkForUpdates(packageVersion).catch(() => {
|
|
130
|
+
// Silently ignore network errors
|
|
131
|
+
});
|
|
132
|
+
process.exit(0);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (args[0] === 'init') {
|
|
136
|
+
const { init } = await import('./init-run.mjs');
|
|
137
|
+
process.exit(await init(pkgRoot, args.slice(1)));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (args[0] === 'doctor') {
|
|
141
|
+
const { doctor } = await import('./doctor.mjs');
|
|
142
|
+
process.exit(doctor(args.slice(1)));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (args[0] === 'status' || args[0] === 'import-specs') {
|
|
146
|
+
const { forward } = await import('./doctor.mjs');
|
|
147
|
+
process.exit(forward(args[0], args.slice(1)));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (args[0] === 'update') {
|
|
151
|
+
const { update } = await import('./update.mjs');
|
|
152
|
+
process.exit(await update(packageVersion));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (args[0] === 'usage') {
|
|
156
|
+
const { usage } = await import('./usage.mjs');
|
|
157
|
+
process.exit(await usage(args.slice(1), { pkgRoot }));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (args[0] === '--help' || args[0] === '-h' || args[0] === 'help') {
|
|
161
|
+
printHelp();
|
|
162
|
+
process.exit(0);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// A leading token that is neither a flag, a comate command, nor a known skills
|
|
166
|
+
// passthrough command is an unknown command. Print help to stderr and exit 1 so
|
|
167
|
+
// typos surface as usage guidance instead of an opaque skills CLI error.
|
|
168
|
+
if (args.length && !args[0].startsWith('-')) {
|
|
169
|
+
const cmd = args[0];
|
|
170
|
+
if (!COMATE_COMMANDS.includes(cmd) && !SKILLS_PASSTHROUGH.has(cmd)) {
|
|
171
|
+
console.error(`comate: 未知命令 '${cmd}'\n`);
|
|
172
|
+
printHelp(console.error);
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
} else if (args[0]?.startsWith('-')) {
|
|
176
|
+
// Bare-flags mode: every arg is forwarded to the implicit `skills add`. Any
|
|
177
|
+
// dash-prefixed arg that isn't a known install flag is a typo (e.g.
|
|
178
|
+
// --vasdasd). Without this it fell through and silently installed everything.
|
|
179
|
+
// Flag values (e.g. `-a claude-code`) don't start with `-`, so they're safe.
|
|
180
|
+
const bad = args.find((a) => a.startsWith('-') && !ADD_FLAGS.has(a));
|
|
181
|
+
if (bad) {
|
|
182
|
+
console.error(`comate: 未知选项 '${bad}'\n`);
|
|
183
|
+
printHelp(console.error);
|
|
184
|
+
process.exit(1);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// No args, or only flags (-g, --list, …) = install every comate skill from this
|
|
189
|
+
// package, forwarding the flags. A leading passthrough subcommand goes straight
|
|
190
|
+
// through, so add/remove/list all still work.
|
|
191
|
+
const argv =
|
|
192
|
+
args.length && !args[0].startsWith('-') ? args : ['add', pkgRoot, '--skill', '*', ...args];
|
|
193
|
+
|
|
194
|
+
const result = run(skillsInvocation(pkgRoot, argv), SKILLS_TIMEOUT_MS);
|
|
195
|
+
if (!result.ok) {
|
|
196
|
+
console.error(`comate: skills CLI 执行失败 — ${result.reason}`);
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
package/bin/doctor.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
// `comate doctor` — run the installed comate.
|
|
1
|
+
// `comate doctor` — run the installed comate.mjs health check.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
3
|
+
// comate.mjs already implements every check. This only locates the installed
|
|
4
|
+
// copy (the one the agent would load) so the user doesn't need the path.
|
|
5
5
|
import { spawnSync } from 'node:child_process';
|
|
6
6
|
import { existsSync, readFileSync } from 'node:fs';
|
|
7
7
|
import { createRequire } from 'node:module';
|
|
8
|
-
import {
|
|
8
|
+
import { dirname, join, resolve } from 'node:path';
|
|
9
9
|
import { fileURLToPath } from 'node:url';
|
|
10
10
|
|
|
11
11
|
import { atLeast, capture, npmInvocation } from './init.mjs';
|
|
@@ -21,60 +21,48 @@ function skillRoots() {
|
|
|
21
21
|
|
|
22
22
|
export function findComateScript(roots = skillRoots()) {
|
|
23
23
|
for (const root of roots) {
|
|
24
|
-
const script = join(root, 'comate', 'scripts', 'comate.
|
|
24
|
+
const script = join(root, 'comate', 'scripts', 'comate.mjs');
|
|
25
25
|
if (existsSync(script)) return script;
|
|
26
26
|
}
|
|
27
27
|
return null;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
// git.exe already on PATH, then the standard install dirs.
|
|
34
|
-
export function findBash(env = process.env, exists = existsSync) {
|
|
35
|
-
if (process.platform !== 'win32') return 'bash';
|
|
36
|
-
|
|
37
|
-
const gitDirs = (env.PATH ?? env.Path ?? '').split(delimiter).filter(Boolean);
|
|
38
|
-
const candidates = [
|
|
39
|
-
// <git>/cmd/git.exe or <git>/mingw64/bin/git.exe -> <git>/bin/bash.exe
|
|
40
|
-
...gitDirs.flatMap((d) =>
|
|
41
|
-
exists(join(d, 'git.exe')) ? [resolve(d, '..', 'bin', 'bash.exe'), resolve(d, '..', '..', 'bin', 'bash.exe')] : [],
|
|
42
|
-
),
|
|
43
|
-
join(env.ProgramFiles ?? 'C:\\Program Files', 'Git', 'bin', 'bash.exe'),
|
|
44
|
-
join(env['ProgramFiles(x86)'] ?? 'C:\\Program Files (x86)', 'Git', 'bin', 'bash.exe'),
|
|
45
|
-
join(env.LOCALAPPDATA ?? '', 'Programs', 'Git', 'bin', 'bash.exe'),
|
|
46
|
-
];
|
|
47
|
-
return candidates.find(exists) ?? null;
|
|
48
|
-
}
|
|
30
|
+
// Installed copy first (the one the agent loads); the package's own copy only
|
|
31
|
+
// when nothing is installed yet, so `comate status` still works right after npm i.
|
|
32
|
+
const scriptOrBundled = () => findComateScript() ?? [join(defaultPkgRoot(), 'skills', 'comate', 'scripts', 'comate.mjs')].find(existsSync) ?? null;
|
|
49
33
|
|
|
50
|
-
|
|
51
|
-
|
|
34
|
+
// `comate status` / `comate import-specs`: run the same state machine the agent uses.
|
|
35
|
+
export function forward(command, argv) {
|
|
36
|
+
const script = scriptOrBundled();
|
|
52
37
|
if (!script) {
|
|
53
|
-
console.error('
|
|
38
|
+
console.error('找不到 comate 脚本。先运行: comate init');
|
|
39
|
+
return 1;
|
|
40
|
+
}
|
|
41
|
+
const { status, error } = spawnSync(process.execPath, [script, command, ...argv], { stdio: 'inherit' });
|
|
42
|
+
if (error) {
|
|
43
|
+
console.error(`无法执行 ${script}:${error.message}`);
|
|
54
44
|
return 1;
|
|
55
45
|
}
|
|
46
|
+
return status ?? 1;
|
|
47
|
+
}
|
|
56
48
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
49
|
+
export function doctor(argv) {
|
|
50
|
+
const script = scriptOrBundled();
|
|
51
|
+
if (!script) {
|
|
52
|
+
console.error('找不到已安装的 comate。先运行: comate init');
|
|
60
53
|
return 1;
|
|
61
54
|
}
|
|
62
55
|
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
const skillsRoot = join(script, '..', '..', '..');
|
|
66
|
-
const { status, error } = spawnSync(bash, [script, 'doctor', ...argv], {
|
|
67
|
-
cwd: skillsRoot,
|
|
68
|
-
stdio: 'inherit',
|
|
69
|
-
});
|
|
56
|
+
// Same node that runs this CLI — no shell, no bash, works the same on Windows.
|
|
57
|
+
const { status, error } = spawnSync(process.execPath, [script, 'doctor', ...argv], { stdio: 'inherit' });
|
|
70
58
|
if (error) {
|
|
71
|
-
console.error(`无法执行
|
|
59
|
+
console.error(`无法执行 ${script}:${error.message}`);
|
|
72
60
|
return 1;
|
|
73
61
|
}
|
|
74
62
|
|
|
75
|
-
// ccusage is a
|
|
76
|
-
//
|
|
77
|
-
//
|
|
63
|
+
// ccusage is a dependency of the npm CLI (for `comate usage`), not of the
|
|
64
|
+
// skill script, so it is checked here. A miss is a warning, never a
|
|
65
|
+
// failure: usage falls back to `npx ccusage@latest`, so it still works.
|
|
78
66
|
reportCcusage();
|
|
79
67
|
|
|
80
68
|
// Version check is the only place a user learns a newer comate exists: the
|