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.
Files changed (58) hide show
  1. package/dist/cli.d.ts +6 -1
  2. package/dist/cli.js +117 -64
  3. package/dist/codex-feature-flag.d.ts +1 -1
  4. package/dist/codex-feature-flag.js +1 -1
  5. package/dist/config.js +3 -0
  6. package/dist/content/cancel-command.d.ts +2 -0
  7. package/dist/content/cancel-command.js +25 -0
  8. package/dist/content/closeout-guidance.js +3 -3
  9. package/dist/content/core-agents.js +5 -5
  10. package/dist/content/harness-doc.js +1 -1
  11. package/dist/content/hooks.js +32 -9
  12. package/dist/content/ideate-command.js +12 -7
  13. package/dist/content/meta-skill.js +7 -9
  14. package/dist/content/next-command.d.ts +2 -2
  15. package/dist/content/next-command.js +31 -27
  16. package/dist/content/node-hooks.js +24 -8
  17. package/dist/content/opencode-plugin.js +1 -1
  18. package/dist/content/session-hooks.js +1 -1
  19. package/dist/content/stage-command.js +1 -1
  20. package/dist/content/stage-common-guidance.js +4 -4
  21. package/dist/content/stages/plan.js +2 -2
  22. package/dist/content/stages/review.js +1 -1
  23. package/dist/content/stages/tdd.js +1 -1
  24. package/dist/content/start-command.d.ts +2 -2
  25. package/dist/content/start-command.js +18 -15
  26. package/dist/content/status-command.js +9 -8
  27. package/dist/content/subagents.js +1 -1
  28. package/dist/content/templates.d.ts +1 -1
  29. package/dist/content/templates.js +2 -2
  30. package/dist/content/track-render-context.d.ts +1 -0
  31. package/dist/content/track-render-context.js +2 -0
  32. package/dist/doctor-registry.d.ts +2 -0
  33. package/dist/doctor-registry.js +37 -10
  34. package/dist/doctor.d.ts +2 -1
  35. package/dist/doctor.js +184 -8
  36. package/dist/flow-state.d.ts +1 -1
  37. package/dist/flow-state.js +1 -1
  38. package/dist/fs-utils.js +6 -0
  39. package/dist/harness-adapters.d.ts +2 -2
  40. package/dist/harness-adapters.js +21 -94
  41. package/dist/harness-selection.d.ts +31 -0
  42. package/dist/harness-selection.js +214 -0
  43. package/dist/install.d.ts +4 -1
  44. package/dist/install.js +47 -10
  45. package/dist/internal/advance-stage.js +7 -7
  46. package/dist/managed-resources.d.ts +53 -0
  47. package/dist/managed-resources.js +289 -0
  48. package/dist/policy.js +1 -1
  49. package/dist/run-archive.d.ts +8 -0
  50. package/dist/run-archive.js +23 -9
  51. package/dist/run-persistence.js +1 -1
  52. package/dist/runs.d.ts +1 -1
  53. package/dist/runs.js +1 -1
  54. package/dist/tdd-cycle.js +10 -10
  55. package/dist/tdd-verification-evidence.js +4 -4
  56. package/dist/track-heuristics.d.ts +2 -0
  57. package/dist/track-heuristics.js +11 -3
  58. package/package.json +1 -1
@@ -445,7 +445,7 @@ Implementation that touches shared source trees must remain **sequential** unles
445
445
  - **3–4:** appendix / “worth tracking” section (not merge-blocking alone)
446
446
  - **1–2:** suppress from primary narrative unless paired with stronger evidence
447
447
 
448
- ### Review Army Artifact Contract (required in review stage via /cc-next)
448
+ ### Review Army Artifact Contract (required in review stage via /cc)
449
449
 
