@house365/comate 0.2.4 → 0.2.6
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/bin/init-run.mjs +43 -25
- package/bin/init.mjs +5 -3
- package/package.json +1 -1
package/bin/init-run.mjs
CHANGED
|
@@ -3,7 +3,6 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
3
3
|
import { join, resolve } from 'node:path';
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
|
-
MIN_OPENSPEC,
|
|
7
6
|
NPM_TIMEOUT_MS,
|
|
8
7
|
SKILLS_TIMEOUT_MS,
|
|
9
8
|
npmInvocation,
|
|
@@ -55,21 +54,29 @@ export async function init(pkgRoot) {
|
|
|
55
54
|
return 1;
|
|
56
55
|
}
|
|
57
56
|
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
// ponytail: printed steps, not a \r spinner. npm's Windows global install
|
|
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`);
|
|
60
63
|
|
|
61
64
|
// 1. OpenSpec CLI — a PATH command, so always global.
|
|
62
65
|
const os = openSpecState();
|
|
63
66
|
if (os.status === 'ready') {
|
|
64
67
|
results.push(['OpenSpec CLI', 'skipped', `已安装 ${os.version}`]);
|
|
65
68
|
} else {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
step('OpenSpec CLI');
|
|
70
|
+
const r = run(
|
|
71
|
+
npmInvocation(['install', '-g', '@fission-ai/openspec@latest']),
|
|
72
|
+
NPM_TIMEOUT_MS,
|
|
73
|
+
{ quiet: true },
|
|
74
|
+
);
|
|
69
75
|
if (!r.ok) {
|
|
70
76
|
// An outdated-but-usable CLI is better than a hard failure.
|
|
71
77
|
const usable = os.status === 'outdated';
|
|
72
|
-
|
|
78
|
+
const note = usable ? `升级失败,沿用 ${os.version}` : r.reason;
|
|
79
|
+
results.push(['OpenSpec CLI', usable ? 'skipped' : 'failed', note, usable ? '' : r.output]);
|
|
73
80
|
} else if (openSpecState().status === 'missing') {
|
|
74
81
|
results.push(['OpenSpec CLI', 'failed', 'npm 安装完成但 PATH 中仍找不到 openspec,请重启终端']);
|
|
75
82
|
} else {
|
|
@@ -82,7 +89,7 @@ export async function init(pkgRoot) {
|
|
|
82
89
|
if (superpowersInstalled('global') || superpowersInstalled('project')) {
|
|
83
90
|
results.push(['Superpowers', 'skipped', '已安装']);
|
|
84
91
|
} else {
|
|
85
|
-
|
|
92
|
+
step('Superpowers');
|
|
86
93
|
const r = run(
|
|
87
94
|
skillsInvocation(pkgRoot, ['add', 'obra/superpowers', '-g', '-y']),
|
|
88
95
|
SKILLS_TIMEOUT_MS,
|
|
@@ -93,29 +100,29 @@ export async function init(pkgRoot) {
|
|
|
93
100
|
const note = r.ok
|
|
94
101
|
? ''
|
|
95
102
|
: `${r.reason} — 需要访问 github.com,检查网络/代理后重试`;
|
|
96
|
-
results.push(['Superpowers', r.ok ? 'installed' : 'failed', note]);
|
|
103
|
+
results.push(['Superpowers', r.ok ? 'installed' : 'failed', note, r.output]);
|
|
97
104
|
}
|
|
98
105
|
|
|
99
106
|
// 3. comate itself. The skills CLI reports per-agent failures without ever
|
|
100
107
|
// setting a non-zero exit code, and we swallow its output — so a zero status
|
|
101
108
|
// is not evidence the skill landed. Check the file.
|
|
102
|
-
|
|
109
|
+
step('comate skills');
|
|
103
110
|
const comateArgs = ['add', pkgRoot, '--skill', '*', '-g', '-y'];
|
|
104
111
|
const r = run(skillsInvocation(pkgRoot, comateArgs), SKILLS_TIMEOUT_MS, { quiet: true });
|
|
105
112
|
const landed = existsSync(join(home, '.agents', 'skills', 'comate', 'SKILL.md'));
|
|
106
113
|
if (r.ok && !landed) {
|
|
107
|
-
results.push(['comate', 'failed', `未装到 ${join(home, '.agents', 'skills')}
|
|
114
|
+
results.push(['comate', 'failed', `未装到 ${join(home, '.agents', 'skills')}`]);
|
|
108
115
|
} else {
|
|
109
|
-
results.push(['comate', r.ok ? 'installed' : 'failed', r.ok ? '' : r.reason]);
|
|
116
|
+
results.push(['comate', r.ok ? 'installed' : 'failed', r.ok ? '' : r.reason, r.output]);
|
|
110
117
|
}
|
|
111
118
|
|
|
112
119
|
// 4. openspec/ project structure. Not optional: comate's open and archive
|
|
113
120
|
// phases read it, so an install without it cannot actually run. An existing
|
|
114
121
|
// one is left alone, which covers projects that already keep it elsewhere.
|
|
115
122
|
if (existsSync('openspec')) {
|
|
116
|
-
results.push(['openspec
|
|
123
|
+
results.push(['openspec/', 'skipped', '已存在']);
|
|
117
124
|
} else {
|
|
118
|
-
|
|
125
|
+
step('openspec/ structure');
|
|
119
126
|
// --tools is not optional in practice: openspec derives the tool list by
|
|
120
127
|
// sniffing existing agent config dirs, so a fresh project (no .claude etc.)
|
|
121
128
|
// aborts with "No tools detected and no --tools flag provided". comate's
|
|
@@ -128,27 +135,38 @@ export async function init(pkgRoot) {
|
|
|
128
135
|
shell: process.platform === 'win32',
|
|
129
136
|
},
|
|
130
137
|
NPM_TIMEOUT_MS,
|
|
138
|
+
{ quiet: true },
|
|
131
139
|
);
|
|
132
|
-
results.push(['openspec
|
|
140
|
+
results.push(['openspec/', r2.ok ? 'installed' : 'failed', r2.ok ? '' : r2.reason, r2.output]);
|
|
133
141
|
}
|
|
134
142
|
|
|
135
|
-
return report(results);
|
|
143
|
+
return report(results, { home, cwd });
|
|
136
144
|
}
|
|
137
145
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
console.log(` ${mark[status]} ${name.padEnd(14)}${note}`);
|
|
143
|
-
}
|
|
144
|
-
|
|
146
|
+
// Success is one screen: the wordmark and where things landed. The per-item
|
|
147
|
+
// breakdown only earns its space when something failed, and then it carries the
|
|
148
|
+
// reason — a bare "失败" would leave the user with nowhere to go.
|
|
149
|
+
function report(results, { home, cwd }) {
|
|
145
150
|
const failed = results.filter(([, s]) => s === 'failed');
|
|
146
151
|
if (failed.length > 0) {
|
|
147
|
-
console.error(
|
|
152
|
+
console.error('\n安装失败\n');
|
|
153
|
+
for (const [name, status, note, output] of results) {
|
|
154
|
+
const mark = { installed: '✓', skipped: '·', failed: '✗' }[status];
|
|
155
|
+
console.error(` ${mark} ${name.padEnd(14)}${note}`);
|
|
156
|
+
// The child's own output, indented under the item it belongs to, so a
|
|
157
|
+
// knock-on failure doesn't look like a second unrelated problem.
|
|
158
|
+
if (status === 'failed' && output) {
|
|
159
|
+
for (const line of output.split('\n')) console.error(` ${line.trim()}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
console.error('\n修好后重跑 comate init。');
|
|
148
163
|
return 1;
|
|
149
164
|
}
|
|
165
|
+
|
|
150
166
|
console.log(banner(pkgVersion()));
|
|
151
|
-
console.log('
|
|
167
|
+
console.log(` skills ${join(home, '.agents', 'skills')}`);
|
|
168
|
+
console.log(` openspec ${join(cwd, 'openspec')}`);
|
|
169
|
+
console.log('\n 输入 /comate 开始使用,comate doctor 可自检\n');
|
|
152
170
|
return 0;
|
|
153
171
|
}
|
|
154
172
|
|
package/bin/init.mjs
CHANGED
|
@@ -89,9 +89,11 @@ function run({ command, args, shell }, timeout, { quiet = false } = {}) {
|
|
|
89
89
|
});
|
|
90
90
|
if (error) return { ok: false, reason: error.message };
|
|
91
91
|
if (status !== 0) {
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
// Hand the buffered output back rather than printing it here: the caller
|
|
93
|
+
// knows whether this failure is the root cause or a knock-on effect, and
|
|
94
|
+
// printing both would bury the one line that matters.
|
|
95
|
+
const out = quiet ? ((stdout ?? '') + (stderr ?? '')).trim() : '';
|
|
96
|
+
return { ok: false, reason: `exit code ${String(status)}`, output: out };
|
|
95
97
|
}
|
|
96
98
|
return { ok: true };
|
|
97
99
|
}
|