@house365/comate 0.1.2 → 0.1.4
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 -17
- package/bin/cli.mjs +9 -9
- package/bin/doctor.mjs +44 -0
- package/bin/init-run.mjs +64 -32
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -25,31 +25,21 @@ open → design → build → verify → archive
|
|
|
25
25
|
## 安装
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
|
|
29
|
-
npx @house365/comate init -g # 装到用户全局
|
|
28
|
+
npm install -g @house365/comate
|
|
30
29
|
```
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
只装 comate 本身、不碰依赖:
|
|
31
|
+
到项目目录初始化:
|
|
35
32
|
|
|
36
33
|
```bash
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
npx @house365/comate --list # 只看有哪些 skill,不安装
|
|
34
|
+
cd your-project
|
|
35
|
+
comate init
|
|
40
36
|
```
|
|
41
37
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
支持 Claude Code、Codex、Cursor 等 70+ agent(底层复用 [`skills`](https://www.npmjs.com/package/skills) CLI,自动探测当前 agent)。
|
|
45
|
-
|
|
46
|
-
装完跑一次健康检查:
|
|
38
|
+
`init` 会装好 comate 及其依赖(OpenSpec CLI、Superpowers),并创建 `openspec/` 项目结构。支持 Claude Code、Codex、Cursor 等 70+ agent。可重复执行,已装的自动跳过。
|
|
47
39
|
|
|
48
|
-
|
|
49
|
-
bash .agents/skills/comate/scripts/comate.sh doctor
|
|
50
|
-
```
|
|
40
|
+
装完输入 `/comate` 开始使用,`comate doctor` 可自检。
|
|
51
41
|
|
|
52
|
-
|
|
42
|
+
想装到用户全局、所有项目共用,加 `-g`。
|
|
53
43
|
|
|
54
44
|
## 用法
|
|
55
45
|
|
package/bin/cli.mjs
CHANGED
|
@@ -13,22 +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
|
-
-g, --global 安装到用户全局目录 (默认: 当前项目)
|
|
26
|
-
--openspec-init 同时运行 openspec init 创建项目结构
|
|
27
|
-
|
|
28
|
-
comate-skills [add|list|remove|update ...]
|
|
29
|
-
直接透传给 skills CLI。不带子命令时安装本包全部 skill。
|
|
28
|
+
comate init 在当前项目安装 comate、依赖和 openspec/ 结构
|
|
29
|
+
comate doctor 健康检查
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
装好后在 agent 中输入 /comate 开始使用。`);
|
|
32
32
|
process.exit(0);
|
|
33
33
|
}
|
|
34
34
|
|
package/bin/doctor.mjs
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
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 { join } from 'node:path';
|
|
8
|
+
|
|
9
|
+
// Where the skills CLI puts things. The project copy comes first so it wins
|
|
10
|
+
// over a global one left from an earlier `comate -g` install.
|
|
11
|
+
function skillRoots() {
|
|
12
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? '';
|
|
13
|
+
const dirs = ['.agents/skills', '.claude/skills', '.cursor/skills', '.codex/skills'];
|
|
14
|
+
return [...dirs.map((d) => join(process.cwd(), d)), ...dirs.map((d) => join(home, d))];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function findComateScript(roots = skillRoots()) {
|
|
18
|
+
for (const root of roots) {
|
|
19
|
+
const script = join(root, 'comate', 'scripts', 'comate.sh');
|
|
20
|
+
if (existsSync(script)) return script;
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function doctor(argv) {
|
|
26
|
+
const script = findComateScript();
|
|
27
|
+
if (!script) {
|
|
28
|
+
console.error('找不到已安装的 comate。先运行: comate init');
|
|
29
|
+
return 1;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// comate.sh resolves sibling skills relative to the skills root, so run it
|
|
33
|
+
// from there rather than from wherever the user happens to be.
|
|
34
|
+
const skillsRoot = join(script, '..', '..', '..');
|
|
35
|
+
const { status, error } = spawnSync('bash', [script, 'doctor', ...argv], {
|
|
36
|
+
cwd: skillsRoot,
|
|
37
|
+
stdio: 'inherit',
|
|
38
|
+
});
|
|
39
|
+
if (error) {
|
|
40
|
+
console.error(`无法执行 bash — comate 的脚本需要 bash。${error.message}`);
|
|
41
|
+
return 1;
|
|
42
|
+
}
|
|
43
|
+
return status ?? 1;
|
|
44
|
+
}
|
package/bin/init-run.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
// The `init` flow:
|
|
1
|
+
// The `init` flow: install whatever the current project is missing.
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
|
+
import { join, resolve } from 'node:path';
|
|
3
4
|
|
|
4
5
|
import {
|
|
5
6
|
MIN_OPENSPEC,
|
|
@@ -12,20 +13,52 @@ import {
|
|
|
12
13
|
superpowersInstalled,
|
|
13
14
|
} from './init.mjs';
|
|
14
15
|
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
// `comate init` initialises the current project — no flags. Global installs are
|
|
17
|
+
// still reachable through the bare `comate -g` passthrough to the skills CLI.
|
|
18
|
+
//
|
|
19
|
+
// cwd is where the install lands, so refuse the two cases that are almost
|
|
20
|
+
// certainly a mistake: the home directory, and a directory with no project
|
|
21
|
+
// marker at all.
|
|
22
|
+
const PROJECT_MARKERS = [
|
|
23
|
+
'.git',
|
|
24
|
+
'package.json',
|
|
25
|
+
'pyproject.toml',
|
|
26
|
+
'Cargo.toml',
|
|
27
|
+
'go.mod',
|
|
28
|
+
'pom.xml',
|
|
29
|
+
'build.gradle',
|
|
30
|
+
'composer.json',
|
|
31
|
+
'Gemfile',
|
|
32
|
+
'openspec',
|
|
33
|
+
'.agents',
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
export function inspectTarget(dir, home) {
|
|
37
|
+
const normalise = (p) => resolve(p).replace(/[\\/]+$/, '').toLowerCase();
|
|
38
|
+
if (home && normalise(dir) === normalise(home)) return { kind: 'home' };
|
|
39
|
+
const marker = PROJECT_MARKERS.find((m) => existsSync(join(dir, m)));
|
|
40
|
+
return marker ? { kind: 'project', marker } : { kind: 'bare' };
|
|
19
41
|
}
|
|
20
42
|
|
|
21
|
-
export async function init(pkgRoot
|
|
22
|
-
const scope = resolveScope(argv);
|
|
23
|
-
const withOpenSpecInit = argv.includes('--openspec-init');
|
|
43
|
+
export async function init(pkgRoot) {
|
|
24
44
|
const results = [];
|
|
45
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? '';
|
|
46
|
+
const cwd = process.cwd();
|
|
25
47
|
|
|
26
|
-
|
|
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;
|
|
56
|
+
}
|
|
27
57
|
|
|
28
|
-
|
|
58
|
+
console.log(`\n安装到 ${join(cwd, '.agents', 'skills')}\n`);
|
|
59
|
+
|
|
60
|
+
// 1. OpenSpec CLI — invoked as a PATH command, so it installs globally even
|
|
61
|
+
// though the skills themselves go into this project.
|
|
29
62
|
const os = openSpecState();
|
|
30
63
|
if (os.status === 'ready') {
|
|
31
64
|
results.push(['OpenSpec CLI', 'skipped', `已安装 ${os.version}`]);
|
|
@@ -45,12 +78,11 @@ export async function init(pkgRoot, argv) {
|
|
|
45
78
|
}
|
|
46
79
|
|
|
47
80
|
// 2. Superpowers — the skills CLI detects the agent itself.
|
|
48
|
-
if (superpowersInstalled(
|
|
81
|
+
if (superpowersInstalled('project')) {
|
|
49
82
|
results.push(['Superpowers', 'skipped', '已安装']);
|
|
50
83
|
} else {
|
|
51
84
|
console.log('\n→ 安装 Superpowers (skills add obra/superpowers)');
|
|
52
|
-
const
|
|
53
|
-
const r = run(skillsInvocation(pkgRoot, args), SKILLS_TIMEOUT_MS);
|
|
85
|
+
const r = run(skillsInvocation(pkgRoot, ['add', 'obra/superpowers', '-y']), SKILLS_TIMEOUT_MS);
|
|
54
86
|
// It clones from GitHub, so a bare exit code hides the usual cause: no
|
|
55
87
|
// network. Say so rather than leaving the user with "exit code 1".
|
|
56
88
|
const note = r.ok
|
|
@@ -61,39 +93,39 @@ export async function init(pkgRoot, argv) {
|
|
|
61
93
|
|
|
62
94
|
// 3. comate itself.
|
|
63
95
|
console.log('\n→ 安装 comate skills');
|
|
64
|
-
const comateArgs = ['add', pkgRoot, '--skill', '*', '-y'
|
|
96
|
+
const comateArgs = ['add', pkgRoot, '--skill', '*', '-y'];
|
|
65
97
|
const r = run(skillsInvocation(pkgRoot, comateArgs), SKILLS_TIMEOUT_MS);
|
|
66
98
|
results.push(['comate', r.ok ? 'installed' : 'failed', r.ok ? '' : r.reason]);
|
|
67
99
|
|
|
68
|
-
// 4. openspec
|
|
69
|
-
//
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
100
|
+
// 4. openspec/ project structure. Not optional: comate's open and archive
|
|
101
|
+
// phases read it, so an install without it cannot actually run. An existing
|
|
102
|
+
// one is left alone, which covers projects that already keep it elsewhere.
|
|
103
|
+
if (existsSync('openspec')) {
|
|
104
|
+
results.push(['openspec 结构', 'skipped', '已存在']);
|
|
105
|
+
} else {
|
|
106
|
+
console.log('\n→ 初始化 openspec/ 项目结构');
|
|
107
|
+
const r2 = run(
|
|
108
|
+
{ command: 'openspec', args: ['init', '.'], shell: process.platform === 'win32' },
|
|
109
|
+
NPM_TIMEOUT_MS,
|
|
110
|
+
);
|
|
111
|
+
results.push(['openspec 结构', r2.ok ? 'installed' : 'failed', r2.ok ? '' : r2.reason]);
|
|
76
112
|
}
|
|
77
113
|
|
|
78
|
-
return report(results
|
|
114
|
+
return report(results);
|
|
79
115
|
}
|
|
80
116
|
|
|
81
|
-
function report(results
|
|
117
|
+
function report(results) {
|
|
82
118
|
const mark = { installed: '✓', skipped: '·', failed: '✗' };
|
|
83
|
-
console.log('
|
|
119
|
+
console.log('');
|
|
84
120
|
for (const [name, status, note] of results) {
|
|
85
|
-
console.log(` ${mark[status]} ${name.padEnd(
|
|
121
|
+
console.log(` ${mark[status]} ${name.padEnd(14)}${note}`);
|
|
86
122
|
}
|
|
87
|
-
console.log('─'.repeat(58));
|
|
88
123
|
|
|
89
124
|
const failed = results.filter(([, s]) => s === 'failed');
|
|
90
125
|
if (failed.length > 0) {
|
|
91
|
-
console.error(`\n${failed.length}
|
|
126
|
+
console.error(`\n${failed.length} 项失败,修好后重跑 comate init。`);
|
|
92
127
|
return 1;
|
|
93
128
|
}
|
|
94
|
-
|
|
95
|
-
scope === 'global' ? '~/.claude/skills/comate/scripts/comate.sh' : '.agents/skills/comate/scripts/comate.sh';
|
|
96
|
-
console.log(`\n完成。健康检查: bash ${doctorPath} doctor`);
|
|
97
|
-
console.log('在 agent 中输入 /comate 开始使用。');
|
|
129
|
+
console.log('\n完成。在 agent 中输入 /comate 开始使用,或跑 comate doctor 自检。');
|
|
98
130
|
return 0;
|
|
99
131
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@house365/comate",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
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": [
|