450
450
  Write a structured reconciliation artifact at \`.cclaw/artifacts/07-review-army.json\` using this schema:
451
451
 
@@ -1,4 +1,4 @@
1
1
  export declare const ARTIFACT_TEMPLATES: Record<string, string>;
2
2
  export declare const RULEBOOK_MARKDOWN = "# Cclaw Rulebook\n\n## MUST_ALWAYS\n- Follow flow order: brainstorm -> scope -> design -> spec -> plan -> tdd -> review -> ship\n- Require explicit user confirmation after plan before TDD\n- Keep evidence artifacts in `.cclaw/artifacts/`\n- Enforce RED before GREEN in TDD\n- Run two-layer review (spec_compliance and code_quality) before ship\n- Validate all inputs before processing \u2014 never trust external data without sanitization\n- Prefer immutable data patterns and pure functions where the language supports them\n- Follow existing repo conventions, patterns, and directory structure \u2014 match the codebase\n- Verify claims with fresh evidence: \"tests pass\" requires running tests in this message\n- Use conventional commits: `type(scope): description` (feat, fix, refactor, test, docs, chore)\n\n## MUST_NEVER\n- Skip RED phase and jump directly to GREEN in TDD\n- Ship with critical review findings\n- Start implementation during /brainstorm\n- Modify generated cclaw files manually when CLI can regenerate them\n- Commit `.cclaw/` or generated shim files\n- Expose secrets, tokens, API keys, or absolute system paths in agent output\n- Duplicate existing functionality without explicit justification \u2014 search before building\n- Bypass security checks, linting hooks, or type checking to \"move faster\"\n- Claim success (\"Done,\" \"All good,\" \"Tests pass\") without running verification in this message\n- Make changes outside the blast radius of the current task without user consent\n\n## DELEGATION\nWhen a task requires specialist knowledge (security audit, performance profiling, database review),\ndelegate to a specialized agent or skill if the harness supports it. The primary agent should:\n1. Identify the specialist domain\n2. Provide focused context (relevant files, the specific concern)\n3. Evaluate the specialist output before acting on it \u2014 do not blindly apply recommendations\n";
3
- export declare const CURSOR_WORKFLOW_RULE_MDC = "---\ndescription: cclaw workflow guardrails for Cursor agent sessions\nglobs:\n - \"**/*\"\nalwaysApply: true\n---\n\n<!-- cclaw-managed-cursor-workflow-rule -->\n\n# Cclaw Workflow Guardrails\n\n## Activation Rule\n\nBefore responding to coding work:\n1. Read `.cclaw/state/flow-state.json`.\n2. Start with `/cc` or continue with `/cc-next`.\n3. If no software-stage flow applies, respond normally.\n\n## Stage Order\n\n`brainstorm -> scope -> design -> spec -> plan -> tdd -> review -> ship`\n\nTrack-specific skips are allowed only when `flow-state.track` + `skippedStages` explicitly say so.\n\n## Task Classification\n\n| Class | Route |\n|---|---|\n| non-trivial software work | `/cc <idea>` |\n| trivial software fix | `/cc <idea>` (quick track) |\n| bugfix with repro | `/cc <idea>` and enforce RED-first in tdd |\n| pure question / non-software | direct answer (no stage flow) |\n\n## Command Surface\n\n- `/cc` = entry and resume.\n- `/cc-next` = only progression path.\n- Knowledge capture and recall use the `learnings` skill when requested.\n\n## Verification Discipline\n\n- No completion claim without fresh command evidence in this turn.\n- Do not mark gates passed from memory.\n- Keep evidence in `.cclaw/artifacts/`; archive via `npx cclaw-cli archive`.\n\n## Delegation And Approvals\n\n- Machine-only checks in design/plan/tdd/review/ship should auto-dispatch when tooling supports it.\n- Ask for user input only at explicit approval gates (scope mode, plan approval, challenge resolution, ship finalization).\n- If harness capabilities are partial, record waiver reasons in delegation logs.\n\n## Routing Source Of Truth\n\n- Primary router: `.cclaw/skills/using-cclaw/SKILL.md`.\n- Stage behavior: current stage skill plus `.cclaw/state/flow-state.json`.\n- Preamble budget: keep role/status announcements brief and avoid repeating\n them unless the stage or role changes.\n";
3
+ export declare const CURSOR_WORKFLOW_RULE_MDC = "---\ndescription: cclaw workflow guardrails for Cursor agent sessions\nglobs:\n - \"**/*\"\nalwaysApply: true\n---\n\n<!-- cclaw-managed-cursor-workflow-rule -->\n\n# Cclaw Workflow Guardrails\n\n## Activation Rule\n\nBefore responding to coding work:\n1. Read `.cclaw/state/flow-state.json`.\n2. Start with `/cc` or continue with `/cc`.\n3. If no software-stage flow applies, respond normally.\n\n## Stage Order\n\n`brainstorm -> scope -> design -> spec -> plan -> tdd -> review -> ship`\n\nTrack-specific skips are allowed only when `flow-state.track` + `skippedStages` explicitly say so.\n\n## Task Classification\n\n| Class | Route |\n|---|---|\n| non-trivial software work | `/cc <idea>` |\n| trivial software fix | `/cc <idea>` (quick track) |\n| bugfix with repro | `/cc <idea>` and enforce RED-first in tdd |\n| pure question / non-software | direct answer (no stage flow) |\n\n## Command Surface\n\n- `/cc` = entry and resume.\n- `/cc` = only progression path.\n- Knowledge capture and recall use the `learnings` skill when requested.\n\n## Verification Discipline\n\n- No completion claim without fresh command evidence in this turn.\n- Do not mark gates passed from memory.\n- Keep evidence in `.cclaw/artifacts/`; archive via `npx cclaw-cli archive`.\n\n## Delegation And Approvals\n\n- Machine-only checks in design/plan/tdd/review/ship should auto-dispatch when tooling supports it.\n- Ask for user input only at explicit approval gates (scope mode, plan approval, challenge resolution, ship finalization).\n- If harness capabilities are partial, record waiver reasons in delegation logs.\n\n## Routing Source Of Truth\n\n- Primary router: `.cclaw/skills/using-cclaw/SKILL.md`.\n- Stage behavior: current stage skill plus `.cclaw/state/flow-state.json`.\n- Preamble budget: keep role/status announcements brief and avoid repeating\n them unless the stage or role changes.\n";
4
4
  export declare function buildRulesJson(): Record<string, unknown>;
@@ -1410,7 +1410,7 @@ alwaysApply: true
1410
1410
 
1411
1411
  Before responding to coding work:
1412
1412
  1. Read \`.cclaw/state/flow-state.json\`.
1413
- 2. Start with \`/cc\` or continue with \`/cc-next\`.
1413
+ 2. Start with \`/cc\` or continue with \`/cc\`.
1414
1414
  3. If no software-stage flow applies, respond normally.
1415
1415
 
1416
1416
  ## Stage Order
@@ -1431,7 +1431,7 @@ Track-specific skips are allowed only when \`flow-state.track\` + \`skippedStage
1431
1431
  ## Command Surface
1432
1432
 
1433
1433
  - \`/cc\` = entry and resume.
1434
- - \`/cc-next\` = only progression path.
1434
+ - \`/cc\` = only progression path.
1435
1435
  - Knowledge capture and recall use the \`learnings\` skill when requested.
1436
1436
 
1437
1437
  ## Verification Discipline
@@ -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;
@@ -1,5 +1,6 @@
1
1
  function ref(fileName) {
2
- return `docs/${fileName}`;
2
+ const anchor = fileName.replace(/\.md$/u, "").replace(/[^a-z0-9]+/giu, "-").toLowerCase();
3
+ return `README.md#${anchor}`;
3
4
  }
