cclaw-cli 0.51.27 → 0.51.29

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 (43) hide show
  1. package/dist/artifact-linter.js +73 -16
  2. package/dist/cli.d.ts +17 -1
  3. package/dist/cli.js +185 -49
  4. package/dist/codex-feature-flag.d.ts +1 -1
  5. package/dist/codex-feature-flag.js +1 -1
  6. package/dist/config.js +3 -0
  7. package/dist/content/cancel-command.d.ts +2 -0
  8. package/dist/content/cancel-command.js +25 -0
  9. package/dist/content/finish-command.d.ts +2 -0
  10. package/dist/content/finish-command.js +26 -0
  11. package/dist/content/harness-doc.js +1 -1
  12. package/dist/content/hooks.js +32 -9
  13. package/dist/content/ideate-command.js +12 -7
  14. package/dist/content/next-command.js +17 -13
  15. package/dist/content/node-hooks.js +22 -6
  16. package/dist/content/opencode-plugin.js +1 -1
  17. package/dist/content/stages/review.js +1 -1
  18. package/dist/content/stages/tdd.js +1 -1
  19. package/dist/content/start-command.js +6 -5
  20. package/dist/content/state-contracts.js +1 -1
  21. package/dist/content/status-command.js +4 -3
  22. package/dist/content/track-render-context.d.ts +1 -0
  23. package/dist/content/track-render-context.js +2 -0
  24. package/dist/doctor-registry.d.ts +2 -0
  25. package/dist/doctor-registry.js +37 -10
  26. package/dist/doctor.d.ts +2 -1
  27. package/dist/doctor.js +183 -2
  28. package/dist/fs-utils.js +6 -0
  29. package/dist/harness-adapters.js +29 -5
  30. package/dist/install.d.ts +4 -1
  31. package/dist/install.js +37 -4
  32. package/dist/internal/advance-stage.js +6 -6
  33. package/dist/managed-resources.d.ts +53 -0
  34. package/dist/managed-resources.js +289 -0
  35. package/dist/run-archive.d.ts +8 -0
  36. package/dist/run-archive.js +19 -5
  37. package/dist/runs.d.ts +1 -1
  38. package/dist/runs.js +1 -1
  39. package/dist/tdd-cycle.js +10 -10
  40. package/dist/tdd-verification-evidence.js +4 -4
  41. package/dist/track-heuristics.d.ts +2 -0
  42. package/dist/track-heuristics.js +11 -3
  43. package/package.json +1 -1
