@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 CHANGED
@@ -25,31 +25,21 @@ open → design → build → verify → archive
25
25
  ## 安装
26
26
 
27
27
  ```bash
28
- npx @house365/comate init # 装 comate + 依赖到当前项目 ./.agents/skills/
29
- npx @house365/comate init -g # 装到用户全局
28
+ npm install -g @house365/comate
30
29
  ```
31
30
 
32
- `init` 会一并装齐两个依赖(OpenSpec CLI、Superpowers),已装的自动跳过,可重复执行。
33
-
34
- 只装 comate 本身、不碰依赖:
31
+ 到项目目录初始化:
35
32
 
36
33
  ```bash
37
- npx @house365/comate # 装到当前项目 ./.agents/skills/
38
- npx @house365/comate -g # 装到用户全局
39
- npx @house365/comate --list # 只看有哪些 skill,不安装
34
+ cd your-project
35
+ comate init
40
36
  ```
41
37
 
42
- 需要同时创建 `openspec/` 项目结构时加 `--openspec-init`。
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
- ```bash
49
- bash .agents/skills/comate/scripts/comate.sh doctor
50
- ```
40
+ 装完输入 `/comate` 开始使用,`comate doctor` 可自检。
51
41
 
52
- 依赖详情见 [docs/COMATE_MANUAL.md](docs/COMATE_MANUAL.md) 第 2 节。
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, args.slice(1)));
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-skills init [-g] [--openspec-init]
24
- 安装 comate 及依赖 (OpenSpec CLI、Superpowers)。已装的自动跳过,可重复执行。
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
- 安装后在 agent 中输入 /comate 开始使用。`);
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: pick a scope, then install what's missing.
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
- // Same convention as the bare `comate-skills` command: no flag means project,
16
- // -g means global. No prompt — the flag already says it.
17
- export function resolveScope(argv) {
18
- return argv.includes('-g') || argv.includes('--global') ? 'global' : 'project';
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, argv) {
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
- console.log(`\n安装范围: ${scope === 'global' ? '全局' : '项目'}\n`);
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
- // 1. OpenSpec CLI — a PATH command, so global regardless of skill scope.
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(scope)) {
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 args = ['add', 'obra/superpowers', '-y', ...(scope === 'global' ? ['-g'] : [])];
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', ...(scope === 'global' ? ['-g'] : [])];
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 init — opt-in: it writes openspec/ into the user's project and
69
- // edits agent config files, a bigger side effect than the installs above.
70
- if (withOpenSpecInit) {
71
- console.log('\n→ 初始化 OpenSpec 项目结构 (openspec init)');
72
- const r2 = run({ command: 'openspec', args: ['init', '.'], shell: process.platform === 'win32' }, NPM_TIMEOUT_MS);
73
- results.push(['openspec init', r2.ok ? 'installed' : 'failed', r2.ok ? '' : r2.reason]);
74
- } else if (!existsSync('openspec')) {
75
- results.push(['openspec init', 'skipped', '未初始化项目结构,需要时加 --openspec-init']);
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, scope);
114
+ return report(results);
79
115
  }
80
116
 
81
- function report(results, scope) {
117
+ function report(results) {
82
118
  const mark = { installed: '✓', skipped: '·', failed: '✗' };
83
- console.log('\n' + '─'.repeat(58));
119
+ console.log('');
84
120
  for (const [name, status, note] of results) {
85
- console.log(` ${mark[status]} ${name.padEnd(16)} ${status.padEnd(10)} ${note}`);
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} 项失败。修复后可重跑 comate-skills init(已安装的会自动跳过)。`);
126
+ console.error(`\n${failed.length} 项失败,修好后重跑 comate init。`);
92
127
  return 1;
93
128
  }
94
- const doctorPath =
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.2",
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": [