4
5
  const RULES = [
5
6
  {
@@ -8,6 +9,7 @@ const RULES = [
8
9
  severity: "info",
9
10
  summary: "Gate reconciliation status update.",
10
11
  fix: "No action required unless subsequent gate checks fail.",
12
+ actionGroup: "informational",
11
13
  docRef: ref("config.md")
12
14
  }
13
15
  },
@@ -17,6 +19,7 @@ const RULES = [
17
19
  severity: "warning",
18
20
  summary: "Advisory signal; runtime can continue with caution.",
19
21
  fix: "Address when possible to prevent future drift or degraded behavior.",
22
+ actionGroup: "informational",
20
23
  docRef: "README.md"
21
24
  }
22
25
  },
@@ -26,6 +29,7 @@ const RULES = [
26
29
  severity: "warning",
27
30
  summary: "Stage skill quality guardrail check.",
28
31
  fix: "Tune generated stage skill content and re-run `cclaw sync`.",
32
+ actionGroup: "sync",
29
33
  docRef: "README.md"
30
34
  }
31
35
  },
@@ -35,6 +39,7 @@ const RULES = [
35
39
  severity: "error",
36
40
  summary: "Required runtime tooling availability check.",
37
41
  fix: "Install the missing required tool and re-run `cclaw doctor`.",
42
+ actionGroup: "user-action",
38
43
  docRef: "README.md"
39
44
  }
40
45
  },
@@ -43,16 +48,28 @@ const RULES = [
43
48
  metadata: {
44
49
  severity: "error",
45
50
  summary: "Generated runtime surface presence check.",
46
- fix: "Run `cclaw sync` to regenerate runtime files, then re-run doctor.",
51
+ fix: "Run `cclaw sync` to safely regenerate generated runtime files, then re-run doctor.",
52
+ actionGroup: "sync",
47
53
  docRef: "README.md"
48
54
  }
49
55
  },
56
+ {
57
+ test: /^managed_resources:/,
58
+ metadata: {
59
+ severity: "error",
60
+ summary: "Managed generated resource manifest integrity check.",
61
+ fix: "Run `cclaw sync` to refresh managed generated files; inspect upgrade backup paths before discarding local edits.",
62
+ actionGroup: "sync",
63
+ docRef: ref("config.md")
64
+ }
65
+ },
50
66
  {
51
67
  test: /^(hook:|hooks:|lifecycle:|git_hooks:)/,
52
68
  metadata: {
53
69
  severity: "error",
54
70
  summary: "Hook wiring and lifecycle integration check.",
55
- fix: "Repair hook/plugin wiring (usually via `cclaw sync`) and validate harness config.",
71
+ fix: "Run `cclaw sync` to regenerate hook/plugin wiring; if the check still fails, validate harness config and permissions.",
72
+ actionGroup: "sync",
56
73
  docRef: ref("harnesses.md")
57
74
  }
58
75
  },
@@ -61,7 +78,8 @@ const RULES = [
61
78
  metadata: {
62
79
  severity: "error",
63
80
  summary: "Harness shim and routing file consistency check.",
64
- fix: "Regenerate harness adapters via `cclaw sync`; confirm enabled harness list.",
81
+ fix: "Run `cclaw sync` to regenerate harness adapters; confirm enabled harness list if it remains failing.",
82
+ actionGroup: "sync",
65
83
  docRef: ref("harnesses.md")
66
84
  }
67
85
  },