@@ -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.";
@@ -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 resolveCliEntrypointForGeneratedHook() {
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
- return null;
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 cliEntrypoint = resolveCliEntrypointForGeneratedHook();
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(cliEntrypoint)};
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 cliEntrypoint = resolveCliEntrypointForGeneratedHook();
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(cliEntrypoint)};
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
- - **Proposed handoff** — exact \`/cc <phrase>\`
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
- - **Counter-argument:** Trimming too hard can remove useful orientation for new users.
259
- - **Handoff:** \`/cc Simplify the confusing generated prompt surface while preserving behavior\`
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
  \`\`\`
@@ -74,17 +74,17 @@ ${conversationLanguagePolicyMarkdown()}
74
74
 
75
75
  ## Algorithm (mandatory)
76
76
 
77
- 1. Read **\`${flowPath}\`**. If missing → **BLOCKED** (state missing).
77
+ 1. Read **\`${flowPath}\`**. If missing → **BLOCKED** (state missing). Next action: run \`cclaw sync\` to safely regenerate generated runtime files, then \`cclaw doctor --explain\`; do not hand-edit state unless doctor says user repair is required.
78
78
  2. Parse JSON. Capture \`currentStage\` and \`stageGateCatalog[currentStage]\`.
79
- 3. If \`staleStages[currentStage]\` exists, do not advance automatically. Report the stale marker reason/rewindId, re-run the stage artifact work, then clear only the current stage marker with \`cclaw internal rewind --ack <currentStage>\`.
80
- 4. Read **\`${reconciliationNoticesPath}\`** when present. If it contains entries for \`activeRunId + currentStage\` and the listed gate is still blocked in \`stageGateCatalog[currentStage].blocked\`, emit a structured warning before any stage-advance decision.
79
+ 3. If \`staleStages[currentStage]\` exists, do not advance automatically. Report \`Blocked by: stale stage\`, the marker reason/rewindId, the stage artifact work to re-run, and clear only the current stage marker with \`cclaw internal rewind --ack <currentStage>\` after rework.
80
+ 4. Read **\`${reconciliationNoticesPath}\`** when present. If it contains entries for \`activeRunId + currentStage\` and the listed gate is still blocked in \`stageGateCatalog[currentStage].blocked\`, emit \`Blocked by: reconciliation notice\` with gate id, reason, and next action \`cclaw doctor --reconcile-gates --explain\`. Clarify that reconciliation refreshes derived gate status only; it does not repair missing artifacts or tests.
81
81
  5. Let \`G\` = \`requiredGates\` for **\`currentStage\`** from the stage schema.
82
82
  6. Let \`catalog\` = \`stageGateCatalog[currentStage]\` from flow state.
83
83
  7. **Satisfied** for gate id \`g\`: \`g\` in \`catalog.passed\` and \`g\` not in \`catalog.blocked\`.
84
84
  8. Let \`M\` = \`mandatoryDelegations\` for \`currentStage\`.
85
85
  9. If \`M\` is non-empty, inspect **\`${delegationPath}\`**. Treat as satisfied only if each mandatory agent is **completed** or **waived**.
86
86
  10. For each satisfied mandatory delegation row, verify \`evidenceRefs\` is a non-empty array (unless status is \`waived\` with rationale). Missing evidenceRefs means delegation is unresolved.
87
- 11. If any mandatory delegation is missing and no waiver exists: **STOP** and ask the user whether to dispatch now or waive with rationale. Do not mark gates passed while delegation is unresolved.
87
+ 11. If any mandatory delegation is missing and no waiver exists: **STOP** and ask the user whether to dispatch \`<agent>\` now or waive with rationale. State who must run, why the role is mandatory, whether the gap is ledger status, event-log dispatch proof, or artifact \`evidenceRefs\`, and do not mark gates passed while delegation is unresolved.
88
88
  12. If \`currentStage === "review"\` and \`catalog.blocked\` includes \`review_criticals_resolved\`, treat this as a hard remediation branch: recommend the managed command \`cclaw internal rewind tdd "review_blocked_by_critical <finding-ids>"\`, and do not attempt to advance toward ship. After TDD rework, require \`cclaw internal rewind --ack tdd\` before continuing.
89
89
 
90
90
  ### Path A: Current stage is NOT complete (any gate unmet or delegation missing)
@@ -109,7 +109,7 @@ ${ralphLoopContractSnippet()}
109
109
 
110
110
  \`flow-state.json\` carries a \`track\` field (\`"quick"\`, \`"medium"\`, or \`"standard"\`) and a \`skippedStages\` array.
111
111
 
112
- - If \`track === "quick"\`, the critical path is **spec → tdd → review → ship**. When advancing, skip any stage listed in \`skippedStages\` — i.e. after the current stage completes, pick the next stage that is NOT in \`skippedStages\`.
112
+ - If \`track === "quick"\`, the critical path is **spec → tdd → review → ship**. Quick skips ceremony, not safety: spec approval, RED/GREEN/REFACTOR evidence, review, and ship gates still apply. When advancing, skip any stage listed in \`skippedStages\` — i.e. after the current stage completes, pick the next stage that is NOT in \`skippedStages\`.
113
113
  - If \`track === "medium"\`, the critical path is **brainstorm → spec → plan → tdd → review → ship**. Scope and design are intentionally skipped unless the run is reclassified to standard.
114
114
  - If \`track === "standard"\`, advance through all 8 stages in their natural order.
115
115
  - Never manually reintroduce a skipped stage mid-run. If evidence shows the track was wrong, stop and use the managed start-flow helper with \`--reclassify\`; only that managed reclassification may add upstream stages back into the active track.
@@ -190,13 +190,16 @@ Current: <currentStage or closeout.shipSubstate> (<track>)
190
190
  Stage: <currentStage>
191
191
  Gates: <passed>/<required> passed, <blocked> blocked
192
192
  Delegations: <done>/<mandatory> done
193
- Blocked by: <none | gate/delegation/reconciliation/stale/TDD/review ids>
193
+ Blocked by: <none | gate/delegation/reconciliation/stale/TDD/review/closeout ids>
194
+ Blocker category: <sync-recovery | user-decision | stage-work | delegation-proof | review-rework | closeout>
194
195
  Next: <exact next action, usually /cc-next or one named remediation>
195
196
  Evidence needed: <artifact/test/review/delegation evidence required to unblock>
196
197
  \`\`\`
197
198
 
198
199
  Only expand beyond this when blocked, when asking a structured question, or when
199
- the user explicitly requests detail. Do not dump full artifacts in progression output.
200
+ the user explicitly requests detail. When blocked, name the blocker category,
201
+ why it blocks progression, the one next command/action, and the exact proof that
202
+ would unblock it. Do not dump full artifacts in progression output.
200
203
 
201
204
  **How it works:**
202
205
  1. Reads \`flow-state.json\` to find \`currentStage\`
@@ -216,9 +219,9 @@ Do **not** mark gates satisfied from memory alone. Cite **artifact evidence** (p
216
219
 
217
220
  1. Open **\`${flowPath}\`**.
218
221
  2. Record \`currentStage\` and \`stageGateCatalog[currentStage]\`.
219
- 3. If \`staleStages[currentStage]\` exists, show the marker reason/rewindId, re-run the stage, and clear only the current marker via \`cclaw internal rewind --ack <currentStage>\` before advancing.
220
- 4. If the file is missing or invalid JSON → **BLOCKED** (report and stop).
221
- 5. Read \`${reconciliationNoticesPath}\` when present. For entries matching \`activeRunId + currentStage\` whose gate is still in \`stageGateCatalog[currentStage].blocked\`, show a warning with gate id + reason before proceeding.
222
+ 3. If \`staleStages[currentStage]\` exists, show \`Blocked by: stale stage\`, the marker reason/rewindId, re-run the stage, and clear only the current marker via \`cclaw internal rewind --ack <currentStage>\` before advancing.
223
+ 4. If the file is missing or invalid JSON → **BLOCKED** (state missing/corrupt). Next action: run \`cclaw sync\` for safe regeneration of generated runtime files, then \`cclaw doctor --explain\`; do not hand-edit flow state unless doctor says user repair is required.
224
+ 5. Read \`${reconciliationNoticesPath}\` when present. For entries matching \`activeRunId + currentStage\` whose gate is still in \`stageGateCatalog[currentStage].blocked\`, show \`Blocked by: reconciliation notice\` with gate id + reason before proceeding; \`cclaw doctor --reconcile-gates --explain\` refreshes derived gate-state only; it does not repair missing artifacts or tests.
222
225
 
223
226
  ### Step 2: Evaluate gates
224
227
 
@@ -229,7 +232,8 @@ For each gate id in \`requiredGates\` for \`currentStage\`:
229
232
  Check \`mandatoryDelegations\` via **\`${delegationPath}\`** — satisfied only if **completed** or **waived**.
230
233
  Also verify each completed mandatory delegation row has non-empty \`evidenceRefs\` (waived rows must include rationale).
231
234
  If a mandatory delegation is missing and no waiver exists, **STOP** and ask:
232
- (A) dispatch now, (B) waive with rationale, (C) cancel stage advance.
235
+ (A) dispatch \`<agent>\` now, (B) waive with rationale, (C) cancel stage advance.
236
+ Explain who must run, why that role is mandatory for this stage, and whether the missing proof is ledger status, event-log dispatch proof, or artifact \`evidenceRefs\`. Waivers must include a user-visible safety reason.
233
237
 
234
238
  If reconciliation warnings were emitted in Step 1, treat them as a pre-advance stop point: require explicit acknowledgement before continuing Path A or Path B.
235
239
 
@@ -246,7 +250,7 @@ ${ralphLoopContractSnippet()}
246
250
 
247
251
  Special-case for review: if \`review_criticals_resolved\` is in \`blocked\`, route to rework instead of looping review forever - recommend \`cclaw internal rewind tdd "review_blocked_by_critical <finding-ids>"\`, then \`cclaw internal rewind --ack tdd\` after TDD rework.
248
252
 
249
- Special-case for TDD blockers: when \`06-tdd.md\` records \`NO_SOURCE_CONTEXT\`, \`NO_TEST_SURFACE\`, \`NO_IMPLEMENTABLE_SLICE\`, \`RED_NOT_EXPRESSIBLE\`, or \`NO_VCS_MODE\`, keep status BLOCKED and print \`Current\`, \`Blocked by\`, \`Next\`, and \`Evidence needed\` instead of retrying speculative RED/GREEN work.
253
+ Special-case for TDD blockers: when \`06-tdd.md\` records \`NO_SOURCE_CONTEXT\`, \`NO_TEST_SURFACE\`, \`NO_IMPLEMENTABLE_SLICE\`, \`RED_NOT_EXPRESSIBLE\`, or \`NO_VCS_MODE\`, keep status BLOCKED and print \`Current\`, \`Blocked by\`, \`Next\`, \`Repair path\`, and \`Evidence needed\` instead of retrying speculative RED/GREEN work. RED blockers need a runnable failing test surface, GREEN blockers need passing full-suite evidence, REFACTOR blockers need behavior-preservation evidence.
250
254
 
251
255
  **Path B — stage IS complete (all gates met, all delegations done):**
252
256
 
@@ -272,7 +276,7 @@ Otherwise (non-terminal \`next\`): load the next stage skill and begin execution
272
276
 
273
277
  ## Stage order
274
278
 
275
- This table is the track-aware critical path. It must match \`flow-state.json.track\`; do not follow the natural schema edge when the active track skips a stage. After \`ship\`, \`/cc-next\` continues closeout via ${closeoutSubstateInline()}: ${closeoutChainInline()}.
279
+ This table is the track-aware critical path. It must match \`flow-state.json.track\`; do not follow the natural schema edge when the active track skips a stage. Quick skips ceremony, not safety: spec approval, RED/GREEN/REFACTOR evidence, review, and ship gates still apply. After \`ship\`, \`/cc-next\` continues closeout via ${closeoutSubstateInline()}: ${closeoutChainInline()}.
276
280
 
277
281
  | Stage | Standard next | Medium next | Quick next | Skill path |
278
282
  |---|---|---|---|---|
@@ -10,7 +10,7 @@ function normalizePatterns(patterns, fallback) {
10
10
  return [...fallback];
11
11
  return patterns.map((value) => value.trim()).filter((value) => value.length > 0);
12
12
  }
13
- function resolveCliEntrypointForGeneratedHook() {
13
+ function resolveCliRuntimeForGeneratedHook() {
14
14
  const here = fileURLToPath(import.meta.url);
15
15
  const candidates = [
16
16
  path.resolve(path.dirname(here), "..", "cli.js"),
@@ -19,9 +19,18 @@ function resolveCliEntrypointForGeneratedHook() {
19
19
  for (const candidate of candidates) {
20
20
  // Synchronous probe runs only during cclaw-cli init/sync generation.
21
21
  if (existsSync(candidate))
22
- return candidate;
22
+ return { entrypoint: candidate, argsPrefix: [] };
23
23
  }
24
- return null;
24
+ // Vitest exercises init/sync directly from src/ without a compiled dist/.
25
+ // Route that dev-only shape through vite-node so hooks still prove a local runtime.
26
+ if (process.env.VITEST === "true") {
27
+ const sourceCli = path.resolve(path.dirname(here), "..", "cli.ts");
28
+ const viteNode = path.resolve(path.dirname(here), "..", "..", "node_modules", "vite-node", "vite-node.mjs");
29
+ if (existsSync(sourceCli) && existsSync(viteNode)) {
30
+ return { entrypoint: viteNode, argsPrefix: ["--script", sourceCli] };
31
+ }
32
+ }
33
+ return { entrypoint: null, argsPrefix: [] };
25
34
  }
26
35
  /**
27
36
  * Node-only hook runtime (single entrypoint).
@@ -42,7 +51,7 @@ export function nodeHookRuntimeScript(options = {}) {
42
51
  options.compoundRecurrenceThreshold >= 1
43
52
  ? options.compoundRecurrenceThreshold
44
53
  : DEFAULT_COMPOUND_RECURRENCE_THRESHOLD;
45
- const cliEntrypoint = resolveCliEntrypointForGeneratedHook();
54
+ const cliRuntime = resolveCliRuntimeForGeneratedHook();
46
55
  return `#!/usr/bin/env node
