@house365/comate 0.1.3 → 0.2.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/README.md +7 -25
- package/bin/cli.mjs +9 -11
- package/bin/doctor.mjs +71 -0
- package/bin/init-run.mjs +46 -71
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -25,39 +25,21 @@ open → design → build → verify → archive
|
|
|
25
25
|
## 安装
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
|
|
29
|
-
npx @house365/comate init # 装到 ./.agents/skills/
|
|
28
|
+
npm install -g @house365/comate
|
|
30
29
|
```
|
|
31
30
|
|
|
32
|
-
|
|
31
|
+
到项目目录初始化:
|
|
33
32
|
|
|
34
33
|
```bash
|
|
35
|
-
|
|
34
|
+
cd your-project
|
|
35
|
+
comate init
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
`init`
|
|
38
|
+
`init` 会装好 comate 及其依赖(OpenSpec CLI、Superpowers),并创建 `openspec/` 项目结构。支持 Claude Code、Codex、Cursor 等 70+ agent。可重复执行,已装的自动跳过。
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
skills 装到用户级(`~/.agents/skills`),装一次所有项目共用;`openspec/` 是项目自己的规约,建在当前目录,所以 `init` 需要在项目目录下运行。
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
npx @house365/comate # 装到当前项目 ./.agents/skills/
|
|
46
|
-
npx @house365/comate -g # 装到用户全局
|
|
47
|
-
npx @house365/comate --list # 只看有哪些 skill,不安装
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
需要同时创建 `openspec/` 项目结构时加 `--openspec-init`。
|
|
51
|
-
|
|
52
|
-
支持 Claude Code、Codex、Cursor 等 70+ agent(底层复用 [`skills`](https://www.npmjs.com/package/skills) CLI,自动探测当前 agent)。
|
|
53
|
-
|
|
54
|
-
装完跑一次健康检查:
|
|
55
|
-
|
|
56
|
-
```bash
|
|
57
|
-
bash .agents/skills/comate/scripts/comate.sh doctor
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
依赖详情见 [docs/COMATE_MANUAL.md](docs/COMATE_MANUAL.md) 第 2 节。
|
|
42
|
+
装完输入 `/comate` 开始使用,`comate doctor` 可自检。
|
|
61
43
|
|
|
62
44
|
## 用法
|
|
63
45
|
|
package/bin/cli.mjs
CHANGED
|
@@ -13,24 +13,22 @@ const args = process.argv.slice(2);
|
|
|
13
13
|
|
|
14
14
|
if (args[0] === 'init') {
|
|
15
15
|
const { init } = await import('./init-run.mjs');
|
|
16
|
-
process.exit(await init(pkgRoot
|
|
16
|
+
process.exit(await init(pkgRoot));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (args[0] === 'doctor') {
|
|
20
|
+
const { doctor } = await import('./doctor.mjs');
|
|
21
|
+
process.exit(doctor(args.slice(1)));
|
|
17
22
|
}
|
|
18
23
|
|
|
19
24
|
if (args[0] === '--help' || args[0] === '-h') {
|
|
20
25
|
console.log(`comate — OpenSpec + Superpowers 规约驱动的开发编排器
|
|
21
26
|
|
|
22
27
|
用法:
|
|
23
|
-
comate
|
|
24
|
-
|
|
25
|
-
项目安装装到当前目录,执行前会打印完整路径并确认这像个项目目录。
|
|
26
|
-
-g, --global 安装到用户全局目录 (默认: 当前项目)
|
|
27
|
-
--openspec-init 同时运行 openspec init 创建项目结构
|
|
28
|
-
-f, --force 跳过目录检查,就装在当前目录
|
|
29
|
-
|
|
30
|
-
comate-skills [add|list|remove|update ...]
|
|
31
|
-
直接透传给 skills CLI。不带子命令时安装本包全部 skill。
|
|
28
|
+
comate init 安装 comate 和依赖到用户级,并在当前项目创建 openspec/
|
|
29
|
+
comate doctor 健康检查
|
|
32
30
|
|
|
33
|
-
|
|
31
|
+
装好后在 agent 中输入 /comate 开始使用。`);
|
|
34
32
|
process.exit(0);
|
|
35
33
|
}
|
|
36
34
|
|
package/bin/doctor.mjs
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// `comate doctor` — run the installed comate.sh health check.
|
|
2
|
+
//
|
|
3
|
+
// ponytail: comate.sh already implements every check. This only locates the
|
|
4
|
+
// installed copy so the user doesn't have to remember the path.
|
|
5
|
+
import { spawnSync } from 'node:child_process';
|
|
6
|
+
import { existsSync } from 'node:fs';
|
|
7
|
+
import { delimiter, join, resolve } from 'node:path';
|
|
8
|
+
|
|
9
|
+
// Where the skills CLI puts things. `init` installs user-level, but a project
|
|
10
|
+
// copy shadows it for the agent, so check cwd first and report on the same one
|
|
11
|
+
// the agent would load.
|
|
12
|
+
function skillRoots() {
|
|
13
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? '';
|
|
14
|
+
const dirs = ['.agents/skills', '.claude/skills', '.cursor/skills', '.codex/skills'];
|
|
15
|
+
return [...dirs.map((d) => join(process.cwd(), d)), ...dirs.map((d) => join(home, d))];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function findComateScript(roots = skillRoots()) {
|
|
19
|
+
for (const root of roots) {
|
|
20
|
+
const script = join(root, 'comate', 'scripts', 'comate.sh');
|
|
21
|
+
if (existsSync(script)) return script;
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// On Windows, bare `bash` usually resolves to System32\bash.exe — the WSL
|
|
27
|
+
// launcher, which cannot open `D:\...` paths (it eats the backslashes and
|
|
28
|
+
// reports "No such file or directory"). Find Git's bash instead, next to the
|
|
29
|
+
// git.exe already on PATH, then the standard install dirs.
|
|
30
|
+
export function findBash(env = process.env, exists = existsSync) {
|
|
31
|
+
if (process.platform !== 'win32') return 'bash';
|
|
32
|
+
|
|
33
|
+
const gitDirs = (env.PATH ?? env.Path ?? '').split(delimiter).filter(Boolean);
|
|
34
|
+
const candidates = [
|
|
35
|
+
// <git>/cmd/git.exe or <git>/mingw64/bin/git.exe -> <git>/bin/bash.exe
|
|
36
|
+
...gitDirs.flatMap((d) =>
|
|
37
|
+
exists(join(d, 'git.exe')) ? [resolve(d, '..', 'bin', 'bash.exe'), resolve(d, '..', '..', 'bin', 'bash.exe')] : [],
|
|
38
|
+
),
|
|
39
|
+
join(env.ProgramFiles ?? 'C:\\Program Files', 'Git', 'bin', 'bash.exe'),
|
|
40
|
+
join(env['ProgramFiles(x86)'] ?? 'C:\\Program Files (x86)', 'Git', 'bin', 'bash.exe'),
|
|
41
|
+
join(env.LOCALAPPDATA ?? '', 'Programs', 'Git', 'bin', 'bash.exe'),
|
|
42
|
+
];
|
|
43
|
+
return candidates.find(exists) ?? null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function doctor(argv) {
|
|
47
|
+
const script = findComateScript();
|
|
48
|
+
if (!script) {
|
|
49
|
+
console.error('找不到已安装的 comate。先运行: comate init');
|
|
50
|
+
return 1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const bash = findBash();
|
|
54
|
+
if (!bash) {
|
|
55
|
+
console.error('找不到 bash — comate 的脚本需要 bash。请安装 Git for Windows。');
|
|
56
|
+
return 1;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// comate.sh resolves sibling skills relative to the skills root, so run it
|
|
60
|
+
// from there rather than from wherever the user happens to be.
|
|
61
|
+
const skillsRoot = join(script, '..', '..', '..');
|
|
62
|
+
const { status, error } = spawnSync(bash, [script, 'doctor', ...argv], {
|
|
63
|
+
cwd: skillsRoot,
|
|
64
|
+
stdio: 'inherit',
|
|
65
|
+
});
|
|
66
|
+
if (error) {
|
|
67
|
+
console.error(`无法执行 bash (${bash}) — comate 的脚本需要 bash。${error.message}`);
|
|
68
|
+
return 1;
|
|
69
|
+
}
|
|
70
|
+
return status ?? 1;
|
|
71
|
+
}
|
package/bin/init-run.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// The `init` flow:
|
|
1
|
+
// The `init` flow: install whatever the current project is missing.
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
3
|
import { join, resolve } from 'node:path';
|
|
4
4
|
|
|
@@ -13,16 +13,12 @@ import {
|
|
|
13
13
|
superpowersInstalled,
|
|
14
14
|
} from './init.mjs';
|
|
15
15
|
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
// A project install lands in cwd, and `npx` runs wherever the user happens to
|
|
23
|
-
// be — so cwd is a guess, not a decision. Report it, and refuse the two cases
|
|
24
|
-
// that are almost certainly a mistake: the home directory (that's what -g is
|
|
25
|
-
// for) and a directory with no project marker at all.
|
|
16
|
+
// `comate init` — no flags. Skills go user-level (~/.agents/skills), matching how
|
|
17
|
+
// the CLI itself is installed (npm i -g): one copy, every project sees it.
|
|
18
|
+
//
|
|
19
|
+
// openspec/ is still per-project — it holds the project's own specs — so cwd
|
|
20
|
+
// must be a project. Refuse the two cases that are almost certainly a mistake:
|
|
21
|
+
// the home directory, and a directory with no project marker at all.
|
|
26
22
|
const PROJECT_MARKERS = [
|
|
27
23
|
'.git',
|
|
28
24
|
'package.json',
|
|
@@ -44,44 +40,25 @@ export function inspectTarget(dir, home) {
|
|
|
44
40
|
return marker ? { kind: 'project', marker } : { kind: 'bare' };
|
|
45
41
|
}
|
|
46
42
|
|
|
47
|
-
export async function init(pkgRoot
|
|
48
|
-
const scope = resolveScope(argv);
|
|
49
|
-
const withOpenSpecInit = argv.includes('--openspec-init');
|
|
50
|
-
const force = argv.includes('-f') || argv.includes('--force');
|
|
43
|
+
export async function init(pkgRoot) {
|
|
51
44
|
const results = [];
|
|
52
|
-
|
|
53
45
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? '';
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
comate-skills init -g
|
|
66
|
-
|
|
67
|
-
确实要装在这里,加 --force。`);
|
|
68
|
-
return 1;
|
|
69
|
-
}
|
|
70
|
-
if (target.kind === 'bare' && !force) {
|
|
71
|
-
console.error(`
|
|
72
|
-
当前目录看不出是个项目(没有 .git / package.json / pyproject.toml 等标志)。
|
|
73
|
-
comate 会把 skill 装进上面这个路径,先确认这是你要的目录:
|
|
74
|
-
|
|
75
|
-
cd <你的项目目录> && npx @house365/comate init # 换个目录
|
|
76
|
-
npx @house365/comate init -g # 装到全局,所有项目可用
|
|
77
|
-
npx @house365/comate init --force # 就装在这里`);
|
|
78
|
-
return 1;
|
|
79
|
-
}
|
|
80
|
-
if (target.kind === 'project') console.log(`检测到项目标志: ${target.marker}`);
|
|
81
|
-
console.log('');
|
|
46
|
+
const cwd = process.cwd();
|
|
47
|
+
|
|
48
|
+
const target = inspectTarget(cwd, home);
|
|
49
|
+
if (target.kind !== 'project') {
|
|
50
|
+
console.error(
|
|
51
|
+
target.kind === 'home'
|
|
52
|
+
? '\n这是主目录,请在项目目录下运行 comate init。'
|
|
53
|
+
: '\n当前目录不像项目(无 .git / package.json 等),请在项目目录下运行 comate init。',
|
|
54
|
+
);
|
|
55
|
+
return 1;
|
|
82
56
|
}
|
|
83
57
|
|
|
84
|
-
|
|
58
|
+
console.log(`\nskills 装到 ${join(home, '.agents', 'skills')}(用户级,所有项目共用)`);
|
|
59
|
+
console.log(`openspec/ 建在 ${cwd}\n`);
|
|
60
|
+
|
|
61
|
+
// 1. OpenSpec CLI — a PATH command, so always global.
|
|
85
62
|
const os = openSpecState();
|
|
86
63
|
if (os.status === 'ready') {
|
|
87
64
|
results.push(['OpenSpec CLI', 'skipped', `已安装 ${os.version}`]);
|
|
@@ -100,13 +77,13 @@ comate 会把 skill 装进上面这个路径,先确认这是你要的目录:
|
|
|
100
77
|
}
|
|
101
78
|
}
|
|
102
79
|
|
|
103
|
-
// 2. Superpowers — the skills CLI detects the agent itself.
|
|
104
|
-
|
|
80
|
+
// 2. Superpowers — the skills CLI detects the agent itself. A pre-existing
|
|
81
|
+
// project-level copy also counts: reinstalling globally would just shadow it.
|
|
82
|
+
if (superpowersInstalled('global') || superpowersInstalled('project')) {
|
|
105
83
|
results.push(['Superpowers', 'skipped', '已安装']);
|
|
106
84
|
} else {
|
|
107
|
-
console.log('\n→ 安装 Superpowers (skills add obra/superpowers)');
|
|
108
|
-
const
|
|
109
|
-
const r = run(skillsInvocation(pkgRoot, args), SKILLS_TIMEOUT_MS);
|
|
85
|
+
console.log('\n→ 安装 Superpowers (skills add obra/superpowers -g)');
|
|
86
|
+
const r = run(skillsInvocation(pkgRoot, ['add', 'obra/superpowers', '-g', '-y']), SKILLS_TIMEOUT_MS);
|
|
110
87
|
// It clones from GitHub, so a bare exit code hides the usual cause: no
|
|
111
88
|
// network. Say so rather than leaving the user with "exit code 1".
|
|
112
89
|
const note = r.ok
|
|
@@ -117,41 +94,39 @@ comate 会把 skill 装进上面这个路径,先确认这是你要的目录:
|
|
|
117
94
|
|
|
118
95
|
// 3. comate itself.
|
|
119
96
|
console.log('\n→ 安装 comate skills');
|
|
120
|
-
const comateArgs = ['add', pkgRoot, '--skill', '*', '-
|
|
97
|
+
const comateArgs = ['add', pkgRoot, '--skill', '*', '-g', '-y'];
|
|
121
98
|
const r = run(skillsInvocation(pkgRoot, comateArgs), SKILLS_TIMEOUT_MS);
|
|
122
99
|
results.push(['comate', r.ok ? 'installed' : 'failed', r.ok ? '' : r.reason]);
|
|
123
100
|
|
|
124
|
-
// 4. openspec
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
101
|
+
// 4. openspec/ project structure. Not optional: comate's open and archive
|
|
102
|
+
// phases read it, so an install without it cannot actually run. An existing
|
|
103
|
+
// one is left alone, which covers projects that already keep it elsewhere.
|
|
104
|
+
if (existsSync('openspec')) {
|
|
105
|
+
results.push(['openspec 结构', 'skipped', '已存在']);
|
|
106
|
+
} else {
|
|
107
|
+
console.log('\n→ 初始化 openspec/ 项目结构');
|
|
108
|
+
const r2 = run(
|
|
109
|
+
{ command: 'openspec', args: ['init', '.'], shell: process.platform === 'win32' },
|
|
110
|
+
NPM_TIMEOUT_MS,
|
|
111
|
+
);
|
|
112
|
+
results.push(['openspec 结构', r2.ok ? 'installed' : 'failed', r2.ok ? '' : r2.reason]);
|
|
132
113
|
}
|
|
133
114
|
|
|
134
|
-
return report(results
|
|
115
|
+
return report(results);
|
|
135
116
|
}
|
|
136
117
|
|
|
137
|
-
function report(results
|
|
118
|
+
function report(results) {
|
|
138
119
|
const mark = { installed: '✓', skipped: '·', failed: '✗' };
|
|
139
|
-
console.log('
|
|
120
|
+
console.log('');
|
|
140
121
|
for (const [name, status, note] of results) {
|
|
141
|
-
console.log(` ${mark[status]} ${name.padEnd(
|
|
122
|
+
console.log(` ${mark[status]} ${name.padEnd(14)}${note}`);
|
|
142
123
|
}
|
|
143
|
-
console.log('─'.repeat(58));
|
|
144
124
|
|
|
145
125
|
const failed = results.filter(([, s]) => s === 'failed');
|
|
146
126
|
if (failed.length > 0) {
|
|
147
|
-
console.error(`\n${failed.length}
|
|
127
|
+
console.error(`\n${failed.length} 项失败,修好后重跑 comate init。`);
|
|
148
128
|
return 1;
|
|
149
129
|
}
|
|
150
|
-
|
|
151
|
-
// landed in, which is the whole problem with a cwd-relative install.
|
|
152
|
-
const root = scope === 'global' ? (process.env.HOME ?? process.env.USERPROFILE ?? '~') : process.cwd();
|
|
153
|
-
const doctorPath = join(root, '.agents', 'skills', 'comate', 'scripts', 'comate.sh');
|
|
154
|
-
console.log(`\n完成。健康检查: bash "${doctorPath}" doctor`);
|
|
155
|
-
console.log('在 agent 中输入 /comate 开始使用。');
|
|
130
|
+
console.log('\n完成。在 agent 中输入 /comate 开始使用,或跑 comate doctor 自检。');
|
|
156
131
|
return 0;
|
|
157
132
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@house365/comate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "comate —— OpenSpec + Superpowers 规约驱动的 AI 开发编排器(Agent Skills)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"registry": "https://registry.npmjs.org"
|
|
10
10
|
},
|
|
11
11
|
"bin": {
|
|
12
|
+
"comate": "bin/cli.mjs",
|
|
12
13
|
"comate-skills": "bin/cli.mjs"
|
|
13
14
|
},
|
|
14
15
|
"files": [
|