@@ -70,7 +88,8 @@ const RULES = [
70
88
  metadata: {
71
89
  severity: "error",
72
90
  summary: "Flow state and gate evidence consistency check.",
73
- fix: "Repair flow-state artifacts and gate evidence, then run `cclaw doctor --reconcile-gates`.",
91
+ fix: "Repair the named stage artifacts/gate evidence, then run `cclaw doctor --reconcile-gates --explain` to refresh derived gate status only.",
92
+ actionGroup: "stage-work",
74
93
  docRef: ref("config.md")
75
94
  }
76
95
  },
@@ -79,7 +98,8 @@ const RULES = [
79
98
  metadata: {
80
99
  severity: "error",
81
100
  summary: "Knowledge and artifact runtime integrity check.",
82
- fix: "Restore missing runtime files under `.cclaw/` or re-run `cclaw sync`.",
101
+ fix: "Restore the missing `.cclaw/` runtime file or run `cclaw sync` when it is generated surface drift.",
102
+ actionGroup: "sync",
83
103
  docRef: "README.md"
84
104
  }
85
105
  },
@@ -88,7 +108,8 @@ const RULES = [
88
108
  metadata: {
89
109
  severity: "error",
90
110
  summary: "Routing skill and protocol integrity check.",
91
- fix: "Regenerate runtime skills via `cclaw sync`, then re-run doctor.",
111
+ fix: "Run `cclaw sync` to regenerate runtime skills, then re-run doctor.",
112
+ actionGroup: "sync",
92
113
  docRef: ref("harnesses.md")
93
114
  }
94
115
  },
@@ -103,7 +124,8 @@ const RULES = [
103
124
  metadata: {
104
125
  severity: "warning",
105
126
  summary: "Reference/overview doc integrity (non-blocking).",
106
- fix: "Run `cclaw sync` to regenerate the reference doc from the canonical source.",
127
+ fix: "Run `cclaw sync` to regenerate the reference surface from the canonical source.",
128
+ actionGroup: "sync",
107
129
  docRef: ref("harnesses.md")
108
130
  }
109
131
  },
@@ -113,6 +135,7 @@ const RULES = [
113
135
  severity: "info",
114
136
  summary: "Harness reality label for dispatch/proof support.",
115
137
  fix: "No action required; use this label to interpret native/generic/role-switch proof requirements.",
138
+ actionGroup: "informational",
116
139
  docRef: ref("harnesses.md")
117
140
  }
118
141
  },
@@ -121,7 +144,8 @@ const RULES = [
121
144
  metadata: {
122
145
  severity: "error",
123
146
  summary: "Mandatory delegation completion check.",
124
- fix: "Complete or explicitly waive missing mandatory delegations in delegation log.",
147
+ fix: "Run the named mandatory agent, record dispatch proof/evidenceRefs, or explicitly waive it with a user-visible rationale.",
148
+ actionGroup: "user-action",
125
149
  docRef: ref("harnesses.md")
126
150
  }
127
151
  },
@@ -130,7 +154,8 @@ const RULES = [
130
154
  metadata: {
131
155
  severity: "error",
132
156
  summary: "Cross-artifact traceability integrity check.",
133
- fix: "Restore criterion/task/test ID mappings across spec, plan, and tdd artifacts.",
157
+ fix: "Repair criterion/task/test ID mappings across spec, plan, and TDD artifacts, then re-run doctor.",
158
+ actionGroup: "stage-work",
134
159
  docRef: "README.md"
135
160
  }
136
161
  },
@@ -140,6 +165,7 @@ const RULES = [
140
165
  severity: "error",
141
166
  summary: "Config or policy schema consistency check.",
142
167
  fix: "Fix config/rules drift, then run `cclaw sync` and re-run doctor.",
168
+ actionGroup: "user-action",
143
169
  docRef: ref("config.md")
144
170
  }
145
171
  }
@@ -154,6 +180,7 @@ export function doctorCheckMetadata(checkName) {
154
180
  severity: "warning",
155
181
  summary: "Unclassified doctor check.",
156
182
  fix: "Report this check name to cclaw maintainers so doctor-registry can classify it explicitly.",
183
+ actionGroup: "informational",
157
184
  docRef: "README.md"
158
185
  };
159
186
  }
