@house365/comate 0.10.2 → 1.0.2-next.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/LICENSE +21 -21
- package/README.md +104 -64
- package/bin/cli.mjs +197 -190
- package/bin/doctor.mjs +29 -41
- package/bin/init-run.mjs +310 -368
- package/bin/init.mjs +53 -71
- package/bin/postinstall.mjs +56 -56
- package/docs/CHANGELOG-fix-simplification.md +145 -0
- package/docs/COMATE_BETA.md +90 -0
- package/docs/COMATE_MANUAL.md +239 -665
- package/docs/superpowers/plans/2026-10-14-review-fixes.md +48 -0
- package/docs/superpowers/plans/2026-10-14-workflow-quality.md +48 -0
- package/package.json +54 -55
- package/skills/comate/SKILL.md +42 -325
- package/skills/comate/reference/archive.md +50 -0
- package/skills/comate/reference/build.md +67 -0
- package/skills/comate/reference/fix.md +150 -0
- package/skills/comate/reference/open.md +162 -0
- package/skills/comate/reference/verify.md +123 -0
- package/skills/comate/scaffold/comate/README.md +18 -0
- package/skills/{comate-gate/scaffold/docs → comate/scaffold/comate}/architecture/README.md +5 -6
- package/skills/comate/scaffold/comate/comate/config.json +10 -0
- package/skills/comate/scaffold/comate/knowledge-base/README.md +42 -0
- package/skills/{comate-gate/scaffold/docs → comate/scaffold/comate}/knowledge-base/integrations/_TEMPLATE/README.md +2 -2
- package/skills/{comate-gate/scaffold/docs → comate/scaffold/comate}/knowledge-base/integrations/_TEMPLATE/api-snapshot.md +47 -47
- package/skills/{comate-gate/scaffold/docs → comate/scaffold/comate}/knowledge-base/requirements/_templates/PRD.md +4 -4
- package/skills/comate/scripts/comate.mjs +147 -0
- package/skills/comate/scripts/lib/acceptance.mjs +112 -0
- package/skills/comate/scripts/lib/brief.mjs +50 -0
- package/skills/comate/scripts/lib/checks.mjs +178 -0
- package/skills/comate/scripts/lib/cmd-archive.mjs +152 -0
- package/skills/comate/scripts/lib/cmd-decide.mjs +116 -0
- package/skills/comate/scripts/lib/cmd-init.mjs +75 -0
- package/skills/comate/scripts/lib/cmd-loop.mjs +273 -0
- package/skills/comate/scripts/lib/cmd-open.mjs +161 -0
- package/skills/comate/scripts/lib/cmd-status.mjs +121 -0
- package/skills/comate/scripts/lib/common.mjs +85 -0
- package/skills/comate/scripts/lib/docs.mjs +45 -0
- package/skills/comate/scripts/lib/finish.mjs +108 -0
- package/skills/comate/scripts/lib/git.mjs +112 -0
- package/skills/comate/scripts/lib/md.mjs +85 -0
- package/skills/comate/scripts/lib/next.mjs +217 -0
- package/skills/comate/scripts/lib/paths.mjs +96 -0
- package/skills/comate/scripts/lib/render.mjs +46 -0
- package/skills/comate/scripts/lib/spec.mjs +106 -0
- package/skills/comate/scripts/lib/state.mjs +128 -0
- package/skills/comate/scripts/lib/tasks.mjs +53 -0
- package/skills/comate/scripts/lib/templates.mjs +58 -0
- package/skills/comate/scripts/lib/util.mjs +108 -0
- package/skills/comate-kb-integration/SKILL.md +128 -128
- package/skills/comate-kb-integration/scripts/fetch_rendered_doc.py +84 -84
- package/bin/cleanup-duplicate-superpowers.mjs +0 -119
- package/docs/CLEANUP_SUPERPOWERS.md +0 -128
- package/docs/COMATE_BEGINNER_GUIDE.md +0 -188
- package/docs/COMATE_INIT_DIRECTORY_GUIDE.md +0 -201
- package/docs/SUPERPOWERS_FIX_SUMMARY.md +0 -114
- package/skills/comate/reference/decision-points.md +0 -103
- package/skills/comate/reference/dirty-worktree.md +0 -58
- package/skills/comate/reference/prerequisites.md +0 -89
- package/skills/comate/scripts/comate-lib.sh +0 -559
- package/skills/comate/scripts/comate.sh +0 -2147
- package/skills/comate/tests/comate.bats +0 -1019
- package/skills/comate/tests/run.sh +0 -101
- package/skills/comate-archive/SKILL.md +0 -63
- package/skills/comate-build/SKILL.md +0 -278
- package/skills/comate-design/SKILL.md +0 -178
- package/skills/comate-fix/SKILL.md +0 -195
- package/skills/comate-gate/SKILL.md +0 -316
- package/skills/comate-gate/scaffold/docs/README.md +0 -36
- package/skills/comate-gate/scaffold/docs/knowledge-base/README.md +0 -47
- package/skills/comate-grill/SKILL.md +0 -185
- package/skills/comate-open/SKILL.md +0 -230
- package/skills/comate-verify/SKILL.md +0 -212
- /package/skills/{comate-gate/scaffold/docs → comate/scaffold/comate}/knowledge-base/integrations/README.md +0 -0
package/bin/init.mjs
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
|
-
// `comate
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// OpenSpec CLI -> npm install -g @fission-ai/openspec@latest (PATH command,
|
|
5
|
-
// so always global regardless of the chosen skill scope)
|
|
6
|
-
// Superpowers -> npx skills add obra/superpowers (scope-aware)
|
|
7
|
-
// comate -> npx skills add <this package> (scope-aware)
|
|
1
|
+
// `comate init` helpers. comate 1.0 has no external workflow dependencies: it
|
|
2
|
+
// needs Node and git, installs its own skills through the pinned `skills` CLI,
|
|
3
|
+
// and lays down the comate/ project scaffold.
|
|
8
4
|
//
|
|
9
5
|
// ponytail: no SKILLS_AGENT_MAP here. The skills CLI detects the running agent
|
|
10
6
|
// on its own, so translating platform ids to agent names would be dead code.
|
|
11
7
|
import { spawnSync } from 'node:child_process';
|
|
12
|
-
import { existsSync, mkdirSync, readdirSync, copyFileSync, statSync, lstatSync,
|
|
8
|
+
import { existsSync, mkdirSync, readdirSync, copyFileSync, statSync, lstatSync, renameSync, rmSync } from 'node:fs';
|
|
13
9
|
import { createRequire } from 'node:module';
|
|
14
10
|
import { dirname, join } from 'node:path';
|
|
15
11
|
|
|
16
|
-
const MIN_OPENSPEC = '1.5.0';
|
|
17
12
|
const NPM_TIMEOUT_MS = 180_000;
|
|
18
13
|
const SKILLS_TIMEOUT_MS = 300_000;
|
|
19
14
|
|
|
@@ -141,63 +136,17 @@ function skillsInvocation(pkgRoot, args) {
|
|
|
141
136
|
}
|
|
142
137
|
}
|
|
143
138
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
// spawned directly. bashVersion needs no shell — it has a real executable path.
|
|
147
|
-
const version = capture('openspec', ['--version'], { shell: process.platform === 'win32' });
|
|
148
|
-
if (version === null) return { status: 'missing' };
|
|
149
|
-
return { status: atLeast(version, MIN_OPENSPEC) ? 'ready' : 'outdated', version };
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Detect skills CLI installation (flattens obra/superpowers into one dir per
|
|
153
|
-
// skill) and Claude Code plugin installation (installed_plugins.json registry).
|
|
154
|
-
const SUPERPOWERS_MARKERS = [
|
|
155
|
-
['using-superpowers'],
|
|
156
|
-
['brainstorming'],
|
|
157
|
-
];
|
|
158
|
-
|
|
159
|
-
function superpowersInstalled(scope) {
|
|
160
|
-
const home = process.env.HOME ?? process.env.USERPROFILE ?? '';
|
|
161
|
-
const roots =
|
|
162
|
-
scope === 'global'
|
|
163
|
-
? ['.agents/skills', '.claude/skills', '.config/skills', '.cursor/skills']
|
|
164
|
-
.map((r) => join(home, r))
|
|
165
|
-
: ['.agents/skills', '.claude/skills', '.cursor/skills', '.codex/skills'];
|
|
166
|
-
|
|
167
|
-
// Check skills CLI installation
|
|
168
|
-
if (roots.some((root) => SUPERPOWERS_MARKERS.some((m) => existsSync(join(root, ...m))))) {
|
|
169
|
-
return true;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Check Claude Code plugin installation (only for global scope - plugins are user-level)
|
|
173
|
-
if (scope === 'global') {
|
|
174
|
-
const pluginRegistry = join(home, '.claude', 'plugins', 'installed_plugins.json');
|
|
175
|
-
try {
|
|
176
|
-
const registry = JSON.parse(readFileSync(pluginRegistry, 'utf8'));
|
|
177
|
-
// Check if superpowers plugin is installed (any marketplace)
|
|
178
|
-
return Object.keys(registry.plugins || {}).some((key) =>
|
|
179
|
-
key.startsWith('superpowers@') && Array.isArray(registry.plugins[key]) && registry.plugins[key].length > 0
|
|
180
|
-
);
|
|
181
|
-
} catch {
|
|
182
|
-
// File doesn't exist or parse failed - not a plugin install
|
|
183
|
-
return false;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
return false;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// The docs scaffold ships inside the comate skill, so it is present both in dev
|
|
191
|
-
// (repo checkout) and after `skills add` copies the skill to ~/.agents/skills.
|
|
139
|
+
// The comate/ scaffold ships inside the comate skill, so it is present both in
|
|
140
|
+
// dev (repo checkout) and after `skills add` copies the skill to ~/.agents/skills.
|
|
192
141
|
// Locating it relative to pkgRoot means init reads the same tree it packed.
|
|
193
142
|
function scaffoldSourceDir(pkgRoot) {
|
|
194
|
-
return join(pkgRoot, 'skills', 'comate
|
|
143
|
+
return join(pkgRoot, 'skills', 'comate', 'scaffold', 'comate');
|
|
195
144
|
}
|
|
196
145
|
|
|
197
146
|
// copyTreeSkipExisting — recursively copy src→dst, never overwriting a file that
|
|
198
147
|
// already exists. Returns { created, skipped } counts so init can report whether
|
|
199
|
-
// it actually laid anything down
|
|
200
|
-
//
|
|
148
|
+
// it actually laid anything down: an existing comate/ is left alone, only
|
|
149
|
+
// missing pieces are filled in.
|
|
201
150
|
function copyTreeSkipExisting(src, dst, acc = { created: 0, skipped: 0 }) {
|
|
202
151
|
mkdirSync(dst, { recursive: true });
|
|
203
152
|
for (const entry of readdirSync(src)) {
|
|
@@ -215,17 +164,45 @@ function copyTreeSkipExisting(src, dst, acc = { created: 0, skipped: 0 }) {
|
|
|
215
164
|
return acc;
|
|
216
165
|
}
|
|
217
166
|
|
|
218
|
-
//
|
|
219
|
-
// template
|
|
220
|
-
// comate
|
|
221
|
-
//
|
|
222
|
-
function
|
|
167
|
+
// scaffoldComate — lay down comate/ (config.json, knowledge-base with the PRD
|
|
168
|
+
// template, architecture placeholder). The layout is fixed: comate.mjs looks for
|
|
169
|
+
// comate/comate/config.json under the git root. Idempotent: existing files are
|
|
170
|
+
// never clobbered.
|
|
171
|
+
function scaffoldComate(pkgRoot, cwd = process.cwd()) {
|
|
223
172
|
const src = scaffoldSourceDir(pkgRoot);
|
|
224
173
|
if (!existsSync(src)) return { ok: false, reason: `scaffold source missing: ${src}` };
|
|
225
|
-
const { created, skipped } = copyTreeSkipExisting(src, join(cwd, '
|
|
174
|
+
const { created, skipped } = copyTreeSkipExisting(src, join(cwd, 'comate'));
|
|
226
175
|
return { ok: true, created, skipped };
|
|
227
176
|
}
|
|
228
177
|
|
|
178
|
+
// 0.x kept long-lived docs under docs/; 1.0 keeps everything under comate/.
|
|
179
|
+
// Only these two directories move — the rest of docs/ belongs to the project.
|
|
180
|
+
const LAYOUT_MOVES = [
|
|
181
|
+
['docs/knowledge-base', 'comate/knowledge-base'],
|
|
182
|
+
['docs/architecture', 'comate/architecture'],
|
|
183
|
+
];
|
|
184
|
+
|
|
185
|
+
// -> { moves: [{ from, to, status: 'move' | 'conflict' | 'moved' }], ok }.
|
|
186
|
+
// git mv keeps history; a destination that already exists is a conflict and
|
|
187
|
+
// nothing is moved at all, so a half-migrated tree never happens.
|
|
188
|
+
function migrateLayout(cwd = process.cwd(), { dryRun = true } = {}) {
|
|
189
|
+
const moves = LAYOUT_MOVES.filter(([from]) => existsSync(join(cwd, from))).map(([from, to]) => ({
|
|
190
|
+
from,
|
|
191
|
+
to,
|
|
192
|
+
status: existsSync(join(cwd, to)) ? 'conflict' : 'move',
|
|
193
|
+
}));
|
|
194
|
+
const ok = moves.every((m) => m.status !== 'conflict');
|
|
195
|
+
if (dryRun || !ok) return { moves, ok };
|
|
196
|
+
const inGit = spawnSync('git', ['rev-parse', '--git-dir'], { cwd, stdio: 'ignore' }).status === 0;
|
|
197
|
+
for (const m of moves) {
|
|
198
|
+
mkdirSync(dirname(join(cwd, m.to)), { recursive: true });
|
|
199
|
+
const r = inGit ? spawnSync('git', ['mv', m.from, m.to], { cwd, encoding: 'utf8' }) : null;
|
|
200
|
+
if (!r || r.status !== 0) renameSync(join(cwd, m.from), join(cwd, m.to));
|
|
201
|
+
m.status = 'moved';
|
|
202
|
+
}
|
|
203
|
+
return { moves, ok };
|
|
204
|
+
}
|
|
205
|
+
|
|
229
206
|
// comate skill dirs that later releases renamed or dropped. `skills add` only
|
|
230
207
|
// adds/overwrites, never removes, so without an explicit prune these linger in
|
|
231
208
|
// ~/.agents/skills as dead slash commands (e.g. /comate-hotfix after it became
|
|
@@ -233,7 +210,13 @@ function scaffoldDocs(pkgRoot, cwd = process.cwd()) {
|
|
|
233
210
|
// unrelated third-party skills (lark-*, openspec-*), so a prefix sweep or a
|
|
234
211
|
// diff-against-current strategy could wipe a user's own work. Add a line here
|
|
235
212
|
// whenever a comate skill is renamed or removed.
|
|
236
|
-
|
|
213
|
+
// 1.0: one /comate skill drives every phase through the Node state machine; the
|
|
214
|
+
// per-phase skills (gate/spec/build/verify/fix) are gone.
|
|
215
|
+
const DEPRECATED_SKILLS = [
|
|
216
|
+
'comate-hotfix', 'comate-tweak', 'comate-intake',
|
|
217
|
+
'comate-open', 'comate-design', 'comate-archive', 'comate-grill',
|
|
218
|
+
'comate-gate', 'comate-spec', 'comate-build', 'comate-verify', 'comate-fix',
|
|
219
|
+
];
|
|
237
220
|
|
|
238
221
|
function userSkillsRoot(home = process.env.HOME ?? process.env.USERPROFILE ?? '') {
|
|
239
222
|
return join(home, '.agents', 'skills');
|
|
@@ -304,7 +287,6 @@ function syncComateSkills(pkgRoot, { home = process.env.HOME ?? process.env.USER
|
|
|
304
287
|
}
|
|
305
288
|
|
|
306
289
|
export {
|
|
307
|
-
MIN_OPENSPEC,
|
|
308
290
|
NPM_TIMEOUT_MS,
|
|
309
291
|
SKILLS_TIMEOUT_MS,
|
|
310
292
|
findNpmCli,
|
|
@@ -315,11 +297,11 @@ export {
|
|
|
315
297
|
run,
|
|
316
298
|
capture,
|
|
317
299
|
atLeast,
|
|
318
|
-
openSpecState,
|
|
319
|
-
superpowersInstalled,
|
|
320
300
|
scaffoldSourceDir,
|
|
321
301
|
copyTreeSkipExisting,
|
|
322
|
-
|
|
302
|
+
scaffoldComate,
|
|
303
|
+
migrateLayout,
|
|
304
|
+
LAYOUT_MOVES,
|
|
323
305
|
DEPRECATED_SKILLS,
|
|
324
306
|
userSkillsRoot,
|
|
325
307
|
pruneDeprecatedSkills,
|
package/bin/postinstall.mjs
CHANGED
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Postinstall hook: show the wordmark and next steps after npm install finishes.
|
|
3
|
-
// Skipped in CI (where the logo wouldn't render anyway) and local dev installs
|
|
4
|
-
// (where the developer already knows what they installed).
|
|
5
|
-
import { fileURLToPath } from 'node:url';
|
|
6
|
-
import { dirname, resolve } from 'node:path';
|
|
7
|
-
|
|
8
|
-
const pkgRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
9
|
-
|
|
10
|
-
// Skip in CI, or when installing the package's own dependencies during dev.
|
|
11
|
-
if (isCI() || isDevInstall()) {
|
|
12
|
-
process.exit(0);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const { banner, pkgVersion } = await import('./init-run.mjs');
|
|
16
|
-
|
|
17
|
-
// Best-effort: refresh the user-level skills so `npm i -g @latest` alone updates
|
|
18
|
-
// them, and prune dirs renamed/dropped in past releases. All guarded — a failure
|
|
19
|
-
// here must never break the npm install, and `comate init` remains the fallback
|
|
20
|
-
// for --ignore-scripts users (who never reach this hook) and per-project setup.
|
|
21
|
-
const sync = await syncSkillsQuietly();
|
|
22
|
-
|
|
23
|
-
console.log(banner(pkgVersion(pkgRoot)));
|
|
24
|
-
console.log(` 🎉 Congratulations! comate 已成功安装。\n`);
|
|
25
|
-
if (sync.synced) console.log(' ✓ 已把 skills 同步到 ~/.agents/skills');
|
|
26
|
-
if (sync.removed.length) console.log(` ✓ 已清理废弃 skill:${sync.removed.join('、')}`);
|
|
27
|
-
console.log(' 下一步:');
|
|
28
|
-
console.log(' 在你的项目目录下运行 comate init 完成项目初始化(
|
|
29
|
-
console.log(' 或运行 comate doctor 健康检查');
|
|
30
|
-
console.log(' 更多帮助 comate --help\n');
|
|
31
|
-
|
|
32
|
-
async function syncSkillsQuietly() {
|
|
33
|
-
try {
|
|
34
|
-
const { syncComateSkills, pruneDeprecatedSkills, userSkillsRoot } = await import('./init.mjs');
|
|
35
|
-
const { ok } = syncComateSkills(pkgRoot);
|
|
36
|
-
const removed = pruneDeprecatedSkills(userSkillsRoot());
|
|
37
|
-
return { synced: ok, removed };
|
|
38
|
-
} catch {
|
|
39
|
-
// Any failure (no skills CLI resolvable, fs error) is silent: init covers it.
|
|
40
|
-
return { synced: false, removed: [] };
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function isCI() {
|
|
45
|
-
return Boolean(process.env.CI || process.env.GITHUB_ACTIONS);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// When npm installs a package's own dependencies (npm i in the repo itself),
|
|
49
|
-
// INIT_CWD points to the package root. A user installing comate globally or as
|
|
50
|
-
// a dependency has INIT_CWD pointing elsewhere.
|
|
51
|
-
function isDevInstall() {
|
|
52
|
-
const initCwd = process.env.INIT_CWD;
|
|
53
|
-
if (!initCwd) return false;
|
|
54
|
-
const normalise = (p) => resolve(p).replace(/[\\/]+$/, '').toLowerCase();
|
|
55
|
-
return normalise(initCwd) === normalise(pkgRoot);
|
|
56
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Postinstall hook: show the wordmark and next steps after npm install finishes.
|
|
3
|
+
// Skipped in CI (where the logo wouldn't render anyway) and local dev installs
|
|
4
|
+
// (where the developer already knows what they installed).
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { dirname, resolve } from 'node:path';
|
|
7
|
+
|
|
8
|
+
const pkgRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
9
|
+
|
|
10
|
+
// Skip in CI, or when installing the package's own dependencies during dev.
|
|
11
|
+
if (isCI() || isDevInstall()) {
|
|
12
|
+
process.exit(0);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { banner, pkgVersion } = await import('./init-run.mjs');
|
|
16
|
+
|
|
17
|
+
// Best-effort: refresh the user-level skills so `npm i -g @latest` alone updates
|
|
18
|
+
// them, and prune dirs renamed/dropped in past releases. All guarded — a failure
|
|
19
|
+
// here must never break the npm install, and `comate init` remains the fallback
|
|
20
|
+
// for --ignore-scripts users (who never reach this hook) and per-project setup.
|
|
21
|
+
const sync = await syncSkillsQuietly();
|
|
22
|
+
|
|
23
|
+
console.log(banner(pkgVersion(pkgRoot)));
|
|
24
|
+
console.log(` 🎉 Congratulations! comate 已成功安装。\n`);
|
|
25
|
+
if (sync.synced) console.log(' ✓ 已把 skills 同步到 ~/.agents/skills');
|
|
26
|
+
if (sync.removed.length) console.log(` ✓ 已清理废弃 skill:${sync.removed.join('、')}`);
|
|
27
|
+
console.log(' 下一步:');
|
|
28
|
+
console.log(' 在你的项目目录下运行 comate init 完成项目初始化(comate/)');
|
|
29
|
+
console.log(' 或运行 comate doctor 健康检查');
|
|
30
|
+
console.log(' 更多帮助 comate --help\n');
|
|
31
|
+
|
|
32
|
+
async function syncSkillsQuietly() {
|
|
33
|
+
try {
|
|
34
|
+
const { syncComateSkills, pruneDeprecatedSkills, userSkillsRoot } = await import('./init.mjs');
|
|
35
|
+
const { ok } = syncComateSkills(pkgRoot);
|
|
36
|
+
const removed = pruneDeprecatedSkills(userSkillsRoot());
|
|
37
|
+
return { synced: ok, removed };
|
|
38
|
+
} catch {
|
|
39
|
+
// Any failure (no skills CLI resolvable, fs error) is silent: init covers it.
|
|
40
|
+
return { synced: false, removed: [] };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function isCI() {
|
|
45
|
+
return Boolean(process.env.CI || process.env.GITHUB_ACTIONS);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// When npm installs a package's own dependencies (npm i in the repo itself),
|
|
49
|
+
// INIT_CWD points to the package root. A user installing comate globally or as
|
|
50
|
+
// a dependency has INIT_CWD pointing elsewhere.
|
|
51
|
+
function isDevInstall() {
|
|
52
|
+
const initCwd = process.env.INIT_CWD;
|
|
53
|
+
if (!initCwd) return false;
|
|
54
|
+
const normalise = (p) => resolve(p).replace(/[\\/]+$/, '').toLowerCase();
|
|
55
|
+
return normalise(initCwd) === normalise(pkgRoot);
|
|
56
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# fix 模式简化:原则而非清单
|
|
2
|
+
|
|
3
|
+
**日期**: 2026-10-08
|
|
4
|
+
**改动范围**: `skills/comate/reference/fix.md`, `skills/comate/reference/open.md`, `skills/comate/SKILL.md`
|
|
5
|
+
|
|
6
|
+
## 背景
|
|
7
|
+
|
|
8
|
+
之前的 fix 模式虽然简化了 brief 结构(三章 vs 七章),但在澄清阶段仍然要求走九大视角的清单式检查。这对于边界清楚的小修来说过于繁重,限制了模型的自主判断能力。
|
|
9
|
+
|
|
10
|
+
## 改动内容
|
|
11
|
+
|
|
12
|
+
### 1. fix 模式采用原则驱动澄清
|
|
13
|
+
|
|
14
|
+
**之前**:fix 模式在 open 阶段仍需逐项检查九大视角
|
|
15
|
+
**现在**:只需回答三个核心问题
|
|
16
|
+
|
|
17
|
+
```markdown
|
|
18
|
+
1. **修什么**(目标) — 现象、影响范围、复现方式
|
|
19
|
+
2. **怎么验收**(验收示例) — 至少一条「修复后原问题不再出现」
|
|
20
|
+
3. **为什么这样修**(决定) — 根因分析与修复方式
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### 2. 按需查证而非强制清单
|
|
24
|
+
|
|
25
|
+
**新增"何时需要查证"指引**:
|
|
26
|
+
|
|
27
|
+
| 情况 | 处理方式 |
|
|
28
|
+
|---|---|
|
|
29
|
+
| 根因不明 | 先复现问题、定位根因,再写 brief |
|
|
30
|
+
| 影响范围不确定 | 检查调用链、依赖关系,明确波及范围 |
|
|
31
|
+
| 修复方案有多种 | 评估可逆性和副作用,选最小改动;不确定时问用户 |
|
|
32
|
+
| 可能破坏已有行为 | 列出可能受影响的场景,验收示例必须包含回归检查 |
|
|
33
|
+
|
|
34
|
+
**判断标准**:如果写完 brief 后发现"其实不太确定影响范围"或"可能有副作用但说不清",那就是该查证的信号。
|
|
35
|
+
|
|
36
|
+
### 3. full 模式九大视角增加快速判定指南
|
|
37
|
+
|
|
38
|
+
在 `reference/open.md` 的九大视角表格中新增第三列"何时可快速标记'不适用'":
|
|
39
|
+
|
|
40
|
+
- **用户与场景**:纯内部技术重构、CLI 工具、开发者工具
|
|
41
|
+
- **架构与边界**:单一模块内的局部改动,不涉及模块间交互
|
|
42
|
+
- **旅程与状态**:无状态变更(纯查询、纯展示)
|
|
43
|
+
- **数据与规则**:不涉及数据存储或传输(纯前端交互)
|
|
44
|
+
- **风险与反例**:仅管理员可见、无外部输入、单机运行
|
|
45
|
+
- 等等...
|
|
46
|
+
|
|
47
|
+
标记"不适用"的判断标准:遗漏这一项**不会**导致返工或生产问题。
|
|
48
|
+
|
|
49
|
+
### 4. 明确 fix 的适用场景和升级时机
|
|
50
|
+
|
|
51
|
+
**适合 fix**:
|
|
52
|
+
- 明确的 bug,能快速复现和定位
|
|
53
|
+
- 影响范围清楚(单一模块或功能)
|
|
54
|
+
- 修复方案直接(不涉及架构调整)
|
|
55
|
+
- 改动文件少(bug 修复 ≤3 个文件,调整 ≤5 个文件)
|
|
56
|
+
|
|
57
|
+
**升级为 full 的时机**:
|
|
58
|
+
- 改动规模超出预期(涉及 3+ 文件或需改 schema/API/架构)
|
|
59
|
+
- 影响范围扩大(需要新的用户可见行为)
|
|
60
|
+
- 根因复杂(需要分阶段处理或产品决策)
|
|
61
|
+
|
|
62
|
+
**边界不清时,默认用 full**。
|
|
63
|
+
|
|
64
|
+
### 5. 增强验收要求
|
|
65
|
+
|
|
66
|
+
明确 Bug 修复的验收**必须包含**:
|
|
67
|
+
1. **正向验证** — 修复后原问题消失
|
|
68
|
+
2. **回归验证** — 相关场景不受影响(列出具体场景)
|
|
69
|
+
3. **边界验证** — 极值、空值、并发(按实际风险选择)
|
|
70
|
+
|
|
71
|
+
## 设计理念
|
|
72
|
+
|
|
73
|
+
### 从"清单驱动"到"原则驱动"
|
|
74
|
+
|
|
75
|
+
**清单驱动**(full 模式):
|
|
76
|
+
- 优势:系统性覆盖,不遗漏关键维度
|
|
77
|
+
- 劣势:认知负担重,可能过度工程,限制模型创造性
|
|
78
|
+
|
|
79
|
+
**原则驱动**(fix 模式):
|
|
80
|
+
- 优势:轻量快速,信任模型判断,聚焦核心问题
|
|
81
|
+
- 劣势:需要明确的边界判断能力
|
|
82
|
+
|
|
83
|
+
### 平衡点
|
|
84
|
+
|
|
85
|
+
- **fix 模式**:信任强模型在边界清楚时的快速决策能力
|
|
86
|
+
- **full 模式**:保留系统性框架,用于复杂或高风险场景
|
|
87
|
+
- **快速判定指南**:降低 full 模式的认知负担,避免为了填表而填表
|
|
88
|
+
|
|
89
|
+
## 向后兼容性
|
|
90
|
+
|
|
91
|
+
- **代码层面**:无破坏性变更,所有测试通过(26 个测试全部 pass)
|
|
92
|
+
- **文档层面**:fix 模式行为不变(三章 brief + 免确认),只是澄清方式从隐式继承九大视角改为显式的原则驱动
|
|
93
|
+
- **状态机**:`mode: fix` 的状态转换逻辑不变
|
|
94
|
+
|
|
95
|
+
## 使用示例
|
|
96
|
+
|
|
97
|
+
### fix 模式的 brief 示例
|
|
98
|
+
|
|
99
|
+
```markdown
|
|
100
|
+
# 目标
|
|
101
|
+
|
|
102
|
+
用户在订单列表页滚动到底部时,点击「加载更多」无反应。
|
|
103
|
+
影响范围:所有用户,订单超过 20 条时必现。
|
|
104
|
+
复现:登录 → 订单列表 → 滚动到底部 → 点击「加载更多」→ 无反应。
|
|
105
|
+
|
|
106
|
+
# 验收示例
|
|
107
|
+
|
|
108
|
+
- 修复后,点击「加载更多」能正常加载下一页订单
|
|
109
|
+
- 已加载全部订单时,「加载更多」按钮变灰且显示「已加载全部」
|
|
110
|
+
- 回归:其他分页场景(商品列表、搜索结果)不受影响
|
|
111
|
+
|
|
112
|
+
# 决定
|
|
113
|
+
|
|
114
|
+
根因:分页请求的 offset 计算错误,`offset = page * pageSize` 应为 `offset = (page - 1) * pageSize`。
|
|
115
|
+
修复方式:修正 `api/orders.js:45` 的 offset 计算公式。
|
|
116
|
+
不改其他分页实现(已单独封装且行为正确)。
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**注意**:没有走九大视角,但根因、影响范围、回归场景都明确了。
|
|
120
|
+
|
|
121
|
+
## 未来展望
|
|
122
|
+
|
|
123
|
+
可进一步考虑的方向:
|
|
124
|
+
|
|
125
|
+
1. **分级策略**:增加 `--rigor standard|minimal|adaptive` 参数
|
|
126
|
+
2. **澄清策略元能力**:在 open 开始前,先评估需求应该用什么澄清策略
|
|
127
|
+
3. **动态调整**:根据过程中发现的复杂度,自动建议从 fix 升级到 full
|
|
128
|
+
|
|
129
|
+
## 测试结果
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
npm test
|
|
133
|
+
# ✔ fix 模式:prepare 直接进 build,可省 tasks.md (1102.3283ms)
|
|
134
|
+
# ℹ tests 26
|
|
135
|
+
# ℹ pass 26
|
|
136
|
+
# ℹ fail 0
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
所有测试通过,包括 fix 模式的专项测试。
|
|
140
|
+
|
|
141
|
+
## 参考
|
|
142
|
+
|
|
143
|
+
- 借鉴 **Comet Native** 的"原则而非清单"设计
|
|
144
|
+
- 参考 Ponytail 模式的"懒惰即高效"哲学
|
|
145
|
+
- 保持与 full 模式的清晰边界,避免混淆
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# comate 1.0 试用说明
|
|
2
|
+
|
|
3
|
+
1.0 使用单个 `/comate` skill 和 Node 状态机,流程为 open → build ⇄ verify → archive。相比 0.x,不再依赖 OpenSpec CLI 和 Superpowers 编排;项目资料统一放在 `comate/`,进行中的旧 change 不自动转换。
|
|
4
|
+
|
|
5
|
+
## 安装与试用环境
|
|
6
|
+
|
|
7
|
+
需要 Node.js ≥ 20、git,以及支持 skills 的 AI 开发工具。完整验收需要工具支持独立子 agent;不支持时,按流程明确接受降级验收。
|
|
8
|
+
|
|
9
|
+
新版安装钩子和 `comate init` 会更新用户级 `~/.agents/skills`,并清理旧版 comate 阶段 skills。需要继续使用旧版的用户,请在独立系统用户、虚拟机或容器中试用。新 clone、worktree 和 `npx` 都不能隔离全局 skills。
|
|
10
|
+
|
|
11
|
+
第一轮请使用新建的测试项目,或已有项目的独立测试副本;测试副本仍需配合独立用户环境来隔离 skills。旧版进行中的 change 请先用旧版完成。
|
|
12
|
+
|
|
13
|
+
发布后安装试用渠道:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g @house365/comate@next
|
|
17
|
+
cd your-test-project
|
|
18
|
+
comate init
|
|
19
|
+
comate doctor
|
|
20
|
+
comate --version
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
本轮固定版本为 `1.0.0-beta.1`。需要复现本轮反馈时,用 `npm install -g @house365/comate@1.0.0-beta.1` 安装。
|
|
24
|
+
|
|
25
|
+
在 AI 开发工具中新开会话,输入 `/comate` 开始。切换版本后请重新打开会话,避免沿用旧 skill 的上下文。
|
|
26
|
+
|
|
27
|
+
## 建议试用任务
|
|
28
|
+
|
|
29
|
+
每人选择一个能判断结果的小任务,至少跑完一次归档。建议覆盖:
|
|
30
|
+
|
|
31
|
+
- 创建一个完整变更,确认需求、实现、独立验收、归档。
|
|
32
|
+
- 用 fix 模式处理一个边界清楚的小修,检查澄清与实现是否顺畅。
|
|
33
|
+
- 验收发现问题后,检查是否能回修并重新验收。
|
|
34
|
+
- 中途关闭会话,重新输入 `/comate`,检查是否能恢复正确阶段。
|
|
35
|
+
- 收尾选择 keep,检查主规格、归档目录和 git 状态。
|
|
36
|
+
|
|
37
|
+
第一轮不要求迁移旧项目。`init --migrate` 和 `import-specs` 留到单独的迁移试用中,先用 `--dry-run` 检查清单,再决定是否执行。
|
|
38
|
+
|
|
39
|
+
## 更新与回退
|
|
40
|
+
|
|
41
|
+
更新试用版:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install -g @house365/comate@next
|
|
45
|
+
cd your-test-project
|
|
46
|
+
comate init
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
当前 `comate update` 固定跟随 `latest`,试用期间请使用上面的命令。
|
|
50
|
+
|
|
51
|
+
需要恢复本次试用前的稳定版时:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm install -g @house365/comate@0.10.3
|
|
55
|
+
cd your-old-project
|
|
56
|
+
comate init
|
|
57
|
+
comate --version
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
这会恢复旧版 CLI 和 skills,但不会把新版 change 转回旧格式,也不会自动撤销目录迁移。回退后在旧项目继续工作,新版测试项目保留用于反馈;再次使用 AI 工具时新开会话。用户自行修改过的全局 skills,请在首次切换前另行备份。
|
|
61
|
+
|
|
62
|
+
## 反馈
|
|
63
|
+
|
|
64
|
+
通过 [GitHub Issues](https://github.com/liangjiankk/comate/issues) 提交,建议标题以 `[1.0 beta]` 开头,并提供:
|
|
65
|
+
|
|
66
|
+
- `comate --version`、操作系统、Node 版本、AI 工具及模型。
|
|
67
|
+
- 任务目标、发生问题的阶段、最短复现步骤。
|
|
68
|
+
- 预期结果、实际结果,以及相关报错或 `comate status --json` 输出。
|
|
69
|
+
- 本次哪些确认或操作造成了额外负担。
|
|
70
|
+
|
|
71
|
+
只提供复现所需片段,提交前移除密钥、个人信息和项目敏感内容。
|
|
72
|
+
|
|
73
|
+
## 维护者发布步骤
|
|
74
|
+
|
|
75
|
+
稳定版继续在 `main` 维护并发布到 `latest`;新版在试用分支维护,发布到 `next`。当前包的 `publishConfig.tag` 默认设为 `next`,防止遗漏渠道参数时切换 `latest`。
|
|
76
|
+
|
|
77
|
+
发布前将本轮试用涉及的代码和文档整理成一个可追踪的提交,检查其中包含预期内容,然后执行:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
npm run prepublishOnly
|
|
81
|
+
npm publish --dry-run --tag next
|
|
82
|
+
npm run publish:next
|
|
83
|
+
npm view @house365/comate dist-tags --json --registry=https://registry.npmjs.org
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
预期渠道为 `latest: 0.10.3`、`next: 1.0.0-beta.1`。实际发布需要 npm 账号拥有 `@house365/comate` 的发布权限,并按 npm 提示完成认证。
|
|
87
|
+
|
|
88
|
+
后续每轮同步修改 `package.json` 和 `package-lock.json` 的版本,使用新的 `1.0.0-beta.N` 版本号,并更新本文的固定版本和预期渠道;已发布的版本不重复使用。
|
|
89
|
+
|
|
90
|
+
正式发布时再移除默认的 `next` 配置、使用正式版本号、明确指定 `--tag latest`,并同步安装和更新说明。
|