cclaw-cli 0.51.28 → 0.51.30
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/dist/cli.d.ts +6 -1
- package/dist/cli.js +117 -64
- package/dist/codex-feature-flag.d.ts +1 -1
- package/dist/codex-feature-flag.js +1 -1
- package/dist/config.js +3 -0
- package/dist/content/cancel-command.d.ts +2 -0
- package/dist/content/cancel-command.js +25 -0
- package/dist/content/closeout-guidance.js +3 -3
- package/dist/content/core-agents.js +5 -5
- package/dist/content/harness-doc.js +1 -1
- package/dist/content/hooks.js +32 -9
- package/dist/content/ideate-command.js +12 -7
- package/dist/content/meta-skill.js +7 -9
- package/dist/content/next-command.d.ts +2 -2
- package/dist/content/next-command.js +31 -27
- package/dist/content/node-hooks.js +24 -8
- package/dist/content/opencode-plugin.js +1 -1
- package/dist/content/session-hooks.js +1 -1
- package/dist/content/stage-command.js +1 -1
- package/dist/content/stage-common-guidance.js +4 -4
- package/dist/content/stages/plan.js +2 -2
- package/dist/content/stages/review.js +1 -1
- package/dist/content/stages/tdd.js +1 -1
- package/dist/content/start-command.d.ts +2 -2
- package/dist/content/start-command.js +18 -15
- package/dist/content/status-command.js +9 -8
- package/dist/content/subagents.js +1 -1
- package/dist/content/templates.d.ts +1 -1
- package/dist/content/templates.js +2 -2
- package/dist/content/track-render-context.d.ts +1 -0
- package/dist/content/track-render-context.js +2 -0
- package/dist/doctor-registry.d.ts +2 -0
- package/dist/doctor-registry.js +37 -10
- package/dist/doctor.d.ts +2 -1
- package/dist/doctor.js +184 -8
- package/dist/flow-state.d.ts +1 -1
- package/dist/flow-state.js +1 -1
- package/dist/fs-utils.js +6 -0
- package/dist/harness-adapters.d.ts +2 -2
- package/dist/harness-adapters.js +21 -94
- package/dist/harness-selection.d.ts +31 -0
- package/dist/harness-selection.js +214 -0
- package/dist/install.d.ts +4 -1
- package/dist/install.js +47 -10
- package/dist/internal/advance-stage.js +7 -7
- package/dist/managed-resources.d.ts +53 -0
- package/dist/managed-resources.js +289 -0
- package/dist/policy.js +1 -1
- package/dist/run-archive.d.ts +8 -0
- package/dist/run-archive.js +23 -9
- package/dist/run-persistence.js +1 -1
- package/dist/runs.d.ts +1 -1
- package/dist/runs.js +1 -1
- package/dist/tdd-cycle.js +10 -10
- package/dist/tdd-verification-evidence.js +4 -4
- package/dist/track-heuristics.d.ts +2 -0
- package/dist/track-heuristics.js +11 -3
- package/package.json +1 -1
package/dist/cli.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import type { FlowTrack, HarnessId } from "./types.js";
|
|
3
|
+
import type { ArchiveDisposition } from "./runs.js";
|
|
4
|
+
export { parseHarnessSelectionAnswer } from "./harness-selection.js";
|
|
3
5
|
type CommandName = "init" | "sync" | "doctor" | "upgrade" | "uninstall" | "archive" | "internal";
|
|
4
6
|
interface ParsedArgs {
|
|
5
7
|
command?: CommandName;
|
|
@@ -15,6 +17,8 @@ interface ParsedArgs {
|
|
|
15
17
|
archiveName?: string;
|
|
16
18
|
archiveSkipRetro?: boolean;
|
|
17
19
|
archiveSkipRetroReason?: string;
|
|
20
|
+
archiveDisposition?: ArchiveDisposition;
|
|
21
|
+
archiveDispositionReason?: string;
|
|
18
22
|
/** Hidden plumbing command (`cclaw internal ...`) arguments. */
|
|
19
23
|
internalArgs?: string[];
|
|
20
24
|
showHelp?: boolean;
|
|
@@ -23,5 +27,6 @@ interface ParsedArgs {
|
|
|
23
27
|
export declare function usage(): string;
|
|
24
28
|
declare function parseHarnesses(raw: string): HarnessId[];
|
|
25
29
|
declare function parseTrack(raw: string): FlowTrack;
|
|
30
|
+
declare function parseArchiveDisposition(raw: string): ArchiveDisposition;
|
|
26
31
|
declare function parseArgs(argv: string[]): ParsedArgs;
|
|
27
|
-
export { parseArgs, parseHarnesses, parseTrack };
|
|
32
|
+
export { parseArgs, parseArchiveDisposition, parseHarnesses, parseTrack };
|
package/dist/cli.js
CHANGED
|
@@ -8,11 +8,13 @@ import { doctorChecks, doctorSucceeded } from "./doctor.js";
|
|
|
8
8
|
import { initCclaw, syncCclaw, uninstallCclaw, upgradeCclaw } from "./install.js";
|
|
9
9
|
import { error, info } from "./logger.js";
|
|
10
10
|
import { FLOW_TRACKS, HARNESS_IDS } from "./types.js";
|
|
11
|
-
import { archiveRun } from "./runs.js";
|
|
11
|
+
import { ARCHIVE_DISPOSITIONS, archiveRun } from "./runs.js";
|
|
12
12
|
import { CCLAW_VERSION, RUNTIME_ROOT } from "./constants.js";
|
|
13
|
-
import { createDefaultConfig } from "./config.js";
|
|
13
|
+
import { createDefaultConfig, readConfig } from "./config.js";
|
|
14
14
|
import { detectHarnesses } from "./init-detect.js";
|
|
15
15
|
import { HARNESS_ADAPTERS } from "./harness-adapters.js";
|
|
16
|
+
import { promptHarnessSelectionChecklist } from "./harness-selection.js";
|
|
17
|
+
export { parseHarnessSelectionAnswer } from "./harness-selection.js";
|
|
16
18
|
import { classifyCodexHooksFlag, codexConfigPath, patchCodexHooksFlag, readCodexConfig, writeCodexConfig } from "./codex-feature-flag.js";
|
|
17
19
|
import { runInternalCommand } from "./internal/advance-stage.js";
|
|
18
20
|
const INSTALLER_COMMANDS = [
|
|
@@ -38,17 +40,21 @@ Commands:
|
|
|
38
40
|
Flags: --harnesses=<list> Comma list of harnesses (claude,cursor,opencode,codex).
|
|
39
41
|
--no-interactive Skip interactive prompts even on TTY (for CI/scripts).
|
|
40
42
|
sync Reconcile generated runtime files with the current config.
|
|
43
|
+
Flags: --harnesses=<list> Update configured harnesses before syncing.
|
|
44
|
+
--interactive Pick harnesses from a numbered TTY menu.
|
|
41
45
|
doctor Check install/runtime wiring and print concrete fixes for failures.
|
|
42
46
|
Flags: --explain Include docs pointers for every check.
|
|
43
47
|
--json Emit machine-readable check results.
|
|
44
48
|
--quiet Show only failing checks.
|
|
45
49
|
--only=<filter> Limit displayed checks (error,warning,hook:,state:,...).
|
|
46
|
-
--reconcile-gates Refresh derived gate status before checking.
|
|
50
|
+
--reconcile-gates Refresh derived gate status before checking; does not repair missing artifacts/tests.
|
|
47
51
|
upgrade Refresh generated files in .cclaw. Preserves your config.yaml.
|
|
48
52
|
archive Archive the active run and reset flow state for the next run.
|
|
49
53
|
Flags: --name=<slug> Override archive folder suffix.
|
|
50
54
|
--skip-retro Skip retro gate only when runtime allows it.
|
|
51
55
|
--retro-reason=<txt> Required rationale with --skip-retro.
|
|
56
|
+
--disposition=<completed|cancelled|abandoned>
|
|
57
|
+
--reason=<txt> Required for cancelled/abandoned archives.
|
|
52
58
|
uninstall Remove .cclaw runtime and the generated harness shim files.
|
|
53
59
|
|
|
54
60
|
Global flags:
|
|
@@ -58,17 +64,18 @@ Global flags:
|
|
|
58
64
|
Examples:
|
|
59
65
|
npx cclaw-cli
|
|
60
66
|
npx cclaw-cli init --harnesses=claude,cursor --no-interactive
|
|
61
|
-
npx cclaw-cli sync
|
|
67
|
+
npx cclaw-cli sync --interactive
|
|
62
68
|
npx cclaw-cli archive --name=my-run
|
|
69
|
+
npx cclaw-cli archive --disposition=cancelled --reason="deprioritized"
|
|
63
70
|
npx cclaw-cli upgrade
|
|
64
71
|
|
|
65
|
-
Happy-path work happens inside your harness via /cc, /cc-
|
|
66
|
-
|
|
72
|
+
Happy-path work happens inside your harness via /cc, /cc-ideate,
|
|
73
|
+
and /cc-cancel. Doctor is an operator/support surface:
|
|
67
74
|
it verifies install/runtime wiring, but a real harness smoke test is
|
|
68
75
|
still needed to prove provider auth and model execution.
|
|
69
76
|
|
|
70
77
|
Docs: https://github.com/zuevrs/cclaw
|
|
71
|
-
Local:
|
|
78
|
+
Local: README.md and generated .cclaw/skills/*.md
|
|
72
79
|
Issues: https://github.com/zuevrs/cclaw/issues
|
|
73
80
|
`;
|
|
74
81
|
}
|
|
@@ -77,6 +84,9 @@ function parseHarnesses(raw) {
|
|
|
77
84
|
.split(",")
|
|
78
85
|
.map((item) => item.trim())
|
|
79
86
|
.filter(Boolean);
|
|
87
|
+
if (requested.length === 0) {
|
|
88
|
+
throw new Error("Select at least one harness.");
|
|
89
|
+
}
|
|
80
90
|
const invalid = requested.filter((item) => !HARNESS_IDS.includes(item));
|
|
81
91
|
if (invalid.length > 0) {
|
|
82
92
|
throw new Error(`Unknown harnesses: ${invalid.join(", ")}`);
|
|
@@ -90,6 +100,13 @@ function parseTrack(raw) {
|
|
|
90
100
|
}
|
|
91
101
|
return trimmed;
|
|
92
102
|
}
|
|
103
|
+
function parseArchiveDisposition(raw) {
|
|
104
|
+
const trimmed = raw.trim();
|
|
105
|
+
if (!ARCHIVE_DISPOSITIONS.includes(trimmed)) {
|
|
106
|
+
throw new Error(`Unknown archive disposition: ${trimmed}. Supported: ${ARCHIVE_DISPOSITIONS.join(", ")}`);
|
|
107
|
+
}
|
|
108
|
+
return trimmed;
|
|
109
|
+
}
|
|
93
110
|
function isInitPromptAllowed(ctx) {
|
|
94
111
|
return Boolean(process.stdin.isTTY && ctx.stdout.isTTY);
|
|
95
112
|
}
|
|
@@ -157,37 +174,8 @@ function buildInitSurfacePreview(harnesses) {
|
|
|
157
174
|
return lines;
|
|
158
175
|
}
|
|
159
176
|
async function promptInitConfig(defaults, ctx) {
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
output: ctx.stdout
|
|
163
|
-
});
|
|
164
|
-
const pickHarnesses = async (fallback) => {
|
|
165
|
-
const fallbackText = fallback.join(",");
|
|
166
|
-
while (true) {
|
|
167
|
-
const answer = (await rl.question(`\nHarnesses (comma list from ${HARNESS_IDS.join(", ")}) [${fallbackText}]: `)).trim();
|
|
168
|
-
if (answer.length === 0) {
|
|
169
|
-
return fallback;
|
|
170
|
-
}
|
|
171
|
-
try {
|
|
172
|
-
const parsed = parseHarnesses(answer);
|
|
173
|
-
if (parsed.length === 0) {
|
|
174
|
-
ctx.stdout.write("Select at least one harness.\n");
|
|
175
|
-
continue;
|
|
176
|
-
}
|
|
177
|
-
return parsed;
|
|
178
|
-
}
|
|
179
|
-
catch (err) {
|
|
180
|
-
ctx.stdout.write(`${err instanceof Error ? err.message : "Invalid harness list"}\n`);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
try {
|
|
185
|
-
const harnesses = await pickHarnesses(defaults.harnesses);
|
|
186
|
-
return { harnesses };
|
|
187
|
-
}
|
|
188
|
-
finally {
|
|
189
|
-
rl.close();
|
|
190
|
-
}
|
|
177
|
+
const harnesses = await promptHarnessSelectionChecklist(defaults, ctx, "Initial cclaw harnesses");
|
|
178
|
+
return { harnesses };
|
|
191
179
|
}
|
|
192
180
|
/**
|
|
193
181
|
* When Codex is one of the installed harnesses, check the Codex CLI
|
|
@@ -293,13 +281,41 @@ async function resolveInitInputs(parsed, ctx) {
|
|
|
293
281
|
const defaults = {
|
|
294
282
|
harnesses: autoHarnesses ?? HARNESS_IDS.slice()
|
|
295
283
|
};
|
|
296
|
-
const prompted = await promptInitConfig(defaults, ctx);
|
|
284
|
+
const prompted = await promptInitConfig({ ...defaults, detectedHarnesses }, ctx);
|
|
297
285
|
return {
|
|
298
286
|
track: parsed.track,
|
|
299
287
|
harnesses: prompted.harnesses,
|
|
300
288
|
detectedHarnesses
|
|
301
289
|
};
|
|
302
290
|
}
|
|
291
|
+
async function resolveSyncInputs(parsed, ctx) {
|
|
292
|
+
const explicitHarnesses = parsed.harnesses;
|
|
293
|
+
if (explicitHarnesses && explicitHarnesses.length > 0) {
|
|
294
|
+
return { harnesses: explicitHarnesses };
|
|
295
|
+
}
|
|
296
|
+
if (parsed.interactive !== true) {
|
|
297
|
+
return {};
|
|
298
|
+
}
|
|
299
|
+
if (!isInitPromptAllowed(ctx)) {
|
|
300
|
+
throw new Error("Interactive sync requires a TTY. Remove --interactive or run in a terminal.");
|
|
301
|
+
}
|
|
302
|
+
let currentHarnesses = [];
|
|
303
|
+
try {
|
|
304
|
+
currentHarnesses = (await readConfig(ctx.cwd)).harnesses;
|
|
305
|
+
}
|
|
306
|
+
catch {
|
|
307
|
+
currentHarnesses = [];
|
|
308
|
+
}
|
|
309
|
+
const detectedHarnesses = await detectHarnesses(ctx.cwd);
|
|
310
|
+
const defaults = detectedHarnesses.length > 0 ? detectedHarnesses : currentHarnesses.length > 0 ? currentHarnesses : HARNESS_IDS.slice();
|
|
311
|
+
return {
|
|
312
|
+
harnesses: await promptHarnessSelectionChecklist({
|
|
313
|
+
harnesses: defaults,
|
|
314
|
+
detectedHarnesses,
|
|
315
|
+
currentHarnesses
|
|
316
|
+
}, ctx, "Sync harness reconfiguration")
|
|
317
|
+
};
|
|
318
|
+
}
|
|
303
319
|
function parseDoctorOnly(raw) {
|
|
304
320
|
return raw
|
|
305
321
|
.split(",")
|
|
@@ -335,24 +351,47 @@ function doctorCountsBySeverity(checks) {
|
|
|
335
351
|
}
|
|
336
352
|
return result;
|
|
337
353
|
}
|
|
354
|
+
const DOCTOR_ACTION_GROUP_LABELS = {
|
|
355
|
+
sync: "Can fix with cclaw sync",
|
|
356
|
+
"user-action": "Requires user action",
|
|
357
|
+
"stage-work": "Requires stage work",
|
|
358
|
+
informational: "Informational warning"
|
|
359
|
+
};
|
|
360
|
+
function doctorActionGroupOrder(group) {
|
|
361
|
+
return group === "sync" ? 0 : group === "user-action" ? 1 : group === "stage-work" ? 2 : 3;
|
|
362
|
+
}
|
|
338
363
|
function printDoctorText(ctx, checks, options) {
|
|
339
364
|
const orderedSeverities = ["error", "warning", "info"];
|
|
340
365
|
const view = options.quiet ? checks.filter((check) => !check.ok) : checks;
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
366
|
+
const actionGroups = [...new Set(view.map((check) => check.actionGroup))]
|
|
367
|
+
.sort((left, right) => doctorActionGroupOrder(left) - doctorActionGroupOrder(right));
|
|
368
|
+
for (const actionGroup of actionGroups) {
|
|
369
|
+
const groupChecks = view.filter((check) => check.actionGroup === actionGroup);
|
|
370
|
+
const failingInGroup = groupChecks.filter((check) => !check.ok).length;
|
|
371
|
+
ctx.stdout.write(`
|
|
372
|
+
[${DOCTOR_ACTION_GROUP_LABELS[actionGroup]}] ${failingInGroup}/${groupChecks.length} failing
|
|
373
|
+
`);
|
|
374
|
+
for (const severity of orderedSeverities) {
|
|
375
|
+
const inBucket = groupChecks.filter((check) => check.severity === severity);
|
|
376
|
+
if (inBucket.length === 0)
|
|
377
|
+
continue;
|
|
378
|
+
ctx.stdout.write(` ${severity.toUpperCase()}
|
|
379
|
+
`);
|
|
380
|
+
for (const check of inBucket) {
|
|
381
|
+
const status = check.ok ? "PASS" : "FAIL";
|
|
382
|
+
ctx.stdout.write(` ${status} ${check.name} :: ${check.summary}
|
|
383
|
+
`);
|
|
384
|
+
if (!options.quiet) {
|
|
385
|
+
ctx.stdout.write(` details: ${check.details}
|
|
386
|
+
`);
|
|
387
|
+
}
|
|
388
|
+
if (!check.ok || options.explain) {
|
|
389
|
+
ctx.stdout.write(` next action: ${check.fix}
|
|
390
|
+
`);
|
|
391
|
+
if (check.docRef) {
|
|
392
|
+
ctx.stdout.write(` reference: ${check.docRef}
|
|
393
|
+
`);
|
|
394
|
+
}
|
|
356
395
|
}
|
|
357
396
|
}
|
|
358
397
|
}
|
|
@@ -392,13 +431,13 @@ function parseArgs(argv) {
|
|
|
392
431
|
}
|
|
393
432
|
const flags = rest;
|
|
394
433
|
const isAllowedForCommand = (flag) => {
|
|
395
|
-
if (parsed.command === "init") {
|
|
434
|
+
if (parsed.command === "init" || parsed.command === "sync") {
|
|
396
435
|
return flag.startsWith("--harnesses=") ||
|
|
397
|
-
flag.startsWith("--track=") ||
|
|
398
|
-
flag.startsWith("--profile=") ||
|
|
436
|
+
(parsed.command === "init" && flag.startsWith("--track=")) ||
|
|
437
|
+
(parsed.command === "init" && flag.startsWith("--profile=")) ||
|
|
399
438
|
flag === "--interactive" ||
|
|
400
439
|
flag === "--no-interactive" ||
|
|
401
|
-
flag === "--dry-run";
|
|
440
|
+
(parsed.command === "init" && flag === "--dry-run");
|
|
402
441
|
}
|
|
403
442
|
if (parsed.command === "doctor") {
|
|
404
443
|
return flag === "--reconcile-gates" ||
|
|
@@ -410,7 +449,9 @@ function parseArgs(argv) {
|
|
|
410
449
|
if (parsed.command === "archive") {
|
|
411
450
|
return flag.startsWith("--name=") ||
|
|
412
451
|
flag === "--skip-retro" ||
|
|
413
|
-
flag.startsWith("--retro-reason=")
|
|
452
|
+
flag.startsWith("--retro-reason=") ||
|
|
453
|
+
flag.startsWith("--disposition=") ||
|
|
454
|
+
flag.startsWith("--reason=");
|
|
414
455
|
}
|
|
415
456
|
return false;
|
|
416
457
|
};
|
|
@@ -473,6 +514,14 @@ function parseArgs(argv) {
|
|
|
473
514
|
parsed.archiveSkipRetroReason = flag.replace("--retro-reason=", "").trim();
|
|
474
515
|
continue;
|
|
475
516
|
}
|
|
517
|
+
if (flag.startsWith("--disposition=")) {
|
|
518
|
+
parsed.archiveDisposition = parseArchiveDisposition(flag.replace("--disposition=", ""));
|
|
519
|
+
continue;
|
|
520
|
+
}
|
|
521
|
+
if (flag.startsWith("--reason=")) {
|
|
522
|
+
parsed.archiveDispositionReason = flag.replace("--reason=", "").trim();
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
476
525
|
}
|
|
477
526
|
return parsed;
|
|
478
527
|
}
|
|
@@ -532,8 +581,10 @@ async function runCommand(parsed, ctx) {
|
|
|
532
581
|
return 0;
|
|
533
582
|
}
|
|
534
583
|
if (command === "sync") {
|
|
535
|
-
await
|
|
536
|
-
|
|
584
|
+
const resolved = await resolveSyncInputs(parsed, ctx);
|
|
585
|
+
await syncCclaw(ctx.cwd, { harnesses: resolved.harnesses });
|
|
586
|
+
const harnessNote = resolved.harnesses ? ` (${resolved.harnesses.join(", ")})` : "";
|
|
587
|
+
info(ctx, `Synchronized harness shims from current .cclaw config${harnessNote}`);
|
|
537
588
|
return 0;
|
|
538
589
|
}
|
|
539
590
|
if (command === "doctor") {
|
|
@@ -571,12 +622,14 @@ async function runCommand(parsed, ctx) {
|
|
|
571
622
|
if (command === "archive") {
|
|
572
623
|
const archived = await archiveRun(ctx.cwd, parsed.archiveName, {
|
|
573
624
|
skipRetro: parsed.archiveSkipRetro === true,
|
|
574
|
-
skipRetroReason: parsed.archiveSkipRetroReason
|
|
625
|
+
skipRetroReason: parsed.archiveSkipRetroReason,
|
|
626
|
+
disposition: parsed.archiveDisposition,
|
|
627
|
+
dispositionReason: parsed.archiveDispositionReason
|
|
575
628
|
});
|
|
576
629
|
const snapshotSummary = archived.snapshottedStateFiles.length > 0
|
|
577
630
|
? ` Snapshotted ${archived.snapshottedStateFiles.length} state file(s) under ${archived.archivePath}/state and wrote archive-manifest.json.`
|
|
578
631
|
: "";
|
|
579
|
-
info(ctx, `Archived active artifacts to ${archived.archivePath}. Flow state reset to brainstorm.${snapshotSummary}`);
|
|
632
|
+
info(ctx, `Archived active artifacts to ${archived.archivePath} (${archived.disposition}). Flow state reset to brainstorm.${snapshotSummary}`);
|
|
580
633
|
const k = archived.knowledge;
|
|
581
634
|
if (k.overThreshold) {
|
|
582
635
|
info(ctx, `Knowledge curation recommended: ${k.knowledgePath} now has ${k.activeEntryCount} active entries (soft threshold ${k.softThreshold}). Ask your harness to curate cclaw knowledge and plan a soft-archive of stale/duplicate entries to ${RUNTIME_ROOT}/knowledge.archive.jsonl.`);
|
|
@@ -624,4 +677,4 @@ function isDirectExecution() {
|
|
|
624
677
|
if (isDirectExecution()) {
|
|
625
678
|
void main();
|
|
626
679
|
}
|
|
627
|
-
export { parseArgs, parseHarnesses, parseTrack };
|
|
680
|
+
export { parseArgs, parseArchiveDisposition, parseHarnesses, parseTrack };
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* ```
|
|
12
12
|
*
|
|
13
13
|
* in `$CODEX_HOME/config.toml` (default: `~/.codex/config.toml`).
|
|
14
|
-
* cclaw
|
|
14
|
+
* cclaw init/sync can prompt the user to flip this flag for them; `cclaw doctor --explain` reports the concrete repair when it is missing;
|
|
15
15
|
* this module owns the detection / mutation code so the prompt logic in
|
|
16
16
|
* `cli.ts` stays small and testable.
|
|
17
17
|
*
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* ```
|
|
12
12
|
*
|
|
13
13
|
* in `$CODEX_HOME/config.toml` (default: `~/.codex/config.toml`).
|
|
14
|
-
* cclaw
|
|
14
|
+
* cclaw init/sync can prompt the user to flip this flag for them; `cclaw doctor --explain` reports the concrete repair when it is missing;
|
|
15
15
|
* this module owns the detection / mutation code so the prompt logic in
|
|
16
16
|
* `cli.ts` stays small and testable.
|
|
17
17
|
*
|
package/dist/config.js
CHANGED
|
@@ -245,6 +245,9 @@ export async function readConfig(projectRoot, options = {}) {
|
|
|
245
245
|
throw configValidationError(fullPath, `unknown harness id(s): ${formatted}`);
|
|
246
246
|
}
|
|
247
247
|
const validatedHarnesses = configuredHarnesses;
|
|
248
|
+
if (hasHarnessesField && validatedHarnesses.length === 0) {
|
|
249
|
+
throw configValidationError(fullPath, `"harnesses" must include at least one harness`);
|
|
250
|
+
}
|
|
248
251
|
const harnesses = hasHarnessesField
|
|
249
252
|
? [...new Set(validatedHarnesses)]
|
|
250
253
|
: DEFAULT_HARNESSES;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export function cancelCommandContract() {
|
|
2
|
+
return `# /cc-cancel command contract
|
|
3
|
+
|
|
4
|
+
Use this command when the user wants to stop the active run without claiming completion.
|
|
5
|
+
|
|
6
|
+
## Protocol
|
|
7
|
+
|
|
8
|
+
1. Ask for a concise cancellation reason if the user has not already provided one.
|
|
9
|
+
2. Run \`cclaw archive --disposition=cancelled --reason=<reason>\` from the project root. Use \`--disposition=abandoned\` only when the user explicitly frames the run as abandoned rather than cancelled.
|
|
10
|
+
3. Report the archive path and reset run id. Make clear that the archived run is not a completed ship.
|
|
11
|
+
|
|
12
|
+
Cancelled and abandoned archives are allowed from any stage, but they require a required reason so future readers know why the run ended.
|
|
13
|
+
`;
|
|
14
|
+
}
|
|
15
|
+
export function cancelCommandSkillMarkdown() {
|
|
16
|
+
return `---
|
|
17
|
+
name: flow-cancel
|
|
18
|
+
description: Cancel or abandon the active cclaw run with a required reason. Use when the user types /cc-cancel or asks to cancel, abandon, stop, discard, or reset an unfinished run.
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# Cancel cclaw Run
|
|
22
|
+
|
|
23
|
+
Load and follow \`.cclaw/commands/cancel.md\`. This is a non-completion path: require a reason and archive with cancelled or abandoned disposition.
|
|
24
|
+
`;
|
|
25
|
+
}
|
|
@@ -13,7 +13,7 @@ export function closeoutSubstateInline() {
|
|
|
13
13
|
return `\`${CLOSEOUT_SUBSTATE_KEY}\``;
|
|
14
14
|
}
|
|
15
15
|
export function closeoutNextCommandGuidance() {
|
|
16
|
-
return `After ship completes, the closeout chain ${closeoutChainInline()} runs automatically, driven by ${closeoutSubstateInline()}. Continue through \`/cc
|
|
16
|
+
return `After ship completes, the closeout chain ${closeoutChainInline()} runs automatically, driven by ${closeoutSubstateInline()}. Continue through \`/cc\`; do not branch into \`ce:compound\`, a separate operations router, or a one-off closeout command. Ralph Loop may be mentioned only as tdd carry-forward context when it explains the next \`/cc\` move; it is not part of compound/archive routing.`;
|
|
17
17
|
}
|
|
18
18
|
export function closeoutSubstateProtocolBullets() {
|
|
19
19
|
return `When \`currentStage === "ship"\`, route by **${closeoutSubstateInline()}**:
|
|
@@ -35,8 +35,8 @@ export function closeoutSubstateProtocolBullets() {
|
|
|
35
35
|
- \`"archived"\` (transient) -> report "run archived" and stop.`;
|
|
36
36
|
}
|
|
37
37
|
export function closeoutFlowMapSentence() {
|
|
38
|
-
return `The first stage names are the critical path. \`retro\`, \`compound\`, and \`archive\` are post-ship closeout substates under ${closeoutSubstateInline()}, not separate stage schemas or commands. Continue them with \`/cc
|
|
38
|
+
return `The first stage names are the critical path. \`retro\`, \`compound\`, and \`archive\` are post-ship closeout substates under ${closeoutSubstateInline()}, not separate stage schemas or commands. Continue them with \`/cc\`; do not route compound closeout through \`ce:compound\`.`;
|
|
39
39
|
}
|
|
40
40
|
export function closeoutProtocolBehaviorSentence() {
|
|
41
|
-
return `Keep decision, completion, and preamble discipline inline: ask only decision-changing questions, verify gates before advancing, and keep context compact. After \`ship\`, keep using \`/cc
|
|
41
|
+
return `Keep decision, completion, and preamble discipline inline: ask only decision-changing questions, verify gates before advancing, and keep context compact. After \`ship\`, keep using \`/cc\` through ${closeoutChainInline()}; do not route normal closeout through \`ce:compound\` or a separate operations command. In compound closeout, assess overlap before appending knowledge: refresh recurring bug-track learnings as actionable rules/tests, keep knowledge-track learnings as durable process/project guidance, and mark outdated entries with lightweight \`supersedes\` / \`superseded_by\` fields instead of building a new doc system.`;
|
|
42
42
|
}
|
|
@@ -498,11 +498,11 @@ export function agentRoutingTable() {
|
|
|
498
498
|
return `| Stage Entry | Primary Agent(s) | Supporting guidance |
|
|
499
499
|
|---|---|---|
|
|
500
500
|
| Brainstorm (start with \`/cc <idea>\`) | ${brainstormPrimary} | Run in-thread research playbooks: \`research/repo-scan.md\`, \`research/learnings-lookup.md\` |
|
|
501
|
-
| Scope / Design / Plan (via \`/cc
|
|
502
|
-
| Spec (via \`/cc
|
|
503
|
-
| TDD (via \`/cc
|
|
504
|
-
| Review (via \`/cc
|
|
505
|
-
| Ship (via \`/cc
|
|
501
|
+
| Scope / Design / Plan (via \`/cc\`) | ${scopeDesignPlanPrimary} | Use \`research/git-history.md\` (scope) and \`research/framework-docs-lookup.md\` + \`research/best-practices-lookup.md\` (design) as needed |
|
|
502
|
+
| Spec (via \`/cc\`) | ${specPrimary} | planner (if ambiguity or conflicts remain) |
|
|
503
|
+
| TDD (via \`/cc\`) | ${tddPrimary} | doc-updater on public behavior/config changes |
|
|
504
|
+
| Review (via \`/cc\`) | ${reviewPrimary} | conditional second reviewer for high blast-radius diffs |
|
|
505
|
+
| Ship (via \`/cc\`) | ${shipPrimary} | security-reviewer when release risk is elevated |
|
|
506
506
|
`;
|
|
507
507
|
}
|
|
508
508
|
/**
|
|
@@ -35,7 +35,7 @@ function perHarnessRecipeMarkdown() {
|
|
|
35
35
|
const examples = recipes
|
|
36
36
|
.map((recipe) => `**${recipe.harnessId}**:\n\n` + recipe.lifecycleCommands.map((cmd) => ` ${cmd}`).join("\n"))
|
|
37
37
|
.join("\n\n");
|
|
38
|
-
return `\n\n## Per-Harness Lifecycle Recipe\n\n| Harness | Surface | Agent definition path | fulfillmentMode | Lifecycle |\n|---|---|---|---|---|\n${rows}\n\nNeutral placeholder tokens only: \`<agent-name>\`, \`<stage>\`, \`<run-id>\`, \`<span-id>\`, \`<dispatch-id>\`, \`<agent-def-path>\`, \`<iso-ts>\`, \`<artifact-anchor>\`. See \`docs/quality-gates.md\` for stage-by-stage gate mapping.\n\nThe four shipped harnesses (\`claude\`, \`cursor\`, \`opencode\`, \`codex\`) each ship with a canonical primary surface in the table above. The remaining enum values \`generic-task\`, \`role-switch\`, and \`manual\` are documented in the dispatch-surface table below and are available to any harness as fallback paths when the primary surface is unavailable.\n\n${examples}\n\n${dispatchSurfaceTableMarkdown()}\n\n### Legacy ledger upgrade\n\nPre-v3 ledger entries that lack a recorded \`dispatchSurface\` are tagged \`fulfillmentMode: "legacy-inferred"\` on read. Stage-complete blocks completion until those rows are re-recorded with the v3 helper:\n\n node .cclaw/hooks/delegation-record.mjs \\\n --rerecord \\\n --span-id=<span-id> \\\n --dispatch-id=<dispatch-id> \\\n --dispatch-surface=<surface> \\\n --agent-definition-path=<agent-def-path> \\\n --ack-ts=<iso-ts> \\\n --completed-ts=<iso-ts> \\\n --json\n\n\`--dispatch-surface\` must be one of the values listed in the dispatch-surface table above (the enum is generated verbatim from \`src/delegation.ts::DELEGATION_DISPATCH_SURFACES\`). Surfaces must align with the allowed agent-definition-path prefixes shown alongside each surface; \`role-switch\` and \`manual\` accept any path. The deprecated \`task\` surface is rejected.\n\n`;
|
|
38
|
+
return `\n\n## Per-Harness Lifecycle Recipe\n\n| Harness | Surface | Agent definition path | fulfillmentMode | Lifecycle |\n|---|---|---|---|---|\n${rows}\n\nNeutral placeholder tokens only: \`<agent-name>\`, \`<stage>\`, \`<run-id>\`, \`<span-id>\`, \`<dispatch-id>\`, \`<agent-def-path>\`, \`<iso-ts>\`, \`<artifact-anchor>\`. See \`docs/quality-gates.md\` for stage-by-stage gate mapping.\n\nThe four shipped harnesses (\`claude\`, \`cursor\`, \`opencode\`, \`codex\`) each ship with a canonical primary surface in the table above. Repair hints: \`cclaw sync\` safely regenerates shims/plugins/agents; Codex also needs \`[features] codex_hooks = true\`; OpenCode needs \`opencode.json(.c)\` plugin registration; role-switch completions require evidenceRefs. The remaining enum values \`generic-task\`, \`role-switch\`, and \`manual\` are documented in the dispatch-surface table below and are available to any harness as fallback paths when the primary surface is unavailable.\n\n${examples}\n\n${dispatchSurfaceTableMarkdown()}\n\n### Legacy ledger upgrade\n\nPre-v3 ledger entries that lack a recorded \`dispatchSurface\` are tagged \`fulfillmentMode: "legacy-inferred"\` on read. Stage-complete blocks completion until those rows are re-recorded with the v3 helper:\n\n node .cclaw/hooks/delegation-record.mjs \\\n --rerecord \\\n --span-id=<span-id> \\\n --dispatch-id=<dispatch-id> \\\n --dispatch-surface=<surface> \\\n --agent-definition-path=<agent-def-path> \\\n --ack-ts=<iso-ts> \\\n --completed-ts=<iso-ts> \\\n --json\n\n\`--dispatch-surface\` must be one of the values listed in the dispatch-surface table above (the enum is generated verbatim from \`src/delegation.ts::DELEGATION_DISPATCH_SURFACES\`). Surfaces must align with the allowed agent-definition-path prefixes shown alongside each surface; \`role-switch\` and \`manual\` accept any path. The deprecated \`task\` surface is rejected.\n\n`;
|
|
39
39
|
}
|
|
40
40
|
export function harnessIntegrationDocMarkdown() {
|
|
41
41
|
const head = "# Harness Integration Matrix\n\nGenerated from `src/harness-adapters.ts` capabilities and hook event mappings.";
|
package/dist/content/hooks.js
CHANGED
|
@@ -3,7 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { RUNTIME_ROOT } from "../constants.js";
|
|
5
5
|
import { DELEGATION_DISPATCH_SURFACES, DELEGATION_DISPATCH_SURFACE_PATH_PREFIXES } from "../delegation.js";
|
|
6
|
-
function
|
|
6
|
+
function resolveCliRuntimeForGeneratedHook() {
|
|
7
7
|
const here = fileURLToPath(import.meta.url);
|
|
8
8
|
const candidates = [
|
|
9
9
|
path.resolve(path.dirname(here), "..", "cli.js"),
|
|
@@ -13,12 +13,21 @@ function resolveCliEntrypointForGeneratedHook() {
|
|
|
13
13
|
// Synchronous probe runs only during cclaw-cli init/sync generation.
|
|
14
14
|
// The generated hook receives a concrete path and does not need a global bin.
|
|
15
15
|
if (existsSync(candidate))
|
|
16
|
-
return candidate;
|
|
16
|
+
return { entrypoint: candidate, argsPrefix: [] };
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
// Vitest exercises init/sync directly from src/ without a compiled dist/.
|
|
19
|
+
// Route that dev-only shape through vite-node so hooks still prove a local runtime.
|
|
20
|
+
if (process.env.VITEST === "true") {
|
|
21
|
+
const sourceCli = path.resolve(path.dirname(here), "..", "cli.ts");
|
|
22
|
+
const viteNode = path.resolve(path.dirname(here), "..", "..", "node_modules", "vite-node", "vite-node.mjs");
|
|
23
|
+
if (existsSync(sourceCli) && existsSync(viteNode)) {
|
|
24
|
+
return { entrypoint: viteNode, argsPrefix: ["--script", sourceCli] };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return { entrypoint: null, argsPrefix: [] };
|
|
19
28
|
}
|
|
20
29
|
function internalHelperScript(helperName, internalSubcommand, usage) {
|
|
21
|
-
const
|
|
30
|
+
const cliRuntime = resolveCliRuntimeForGeneratedHook();
|
|
22
31
|
return `#!/usr/bin/env node
|
|
23
32
|
import fs from "node:fs/promises";
|
|
24
33
|
import path from "node:path";
|
|
@@ -26,7 +35,8 @@ import process from "node:process";
|
|
|
26
35
|
import { spawn } from "node:child_process";
|
|
27
36
|
|
|
28
37
|
const RUNTIME_ROOT = ${JSON.stringify(RUNTIME_ROOT)};
|
|
29
|
-
const CCLAW_CLI_ENTRYPOINT = ${JSON.stringify(
|
|
38
|
+
const CCLAW_CLI_ENTRYPOINT = ${JSON.stringify(cliRuntime.entrypoint)};
|
|
39
|
+
const CCLAW_CLI_ARGS_PREFIX = ${JSON.stringify(cliRuntime.argsPrefix)};
|
|
30
40
|
const HELPER_NAME = ${JSON.stringify(helperName)};
|
|
31
41
|
const INTERNAL_SUBCOMMAND = ${JSON.stringify(internalSubcommand)};
|
|
32
42
|
const USAGE = ${JSON.stringify(usage)};
|
|
@@ -77,6 +87,7 @@ async function main() {
|
|
|
77
87
|
}
|
|
78
88
|
|
|
79
89
|
const cliEntrypoint = process.env.CCLAW_CLI_JS || CCLAW_CLI_ENTRYPOINT;
|
|
90
|
+
const cliArgsPrefix = process.env.CCLAW_CLI_JS ? [] : CCLAW_CLI_ARGS_PREFIX;
|
|
80
91
|
if (!cliEntrypoint || cliEntrypoint.trim().length === 0) {
|
|
81
92
|
process.stderr.write(
|
|
82
93
|
"[cclaw] " + HELPER_NAME + ": local Node runtime entrypoint is missing. Re-run npx cclaw-cli sync, or set CCLAW_CLI_JS=/absolute/path/to/dist/cli.js for this session.\\n"
|
|
@@ -88,6 +99,11 @@ async function main() {
|
|
|
88
99
|
try {
|
|
89
100
|
const stat = await fs.stat(cliEntrypoint);
|
|
90
101
|
if (!stat.isFile()) throw new Error("not-file");
|
|
102
|
+
for (const argPath of cliArgsPrefix) {
|
|
103
|
+
if (typeof argPath !== "string" || argPath.startsWith("-")) continue;
|
|
104
|
+
const argStat = await fs.stat(argPath);
|
|
105
|
+
if (!argStat.isFile()) throw new Error("arg-not-file");
|
|
106
|
+
}
|
|
91
107
|
} catch {
|
|
92
108
|
process.stderr.write(
|
|
93
109
|
"[cclaw] " + HELPER_NAME + ": local Node runtime entrypoint not found at " + cliEntrypoint + ". Re-run npx cclaw-cli sync, or set CCLAW_CLI_JS=/absolute/path/to/dist/cli.js for this session.\\n"
|
|
@@ -96,7 +112,7 @@ async function main() {
|
|
|
96
112
|
return;
|
|
97
113
|
}
|
|
98
114
|
|
|
99
|
-
const child = spawn(process.execPath, [cliEntrypoint, "internal", INTERNAL_SUBCOMMAND, ...flags], {
|
|
115
|
+
const child = spawn(process.execPath, [cliEntrypoint, ...cliArgsPrefix, "internal", INTERNAL_SUBCOMMAND, ...flags], {
|
|
100
116
|
cwd: root,
|
|
101
117
|
env: process.env,
|
|
102
118
|
stdio: "inherit"
|
|
@@ -140,7 +156,7 @@ export function startFlowScript() {
|
|
|
140
156
|
return internalHelperScript("start-flow", "start-flow", "Usage: node " + RUNTIME_ROOT + "/hooks/start-flow.mjs --track=<standard|medium|quick> [--class=...] [--prompt=...] [--stack=...] [--reason=...] [--reclassify] [--force-reset]");
|
|
141
157
|
}
|
|
142
158
|
export function stageCompleteScript() {
|
|
143
|
-
const
|
|
159
|
+
const cliRuntime = resolveCliRuntimeForGeneratedHook();
|
|
144
160
|
return `#!/usr/bin/env node
|
|
145
161
|
import fs from "node:fs/promises";
|
|
146
162
|
import path from "node:path";
|
|
@@ -148,7 +164,8 @@ import process from "node:process";
|
|
|
148
164
|
import { spawn } from "node:child_process";
|
|
149
165
|
|
|
150
166
|
const RUNTIME_ROOT = ${JSON.stringify(RUNTIME_ROOT)};
|
|
151
|
-
const CCLAW_CLI_ENTRYPOINT = ${JSON.stringify(
|
|
167
|
+
const CCLAW_CLI_ENTRYPOINT = ${JSON.stringify(cliRuntime.entrypoint)};
|
|
168
|
+
const CCLAW_CLI_ARGS_PREFIX = ${JSON.stringify(cliRuntime.argsPrefix)};
|
|
152
169
|
|
|
153
170
|
async function detectRoot() {
|
|
154
171
|
const candidates = [
|
|
@@ -201,6 +218,7 @@ async function main() {
|
|
|
201
218
|
}
|
|
202
219
|
|
|
203
220
|
const cliEntrypoint = process.env.CCLAW_CLI_JS || CCLAW_CLI_ENTRYPOINT;
|
|
221
|
+
const cliArgsPrefix = process.env.CCLAW_CLI_JS ? [] : CCLAW_CLI_ARGS_PREFIX;
|
|
204
222
|
if (!cliEntrypoint || cliEntrypoint.trim().length === 0) {
|
|
205
223
|
process.stderr.write(
|
|
206
224
|
"[cclaw] stage-complete: local Node runtime entrypoint is missing. Re-run npx cclaw-cli sync, or set CCLAW_CLI_JS=/absolute/path/to/dist/cli.js for this session.\\n"
|
|
@@ -212,6 +230,11 @@ async function main() {
|
|
|
212
230
|
try {
|
|
213
231
|
const stat = await fs.stat(cliEntrypoint);
|
|
214
232
|
if (!stat.isFile()) throw new Error("not-file");
|
|
233
|
+
for (const argPath of cliArgsPrefix) {
|
|
234
|
+
if (typeof argPath !== "string" || argPath.startsWith("-")) continue;
|
|
235
|
+
const argStat = await fs.stat(argPath);
|
|
236
|
+
if (!argStat.isFile()) throw new Error("arg-not-file");
|
|
237
|
+
}
|
|
215
238
|
} catch {
|
|
216
239
|
process.stderr.write(
|
|
217
240
|
"[cclaw] stage-complete: local Node runtime entrypoint not found at " + cliEntrypoint + ". Re-run npx cclaw-cli sync, or set CCLAW_CLI_JS=/absolute/path/to/dist/cli.js for this session.\\n"
|
|
@@ -222,7 +245,7 @@ async function main() {
|
|
|
222
245
|
|
|
223
246
|
const child = spawn(
|
|
224
247
|
process.execPath,
|
|
225
|
-
[cliEntrypoint, "internal", "advance-stage", stage, ...flags],
|
|
248
|
+
[cliEntrypoint, ...cliArgsPrefix, "internal", "advance-stage", stage, ...flags],
|
|
226
249
|
{
|
|
227
250
|
cwd: root,
|
|
228
251
|
env: process.env,
|
|
@@ -77,7 +77,7 @@ ${frameBullets}
|
|
|
77
77
|
5. **Adversarial critique pass.** For each candidate, write the strongest
|
|
78
78
|
counter-argument, kill weak ideas, and keep survivors only.
|
|
79
79
|
6. **Produce 5-10 survivors** with impact (High/Medium/Low),
|
|
80
|
-
effort (S/M/L), confidence (High/Medium/Low), and one evidence path per
|
|
80
|
+
effort (S/M/L), confidence (High/Medium/Low), **why now**, expected user impact, risk, and one evidence path per
|
|
81
81
|
survivor.
|
|
82
82
|
7. **Rank by impact/effort/confidence** using
|
|
83
83
|
\`(impact points / effort cost) * confidence multiplier\` and recommend
|
|
@@ -209,8 +209,11 @@ Only survivors advance to ranking.
|
|
|
209
209
|
- **Effort** — S / M / L
|
|
210
210
|
- **Confidence** — High / Medium / Low
|
|
211
211
|
- **Evidence** — path(s) or command output, inline if short
|
|
212
|
+
- **Why now** — timing signal from repo evidence, user friction, repeated knowledge, or blocked flow
|
|
213
|
+
- **Expected impact** — concrete user-facing benefit if this lands
|
|
214
|
+
- **Risk** — main implementation/product risk to manage
|
|
212
215
|
- **Counter-argument** — strongest concern that survived
|
|
213
|
-
- **
|
|
216
|
+
- **Next /cc prompt** — exact \`/cc <phrase>\` that starts the work
|
|
214
217
|
3. Sort by score \`(impact points / effort cost) * confidence multiplier\`
|
|
215
218
|
and break ties with rationale strength.
|
|
216
219
|
4. Compute the artifact filename:
|
|
@@ -246,17 +249,19 @@ Only survivors advance to ranking.
|
|
|
246
249
|
|
|
247
250
|
## Ranked survivors
|
|
248
251
|
|
|
249
|
-
| ID | Improvement | Impact | Effort | Confidence | Evidence |
|
|
250
|
-
|
|
251
|
-
| I-1 | Simplify a confusing generated prompt surface | High | S | High | <path-to-generated-surface> |
|
|
252
|
+
| ID | Improvement | Why now | Expected impact | Risk | Impact | Effort | Confidence | Evidence | Next /cc prompt |
|
|
253
|
+
|---|---|---|---|---|---|---|---|---|---|
|
|
254
|
+
| I-1 | Simplify a confusing generated prompt surface | Repeated blocker in generated UX | Faster operator recovery | Might over-trim context | High | S | High | <path-to-generated-surface> | \`/cc Simplify the confusing generated prompt surface while preserving behavior\` |
|
|
252
255
|
| … | … | … | … | … | … |
|
|
253
256
|
|
|
254
257
|
## Candidate detail
|
|
255
258
|
|
|
256
259
|
### I-1 — Simplify a confusing generated prompt surface
|
|
257
260
|
- **Evidence:** \`<path>\` contains repeated or stale guidance that a user would see.
|
|
258
|
-
- **
|
|
259
|
-
- **
|
|
261
|
+
- **Why now:** The prompt is on the daily /cc path, so confusion compounds quickly.
|
|
262
|
+
- **Expected impact:** Operators get a clearer next action without changing gates.
|
|
263
|
+
- **Risk:** Trimming too hard can remove useful orientation for new users.
|
|
264
|
+
- **Next /cc prompt:** \`/cc Simplify the confusing generated prompt surface while preserving behavior\`
|
|
260
265
|
|
|
261
266
|
### I-2 — …
|
|
262
267
|
\`\`\`
|