package/dist/doctor.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { DoctorSeverity } from "./doctor-registry.js";
1
+ import type { DoctorActionGroup, DoctorSeverity } from "./doctor-registry.js";
2
2
  export interface DoctorCheck {
3
3
  name: string;
4
4
  ok: boolean;
@@ -6,6 +6,7 @@ export interface DoctorCheck {
6
6
  severity: DoctorSeverity;
7
7
  summary: string;
8
8
  fix: string;
9
+ actionGroup: DoctorActionGroup;
9
10
  docRef?: string;
10
11
  }
11
12
  export interface DoctorOptions {
package/dist/doctor.js CHANGED
@@ -3,10 +3,11 @@ import path from "node:path";
3
3
  import { execFile } from "node:child_process";
4
4
  import { pathToFileURL } from "node:url";
5
5
  import { promisify } from "node:util";
6
- import { REQUIRED_DIRS, RUNTIME_ROOT } from "./constants.js";
6
+ import { CCLAW_VERSION, REQUIRED_DIRS, RUNTIME_ROOT } from "./constants.js";
7
7
  import { CCLAW_AGENTS } from "./content/core-agents.js";
8
8
  import { detectAdvancedKeys, InvalidConfigError, readConfig } from "./config.js";
9
9
  import { exists } from "./fs-utils.js";
10
+ import { hashManagedResourceContent, isManagedGeneratedPath, MANAGED_RESOURCE_MANIFEST_REL_PATH, readManagedResourceManifest, validateManagedResourceManifest } from "./managed-resources.js";
10
11
  import { gitignoreHasRequiredPatterns } from "./gitignore.js";
11
12
  import { HARNESS_ADAPTERS, CCLAW_MARKER_START, CCLAW_MARKER_END, harnessShimFileNames, harnessShimSkillNames } from "./harness-adapters.js";
12
13
  import { policyChecks } from "./policy.js";
@@ -21,6 +22,7 @@ import { stageSkillFolder } from "./content/skills.js";
21
22
  import { stageCommandShimMarkdown } from "./content/stage-command.js";
22
23
  import { doctorCheckMetadata } from "./doctor-registry.js";
23
24
  import { resolveTrackFromPrompt } from "./track-heuristics.js";
25
+ import { detectHarnesses } from "./init-detect.js";
24
26
  import { classifyCodexHooksFlag, codexConfigPath, readCodexConfig } from "./codex-feature-flag.js";
25
27
  import { LANGUAGE_RULE_PACK_DIR, LANGUAGE_RULE_PACK_FILES, LEGACY_LANGUAGE_RULE_PACK_FOLDERS } from "./content/utility-skills.js";
26
28
  import { validateHookDocument } from "./hook-schema.js";
@@ -92,8 +94,48 @@ function extractGeneratedCliEntrypoints(scriptContent) {
92
94
  // malformed generated constant; treat below as missing/unusable
93
95
  }
94
96
  }
97
+ for (const match of scriptContent.matchAll(/const\s+CCLAW_CLI_ARGS_PREFIX\s*=\s*(\[(?:\\.|[^\]])*\]);/gu)) {
98
+ try {
99
+ const parsed = JSON.parse(match[1] ?? "[]");
100
+ if (Array.isArray(parsed)) {
101
+ for (const item of parsed) {
102
+ if (typeof item === "string" && item.trim().length > 0 && !item.startsWith("-")) {
103
+ paths.push(item);
104
+ }
105
+ }
106
+ }
107
+ }
108
+ catch {
109
+ // malformed generated constant; treat below as missing/unusable
110
+ }
111
+ }
95
112
  return paths;
96
113
  }
114
+ async function walkGeneratedCandidates(projectRoot, relDir, candidates) {
115
+ const fullDir = path.join(projectRoot, relDir);
116
+ if (!(await exists(fullDir)))
117
+ return;
118
+ let entries = [];
119
+ try {
120
+ entries = await fs.readdir(fullDir, { withFileTypes: true });
121
+ }
122
+ catch {
123
+ return;
124
+ }
125
+ for (const entry of entries) {
126
+ const rel = path.join(relDir, entry.name).replace(/\\/gu, "/");
127
+ if (entry.isDirectory()) {
128
+ await walkGeneratedCandidates(projectRoot, rel, candidates);
129
+ }
130
+ else if (entry.isFile() && isManagedGeneratedPath(rel)) {
131
+ candidates.push(rel);
132
+ }
133
+ }
134
+ }
135
+ function formatManagedValidationIssue(issue) {
136
+ const subject = issue.path ?? (issue.index !== undefined ? `resources[${issue.index}]` : "manifest");
137
+ return `${subject} ${issue.field}: ${issue.message}`;
138
+ }
97
139
  async function generatedCliEntrypointsOk(projectRoot) {
98
140
  const hookScripts = ["stage-complete.mjs", "start-flow.mjs", "run-hook.mjs"];
99
141
  const problems = [];
@@ -690,8 +732,140 @@ export async function doctorChecks(projectRoot, options = {}) {
690
732
  ok: await gitignoreHasRequiredPatterns(projectRoot),
691
733
  details: ".gitignore must include cclaw ignore block"
692
734
  });
