cclaw-cli 4.0.0 → 6.0.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.
Files changed (39) hide show
  1. package/dist/artifact-linter/brainstorm.js +40 -2
  2. package/dist/artifact-linter/design.js +2 -2
  3. package/dist/artifact-linter/review-army.d.ts +25 -0
  4. package/dist/artifact-linter/review-army.js +155 -0
  5. package/dist/artifact-linter/review.js +13 -0
  6. package/dist/artifact-linter/scope.js +9 -17
  7. package/dist/artifact-linter/shared.d.ts +93 -19
  8. package/dist/artifact-linter/shared.js +214 -96
  9. package/dist/artifact-linter.d.ts +1 -1
  10. package/dist/artifact-linter.js +1 -1
  11. package/dist/content/core-agents.js +6 -1
  12. package/dist/content/idea.js +14 -2
  13. package/dist/content/skills-elicitation.js +35 -18
  14. package/dist/content/skills.js +10 -4
  15. package/dist/content/stage-schema.d.ts +29 -0
  16. package/dist/content/stage-schema.js +17 -0
  17. package/dist/content/stages/_lint-metadata/index.js +1 -2
  18. package/dist/content/stages/brainstorm.js +5 -2
  19. package/dist/content/stages/design.js +13 -12
  20. package/dist/content/stages/review.js +21 -21
  21. package/dist/content/stages/scope.js +20 -18
  22. package/dist/content/stages/spec.js +3 -3
  23. package/dist/content/stages/tdd.js +1 -0
  24. package/dist/content/subagents.js +3 -1
  25. package/dist/content/templates.d.ts +2 -2
  26. package/dist/content/templates.js +52 -36
  27. package/dist/delegation.d.ts +16 -0
  28. package/dist/delegation.js +64 -3
  29. package/dist/flow-state.d.ts +12 -0
  30. package/dist/gate-evidence.d.ts +12 -0
  31. package/dist/gate-evidence.js +4 -1
  32. package/dist/harness-adapters.js +1 -1
  33. package/dist/internal/advance-stage/advance.d.ts +2 -0
  34. package/dist/internal/advance-stage/advance.js +2 -1
  35. package/dist/internal/advance-stage/parsers.d.ts +8 -0
  36. package/dist/internal/advance-stage/parsers.js +27 -1
  37. package/dist/internal/advance-stage/start-flow.js +13 -0
  38. package/dist/run-persistence.js +14 -2
  39. package/package.json +1 -1