47
56
  import fs from "node:fs/promises";
48
57
  import path from "node:path";
@@ -64,7 +73,8 @@ const DEFAULT_TDD_PRODUCTION_PATH_PATTERNS = ${JSON.stringify(tddProductionPathP
64
73
  const COMPOUND_RECURRENCE_THRESHOLD = ${JSON.stringify(compoundRecurrenceThreshold)};
65
74
  const SMALL_PROJECT_ARCHIVE_RUNS_THRESHOLD = ${JSON.stringify(SMALL_PROJECT_ARCHIVE_RUNS_THRESHOLD)};
66
75
  const SMALL_PROJECT_RECURRENCE_THRESHOLD = ${JSON.stringify(SMALL_PROJECT_RECURRENCE_THRESHOLD)};
67
- const CCLAW_CLI_ENTRYPOINT = ${JSON.stringify(cliEntrypoint)};
76
+ const CCLAW_CLI_ENTRYPOINT = ${JSON.stringify(cliRuntime.entrypoint)};
77
+ const CCLAW_CLI_ARGS_PREFIX = ${JSON.stringify(cliRuntime.argsPrefix)};
68
78
 
69
79
  function resolveStrictness() {
70
80
  return process.env.CCLAW_STRICTNESS === "strict" ? "strict" : DEFAULT_STRICTNESS;
@@ -313,6 +323,7 @@ async function readStdin() {
313
323
 
314
324
  async function runCclawInternal(root, args, options = {}) {
315
325
  const cliEntrypoint = process.env.CCLAW_CLI_JS || CCLAW_CLI_ENTRYPOINT;
326
+ const cliArgsPrefix = process.env.CCLAW_CLI_JS ? [] : CCLAW_CLI_ARGS_PREFIX;
316
327
  if (!cliEntrypoint || String(cliEntrypoint).trim().length === 0) {
317
328
  return {
318
329
  code: 1,
@@ -324,6 +335,11 @@ async function runCclawInternal(root, args, options = {}) {
324
335
  try {
325
336
  const stat = await fs.stat(cliEntrypoint);
326
337
  if (!stat.isFile()) throw new Error("not-file");
338
+ for (const argPath of cliArgsPrefix) {
339
+ if (typeof argPath !== "string" || argPath.startsWith("-")) continue;
340
+ const argStat = await fs.stat(argPath);
341
+ if (!argStat.isFile()) throw new Error("arg-not-file");
342
+ }
327
343
  } catch {
328
344
  return {
329
345
  code: 1,
@@ -345,7 +361,7 @@ async function runCclawInternal(root, args, options = {}) {
345
361
  };
346
362
  let child;
347
363
  try {
348
- child = spawn(process.execPath, [cliEntrypoint, "internal", ...args], {
364
+ child = spawn(process.execPath, [cliEntrypoint, ...cliArgsPrefix, "internal", ...args], {
349
365
  cwd: root,
350
366
  env: process.env,
351
367
  stdio: ["ignore", captureStdout ? "pipe" : "ignore", "pipe"]
@@ -131,7 +131,7 @@ export default function cclawPlugin(ctx) {
131
131
  if (stageSupport.length > 0) parts.push(...stageSupport);
132
132
 
133
133
  parts.push(
134
- "If you discover a non-obvious rule or pattern during stage work, add it to the current artifact ## Learnings section; stage-complete harvests it into .cclaw/knowledge.jsonl. Direct JSONL append is only for explicit manual learnings operations."
134
+ "If you discover a non-obvious rule or pattern during stage work, add it to the current artifact ## Learnings section; stage-complete harvests it into .cclaw/knowledge.jsonl. If this plugin does not load, run \`cclaw sync\`, verify opencode.json(.c) includes the cclaw plugin registration, then run \`cclaw doctor --explain\`. Direct JSONL append is only for explicit manual learnings operations."
135
135
  );
136
136
 
137
137
  const meta = (await readFileText(metaSkillPath)).trim();
@@ -47,7 +47,7 @@ export const REVIEW = {
47
47
  "Classify findings — Critical (blocks ship), Important (should fix), Suggestion (optional improvement).",
48
48
  "Victory Detector — before verdict, confirm Layer 1, Layer 2, security sweep, structured findings, trace evidence, and unresolved-critical status are complete; otherwise iterate findings or route back to TDD.",
49
49
  "Produce verdict — APPROVED, APPROVED_WITH_CONCERNS, or BLOCKED.",
50
- "If verdict is BLOCKED, emit remediation route token `ROUTE_BACK_TO_TDD`, include the managed command `cclaw internal rewind tdd \"review_blocked_by_critical <finding-ids>\"`, and satisfy the special transition guard `review_verdict_blocked` instead of `review_criticals_resolved`. After TDD rework, clear the stale marker with `cclaw internal rewind --ack tdd` before `/cc-next`."
50
+ "If verdict is BLOCKED, emit remediation route token `ROUTE_BACK_TO_TDD`, include the managed command `cclaw internal rewind tdd \"review_blocked_by_critical <finding-ids>\"`, list the critical finding IDs and required TDD evidence to repair, and satisfy the special transition guard `review_verdict_blocked` instead of `review_criticals_resolved`. After TDD rework, clear the stale marker with `cclaw internal rewind --ack tdd` before `/cc-next`."
51
51
  ],
52
52
  interactionProtocol: [
53
53
  "Run Layer 1 (spec compliance) completely before starting Layer 2.",
@@ -118,7 +118,7 @@ export const TDD = {
118
118
  "full suite not green",
119
119
  "behavior changed during refactor",
120
120
  "no evidence recorded",
121
- "RED/GREEN blocked — classify with the managed taxonomy `NO_SOURCE_CONTEXT`, `NO_TEST_SURFACE`, `NO_IMPLEMENTABLE_SLICE`, `RED_NOT_EXPRESSIBLE`, or `NO_VCS_MODE` and capture blockedBecause, missingInputs, recommendedRoute, nextCommand, and resumeCriteria.",
121
+ "RED/GREEN blocked — classify with the managed taxonomy `NO_SOURCE_CONTEXT`, `NO_TEST_SURFACE`, `NO_IMPLEMENTABLE_SLICE`, `RED_NOT_EXPRESSIBLE`, or `NO_VCS_MODE` and capture blockedBecause, missingInputs, recommendedRoute, nextCommand, resumeCriteria, and the repair path: RED needs a failing test surface, GREEN needs full-suite pass evidence, REFACTOR needs behavior-preservation evidence.",
122
122
  "no-VCS workspace without explicit `vcs: none`, no-vcs reason, content/artifact hash, or `tdd.verificationRef: disabled`"
123
123
  ],
124
124
  exitCriteria: [
@@ -74,18 +74,19 @@ ${conversationLanguagePolicyMarkdown()}
74
74
  6. If flow already has completed stages, warn the user that starting a new tracked flow will reset progress. Ask for confirmation before proceeding. A fresh init placeholder state with \`completedStages: []\`, no passed gates, and no \`00-idea.md\` is **not** an active flow; do not ask the user to resume it.
75
75
  7. **Track heuristic** — classify the idea text and **recommend** a track (the user can override before any state mutation):
76
76
  - First, load \`${RUNTIME_ROOT}/config.yaml\`. If \`trackHeuristics\` is defined, apply those per-track vocabulary hints (\`fallback\`, \`tracks.<id>.{triggers,veto}\`) on top of the built-in defaults. Evaluation order is always \`standard -> medium -> quick\` (narrow-to-broad).
77
- - **quick** (\`spec → tdd → review → ship\`) — single-purpose work where the spec is essentially already known.
77
+ - **quick** (\`spec → tdd → review → ship\`) — single-purpose work where the spec is essentially already known. Quick skips ceremony, not safety: spec approval, TDD evidence, review, and ship gates remain mandatory.
78
78
  Triggers (case-insensitive substring or close variant): \`bug\`, \`bugfix\`, \`fix\`, \`hotfix\`, \`patch\`, \`typo\`, \`regression\`, \`copy change\`, \`rename\`, \`bump\`, \`upgrade dep\`, \`config tweak\`, \`docs only\`, \`comment\`, \`lint\`, \`format\`, \`small\`, \`tiny\`, \`one-liner\`, \`revert\`.
79
79
  - **medium** (\`brainstorm → spec → plan → tdd → review → ship\`) — additive work that fits existing architecture and still needs product framing.
80
80
  Triggers: \`add endpoint\`, \`add field\`, \`extend existing\`, \`wire integration\`, \`small migration\`, \`new screen following existing patterns\`.
81
81
  - **standard** (full 8 stages — default fallback) — anything that introduces a new capability with architecture uncertainty, touches many modules, or has unclear scope.
82
82
  Triggers: \`new feature\`, \`refactor\`, \`migration\`, \`platform\`, \`architecture\`, \`schema\`, \`integrate\`, \`workflow\`, \`onboarding\`, or any prompt that does not match quick/medium confidently.
83
83
  - When triggers conflict, prefer **standard** over **medium**, and **medium** over **quick**.
84
- - Report **track selection confidence** as high/medium/low with the matched trigger or fallback reason. Be explicit that this recommendation is advisory until the user accepts and the managed helper writes state; after that, \`/cc-next\` follows the configured track.
84
+ - Report **track selection confidence** as high/medium/low with the matched trigger or fallback reason, plus one sentence explaining what the selected track skips and what safety gates remain. Be explicit that this recommendation is advisory until the user accepts and the managed helper writes state; after that, \`/cc-next\` follows the configured track.
85
85
  8. Present one compact **Start framing** summary: class, recommended track, track selection confidence, stack, origin docs, seed recalls, and the recommended next action. Ask a single confirmation question only when there is a destructive reset, a real contradiction, or ambiguous software/non-software classification.
86
86
  9. Present the recommendation as a single decision with explicit options:
87
87
  > \`Recommended track: <quick|medium|standard>\` because \`<one-line reason citing matched triggers>\`.
88
- > Override? (A) keep \`<recommended>\` (B) switch track (C) cancel.
88
+ > \`Safety retained: <spec/TDD/review/ship gates that still apply>\`.
89
+ > Override? (A) keep \`<recommended>\` (B) switch track with reason (C) cancel.
89
90
  If the harness's native ask tool is available (\`AskUserQuestion\` / \`AskQuestion\` / \`question\` / \`request_user_input\`), send exactly ONE question; on schema error, fall back to a plain-text lettered list.
90
91
  10. Start the tracked flow only through the managed helper:
91
92
  \`node .cclaw/hooks/start-flow.mjs --track=<quick|medium|standard> --class=<class> --prompt=<prompt> --stack=<stack> --reason=<matched heuristic>\`
@@ -179,12 +180,12 @@ ${conversationLanguagePolicyMarkdown()}
179
180
 
180
181
  | Track | Triggers | Use when |
181
182
  |---|---|---|
182
- | \`quick\` | \`bug\`, \`bugfix\`, \`fix\`, \`hotfix\`, \`patch\`, \`typo\`, \`regression\`, \`rename\`, \`bump\`, \`upgrade dep\`, \`docs only\`, \`comment\`, \`lint\`, \`format\`, \`small\`, \`tiny\`, \`one-liner\`, \`revert\`, \`copy change\` | Single-purpose, spec is essentially known, low blast radius |
183
+ | \`quick\` | \`bug\`, \`bugfix\`, \`fix\`, \`hotfix\`, \`patch\`, \`typo\`, \`regression\`, \`rename\`, \`bump\`, \`upgrade dep\`, \`docs only\`, \`comment\`, \`lint\`, \`format\`, \`small\`, \`tiny\`, \`one-liner\`, \`revert\`, \`copy change\` | Single-purpose, spec is essentially known, low blast radius; skips ceremony, not safety |
183
184
  | \`medium\` | \`add endpoint\`, \`add field\`, \`extend existing\`, \`wire integration\`, \`small migration\`, \`new screen following existing pattern\` | Additive work with existing architecture |
184
185
  | \`standard\` | \`new feature\`, \`refactor\`, \`migration\`, \`platform\`, \`architecture\`, \`schema\`, \`integrate\`, \`workflow\`, \`onboarding\` (or no confident quick/medium match) | New or uncertain multi-module work |
185
186
 
186
187
  - On conflict, prefer \`standard\` over \`medium\`, and \`medium\` over \`quick\`.
187
- - Always state the recommendation as a one-line reason citing matched triggers and a high/medium/low track selection confidence. Clarify that the heuristic is advisory until the managed helper writes state; after that, \`/cc-next\` follows the selected track.
188
+ - Always state the recommendation as a one-line reason citing matched triggers and a high/medium/low track selection confidence. Clarify that the heuristic is advisory until the managed helper writes state; after that, \`/cc-next\` follows the selected track. Include override guidance: switch to standard when architecture, schema, migration, security, or unclear scope appears; switch to medium when product framing is needed but architecture is known.
188
189
  8. Run the managed start helper: \`node .cclaw/hooks/start-flow.mjs --track=<quick|medium|standard> --class=<class> --prompt=<prompt> --stack=<stack> --reason=<matched heuristic>\`. The helper writes \`${flowPath}\`, computes \`skippedStages\`, resets the gate catalog, and writes \`${RUNTIME_ROOT}/artifacts/00-idea.md\`. If it fails, STOP and report the exact command/output; do not manually edit flow state.
189
190
  9. Load and execute the **first stage skill of the chosen track** (\`brainstorming\` for medium/standard, \`specification-authoring\` for quick) plus its matching command file.
190
191
 
@@ -12,7 +12,7 @@ const REQUIRED_TOP_LEVEL_FIELDS = {
12
12
  };
13
13
  const STAGE_TAXONOMIES = {
14
14
  brainstorm: {
15
- approachTier: ["Lightweight", "Standard", "Deep"],
15
+ approachTier: ["Lightweight", "Standard", "Deep", "lite", "standard", "deep"],
16
16
  approachRole: ["baseline", "challenger", "wild-card"],
17
17
  approachUpside: ["low", "modest", "high", "higher"]
18
18
  },
@@ -28,7 +28,8 @@ export function statusSubcommandMarkdown() {
28
28
  ## Overview
29
29
 
30
30
  \`/cc-view status\` is the quickest way to answer "where are we in the flow?" without
31
- advancing or mutating anything. Safe to run at any point. The snapshot reflects:
31
+ advancing or mutating anything. Treat it as an operator note, not a JSON dump:
32
+ progress, blockers, risks, next action, and human-readable gate/delegation/closeout labels. Safe to run at any point. The snapshot reflects:
32
33
 
33
34
  - progress across stages with per-stage markers,
34
35
  - gate coverage,
@@ -88,10 +89,10 @@ a read-only command.
88
89
 
89
90
  - Keep output compact (≤ 40 lines) — status, not narrative.
90
91
  - Start with the same operator rows as \`/cc-next\` when possible:
91
- \`Current\`, \`Stage\`, \`Gates\`, \`Delegations\`, \`Blocked by\`, \`Next\`, \`Evidence needed\`.
92
+ \`Current\`, \`Stage\`, \`Progress\`, \`Gates\`, \`Delegations\`, \`Risks\`, \`Blocked by\`, \`Next\`, \`Evidence needed\`. Use labels like \`gate: tdd_green_full_suite\`, \`delegation proof: reviewer evidenceRefs\`, and \`closeout: compound_review\` instead of raw JSON tone.
92
93
  - When blocked, include a plain-English action block:
93
94
  \`Current: <stage or closeout substate>\`; \`Blocked by: <gate/delegation/blocker code>\`; \`Next: <exact command or managed remediation>\`; \`Evidence needed: <artifact/test/review/delegation evidence>\`.
94
- - Report counts, not full artifact contents. Include active subagent count from \`${subagentsPath()}\` and proof gaps from \`${delegationEventsPath()}\` when present.
95
+ - Report counts, not full artifact contents. Include active subagent count from \`${subagentsPath()}\` and proof gaps from \`${delegationEventsPath()}\` when present. Convert gate/delegation state into human labels: \`passed\`, \`blocked\`, \`missing proof\`, \`waived with reason\`, \`stale\`, \`ready to advance\`, or the closeout substate label.
95
96
  - If any data source is missing or corrupt, say so explicitly rather than guessing.
96
97
  - Include \`/cc-view tree\` for deep structure and \`/cc-view diff\` for before/after map in the final line.
97
98
 
@@ -5,6 +5,7 @@ export interface TrackRenderContext {
5
5
  traceabilitySourceNoun: string;
6
6
  traceabilityIdNoun: string;
7
7
  traceabilitySliceNoun: string;
8
+ safetySummary: string;
8
9
  upstreamArtifactLabel: string;
9
10
  upstreamArtifactPath: string;
10
11
  }
@@ -9,6 +9,7 @@ export function trackRenderContext(track) {
9
9
  traceabilitySourceNoun: "acceptance criterion",
10
10
  traceabilityIdNoun: "acceptance criterion ID",
11
11
  traceabilitySliceNoun: "acceptance slice",
12
+ safetySummary: "quick skips ceremony, not safety: spec approval, TDD, review, and ship gates remain mandatory",
12
13
  upstreamArtifactLabel: "spec artifact",
13
14
  upstreamArtifactPath: ".cclaw/artifacts/04-spec.md"
14
15
  };
@@ -19,6 +20,7 @@ export function trackRenderContext(track) {
19
20
  traceabilitySourceNoun: "plan task",
20
21
  traceabilityIdNoun: "plan task ID",
21
22
  traceabilitySliceNoun: "plan slice",
23
+ safetySummary: "full upstream planning safety remains in the active track",
22
24
  upstreamArtifactLabel: "plan artifact",
23
25
  upstreamArtifactPath: ".cclaw/artifacts/05-plan.md"
24
26
  };
@@ -1,8 +1,10 @@
1
1
  export type DoctorSeverity = "error" | "warning" | "info";
2
+ export type DoctorActionGroup = "sync" | "user-action" | "stage-work" | "informational";
2
3
  export interface DoctorCheckMetadata {
3
4
  severity: DoctorSeverity;
4
5
  summary: string;
5
6
  fix: string;
7
+ actionGroup: DoctorActionGroup;
6
8
  docRef?: string;
7
9
  }
8
10
  export declare function doctorCheckMetadata(checkName: string): DoctorCheckMetadata;