735
+ const managedManifestPath = path.join(projectRoot, MANAGED_RESOURCE_MANIFEST_REL_PATH);
736
+ let rawManagedManifest = null;
737
+ let managedManifestParseError = null;
738
+ if (await exists(managedManifestPath)) {
739
+ try {
740
+ rawManagedManifest = JSON.parse(await fs.readFile(managedManifestPath, "utf8"));
741
+ }
742
+ catch (error) {
743
+ managedManifestParseError = error instanceof Error ? error.message : String(error);
744
+ }
745
+ }
746
+ const managedManifestValidationIssues = rawManagedManifest === null
747
+ ? []
748
+ : validateManagedResourceManifest(rawManagedManifest);
749
+ const managedManifest = await readManagedResourceManifest(projectRoot).catch(() => null);
750
+ checks.push({
751
+ name: "managed_resources:manifest_exists",
752
+ ok: managedManifest !== null,
753
+ details: managedManifest
754
+ ? `${MANAGED_RESOURCE_MANIFEST_REL_PATH} tracks ${managedManifest.resources.length} managed generated file(s)`
755
+ : `${MANAGED_RESOURCE_MANIFEST_REL_PATH} missing; run cclaw sync to establish generated file ownership`
756
+ });
757
+ checks.push({
758
+ name: "managed_resources:manifest_valid",
759
+ ok: managedManifestParseError === null && managedManifestValidationIssues.length === 0,
760
+ details: managedManifestParseError
761
+ ? `${MANAGED_RESOURCE_MANIFEST_REL_PATH} is unreadable JSON (${managedManifestParseError})`
762
+ : managedManifestValidationIssues.length === 0
763
+ ? `${MANAGED_RESOURCE_MANIFEST_REL_PATH} metadata is structurally valid`
764
+ : `malformed managed resource metadata: ${managedManifestValidationIssues.slice(0, 12).map(formatManagedValidationIssue).join("; ")}`
765
+ });
766
+ if (managedManifest) {
767
+ checks.push({
768
+ name: "managed_resources:manifest_package_version",
769
+ ok: managedManifest.packageVersion === CCLAW_VERSION,
770
+ details: managedManifest.packageVersion === CCLAW_VERSION
771
+ ? `${MANAGED_RESOURCE_MANIFEST_REL_PATH} packageVersion matches cclaw ${CCLAW_VERSION}`
772
+ : `${MANAGED_RESOURCE_MANIFEST_REL_PATH} packageVersion ${managedManifest.packageVersion} is stale; current cclaw is ${CCLAW_VERSION}. Run cclaw upgrade.`
773
+ });
774
+ const rawResources = toObject(rawManagedManifest)?.resources;
775
+ const stalePackageEntries = Array.isArray(rawResources)
776
+ ? rawResources.flatMap((entry, index) => {
777
+ const obj = toObject(entry);
778
+ if (!obj)
779
+ return [];
780
+ const entryPath = typeof obj.path === "string" ? obj.path : `resources[${index}]`;
781
+ return typeof obj.packageVersion === "string" && obj.packageVersion !== CCLAW_VERSION
782
+ ? [`${entryPath} (${obj.packageVersion})`]
783
+ : [];
784
+ })
785
+ : [];
786
+ const stale = [];
787
+ const missing = [];
788
+ for (const entry of managedManifest.resources) {
789
+ const filePath = path.join(projectRoot, entry.path);
790
+ if (!(await exists(filePath))) {
791
+ missing.push(entry.path);
792
+ continue;
793
+ }
794
+ const currentHash = hashManagedResourceContent(await fs.readFile(filePath));
795
+ if (currentHash !== entry.sha256) {
796
+ stale.push(entry.path);
797
+ }
798
+ }
799
+ checks.push({
800
+ name: "managed_resources:entry_package_versions",
801
+ ok: stalePackageEntries.length === 0,
802
+ details: stalePackageEntries.length === 0
803
+ ? `all manifest entries match cclaw ${CCLAW_VERSION}`
804
+ : `manifest entries have stale packageVersion; run cclaw upgrade: ${stalePackageEntries.slice(0, 12).join(", ")}`
805
+ });
806
+ checks.push({
807
+ name: "managed_resources:user_modified",
808
+ ok: stale.length === 0,
809
+ details: stale.length === 0
810
+ ? "all manifest-tracked managed files match recorded hashes"
811
+ : `manifest-tracked managed files have user modifications: ${stale.slice(0, 12).join(", ")}`
812
+ });
813
+ checks.push({
814
+ name: "managed_resources:stale_entries",
815
+ ok: missing.length === 0,
816
+ details: missing.length === 0
817
+ ? "all manifest entries still exist"
818
+ : `manifest entries point to missing files: ${missing.slice(0, 12).join(", ")}`
819
+ });
820
+ const manifestPaths = new Set(managedManifest.resources.map((entry) => entry.path));
821
+ const candidates = [];
822
+ for (const relDir of [
823
+ `${RUNTIME_ROOT}/commands`,
824
+ `${RUNTIME_ROOT}/skills`,
825
+ `${RUNTIME_ROOT}/templates`,
826
+ `${RUNTIME_ROOT}/rules`,
827
+ `${RUNTIME_ROOT}/agents`,
828
+ `${RUNTIME_ROOT}/hooks`,
829
+ ".claude/commands",
830
+ ".cursor/commands",
831
+ ".opencode/commands",
832
+ ".opencode/agents",
833
+ ".codex/agents",
834
+ ".agents/skills",
835
+ ".claude/hooks",
836
+ ".cursor",
837
+ ".codex",
838
+ ".opencode/plugins"
839
+ ]) {
840
+ await walkGeneratedCandidates(projectRoot, relDir, candidates);
841
+ }
842
+ for (const rel of ["AGENTS.md", "CLAUDE.md"]) {
843
+ if ((await exists(path.join(projectRoot, rel))) && isManagedGeneratedPath(rel)) {
844
+ candidates.push(rel);
845
+ }
846
+ }
847
+ const orphaned = [...new Set(candidates)].filter((rel) => !manifestPaths.has(rel)).sort();
848
+ checks.push({
849
+ name: "managed_resources:orphaned_generated_files",
850
+ ok: orphaned.length === 0,
851
+ details: orphaned.length === 0
852
+ ? "no orphaned generated files detected across known cclaw surfaces"
853
+ : `warning: generated-looking files are not tracked in manifest: ${orphaned.slice(0, 12).join(", ")}`
854
+ });
855
+ }
693
856
  let configuredHarnesses = [];
