@house365/comate 0.2.6 → 0.2.8
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 +9 -0
- package/bin/init-run.mjs +36 -17
- package/bin/spinner.mjs +28 -0
- package/docs/COMATE_MANUAL.md +18 -7
- package/package.json +1 -1
- package/skills/comate/SKILL.md +1 -1
- package/skills/comate/reference/prerequisites.md +8 -6
package/README.md
CHANGED
|
@@ -41,6 +41,15 @@ skills 装到用户级(`~/.agents/skills`),装一次所有项目共用;`
|
|
|
41
41
|
|
|
42
42
|
装完输入 `/comate` 开始使用,`comate doctor` 可自检。
|
|
43
43
|
|
|
44
|
+
## 更新
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npm install -g @house365/comate@latest
|
|
48
|
+
cd your-project && comate init
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
两步都要跑:`npm` 只换 CLI 本身,skills 是 `comate init` 铺到 `~/.agents/skills` 的,npm 不管。这里的 `@latest` 不能省——本地已装时,不带 tag 的 `npm install -g` 可能认为已满足而不去 registry 取新版。
|
|
52
|
+
|
|
44
53
|
## 用法
|
|
45
54
|
|
|
46
55
|
输入 `/comate` 自动探测当前阶段并分派,或直接调用某个阶段 skill。状态记录在每个 change 的 `openspec/changes/<name>/.comate.yaml` 中,支持上下文压缩后断点恢复。
|
package/bin/init-run.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// The `init` flow: install whatever the current project is missing.
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
2
3
|
import { existsSync, readFileSync } from 'node:fs';
|
|
3
4
|
import { join, resolve } from 'node:path';
|
|
4
5
|
|
|
@@ -54,19 +55,13 @@ export async function init(pkgRoot) {
|
|
|
54
55
|
return 1;
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
// routes `comate` through a comate.ps1 shim that makes stdout a pipe, where
|
|
59
|
-
// \r does not overwrite — every frame would stay on screen. A line per step
|
|
60
|
-
// shows progress in both a terminal and a pipe.
|
|
61
|
-
console.log('\nInitializing…');
|
|
62
|
-
const step = (name) => process.stdout.write(` ${name}\n`);
|
|
58
|
+
const stopSpinner = startSpinner('Initializing…');
|
|
63
59
|
|
|
64
60
|
// 1. OpenSpec CLI — a PATH command, so always global.
|
|
65
61
|
const os = openSpecState();
|
|
66
62
|
if (os.status === 'ready') {
|
|
67
63
|
results.push(['OpenSpec CLI', 'skipped', `已安装 ${os.version}`]);
|
|
68
64
|
} else {
|
|
69
|
-
step('OpenSpec CLI');
|
|
70
65
|
const r = run(
|
|
71
66
|
npmInvocation(['install', '-g', '@fission-ai/openspec@latest']),
|
|
72
67
|
NPM_TIMEOUT_MS,
|
|
@@ -89,7 +84,6 @@ export async function init(pkgRoot) {
|
|
|
89
84
|
if (superpowersInstalled('global') || superpowersInstalled('project')) {
|
|
90
85
|
results.push(['Superpowers', 'skipped', '已安装']);
|
|
91
86
|
} else {
|
|
92
|
-
step('Superpowers');
|
|
93
87
|
const r = run(
|
|
94
88
|
skillsInvocation(pkgRoot, ['add', 'obra/superpowers', '-g', '-y']),
|
|
95
89
|
SKILLS_TIMEOUT_MS,
|
|
@@ -106,7 +100,6 @@ export async function init(pkgRoot) {
|
|
|
106
100
|
// 3. comate itself. The skills CLI reports per-agent failures without ever
|
|
107
101
|
// setting a non-zero exit code, and we swallow its output — so a zero status
|
|
108
102
|
// is not evidence the skill landed. Check the file.
|
|
109
|
-
step('comate skills');
|
|
110
103
|
const comateArgs = ['add', pkgRoot, '--skill', '*', '-g', '-y'];
|
|
111
104
|
const r = run(skillsInvocation(pkgRoot, comateArgs), SKILLS_TIMEOUT_MS, { quiet: true });
|
|
112
105
|
const landed = existsSync(join(home, '.agents', 'skills', 'comate', 'SKILL.md'));
|
|
@@ -122,7 +115,6 @@ export async function init(pkgRoot) {
|
|
|
122
115
|
if (existsSync('openspec')) {
|
|
123
116
|
results.push(['openspec/', 'skipped', '已存在']);
|
|
124
117
|
} else {
|
|
125
|
-
step('openspec/ structure');
|
|
126
118
|
// --tools is not optional in practice: openspec derives the tool list by
|
|
127
119
|
// sniffing existing agent config dirs, so a fresh project (no .claude etc.)
|
|
128
120
|
// aborts with "No tools detected and no --tools flag provided". comate's
|
|
@@ -140,13 +132,39 @@ export async function init(pkgRoot) {
|
|
|
140
132
|
results.push(['openspec/', r2.ok ? 'installed' : 'failed', r2.ok ? '' : r2.reason, r2.output]);
|
|
141
133
|
}
|
|
142
134
|
|
|
143
|
-
|
|
135
|
+
stopSpinner();
|
|
136
|
+
return report(results);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// The spinner runs in its own process because every step above is a synchronous
|
|
140
|
+
// spawnSync — an interval on this thread would never fire. In a pipe \r does not
|
|
141
|
+
// overwrite, so animating there would leave every frame on screen; print one
|
|
142
|
+
// static line instead.
|
|
143
|
+
function startSpinner(label) {
|
|
144
|
+
if (!process.stdout.isTTY) {
|
|
145
|
+
console.log(`\n${label}`);
|
|
146
|
+
return () => {};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const child = spawn(process.execPath, [join(import.meta.dirname, 'spinner.mjs'), label], {
|
|
150
|
+
stdio: ['ignore', 'inherit', 'ignore'],
|
|
151
|
+
});
|
|
152
|
+
let stopped = false;
|
|
153
|
+
return () => {
|
|
154
|
+
if (stopped) return;
|
|
155
|
+
stopped = true;
|
|
156
|
+
child.kill();
|
|
157
|
+
// The parent erases the line, not the child: on Windows SIGTERM is not a
|
|
158
|
+
// real signal — Node terminates the process outright, so a handler in the
|
|
159
|
+
// child never runs and its last frame would sit under the logo.
|
|
160
|
+
process.stdout.write(`\r${' '.repeat(label.length + 6)}\r`);
|
|
161
|
+
};
|
|
144
162
|
}
|
|
145
163
|
|
|
146
164
|
// Success is one screen: the wordmark and where things landed. The per-item
|
|
147
165
|
// breakdown only earns its space when something failed, and then it carries the
|
|
148
166
|
// reason — a bare "失败" would leave the user with nowhere to go.
|
|
149
|
-
function report(results
|
|
167
|
+
function report(results) {
|
|
150
168
|
const failed = results.filter(([, s]) => s === 'failed');
|
|
151
169
|
if (failed.length > 0) {
|
|
152
170
|
console.error('\n安装失败\n');
|
|
@@ -164,9 +182,7 @@ function report(results, { home, cwd }) {
|
|
|
164
182
|
}
|
|
165
183
|
|
|
166
184
|
console.log(banner(pkgVersion()));
|
|
167
|
-
console.log(
|
|
168
|
-
console.log(` openspec ${join(cwd, 'openspec')}`);
|
|
169
|
-
console.log('\n 输入 /comate 开始使用,comate doctor 可自检\n');
|
|
185
|
+
console.log(' Type /comate in your agent to start, or run comate doctor\n');
|
|
170
186
|
return 0;
|
|
171
187
|
}
|
|
172
188
|
|
|
@@ -204,13 +220,16 @@ export function banner(version, { ci = isCI() } = {}) {
|
|
|
204
220
|
'╚██████╗╚██████╔╝██║ ╚═╝ ██║██║ ██║ ██║ ███████╗',
|
|
205
221
|
' ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚══════╝',
|
|
206
222
|
];
|
|
207
|
-
|
|
223
|
+
// #ed6d00 as a 24-bit SGR sequence. Truecolor is not universal, but the two
|
|
224
|
+
// terminals that matter here (Windows Terminal, VS Code) both support it, and
|
|
225
|
+
// one that doesn't degrades to its nearest palette entry rather than breaking.
|
|
226
|
+
const brand = (s) => (process.env.NO_COLOR ? s : `\x1B[38;2;237;109;0m${s}\x1B[0m`);
|
|
208
227
|
const dim = (s) => (process.env.NO_COLOR ? s : `\x1B[2m${s}\x1B[0m`);
|
|
209
228
|
return [
|
|
210
229
|
'',
|
|
211
230
|
// Trailing padding keeps the source rows aligned; strip it so the colour
|
|
212
231
|
// reset doesn't sit behind spaces the terminal may highlight on select.
|
|
213
|
-
...art.map((line) => ` ${
|
|
232
|
+
...art.map((line) => ` ${brand(line.replace(/\s+$/, ''))}`),
|
|
214
233
|
'',
|
|
215
234
|
` ${dim(`${tag} - AI coding almost there!`)}`,
|
|
216
235
|
'',
|
package/bin/spinner.mjs
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The init spinner, as its own process.
|
|
3
|
+
//
|
|
4
|
+
// It cannot run on init's main thread: every install step is a synchronous
|
|
5
|
+
// spawnSync, which blocks the event loop, so an interval would not fire and the
|
|
6
|
+
// frame would sit frozen for the whole install — worse than plain text.
|
|
7
|
+
//
|
|
8
|
+
// Animating means redrawing with \r, which only overwrites on a real terminal.
|
|
9
|
+
// In a pipe every frame would stay on screen, so there the parent prints a
|
|
10
|
+
// static line instead and never starts this process.
|
|
11
|
+
const FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
12
|
+
const INTERVAL_MS = 80;
|
|
13
|
+
|
|
14
|
+
const label = process.argv[2] ?? 'Initializing…';
|
|
15
|
+
let i = 0;
|
|
16
|
+
|
|
17
|
+
process.stdout.write('\n');
|
|
18
|
+
const timer = setInterval(() => {
|
|
19
|
+
process.stdout.write(`\r ${FRAMES[i++ % FRAMES.length]} ${label}`);
|
|
20
|
+
}, INTERVAL_MS);
|
|
21
|
+
|
|
22
|
+
// No cleanup handler here on purpose: on Windows SIGTERM is not a real signal,
|
|
23
|
+
// Node terminates the process outright and a handler would never run. The parent
|
|
24
|
+
// erases the line after killing us, which works on every platform.
|
|
25
|
+
//
|
|
26
|
+
// timer is the only thing holding the loop open, so nothing else is needed to
|
|
27
|
+
// keep animating until that kill arrives.
|
|
28
|
+
void timer;
|
package/docs/COMATE_MANUAL.md
CHANGED
|
@@ -64,6 +64,13 @@ comate 是一个规约驱动、AI 辅助的开发编排器。它将 **OpenSpec**
|
|
|
64
64
|
|
|
65
65
|
## 2. 安装与前置条件
|
|
66
66
|
|
|
67
|
+
```bash
|
|
68
|
+
npm install -g @house365/comate
|
|
69
|
+
cd your-project && comate init
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`init` 会装好下面 2.2–2.4 的全部内容。本节余下部分用于排查:init 报某项失败时,对照确认要装什么、怎么自查。
|
|
73
|
+
|
|
67
74
|
### 2.1 运行环境
|
|
68
75
|
|
|
69
76
|
| 依赖 | 要求 | 检查方式 |
|
|
@@ -79,7 +86,9 @@ comate 是一个规约驱动、AI 辅助的开发编排器。它将 **OpenSpec**
|
|
|
79
86
|
|
|
80
87
|
```bash
|
|
81
88
|
npm install -g @fission-ai/openspec@latest
|
|
82
|
-
|
|
89
|
+
# --tools 必填:openspec 靠探测已有 agent 配置目录决定写哪些 tool 文件,
|
|
90
|
+
# 干净项目里探测不到会直接报 No tools detected 退出
|
|
91
|
+
cd <project-root> && openspec init . --tools none
|
|
83
92
|
openspec list --json # 验证安装
|
|
84
93
|
```
|
|
85
94
|
|
|
@@ -89,7 +98,7 @@ comate 使用以下 OpenSpec 能力(以技能形式调用):`openspec-explo
|
|
|
89
98
|
|
|
90
99
|
处理技术设计/规划/执行/收尾。comate 的 design、build 和 verify 阶段依赖它。
|
|
91
100
|
|
|
92
|
-
|
|
101
|
+
`comate init` 已用 `skills add obra/superpowers -g` 装到用户级。手动补装同理。确认以下技能可加载:
|
|
93
102
|
|
|
94
103
|
- `superpowers:brainstorming`
|
|
95
104
|
- `superpowers:writing-plans`
|
|
@@ -102,7 +111,9 @@ Superpowers 是一个技能集。按你的平台约定安装。确认以下技
|
|
|
102
111
|
|
|
103
112
|
### 2.4 comate 本身
|
|
104
113
|
|
|
105
|
-
|
|
114
|
+
comate 以 npm 包分发(`npm install -g @house365/comate`),`comate init` 通过 skills CLI 装到用户级 `~/.agents/skills`,一次装完所有项目共用,支持 Claude Code、Codex、Cursor 等 70+ agent。
|
|
115
|
+
|
|
116
|
+
采用扁平布局——每个 phase 是顶层技能目录,而非 `comate/<phase>/` 嵌套。部分 agent(含 Claude Code)只发现顶层目录,扁平是共同可用的最小公倍数:
|
|
106
117
|
|
|
107
118
|
```
|
|
108
119
|
skills/
|
|
@@ -183,8 +194,8 @@ skills/
|
|
|
183
194
|
|
|
184
195
|
| 场景 | 处理方式 |
|
|
185
196
|
|----------|----------|
|
|
186
|
-
| `openspec list --json` 失败 | 检查 openspec 安装,提示 `openspec init` |
|
|
187
|
-
| 子技能不可用 |
|
|
197
|
+
| `openspec list --json` 失败 | 检查 openspec 安装,提示 `openspec init . --tools none` |
|
|
198
|
+
| 子技能不可用 | 停止流程,提示运行 `comate init` 补装 |
|
|
188
199
|
| `.comate.yaml` 损坏或缺失 | 以文件状态为真相源,用 `state set` 修复后继续 |
|
|
189
200
|
| 构建/测试失败 | 回到 build 阶段修复,不要进入 verify |
|
|
190
201
|
| 变更目录结构不完整 | 按 comate-open 产出物要求补全缺失文件 |
|
|
@@ -542,8 +553,8 @@ bash comate/scripts/comate.sh status # 所有活动变更状态
|
|
|
542
553
|
| Guard 持续报告 isolation/build_mode 未设置 | 断点恢复时未填写 | 返回 build 阶段完成设置 |
|
|
543
554
|
| 验证失败后无法推进 | verify_result: fail | 用户先选择修复方案,智能体执行 `state transition <name> verify-fail` 后返回 build |
|
|
544
555
|
| 变更目录结构不完整 | 流程中断 | 按 comate-open 产出物要求补全 |
|
|
545
|
-
| `openspec list --json` 失败 | openspec 未安装或未初始化 | 运行 `openspec init` |
|
|
546
|
-
| 子技能不可用 | Superpowers 未安装 |
|
|
556
|
+
| `openspec list --json` 失败 | openspec 未安装或未初始化 | 运行 `comate init`,或 `openspec init . --tools none` |
|
|
557
|
+
| 子技能不可用 | Superpowers 未安装 | 运行 `comate init` 补装 |
|
|
547
558
|
| bash 版本过低 | bash < 4(无关联数组) | Windows:Git Bash/WSL;macOS:`brew install bash` |
|
|
548
559
|
| .sh 文件包含 CRLF | git 配置问题 | 仓库有 `.gitattributes` 强制 `eol=lf`;如已损坏,使用 `dos2unix` |
|
|
549
560
|
| 脏工作树无法推进 | 未遵循 dirty-worktree 协议 | 按协议归属,暂停并询问用户 |
|
package/package.json
CHANGED
package/skills/comate/SKILL.md
CHANGED
|
@@ -75,7 +75,7 @@ agent 做决策只需读本节,其余参见末尾「参考附录」。决策
|
|
|
75
75
|
|
|
76
76
|
| 场景 | 处理 |
|
|
77
77
|
|------|------|
|
|
78
|
-
| `openspec list --json` 失败 | 检查 openspec 是否安装,提示运行 `
|
|
78
|
+
| `openspec list --json` 失败 | 检查 openspec 是否安装,提示运行 `comate init` |
|
|
79
79
|
| 子 skill 不可用 | 停止流程,提示安装或启用对应 skill |
|
|
80
80
|
| `.comate.yaml` 损坏或缺失 | 以文件状态为真相源,用 `bash "$COMATE" state set` 修正后继续 |
|
|
81
81
|
| 构建/测试失败 | 回 build 阶段修复,不进入 verify |
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
规范路径:`comate/reference/prerequisites.md`
|
|
4
4
|
|
|
5
|
-
comate
|
|
5
|
+
`comate init` 会自动装好 OpenSpec CLI、Superpowers 和 comate 自身,正常情况下不需要手动执行本清单。清单保留下来用于排查:init 报某项失败时,对照这里确认要装什么、怎么自查、怎么补。
|
|
6
6
|
|
|
7
|
-
>
|
|
7
|
+
> 一键自查:`comate doctor`(或直接 `bash comate/scripts/comate.sh doctor`)。它会检查下列大部分项目并给出可执行提示。
|
|
8
8
|
|
|
9
9
|
## 1. 运行环境
|
|
10
10
|
|
|
@@ -25,10 +25,10 @@ comate 不附带安装器:OpenSpec 与 Superpowers 需要**手动安装**,co
|
|
|
25
25
|
npm install -g @fission-ai/openspec@latest
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
初始化(在项目根目录)。`comate init` 已经做过这一步,手动补做时需要 `--tools`:openspec 靠探测已有的 agent 配置目录决定写哪些 tool 文件,干净项目里探测不到会直接报 `No tools detected` 退出。
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
|
-
openspec init
|
|
31
|
+
openspec init . --tools none
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
自查:
|
|
@@ -44,7 +44,7 @@ comate 用到的 OpenSpec 能力(以 skill 形式调用):`openspec-explore
|
|
|
44
44
|
|
|
45
45
|
负责技术设计 / 计划 / 执行 / 收尾。comate 的 design / build / verify 阶段依赖它。
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
`comate init` 已用 `skills add obra/superpowers -g` 装到用户级。手动补装同理。安装后确认下列 skill 可加载:
|
|
48
48
|
|
|
49
49
|
- `superpowers:brainstorming`
|
|
50
50
|
- `superpowers:writing-plans`
|
|
@@ -58,7 +58,9 @@ Superpowers 是一组 skill,按你所用平台的约定安装到 skills 目录
|
|
|
58
58
|
|
|
59
59
|
## 4. comate 自身
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
comate 以 npm 包分发(`npm install -g @house365/comate`),`comate init` 通过 skills CLI 装到用户级 `~/.agents/skills`,一次装完所有项目共用,支持 Claude Code、Codex、Cursor 等 70+ agent。
|
|
62
|
+
|
|
63
|
+
采用**平铺布局**——每个 phase 是顶层 skill 目录,而非 `comate/<phase>/` 嵌套。部分 agent(含 Claude Code)只发现顶层目录,平铺是共同可用的最小公倍数:
|
|
62
64
|
|
|
63
65
|
```
|
|
64
66
|
skills/
|