@@ -38,6 +38,13 @@ export const ARTIFACT_TEMPLATES = {
38
38
  |---|---|---|---|
39
39
  | | | | |
40
40
 
41
+ ## Idea Evidence Carry-forward
42
+ > Required only when this brainstorm started from \`/cc-ideate\` (\`flow-state.interactionHints.brainstorm.fromIdeaArtifact\` is set). Skip the section entirely otherwise.
43
+ - Source: \`<.cclaw/ideas/idea-YYYY-MM-DD-slug.md>\`
44
+ - Candidate: \`I-#\`
45
+ - Reused fields: Title, Why-now, Expected impact, Risk, Counter-argument
46
+ - Newly generated: challenger row(s) only — the idea candidate becomes the \`baseline\` row of \`## Approaches\` and the seed of \`## Selected Direction\`; do NOT regenerate divergent + critique + rank work that \`/cc-ideate\` already produced.
47
+
41
48
  ## Problem Decision Record
42
49
  - **Depth:** lite | standard | deep
43
50
  - **Frame type:** \`<free-form-label>\` (one short token that names how this work is framed; pick whatever fits — examples in commentary only: \`product\`, \`technical-maintenance\`, \`research-spike\`, \`ops-incident\`, \`infrastructure\`, \`library-extraction\`. Do NOT treat the examples as an enum.)
@@ -79,9 +86,10 @@ export const ARTIFACT_TEMPLATES = {
79
86
  ## Q&A Log
80
87
  | Turn | Question | User answer (1-line) | Decision impact |
81
88
  |---|---|---|---|
82
- | 1 | | | |
89
+ | 1 | | | scope-shaping [topic:pain] |
83
90
 
84
91
  > Append-only by turn. Add one row after each user answer; do not rewrite prior rows.
92
+ > **Topic tag is MANDATORY for forcing-question rows.** Stamp \`[topic:<id>]\` in the \`Decision impact\` cell so the linter can verify coverage in any natural language (RU/EN/UA/etc.). Brainstorm IDs: \`pain\`, \`direct-path\`, \`do-nothing\`, \`operator\`, \`no-go\`. Multiple tags allowed when one answer covers several topics. Stop-signal rows do NOT need a tag. Wave 24 (v6.0.0) removed the English keyword fallback.
85
93
 
86
94
  ## Approach Tier
87
95
  - Tier: lite | standard | deep
@@ -202,9 +210,10 @@ ${MARKDOWN_CODE_FENCE}
202
210
  ## Q&A Log
203
211
  | Turn | Question | User answer (1-line) | Decision impact |
204
212
  |---|---|---|---|
205
- | 1 | | | |
213
+ | 1 | | | scope-shaping [topic:in-out] |
206
214
 
207
215
  > Append-only by turn. Add one row after each user answer; do not rewrite prior rows.
216
+ > **Topic tag is MANDATORY for forcing-question rows.** Stamp \`[topic:<id>]\` in the \`Decision impact\` cell so the linter can verify coverage in any natural language (RU/EN/UA/etc.). Scope IDs: \`in-out\`, \`locked-upstream\`, \`rollback\`, \`failure-modes\`. Multiple tags allowed when one answer covers several topics. Stop-signal rows do NOT need a tag. Wave 24 (v6.0.0) removed the English keyword fallback.
208
217
 
209
218
  ## Pre-Scope System Audit
210
219
  | Check | Command | Findings |
@@ -219,23 +228,14 @@ ${MARKDOWN_CODE_FENCE}
219
228
  - Every error has a name:
220
229
  - Four paths per data flow:
221
230
 
222
- ## Premise Challenge
223
- | Question | Answer (take a position) | Evidence / leverage |
224
- |---|---|---|
225
- | Right problem? | | |
226
- | Direct path? | | |
227
- | What if we do nothing? | | |
228
- | Existing-code leverage? | | |
229
- | Reversibility cost? | | |
230
-
231
- ## Implementation Alternatives
232
- | Option | Summary | Effort (S/M/L/XL) | Risk (Low/Med/High) | Pros | Cons | Reuses |
233
- |---|---|---|---|---|---|---|
234
- | A (minimum viable) | | | | | | |
235
- | B (ideal architecture) | | | | | | |
236
- | C (optional) | | | | | | |
231
+ ## Premise Drift
232
+ > Optional. Brainstorm OWNS the premise check. Record \`None\` unless scope-stage Q&A surfaced new evidence (constraint, user signal, regulatory change) that materially changes brainstorm's \`## Premise Check\` answer.
233
+
234
+ | Brainstorm question | New evidence (scope-stage) | Drift verdict (no-change / shift / reverse) | Action |
235
+ |---|---|---|---|
236
+ | (cite brainstorm Q) | | | |
237
237
 
238
- RECOMMENDATION: <option letterone-line rationale tying back to premise challenge and existing-code leverage>
238
+ - Default: \`Drift: Nonebrainstorm Premise Check stands.\`
239
239
 
240
240
  ## Scope Contract
241
241
  - **Selected mode:** HOLD SCOPE | SELECTIVE EXPANSION | SCOPE EXPANSION | SCOPE REDUCTION
@@ -247,8 +247,9 @@ RECOMMENDATION: <option letter — one-line rationale tying back to premise chal
247
247
  - **Deferred ideas:**
248
248
  - **Accepted reference ideas:**
249
249
  - **Rejected reference ideas:**
250
+ - **Constraints (external/regulatory/system/integration):** (spec carries these forward — do NOT restate as assumptions)
250
251
  - **Success definition:**
251
- - **Design handoff:**
252
+ - **Design handoff:** (name what design must decide: architecture-tier, framework, data-model, etc. — design OWNS the architecture choice)
252
253
 
253
254
  ## Decision Drivers
254
255
  | Driver | Weight (1-5) | Option A | Option B | Option C | Notes |
@@ -448,9 +449,10 @@ ${MARKDOWN_CODE_FENCE}
448
449
  ## Q&A Log
449
450
  | Turn | Question | User answer (1-line) | Decision impact |
450
451
  |---|---|---|---|
451
- | 1 | | | |
452
+ | 1 | | | architecture-shaping [topic:data-flow] |
452
453
 
453
454
  > Append-only by turn. Add one row after each user answer; do not rewrite prior rows.
455
+ > **Topic tag is MANDATORY for forcing-question rows.** Stamp \`[topic:<id>]\` in the \`Decision impact\` cell so the linter can verify coverage in any natural language (RU/EN/UA/etc.). Design IDs: \`data-flow\`, \`seams\`, \`invariants\`, \`not-refactor\`. Multiple tags allowed when one answer covers several topics. Stop-signal rows do NOT need a tag. Wave 24 (v6.0.0) removed the English keyword fallback.
454
456
 
455
457
  ## Codebase Investigation
456
458
  | File | Current responsibility | Patterns discovered | Existing fit / reuse candidate |
@@ -528,8 +530,12 @@ ${MARKDOWN_CODE_FENCE}
528
530
  |---|---|---|---|---|
529
531
  | | | | clear/stale | |
530
532
 
531
- ## What Already Exists
532
- | Sub-problem | Existing code/library | Layer | Reuse decision |
533
+ ## Blast-radius Diff
534
+ > Diff since scope artifact baseline. Scope OWNS the full repo audit (\`## Pre-Scope System Audit\`); design only diffs touched paths.
535
+ >
536
+ > Suggested command: \`git diff <scope-artifact-head-sha>..HEAD -- <touched-paths>\`
537
+
538
+ | File | Change since scope (\`git diff\` summary) | Current responsibility | Reuse candidate / existing pattern |
533
539
  |---|---|---|---|
534
540
  | | | | |
535
541
 
@@ -624,9 +630,6 @@ ${MARKDOWN_CODE_FENCE}
624
630
  - Max iterations: 3
625
631
  - Unresolved concerns:
626
632
 
627
- ## NOT in scope
628
- -
629
-
630
633
  ## Parallelization Strategy
631
634
  - Standard/Deep add-on when multi-module; omit for compact sequential work.
632
635
  - Parallel lanes:
@@ -722,8 +725,10 @@ ${MARKDOWN_CODE_FENCE}
722
725
  | AC-1 | | |
723
726
 
724
727
  ## Constraints and Assumptions
725
- - Constraints:
726
- - Assumptions:
728
+ > Constraints are CARRIED FORWARD from scope's \`## Scope Contract > Constraints\`. Cite or copy with attribution; do NOT re-author. Spec OWNS testable assumptions in \`## Assumptions Before Finalization\` below.
729
+
730
+ - **Constraints (carry-forward):** See scope: \`02-scope-<slug>.md#scope-contract\` (or list new spec-stage constraints with citation to the Q&A row that surfaced them).
731
+ - **Assumptions:** See \`## Assumptions Before Finalization\` (spec-only owner).
727
732
 
728
733
  ## Assumptions Before Finalization
729
734
  | Assumption | Source / confidence | Validation path | Disposition |
@@ -1184,9 +1189,14 @@ Execution rule: complete and verify each batch before starting the next batch.
1184
1189
  | AC-1 | PASS/FAIL | |
1185
1190
 
1186
1191
  ## Layer 2 Findings
1192
+ > Wave 23 (v5.0.0): Layer 2 categories OWNED by review = cross-slice correctness, security, dependency/version, observability, external-safety. Performance + architecture findings are CARRY-FORWARD from \`03-design-<slug>.md\` (Performance Budget, ADR) — cite, do NOT re-derive. Single-slice findings stay in \`06-tdd.md > Per-Slice Review\`; review may cite their IDs (severity/disposition must match — cross-artifact-duplication linter blocks otherwise).
1193
+
1187
1194
  | ID | Severity | Category | File:line / no-line reason | Description | Status |
1188
1195
  |---|---|---|---|---|---|
1189
- | R-1 | Critical/Important/Suggestion | correctness/security/performance/architecture/external-safety | path:line | | open/resolved |
1196
+ | R-1 | Critical/Important/Suggestion | cross-slice-correctness/security/dependency-version/observability/external-safety | path:line | | open/resolved |
1197
+ | R-2 | from-design | performance | cite \`03-design-<slug>.md > Performance Budget\` | | carry-forward |
1198
+ | R-3 | from-design | architecture | cite \`03-design-<slug>.md > ADR\` | | carry-forward |
1199
+ | R-4 | from-tdd | from-tdd | cite \`06-tdd.md > Per-Slice Review > F-<n>\` | | carry-forward |
1190
1200
  - NO_FINDINGS_ATTESTATION: <required when no findings are reported; cite inspected coverage>
1191
1201
 
1192
1202
  ## Lens Coverage
@@ -1477,13 +1487,19 @@ regardless of whether stage skills loaded.
1477
1487
 
1478
1488
  Before drafting any \`.cclaw/artifacts/01-brainstorm-*.md\`,
1479
1489
  \`02-scope-*.md\`, or \`03-design-*.md\`, verify that the artifact's
1480
- \`## Q&A Log\` table contains at least the floor count for the active track
1481
- (see \`questionBudgetHint(track, stage).min\`). Walk the stage forcing
1482
- questions one at a time via the \`AskQuestion\` tool. If you find yourself
1483
- proposing a draft after 1-2 questions, STOP and continue the loop.
1484
-
1485
- The \`qa_log_below_min\` linter rule will block \`stage-complete\` when below
1486
- floor unless an explicit user stop-signal row is recorded.
1490
+ \`## Q&A Log\` table demonstrates Ralph-Loop convergence: every
1491
+ forcing-question topic id is tagged \`[topic:<id>]\` on at least one row
1492
+ (see the stage's forcing-questions checklist for the id list), the last
1493
+ 2 turns produce no new decision-changing impact, OR an explicit user
1494
+ stop-signal row is recorded. Walk the stage forcing questions one at a
1495
+ time via the \`AskQuestion\` tool. If you find yourself proposing a
1496
+ draft after 1-2 questions while forcing topic ids remain untagged, STOP
1497
+ and continue the loop.
1498
+
1499
+ The \`qa_log_unconverged\` linter rule will block \`stage-complete\` when
1500
+ convergence has not been reached. Wave 24 (v6.0.0) made \`[topic:<id>]\`
1501
+ tagging mandatory; the English keyword fallback was removed because it
1502
+ mis-reported convergence on RU/UA Q&A logs.
1487
1503
 
1488
1504
  ## 2. Mandatory subagents run after Q&A approval
1489
1505
 
@@ -1555,7 +1571,7 @@ Track-specific skips are allowed only when \`flow-state.track\` + \`skippedStage
1555
1571
  ## Delegation And Approvals
1556
1572
 
1557
1573
  - Machine-only checks in design/plan/tdd/review/ship should auto-dispatch when tooling supports it.
1558
- - **For brainstorm / scope / design stages**: ask user input continuously via adaptive elicitation (one question per turn through the harness-native question tool — \`AskQuestion\` in Cursor). Walk the stage forcing-questions list one-by-one. Do NOT batch and do NOT defer to a single approval gate at the end. The \`qa_log_below_min\` linter rule will block \`stage-complete\` when below floor.
1574
+ - **For brainstorm / scope / design stages**: ask user input continuously via adaptive elicitation (one question per turn through the harness-native question tool — \`AskQuestion\` in Cursor). Walk the stage forcing-questions list one-by-one. **Tag each Q&A Log row's \`Decision impact\` cell with \`[topic:<id>]\`** (the id is given in the stage's forcing-questions checklist) so the linter can verify coverage in any natural language. Do NOT batch and do NOT defer to a single approval gate at the end. The \`qa_log_unconverged\` linter rule will block \`stage-complete\` when convergence is not reached (forcing topic ids untagged AND last 2 turns still produce decision-changing rows AND no stop-signal).
1559
1575
  - **For other stages** (spec/plan/tdd/build/review/ship): ask user input only at explicit approval gates (scope mode, plan approval, challenge resolution, ship finalization), not for routine progress updates.
1560
1576
  - If you find yourself proposing a draft after 1-2 questions in brainstorm/scope/design, STOP — go back to the forcing-questions list and continue.
1561
1577
  - Mandatory subagents in brainstorm/scope/design run only AFTER the user approves the elicitation outcome (see each stage's "Run Phase: post-elicitation" rows). Dispatching them before the Q&A loop converges violates the contract.
@@ -1,4 +1,5 @@
1
1
  import { type SubagentFallback } from "./harness-adapters.js";
2
+ import { type MandatoryDelegationTaskClass } from "./content/stage-schema.js";
2
3
  import type { FlowStage } from "./types.js";
3
4
  export type DelegationMode = "mandatory" | "proactive";
4
5
  export type DelegationStatus = "scheduled" | "launched" | "acknowledged" | "completed" | "failed" | "waived" | "stale";
@@ -143,6 +144,13 @@ export declare function appendDelegation(projectRoot: string, entry: DelegationE
143
144
  export declare function expectedFulfillmentMode(fallbacks: SubagentFallback[]): DelegationFulfillmentMode;
144
145
  export declare function checkMandatoryDelegations(projectRoot: string, stage: FlowStage, options?: {
145
146
  repairFeatureSystem?: boolean;
147
+ /**
148
+ * Optional task class for the active run. When set to
149
+ * `"software-bugfix"`, the mandatory delegation gate is skipped
150
+ * entirely (Wave 24). Callers that don't classify the run leave
151
+ * this undefined and rely on the track-based skip.
152
+ */
153
+ taskClass?: MandatoryDelegationTaskClass | null;
146
154
  }): Promise<{
147
155
  satisfied: boolean;
148
156
  missing: string[];
@@ -160,4 +168,12 @@ export declare function checkMandatoryDelegations(projectRoot: string, stage: Fl
160
168
  staleWorkers: string[];
161
169
  /** Expected fulfillment mode for the active harness set. */
162
170
  expectedMode: DelegationFulfillmentMode;
171
+ /**
172
+ * Wave 24 (v6.0.0): true when `mandatoryAgentsFor` returned [] for
173
+ * this (track, taskClass) combination — i.e. the gate was skipped
174
+ * entirely on quick track or software-bugfix runs. The skip is also
175
+ * recorded as a `mandatory_delegations_skipped_by_track` event in
176
+ * `delegation-events.jsonl` for audit traceability.
177
+ */
178
+ skippedByTrack: boolean;
163
179
  }>;
@@ -7,7 +7,7 @@ import { readConfig } from "./config.js";
7
7
  import { exists, withDirectoryLock, writeFileSafe } from "./fs-utils.js";
8
8
  import { HARNESS_ADAPTERS } from "./harness-adapters.js";
9
9
  import { readFlowState } from "./runs.js";
10
- import { stageSchema } from "./content/stage-schema.js";
10
+ import { mandatoryAgentsFor, stageSchema } from "./content/stage-schema.js";
11
11
  const execFileAsync = promisify(execFile);
12
12
  const TERMINAL_DELEGATION_STATUSES = new Set(["completed", "failed", "waived", "stale"]);
13
13
  export const DELEGATION_DISPATCH_SURFACES = [
@@ -320,6 +320,21 @@ export async function readDelegationLedger(projectRoot) {
320
320
  return { runId: activeRunId, entries: [] };
321
321
  }
322
322
  }
323
+ /**
324
+ * Wave 24 (v6.0.0) audit-only event types that live in
325
+ * `delegation-events.jsonl` but do NOT carry a delegation lifecycle
326
+ * payload (no agent/spanId). The parser must accept them so they
327
+ * don't show up as corrupt lines.
328
+ */
329
+ const NON_DELEGATION_AUDIT_EVENTS = new Set([
330
+ "mandatory_delegations_skipped_by_track"
331
+ ]);
332
+ function isAuditEventLine(parsed) {
333
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
334
+ return false;
335
+ const evt = parsed.event;
336
+ return typeof evt === "string" && NON_DELEGATION_AUDIT_EVENTS.has(evt);
337
+ }
323
338
  export async function readDelegationEvents(projectRoot) {
324
339
  const filePath = delegationEventsPath(projectRoot);
325
340
  if (!(await exists(filePath))) {
@@ -338,6 +353,11 @@ export async function readDelegationEvents(projectRoot) {
338
353
  if (isDelegationEvent(parsed)) {
339
354
  events.push(parsed);
340
355
  }
356
+ else if (isAuditEventLine(parsed)) {
357
+ // Wave 24 audit-only row (e.g. mandatory_delegations_skipped_by_track).
358
+ // Not a delegation lifecycle event but valid audit content.
359
+ continue;
360
+ }
341
361
  else {
342
362
  corruptLines.push(index + 1);
343
363
  }
@@ -451,7 +471,17 @@ export async function checkMandatoryDelegations(projectRoot, stage, options = {}
451
471
  const flowState = await readFlowState(projectRoot, {
452
472
  repairFeatureSystem: options.repairFeatureSystem
453
473
  });
454
- const mandatory = stageSchema(stage, flowState.track).mandatoryDelegations;
474
+ const mandatory = mandatoryAgentsFor(stage, flowState.track, options.taskClass ?? null);
475
+ const skippedByTrack = mandatory.length === 0 &&
476
+ stageSchema(stage, flowState.track).mandatoryDelegations.length > 0;
477
+ if (skippedByTrack) {
478
+ await recordMandatorySkippedByTrack(projectRoot, {
479
+ stage,
480
+ track: flowState.track,
481
+ taskClass: options.taskClass ?? null,
482
+ runId: flowState.activeRunId
483
+ });
484
+ }
455
485
  const { activeRunId } = flowState;
456
486
  const ledger = await readDelegationLedger(projectRoot);
457
487
  const events = await readDelegationEvents(projectRoot);
@@ -553,6 +583,37 @@ export async function checkMandatoryDelegations(projectRoot, stage, options = {}
553
583
  legacyInferredCompletions,
554
584
  corruptEventLines: events.corruptLines,
555
585
  staleWorkers,
556
- expectedMode
586
+ expectedMode,
587
+ skippedByTrack
557
588
  };
558
589
  }
590
+ /**
591
+ * Wave 24 (v6.0.0) — append a non-delegation audit event to
592
+ * `delegation-events.jsonl` recording that the mandatory delegation
593
+ * gate was skipped because of the active track / task class. Plays the
594
+ * same audit role as a `waived` row but does NOT carry an agent —
595
+ * downstream tooling treats `event === "mandatory_delegations_skipped_by_track"`
596
+ * lines as informational.
597
+ *
598
+ * Failures are swallowed: the audit log is best-effort. Missing the
599
+ * event must never block stage advance because the gate skip itself is
600
+ * authoritative.
601
+ */
602
+ async function recordMandatorySkippedByTrack(projectRoot, params) {
603
+ const eventsPath = delegationEventsPath(projectRoot);
604
+ const payload = {
605
+ event: "mandatory_delegations_skipped_by_track",
606
+ stage: params.stage,
607
+ track: params.track,
608
+ taskClass: params.taskClass,
609
+ runId: params.runId,
610
+ ts: new Date().toISOString()
611
+ };
612
+ try {
613
+ await fs.mkdir(path.dirname(eventsPath), { recursive: true });
614
+ await fs.appendFile(eventsPath, `${JSON.stringify(payload)}\n`, "utf8");
615
+ }
616
+ catch {
617
+ // best-effort audit; never block stage advance.
618
+ }
619
+ }
@@ -93,6 +93,18 @@ export interface StageInteractionHint {
93
93
  skipQuestions?: boolean;
94
94
  sourceStage?: FlowStage;
95
95
  recordedAt?: string;
96
+ /**
97
+ * Wave 23 (v5.0.0) — `/cc-ideate` handoff carry-forward.
98
+ * When a brainstorm run is started from a `/cc-ideate` recommendation,
99
+ * `start-flow` records the originating idea artifact so brainstorm can
100
+ * reuse the divergent + critique + rank work instead of re-generating it.
101
+ *
102
+ * `fromIdeaArtifact` is a workspace-relative POSIX path to
103
+ * `.cclaw/ideas/idea-YYYY-MM-DD-<slug>.md` (or wherever `/cc-ideate`
104
+ * wrote its artifact). `fromIdeaCandidateId` is the chosen `I-#` row.
105
+ */
106
+ fromIdeaArtifact?: string;
107
+ fromIdeaCandidateId?: string;
96
108
  }