694
857
  let parsedConfig = null;
858
+ const configFileExists = await exists(path.join(projectRoot, RUNTIME_ROOT, "config.yaml"));
859
+ if (!configFileExists) {
860
+ const detectedHarnesses = await detectHarnesses(projectRoot).catch(() => []);
861
+ checks.push({
862
+ name: "config:present",
863
+ ok: detectedHarnesses.length === 0,
864
+ details: detectedHarnesses.length > 0
865
+ ? `${RUNTIME_ROOT}/config.yaml is missing but harness markers were detected (${detectedHarnesses.join(", ")}). Run cclaw sync --harnesses=${detectedHarnesses.join(",")} or cclaw sync --interactive.`
866
+ : `${RUNTIME_ROOT}/config.yaml missing and no harness markers were detected; run cclaw init or cclaw sync when ready.`
867
+ });
868
+ }
695
869
  try {
696
870
  const config = await readConfig(projectRoot);
697
871
  parsedConfig = config;
@@ -808,17 +982,17 @@ export async function doctorChecks(projectRoot, options = {}) {
808
982
  const content = await fs.readFile(agentsFile, "utf8");
809
983
  const hasMarkers = content.includes(CCLAW_MARKER_START) && content.includes(CCLAW_MARKER_END);
810
984
  const hasCcCommand = content.includes("/cc");
811
- const hasCcNext = content.includes("/cc-next");
812
985
  const hasCcIdeate = content.includes("/cc-ideate");
813
- const hasCcView = content.includes("/cc-view");
986
+ const hasCcCancel = content.includes("/cc-cancel");
987
+ const omitsFinish = !content.includes("/cc-finish");
814
988
  const hasVerification = content.includes("Verification Discipline");
815
989
  const hasMinimalMarker = content.includes("intentionally minimal for cross-project use");
816
990
  const hasMetaSkillPointer = content.includes(".cclaw/skills/using-cclaw/SKILL.md");
817
991
  agentsBlockOk = hasMarkers
818
992
  && hasCcCommand
819
- && hasCcNext
820
993
  && hasCcIdeate
821
- && hasCcView
994
+ && hasCcCancel
995
+ && omitsFinish
822
996
  && hasVerification
823
997
  && hasMinimalMarker
824
998
  && hasMetaSkillPointer;
@@ -828,7 +1002,7 @@ export async function doctorChecks(projectRoot, options = {}) {
828
1002
  ok: agentsBlockOk,
829
1003
  details: `${agentsFile} must contain the managed cclaw marker block with routing, verification, and minimal detail pointer`
830
1004
  });
831
- for (const cmd of ["start", "next", "ideate", "view"]) {
1005
+ for (const cmd of ["start", "next", "ideate", "view", "cancel"]) {
832
1006
  const cmdPath = path.join(projectRoot, RUNTIME_ROOT, "commands", `${cmd}.md`);
833
1007
  checks.push({
834
1008
  name: `utility_command:${cmd}`,
@@ -846,7 +1020,7 @@ export async function doctorChecks(projectRoot, options = {}) {
846
1020
  checks.push({
847
1021
  name: `stage_command:${stage}`,
848
1022
  ok: stageCommandOk,
849
- details: `${cmdPath} must be a thin shim to ${RUNTIME_ROOT}/skills/${stageSkillFolder(stage)}/SKILL.md and /cc-next`
1023
+ details: `${cmdPath} must be a thin shim to ${RUNTIME_ROOT}/skills/${stageSkillFolder(stage)}/SKILL.md and /cc`
850
1024
  });
851
1025
  }
852
1026
  // Utility skills
@@ -854,6 +1028,7 @@ export async function doctorChecks(projectRoot, options = {}) {
854
1028
  ["learnings", "learnings"],
855
1029
  ["flow-ideate", "flow-ideate"],
856
1030
  ["flow-view", "flow-view"],
1031
+ ["flow-cancel", "flow-cancel"],
857
1032
  ["subagent-dev", "sdd"],
858
1033
  ["parallel-dispatch", "parallel-agents"],
859
1034
  ["session", "session"],
@@ -1090,7 +1265,7 @@ export async function doctorChecks(projectRoot, options = {}) {
1090
1265
  cursorRuleOk =
1091
1266
  content.includes("cclaw-managed-cursor-workflow-rule") &&
1092
1267
  content.includes(".cclaw/state/flow-state.json") &&
1093
- content.includes("/cc-next");
1268
+ content.includes("/cc");
1094
1269
  }
1095
1270
  checks.push({
1096
1271
  name: "rules:cursor:workflow",
@@ -2016,6 +2191,7 @@ export async function doctorChecks(projectRoot, options = {}) {
2016
2191
  severity: check.severity ?? metadata.severity,
2017
2192
  summary: check.summary ?? metadata.summary,
2018
2193
  fix: check.fix ?? metadata.fix,
2194
+ actionGroup: check.actionGroup ?? metadata.actionGroup,
2019
2195
  docRef: check.docRef ?? metadata.docRef
2020
2196
  };
2021
2197
  });
@@ -33,7 +33,7 @@ export interface RetroState {
33
33
  * Ship closeout substate machine.
34
34
  *
35
35
  * After ship completes, cclaw auto-chains retro → compound → archive.
36
- * Each step is interruptible: `/cc-next` reads `shipSubstate` and resumes
36
+ * Each step is interruptible: `/cc` reads `shipSubstate` and resumes
37
37
  * from the correct step even across sessions.
38
38
  *
39
39
  * - `idle` — ship not complete, or closeout not yet started.
@@ -6,7 +6,7 @@ export const FLOW_STATE_SCHEMA_VERSION = 1;
6
6
  * Ship closeout substate machine.
7
7
  *
8
8
  * After ship completes, cclaw auto-chains retro → compound → archive.
9
- * Each step is interruptible: `/cc-next` reads `shipSubstate` and resumes
9
+ * Each step is interruptible: `/cc` reads `shipSubstate` and resumes
10
10
  * from the correct step even across sessions.
11
11
  *
12
12
  * - `idle` — ship not complete, or closeout not yet started.
package/dist/fs-utils.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
+ import { getActiveManagedResourceSession } from "./managed-resources.js";
3
4
  export async function ensureDir(dirPath) {
4
5
  await fs.mkdir(dirPath, { recursive: true });
5
6
  }
@@ -83,6 +84,11 @@ export async function withDirectoryLock(lockPath, fn, options = {}) {
83
84
  }
84
85
  }
85
86
  export async function writeFileSafe(filePath, content, options = {}) {
87
+ const managedSession = getActiveManagedResourceSession();
88
+ if (managedSession?.shouldManage(filePath)) {
89
+ await managedSession.writeFileSafe(filePath, content, options);
90
+ return;
91
+ }
86
92
  await ensureDir(path.dirname(filePath));
87
93
  const tempPath = path.join(path.dirname(filePath), `.${path.basename(filePath)}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`);
88
94
  const targetMode = options.mode;
@@ -32,7 +32,7 @@ export type SubagentFallback =
32
32
  * directories under a skills root (Codex CLI ≥0.89, Jan 2026). cclaw
33
33
  * writes `<commandDir>/<skillName>/SKILL.md` and the agent invokes it
34
34
  * either via `/use <skillName>` or via automatic description matching
35
- * when the user's text mentions `/cc`, `/cc-next`, etc.
35
+ * when the user's text mentions `/cc`, `/cc-ideate`, or `/cc-cancel`.
36
36
  */
37
37
  export type ShimKind = "command" | "skill";
38
38
  export interface HarnessAdapter {
@@ -47,7 +47,7 @@ export interface HarnessAdapter {
47
47
  * Root directory where cclaw writes `/cc*` entry points.
48
48
  *
49
49
  * - For `shimKind: "command"` this is the directory containing flat
50
- * markdown files (`<commandDir>/cc.md`, `<commandDir>/cc-next.md`, …).
50
+ * markdown files (`<commandDir>/cc.md`, `<commandDir>/cc-ideate.md`, …).
51
51
  * - For `shimKind: "skill"` this is the skills root that contains
52
52
  * per-skill subdirectories (`<commandDir>/<skillName>/SKILL.md`).
53
53
  */