97
109
  export interface InitialFlowStateOptions {
98
110
  activeRunId?: string;
@@ -12,11 +12,23 @@ import { type FlowStage } from "./types.js";
12
12
  export interface QaLogFloorSignal {
13
13
  ok: boolean;
14
14
  count: number;
15
+ /**
16
+ * Wave 23 (v5.0.0): always 0. The convergence floor no longer enforces
17
+ * a fixed count. Harness UIs may render `questionBudgetHint(track,
18
+ * stage).recommended` separately as a soft hint.
19
+ */
15
20
  min: number;
16
21
  hasStopSignal: boolean;
22
+ /** Wave 23: always false. See `min` note above. */
17
23
  liteShortCircuit: boolean;
18
24
  skipQuestionsAdvisory: boolean;
19
25
  blocking: boolean;
26
+ /** Forcing-question topics deemed addressed in `## Q&A Log`. */
27
+ forcingCovered: string[];
28
+ /** Forcing-question topics still pending (no Q&A row matched). */
29
+ forcingPending: string[];
30
+ /** Ralph-Loop convergence detector verdict for the last 2 rows. */
31
+ noNewDecisions: boolean;
20
32
  }
21
33
  export interface GateEvidenceCheckResult {
22
34
  ok: boolean;
@@ -471,7 +471,10 @@ export async function verifyCurrentStageGateEvidence(projectRoot, flowState, opt
471
471
  hasStopSignal: floor.hasStopSignal,
472
472
  liteShortCircuit: floor.liteShortCircuit,
473
473
  skipQuestionsAdvisory: floor.skipQuestionsAdvisory,
474
- blocking: !floor.ok && !floor.skipQuestionsAdvisory
474
+ blocking: !floor.ok && !floor.skipQuestionsAdvisory,
475
+ forcingCovered: floor.forcingCovered,
476
+ forcingPending: floor.forcingPending,
477
+ noNewDecisions: floor.noNewDecisions
475
478
  };
476
479
  }
477
480
  return {
@@ -349,7 +349,7 @@ Before responding to a coding request:
349
349
 
350
350
  Three rules apply to every cclaw stage in this project, regardless of which skills loaded:
351
351
 
352
- 1. **Q&A floor before drafting** — for brainstorm / scope / design, walk the stage forcing questions one at a time via the harness-native question tool (Claude \`AskUserQuestion\`, Cursor \`AskQuestion\`, Codex \`request_user_input\`, Gemini \`ask_user\`). The \`qa_log_below_min\` linter rule will block \`stage-complete\` when the artifact's \`## Q&A Log\` is below \`questionBudgetHint(track, stage).min\` unless an explicit user stop-signal row is recorded.
352
+ 1. **Q&A convergence before drafting** — for brainstorm / scope / design, walk the stage forcing questions one at a time via the harness-native question tool (Claude \`AskUserQuestion\`, Cursor \`AskQuestion\`, Codex \`request_user_input\`, Gemini \`ask_user\`). The \`qa_log_unconverged\` linter rule will block \`stage-complete\` when convergence has not been reached. Convergence is satisfied when ANY of: (a) every forcing-question topic id is tagged \`[topic:<id>]\` in at least one \`## Q&A Log\` row, (b) the last 2 substantive rows produce no decision-changing impact (Ralph-Loop), or (c) an explicit user stop-signal row is recorded. The fixed count floor (10 for standard) was removed in Wave 23. Wave 24 (v6.0.0) made \`[topic:<id>]\` tagging mandatory (no English keyword fallback) so the gate works in any natural language.
353
353
  2. **Subagents run after Q&A approval** — mandatory subagents in brainstorm / scope / design (\`product-discovery\`, \`critic\`, \`planner\`, \`architect\`, \`test-author\`) run only AFTER the user approves the elicitation outcome. See each stage's "Run Phase: post-elicitation" rows in the materialized Automatic Subagent Dispatch table.
354
354
  3. **No command-line echo to chat** — the user does not run cclaw helpers manually. Never paste \`node .cclaw/hooks/...\` invocations, \`--evidence-json '{...}'\` payloads, or shell hash commands (\`shasum\`, \`sha256sum\`, \`Get-FileHash\`, \`certutil\`, etc.) into chat. Run helpers via the tool layer; report only the resulting summary.
355
355
 
@@ -19,6 +19,8 @@ interface InternalValidationReport {
19
19
  corruptEventLines: number[];
20
20
  staleWorkers: string[];
21
21
  expectedMode: string;
22
+ /** Wave 24: true when mandatoryAgentsFor returned [] for the run's track / taskClass. */
23
+ skippedByTrack: boolean;
22
24
  };
23
25
  gates: {
24
26
  ok: boolean;
@@ -111,7 +111,8 @@ export async function buildValidationReport(projectRoot, flowState, options = {}
111
111
  legacyInferredCompletions: delegation.legacyInferredCompletions,
112
112
  corruptEventLines: delegation.corruptEventLines,
113
113
  staleWorkers: delegation.staleWorkers,
114
- expectedMode: delegation.expectedMode
114
+ expectedMode: delegation.expectedMode,
115
+ skippedByTrack: delegation.skippedByTrack
115
116
  },
116
117
  gates: {
117
118
  ok: gates.ok,
@@ -39,6 +39,14 @@ export interface StartFlowArgs {
39
39
  forceReset: boolean;
40
40
  reclassify: boolean;
41
41
  quiet: boolean;
42
+ /**
43
+ * Wave 23 (v5.0.0) — `/cc-ideate` handoff carry-forward.
44
+ * Workspace-relative POSIX path to `.cclaw/ideas/idea-YYYY-MM-DD-<slug>.md`
45
+ * (or wherever `/cc-ideate` wrote its artifact).
46
+ */
47
+ fromIdeaArtifact?: string;
48
+ /** Optional `I-#` row id chosen from the idea artifact's ranked list. */
49
+ fromIdeaCandidateId?: string;
42
50
  }
43
51
  export interface CancelRunArgs {
44
52
  reason: string;
@@ -211,6 +211,8 @@ export function parseStartFlowArgs(tokens) {
211
211
  let forceReset = false;
212
212
  let reclassify = false;
213
213
  let quiet = false;
214
+ let fromIdeaArtifact;
215
+ let fromIdeaCandidateId;
214
216
  for (let i = 0; i < tokens.length; i += 1) {
215
217
  const token = tokens[i];
216
218
  const nextToken = tokens[i + 1];
@@ -259,12 +261,36 @@ export function parseStartFlowArgs(tokens) {
259
261
  stack = readValue("--stack").trim();
260
262
  continue;
261
263
  }
264
+ if (token === "--from-idea-artifact" || token.startsWith("--from-idea-artifact=")) {
265
+ const raw = readValue("--from-idea-artifact").trim();
266
+ fromIdeaArtifact = raw.length > 0 ? raw : undefined;
267
+ continue;
268
+ }
269
+ if (token === "--from-idea-candidate" || token.startsWith("--from-idea-candidate=")) {
270
+ const raw = readValue("--from-idea-candidate").trim();
271
+ fromIdeaCandidateId = raw.length > 0 ? raw : undefined;
272
+ continue;
273
+ }
262
274
  throw new Error(`Unknown flag for internal start-flow: ${token}`);
263
275
  }
264
276
  if (!track) {
265
277
  throw new Error("internal start-flow requires --track=<standard|medium|quick>.");
266
278
  }
267
- return { track, className, prompt, reason, stack, forceReset, reclassify, quiet };
279
+ if (fromIdeaCandidateId && !fromIdeaArtifact) {
280
+ throw new Error("--from-idea-candidate requires --from-idea-artifact=<path> to be set as well.");
281
+ }
282
+ return {
283
+ track,
284
+ className,
285
+ prompt,
286
+ reason,
287
+ stack,
288
+ forceReset,
289
+ reclassify,
290
+ quiet,
291
+ fromIdeaArtifact,
292
+ fromIdeaCandidateId
293
+ };
268
294
  }
269
295
  export function parseCancelRunArgs(tokens) {
270
296
  let reason;
@@ -119,6 +119,19 @@ export async function runStartFlow(projectRoot, args, io) {
119
119
  else {
120
120
  nextState = createInitialFlowState({ track: args.track });
121
121
  }
122
+ if (args.fromIdeaArtifact) {
123
+ const existingHints = nextState.interactionHints ?? {};
124
+ const existingBrainstorm = existingHints.brainstorm ?? {};
125
+ nextState.interactionHints = {
126
+ ...existingHints,
127
+ brainstorm: {
128
+ ...existingBrainstorm,
129
+ fromIdeaArtifact: args.fromIdeaArtifact,
130
+ ...(args.fromIdeaCandidateId ? { fromIdeaCandidateId: args.fromIdeaCandidateId } : {}),
131
+ recordedAt: new Date().toISOString()
132
+ }
133
+ };
134
+ }
122
135
  await writeFlowState(projectRoot, nextState, { allowReset: true });
123
136
  await appendIdeaArtifact(projectRoot, args, current);
124
137
  if (!args.quiet) {
@@ -246,13 +246,25 @@ function sanitizeInteractionHints(value) {
246
246
  const skipQuestions = typed.skipQuestions === true ? true : undefined;
247
247
  const sourceStage = isFlowStage(typed.sourceStage) ? typed.sourceStage : undefined;
248
248
  const recordedAt = typeof typed.recordedAt === "string" ? typed.recordedAt : undefined;
249
- if (skipQuestions !== true && !sourceStage && !recordedAt) {
249
+ const fromIdeaArtifact = typeof typed.fromIdeaArtifact === "string" && typed.fromIdeaArtifact.trim().length > 0
250
+ ? typed.fromIdeaArtifact.trim()
251
+ : undefined;
252
+ const fromIdeaCandidateId = typeof typed.fromIdeaCandidateId === "string" && typed.fromIdeaCandidateId.trim().length > 0
253
+ ? typed.fromIdeaCandidateId.trim()
254
+ : undefined;
255
+ if (skipQuestions !== true &&
256
+ !sourceStage &&
257
+ !recordedAt &&
258
+ !fromIdeaArtifact &&
259
+ !fromIdeaCandidateId) {
250
260
  continue;
251
261
  }
252
262
  out[stage] = {
253
263
  ...(skipQuestions ? { skipQuestions } : {}),
254
264
  ...(sourceStage ? { sourceStage } : {}),
255
- ...(recordedAt ? { recordedAt } : {})
265
+ ...(recordedAt ? { recordedAt } : {}),
266
+ ...(fromIdeaArtifact ? { fromIdeaArtifact } : {}),
267
+ ...(fromIdeaCandidateId ? { fromIdeaCandidateId } : {})
256
268
  };
257
269
  }
258
270
  return out;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cclaw-cli",
3
- "version": "4.0.0",
3
+ "version": "6.0.0",
4
4
  "description": "Installer-first flow toolkit for coding agents",
5
5
  "type": "module",
6
6
  "bin": {