cclaw-cli 0.51.30 → 1.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 (160) hide show
  1. package/README.md +24 -18
  2. package/dist/artifact-linter/brainstorm.d.ts +2 -0
  3. package/dist/artifact-linter/brainstorm.js +289 -0
  4. package/dist/artifact-linter/design.d.ts +2 -0
  5. package/dist/artifact-linter/design.js +354 -0
  6. package/dist/artifact-linter/plan.d.ts +2 -0
  7. package/dist/artifact-linter/plan.js +183 -0
  8. package/dist/artifact-linter/review-army.d.ts +24 -0
  9. package/dist/artifact-linter/review-army.js +365 -0
  10. package/dist/artifact-linter/review.d.ts +2 -0
  11. package/dist/artifact-linter/review.js +99 -0
  12. package/dist/artifact-linter/scope.d.ts +2 -0
  13. package/dist/artifact-linter/scope.js +125 -0
  14. package/dist/artifact-linter/shared.d.ts +247 -0
  15. package/dist/artifact-linter/shared.js +1517 -0
  16. package/dist/artifact-linter/ship.d.ts +2 -0
  17. package/dist/artifact-linter/ship.js +82 -0
  18. package/dist/artifact-linter/spec.d.ts +2 -0
  19. package/dist/artifact-linter/spec.js +130 -0
  20. package/dist/artifact-linter/tdd.d.ts +2 -0
  21. package/dist/artifact-linter/tdd.js +198 -0
  22. package/dist/artifact-linter.d.ts +4 -76
  23. package/dist/artifact-linter.js +56 -2949
  24. package/dist/cli.d.ts +1 -6
  25. package/dist/cli.js +4 -159
  26. package/dist/codex-feature-flag.d.ts +1 -1
  27. package/dist/codex-feature-flag.js +1 -1
  28. package/dist/config.d.ts +3 -2
  29. package/dist/config.js +67 -3
  30. package/dist/constants.d.ts +1 -7
  31. package/dist/constants.js +10 -15
  32. package/dist/content/cancel-command.js +2 -2
  33. package/dist/content/closeout-guidance.d.ts +1 -1
  34. package/dist/content/closeout-guidance.js +15 -13
  35. package/dist/content/core-agents.d.ts +46 -29
  36. package/dist/content/core-agents.js +216 -82
  37. package/dist/content/decision-protocol.d.ts +1 -1
  38. package/dist/content/decision-protocol.js +1 -1
  39. package/dist/content/diff-command.js +1 -1
  40. package/dist/content/examples.d.ts +0 -3
  41. package/dist/content/examples.js +197 -752
  42. package/dist/content/harness-doc.js +20 -2
  43. package/dist/content/hook-manifest.d.ts +2 -2
  44. package/dist/content/hook-manifest.js +2 -2
  45. package/dist/content/hooks.d.ts +1 -0
  46. package/dist/content/hooks.js +32 -137
  47. package/dist/content/idea.d.ts +60 -0
  48. package/dist/content/idea.js +404 -0
  49. package/dist/content/iron-laws.d.ts +0 -1
  50. package/dist/content/iron-laws.js +31 -16
  51. package/dist/content/learnings.d.ts +2 -4
  52. package/dist/content/learnings.js +11 -27
  53. package/dist/content/meta-skill.js +7 -7
  54. package/dist/content/node-hooks.d.ts +10 -0
  55. package/dist/content/node-hooks.js +163 -95
  56. package/dist/content/opencode-plugin.js +15 -29
  57. package/dist/content/reference-patterns.js +2 -2
  58. package/dist/content/runtime-shared-snippets.d.ts +8 -0
  59. package/dist/content/runtime-shared-snippets.js +80 -0
  60. package/dist/content/session-hooks.js +1 -1
  61. package/dist/content/skills.d.ts +1 -0
  62. package/dist/content/skills.js +69 -7
  63. package/dist/content/stage-schema.js +147 -61
  64. package/dist/content/stages/_lint-metadata/index.js +26 -2
  65. package/dist/content/stages/brainstorm.js +13 -7
  66. package/dist/content/stages/design.js +16 -11
  67. package/dist/content/stages/plan.js +7 -4
  68. package/dist/content/stages/review.js +12 -12
  69. package/dist/content/stages/schema-types.d.ts +2 -2
  70. package/dist/content/stages/scope.js +15 -12
  71. package/dist/content/stages/ship.js +3 -3
  72. package/dist/content/stages/spec.js +9 -3
  73. package/dist/content/stages/tdd.js +14 -4
  74. package/dist/content/start-command.js +11 -10
  75. package/dist/content/status-command.js +5 -5
  76. package/dist/content/subagent-context-skills.js +156 -1
  77. package/dist/content/subagents.d.ts +0 -5
  78. package/dist/content/subagents.js +65 -81
  79. package/dist/content/templates.d.ts +1 -1
  80. package/dist/content/templates.js +187 -154
  81. package/dist/content/tree-command.js +2 -2
  82. package/dist/content/utility-skills.d.ts +2 -2
  83. package/dist/content/utility-skills.js +28 -99
  84. package/dist/content/view-command.js +4 -2
  85. package/dist/delegation.d.ts +2 -0
  86. package/dist/delegation.js +2 -1
  87. package/dist/early-loop.d.ts +66 -0
  88. package/dist/early-loop.js +275 -0
  89. package/dist/flow-state.d.ts +5 -6
  90. package/dist/flow-state.js +4 -6
  91. package/dist/gate-evidence.d.ts +0 -23
  92. package/dist/gate-evidence.js +111 -153
  93. package/dist/harness-adapters.d.ts +2 -2
  94. package/dist/harness-adapters.js +48 -19
  95. package/dist/install.js +190 -32
  96. package/dist/internal/advance-stage/advance.d.ts +50 -0
  97. package/dist/internal/advance-stage/advance.js +479 -0
  98. package/dist/internal/advance-stage/cancel-run.d.ts +8 -0
  99. package/dist/internal/advance-stage/cancel-run.js +19 -0
  100. package/dist/internal/advance-stage/flow-state-coercion.d.ts +3 -0
  101. package/dist/internal/advance-stage/flow-state-coercion.js +81 -0
  102. package/dist/internal/advance-stage/helpers.d.ts +14 -0
  103. package/dist/internal/advance-stage/helpers.js +145 -0
  104. package/dist/internal/advance-stage/hook.d.ts +8 -0
  105. package/dist/internal/advance-stage/hook.js +40 -0
  106. package/dist/internal/advance-stage/parsers.d.ts +54 -0
  107. package/dist/internal/advance-stage/parsers.js +307 -0
  108. package/dist/internal/advance-stage/review-loop.d.ts +7 -0
  109. package/dist/internal/advance-stage/review-loop.js +161 -0
  110. package/dist/internal/advance-stage/rewind.d.ts +14 -0
  111. package/dist/internal/advance-stage/rewind.js +108 -0
  112. package/dist/internal/advance-stage/start-flow.d.ts +11 -0
  113. package/dist/internal/advance-stage/start-flow.js +136 -0
  114. package/dist/internal/advance-stage/verify.d.ts +29 -0
  115. package/dist/internal/advance-stage/verify.js +225 -0
  116. package/dist/internal/advance-stage.js +21 -1470
  117. package/dist/internal/compound-readiness.d.ts +1 -1
  118. package/dist/internal/compound-readiness.js +2 -2
  119. package/dist/internal/early-loop-status.d.ts +7 -0
  120. package/dist/internal/early-loop-status.js +90 -0
  121. package/dist/internal/runtime-integrity.d.ts +7 -0
  122. package/dist/internal/runtime-integrity.js +288 -0
  123. package/dist/internal/tdd-red-evidence.js +1 -1
  124. package/dist/knowledge-store.d.ts +5 -28
  125. package/dist/knowledge-store.js +57 -84
  126. package/dist/managed-resources.js +24 -2
  127. package/dist/policy.js +7 -9
  128. package/dist/retro-gate.js +8 -90
  129. package/dist/run-archive.d.ts +1 -1
  130. package/dist/run-archive.js +13 -16
  131. package/dist/run-persistence.js +20 -15
  132. package/dist/runtime/run-hook.entry.d.ts +3 -0
  133. package/dist/runtime/run-hook.entry.js +5 -0
  134. package/dist/runtime/run-hook.mjs +9477 -0
  135. package/dist/tdd-cycle.d.ts +3 -3
  136. package/dist/tdd-cycle.js +1 -1
  137. package/dist/types.d.ts +18 -10
  138. package/package.json +4 -2
  139. package/dist/content/hook-inline-snippets.d.ts +0 -83
  140. package/dist/content/hook-inline-snippets.js +0 -302
  141. package/dist/content/ideate-command.d.ts +0 -8
  142. package/dist/content/ideate-command.js +0 -315
  143. package/dist/content/ideate-frames.d.ts +0 -31
  144. package/dist/content/ideate-frames.js +0 -140
  145. package/dist/content/ideate-ranking.d.ts +0 -25
  146. package/dist/content/ideate-ranking.js +0 -65
  147. package/dist/content/next-command.d.ts +0 -20
  148. package/dist/content/next-command.js +0 -298
  149. package/dist/content/seed-shelf.d.ts +0 -36
  150. package/dist/content/seed-shelf.js +0 -301
  151. package/dist/content/stage-common-guidance.d.ts +0 -1
  152. package/dist/content/stage-common-guidance.js +0 -106
  153. package/dist/doctor-registry.d.ts +0 -10
  154. package/dist/doctor-registry.js +0 -186
  155. package/dist/doctor.d.ts +0 -17
  156. package/dist/doctor.js +0 -2201
  157. package/dist/internal/hook-manifest.d.ts +0 -16
  158. package/dist/internal/hook-manifest.js +0 -77
  159. package/dist/trace-matrix.d.ts +0 -27
  160. package/dist/trace-matrix.js +0 -226
@@ -5,7 +5,7 @@ interface InternalIo {
5
5
  stderr: Writable;
6
6
  }
7
7
  /**
8
- * Count archived runs as sub-directories under `.cclaw/runs/`. Missing
8
+ * Count archived runs as sub-directories under `.cclaw/archive/`. Missing
9
9
  * dir / ENOENT is interpreted as zero — callers should NOT conflate
10
10
  * that with "unknown" (undefined); we only return undefined on
11
11
  * unexpected errors so the caller can choose to skip the relaxation
@@ -42,10 +42,10 @@ function stateDir(projectRoot) {
42
42
  return path.join(projectRoot, RUNTIME_ROOT, "state");
43
43
  }
44
44
  function archiveRunsDir(projectRoot) {
45
- return path.join(projectRoot, RUNTIME_ROOT, "runs");
45
+ return path.join(projectRoot, RUNTIME_ROOT, "archive");
46
46
  }
47
47
  /**
48
- * Count archived runs as sub-directories under `.cclaw/runs/`. Missing
48
+ * Count archived runs as sub-directories under `.cclaw/archive/`. Missing
49
49
  * dir / ENOENT is interpreted as zero — callers should NOT conflate
50
50
  * that with "unknown" (undefined); we only return undefined on
51
51
  * unexpected errors so the caller can choose to skip the relaxation
@@ -0,0 +1,7 @@
1
+ import type { Writable } from "node:stream";
2
+ interface InternalIo {
3
+ stdout: Writable;
4
+ stderr: Writable;
5
+ }
6
+ export declare function runEarlyLoopStatusCommand(projectRoot: string, argv: string[], io: InternalIo): Promise<number>;
7
+ export {};
@@ -0,0 +1,90 @@
1
+ import path from "node:path";
2
+ import { readConfig } from "../config.js";
3
+ import { RUNTIME_ROOT } from "../constants.js";
4
+ import { computeEarlyLoopStatus, formatEarlyLoopStatusLine, isEarlyLoopStage } from "../early-loop.js";
5
+ import { writeFileSafe } from "../fs-utils.js";
6
+ import { readFlowState } from "../runs.js";
7
+ function parseArgs(tokens) {
8
+ const args = { json: false, quiet: false, write: true };
9
+ for (let index = 0; index < tokens.length; index += 1) {
10
+ const token = tokens[index];
11
+ const nextToken = tokens[index + 1];
12
+ if (token === "--json") {
13
+ args.json = true;
14
+ continue;
15
+ }
16
+ if (token === "--quiet") {
17
+ args.quiet = true;
18
+ continue;
19
+ }
20
+ if (token === "--write") {
21
+ args.write = true;
22
+ continue;
23
+ }
24
+ if (token === "--no-write") {
25
+ args.write = false;
26
+ continue;
27
+ }
28
+ if (token === "--stage") {
29
+ if (!nextToken || nextToken.startsWith("--")) {
30
+ throw new Error("--stage requires a value: brainstorm | scope | design");
31
+ }
32
+ if (!isEarlyLoopStage(nextToken)) {
33
+ throw new Error("--stage must be one of: brainstorm, scope, design");
34
+ }
35
+ args.stage = nextToken;
36
+ index += 1;
37
+ continue;
38
+ }
39
+ if (token.startsWith("--stage=")) {
40
+ const stageRaw = token.slice("--stage=".length);
41
+ if (!isEarlyLoopStage(stageRaw)) {
42
+ throw new Error("--stage must be one of: brainstorm, scope, design");
43
+ }
44
+ args.stage = stageRaw;
45
+ continue;
46
+ }
47
+ if (token === "--run-id") {
48
+ if (!nextToken || nextToken.startsWith("--")) {
49
+ throw new Error("--run-id requires a value.");
50
+ }
51
+ args.runId = nextToken.trim();
52
+ index += 1;
53
+ continue;
54
+ }
55
+ if (token.startsWith("--run-id=")) {
56
+ args.runId = token.slice("--run-id=".length).trim();
57
+ continue;
58
+ }
59
+ throw new Error(`Unknown early-loop-status flag: ${token}`);
60
+ }
61
+ return args;
62
+ }
63
+ function stateDir(projectRoot) {
64
+ return path.join(projectRoot, RUNTIME_ROOT, "state");
65
+ }
66
+ export async function runEarlyLoopStatusCommand(projectRoot, argv, io) {
67
+ const args = parseArgs(argv);
68
+ const flow = await readFlowState(projectRoot).catch(() => null);
69
+ const config = await readConfig(projectRoot).catch(() => null);
70
+ const stage = args.stage ?? flow?.currentStage;
71
+ if (!isEarlyLoopStage(stage)) {
72
+ io.stderr.write("cclaw internal early-loop-status: current stage is not an early-loop stage. Pass --stage=brainstorm|scope|design.\n");
73
+ return 1;
74
+ }
75
+ const runId = (args.runId ?? flow?.activeRunId ?? "active").trim() || "active";
76
+ const status = await computeEarlyLoopStatus(stage, runId, path.join(stateDir(projectRoot), "early-loop-log.jsonl"), { maxIterations: config?.earlyLoop?.maxIterations });
77
+ if (args.write) {
78
+ const target = path.join(stateDir(projectRoot), "early-loop.json");
79
+ await writeFileSafe(target, `${JSON.stringify(status, null, 2)}\n`);
80
+ }
81
+ if (!args.quiet) {
82
+ if (args.json) {
83
+ io.stdout.write(`${JSON.stringify(status, null, 2)}\n`);
84
+ }
85
+ else {
86
+ io.stdout.write(`${formatEarlyLoopStatusLine(status)}\n`);
87
+ }
88
+ }
89
+ return 0;
90
+ }
@@ -0,0 +1,7 @@
1
+ import type { Writable } from "node:stream";
2
+ interface InternalIo {
3
+ stdout: Writable;
4
+ stderr: Writable;
5
+ }
6
+ export declare function runRuntimeIntegrityCommand(projectRoot: string, argv: string[], io: InternalIo): Promise<number>;
7
+ export {};
@@ -0,0 +1,288 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { readConfig } from "../config.js";
4
+ import { RUNTIME_ROOT } from "../constants.js";
5
+ import { classifyCodexHooksFlag, codexConfigPath, readCodexConfig } from "../codex-feature-flag.js";
6
+ import { exists } from "../fs-utils.js";
7
+ import { HARNESS_ADAPTERS, harnessShimFileNames, harnessShimSkillNames } from "../harness-adapters.js";
8
+ import { validateHookDocument } from "../hook-schema.js";
9
+ import { MANAGED_RESOURCE_MANIFEST_REL_PATH, validateManagedResourceManifest } from "../managed-resources.js";
10
+ import { CorruptFlowStateError, readFlowState } from "../runs.js";
11
+ function parseArgs(tokens) {
12
+ const args = { json: false, quiet: false };
13
+ for (const token of tokens) {
14
+ if (token === "--json") {
15
+ args.json = true;
16
+ continue;
17
+ }
18
+ if (token === "--quiet") {
19
+ args.quiet = true;
20
+ continue;
21
+ }
22
+ throw new Error(`Unknown runtime-integrity flag: ${token}`);
23
+ }
24
+ return args;
25
+ }
26
+ function stripJsonCommentsOutsideStrings(input) {
27
+ let out = "";
28
+ let i = 0;
29
+ let inString = false;
30
+ let escape = false;
31
+ while (i < input.length) {
32
+ const c = input[i];
33
+ if (inString) {
34
+ out += c;
35
+ if (escape) {
36
+ escape = false;
37
+ }
38
+ else if (c === "\\") {
39
+ escape = true;
40
+ }
41
+ else if (c === "\"") {
42
+ inString = false;
43
+ }
44
+ i += 1;
45
+ continue;
46
+ }
47
+ if (c === "\"") {
48
+ inString = true;
49
+ out += c;
50
+ i += 1;
51
+ continue;
52
+ }
53
+ const next = input[i + 1];
54
+ if (c === "/" && next === "/") {
55
+ while (i < input.length && input[i] !== "\n" && input[i] !== "\r")
56
+ i += 1;
57
+ continue;
58
+ }
59
+ if (c === "/" && next === "*") {
60
+ i += 2;
61
+ while (i < input.length - 1 && !(input[i] === "*" && input[i + 1] === "/"))
62
+ i += 1;
63
+ i = Math.min(i + 2, input.length);
64
+ continue;
65
+ }
66
+ out += c;
67
+ i += 1;
68
+ }
69
+ return out;
70
+ }
71
+ function parseJsonWithRecovery(raw) {
72
+ try {
73
+ return JSON.parse(raw);
74
+ }
75
+ catch {
76
+ // Continue with comment/trailing-comma recovery.
77
+ }
78
+ try {
79
+ const normalized = stripJsonCommentsOutsideStrings(raw).replace(/,\s*([}\]])/gu, "$1");
80
+ return JSON.parse(normalized);
81
+ }
82
+ catch {
83
+ return null;
84
+ }
85
+ }
86
+ function okFinding(id, message) {
87
+ return {
88
+ id,
89
+ severity: "error",
90
+ ok: true,
91
+ message
92
+ };
93
+ }
94
+ function errorFinding(id, message, details) {
95
+ return {
96
+ id,
97
+ severity: "error",
98
+ ok: false,
99
+ message,
100
+ ...(details && details.length > 0 ? { details } : {})
101
+ };
102
+ }
103
+ function warningFinding(id, ok, message, details) {
104
+ return {
105
+ id,
106
+ severity: "warning",
107
+ ok,
108
+ message,
109
+ ...(details && details.length > 0 ? { details } : {})
110
+ };
111
+ }
112
+ async function checkStaleSentinel(projectRoot) {
113
+ const sentinelPath = path.join(projectRoot, RUNTIME_ROOT, "state", ".init-in-progress");
114
+ if (!(await exists(sentinelPath))) {
115
+ return warningFinding("stale_init_sentinel", true, "No stale init sentinel detected.");
116
+ }
117
+ let startedAt = "unknown time";
118
+ try {
119
+ const raw = await fs.readFile(sentinelPath, "utf8");
120
+ const parsed = JSON.parse(raw);
121
+ if (parsed && typeof parsed.startedAt === "string" && parsed.startedAt.trim().length > 0) {
122
+ startedAt = parsed.startedAt;
123
+ }
124
+ }
125
+ catch {
126
+ // best-effort parse only
127
+ }
128
+ return warningFinding("stale_init_sentinel", false, "Detected stale .init-in-progress sentinel from a previous interrupted sync/init run.", [`startedAt: ${startedAt}`, `path: ${sentinelPath}`]);
129
+ }
130
+ async function checkFlowState(projectRoot) {
131
+ try {
132
+ await readFlowState(projectRoot);
133
+ return okFinding("flow_state", "Flow state is readable.");
134
+ }
135
+ catch (error) {
136
+ if (error instanceof CorruptFlowStateError) {
137
+ return errorFinding("flow_state", "Corrupt flow-state detected.", [error.message]);
138
+ }
139
+ return errorFinding("flow_state", "Flow-state read failed.", [
140
+ error instanceof Error ? error.message : String(error)
141
+ ]);
142
+ }
143
+ }
144
+ async function checkManagedManifest(projectRoot) {
145
+ const manifestPath = path.join(projectRoot, MANAGED_RESOURCE_MANIFEST_REL_PATH);
146
+ if (!(await exists(manifestPath))) {
147
+ return errorFinding("managed_manifest", "Managed resource manifest is missing.", [`missing: ${manifestPath}`]);
148
+ }
149
+ const rawText = await fs.readFile(manifestPath, "utf8");
150
+ let parsed;
151
+ try {
152
+ parsed = JSON.parse(rawText);
153
+ }
154
+ catch (error) {
155
+ return errorFinding("managed_manifest", "Managed resource manifest is not valid JSON.", [error instanceof Error ? error.message : String(error)]);
156
+ }
157
+ const issues = validateManagedResourceManifest(parsed);
158
+ if (issues.length > 0) {
159
+ const detail = issues.slice(0, 12).map((issue) => {
160
+ const scope = issue.path ?? (issue.index !== undefined ? `resources[${issue.index}]` : "manifest");
161
+ return `${scope}.${issue.field}: ${issue.message}`;
162
+ });
163
+ return errorFinding("managed_manifest", "Managed resource manifest schema validation failed.", detail);
164
+ }
165
+ return okFinding("managed_manifest", "Managed resource manifest is valid.");
166
+ }
167
+ function hookFilePath(projectRoot, harness) {
168
+ if (harness === "claude")
169
+ return path.join(projectRoot, ".claude/hooks/hooks.json");
170
+ if (harness === "cursor")
171
+ return path.join(projectRoot, ".cursor/hooks.json");
172
+ return path.join(projectRoot, ".codex/hooks.json");
173
+ }
174
+ async function checkHookDocument(projectRoot, harness) {
175
+ const hookPath = hookFilePath(projectRoot, harness);
176
+ if (!(await exists(hookPath))) {
177
+ return errorFinding(`hook_document_${harness}`, `Hook document is missing for ${harness}.`, [`missing: ${hookPath}`]);
178
+ }
179
+ const raw = await fs.readFile(hookPath, "utf8");
180
+ const parsed = parseJsonWithRecovery(raw);
181
+ if (parsed === null) {
182
+ return errorFinding(`hook_document_${harness}`, `Hook document for ${harness} is unparseable JSON.`, [`path: ${hookPath}`]);
183
+ }
184
+ const validation = validateHookDocument(harness, parsed);
185
+ if (!validation.ok) {
186
+ return errorFinding(`hook_document_${harness}`, `Hook document for ${harness} is invalid.`, validation.errors);
187
+ }
188
+ return okFinding(`hook_document_${harness}`, `Hook document for ${harness} is valid.`);
189
+ }
190
+ async function checkHarnessShims(projectRoot, harnesses) {
191
+ const findings = [];
192
+ const expectedFiles = harnessShimFileNames();
193
+ const expectedSkillFolders = harnessShimSkillNames();
194
+ for (const harness of harnesses) {
195
+ const adapter = HARNESS_ADAPTERS[harness];
196
+ const base = path.join(projectRoot, adapter.commandDir);
197
+ const missing = [];
198
+ for (const fileName of expectedFiles) {
199
+ const target = adapter.shimKind === "skill"
200
+ ? path.join(base, fileName.replace(/\.md$/u, ""), "SKILL.md")
201
+ : path.join(base, fileName);
202
+ if (!(await exists(target))) {
203
+ missing.push(target);
204
+ }
205
+ }
206
+ if (adapter.shimKind === "skill") {
207
+ for (const folder of expectedSkillFolders) {
208
+ const target = path.join(base, folder, "SKILL.md");
209
+ if (!(await exists(target))) {
210
+ missing.push(target);
211
+ }
212
+ }
213
+ }
214
+ if (missing.length > 0) {
215
+ findings.push(errorFinding(`shim_drift_${harness}`, `Harness shim drift detected for ${harness}.`, missing));
216
+ }
217
+ else {
218
+ findings.push(okFinding(`shim_drift_${harness}`, `Harness shims for ${harness} are present.`));
219
+ }
220
+ }
221
+ return findings;
222
+ }
223
+ async function checkCodexHooksFlag(harnesses) {
224
+ if (!harnesses.includes("codex")) {
225
+ return warningFinding("codex_hooks_flag", true, "Codex harness is not enabled.");
226
+ }
227
+ const configTomlPath = codexConfigPath();
228
+ let existing;
229
+ try {
230
+ existing = await readCodexConfig(configTomlPath);
231
+ }
232
+ catch (error) {
233
+ return warningFinding("codex_hooks_flag", false, "Could not read Codex config.toml to validate codex_hooks.", [error instanceof Error ? error.message : String(error)]);
234
+ }
235
+ const state = classifyCodexHooksFlag(existing);
236
+ if (state === "enabled") {
237
+ return warningFinding("codex_hooks_flag", true, "Codex hooks feature flag is enabled.");
238
+ }
239
+ return warningFinding("codex_hooks_flag", false, "Codex hooks file is present, but [features] codex_hooks is not true in Codex config.", [`configPath: ${configTomlPath}`, `state: ${state}`]);
240
+ }
241
+ function buildReport(findings) {
242
+ const errors = findings.filter((finding) => !finding.ok && finding.severity === "error").length;
243
+ const warnings = findings.filter((finding) => !finding.ok && finding.severity === "warning").length;
244
+ return {
245
+ ok: errors === 0,
246
+ generatedAt: new Date().toISOString(),
247
+ findings,
248
+ summary: { errors, warnings }
249
+ };
250
+ }
251
+ function writeTextReport(io, report) {
252
+ io.stdout.write(`runtime-integrity: ${report.ok ? "ok" : "failed"}\n`);
253
+ io.stdout.write(`errors=${report.summary.errors} warnings=${report.summary.warnings}\n`);
254
+ for (const finding of report.findings) {
255
+ if (finding.ok)
256
+ continue;
257
+ io.stdout.write(`[${finding.severity}] ${finding.id}: ${finding.message}\n`);
258
+ for (const detail of finding.details ?? []) {
259
+ io.stdout.write(` - ${detail}\n`);
260
+ }
261
+ }
262
+ }
263
+ export async function runRuntimeIntegrityCommand(projectRoot, argv, io) {
264
+ const args = parseArgs(argv);
265
+ const config = await readConfig(projectRoot);
266
+ const harnesses = config.harnesses;
267
+ const findings = [];
268
+ findings.push(await checkStaleSentinel(projectRoot));
269
+ findings.push(await checkFlowState(projectRoot));
270
+ findings.push(await checkManagedManifest(projectRoot));
271
+ findings.push(...await checkHarnessShims(projectRoot, harnesses));
272
+ for (const harness of harnesses) {
273
+ if (harness === "claude" || harness === "cursor" || harness === "codex") {
274
+ findings.push(await checkHookDocument(projectRoot, harness));
275
+ }
276
+ }
277
+ findings.push(await checkCodexHooksFlag(harnesses));
278
+ const report = buildReport(findings);
279
+ if (!args.quiet) {
280
+ if (args.json) {
281
+ io.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
282
+ }
283
+ else {
284
+ writeTextReport(io, report);
285
+ }
286
+ }
287
+ return report.ok ? 0 : 1;
288
+ }
@@ -95,7 +95,7 @@ export async function runTddRedEvidenceCommand(projectRoot, tokens, io) {
95
95
  if (!effectiveRunId || effectiveRunId.trim().length === 0) {
96
96
  const reason = "tdd-red-evidence: cannot scope check — no --runId provided and " +
97
97
  "flow-state.json has no activeRunId. Pass --runId=<id> explicitly " +
98
- "or run `cclaw doctor` to reconcile state.";
98
+ "or run `npx cclaw-cli sync` to reconcile state.";
99
99
  if (!args.quiet) {
100
100
  io.stdout.write(`${JSON.stringify({
101
101
  ok: false,
@@ -2,29 +2,21 @@ import { type FlowStage } from "./types.js";
2
2
  export type KnowledgeEntryType = "rule" | "pattern" | "lesson" | "compound";
3
3
  export type KnowledgeEntryConfidence = "high" | "medium" | "low";
4
4
  export type KnowledgeEntrySeverity = "critical" | "important" | "suggestion";
5
- export type KnowledgeEntryUniversality = "project" | "personal" | "universal";
6
- export type KnowledgeEntryMaturity = "raw" | "lifted-to-rule" | "lifted-to-enforcement";
7
- export type KnowledgeEntrySource = "stage" | "retro" | "compound" | "ideate" | "manual";
5
+ export type KnowledgeEntrySource = "stage" | "retro" | "compound" | "idea" | "manual";
8
6
  export interface KnowledgeEntry {
9
7
  type: KnowledgeEntryType;
10
8
  trigger: string;
11
9
  action: string;
12
10
  confidence: KnowledgeEntryConfidence;
13
11
  severity?: KnowledgeEntrySeverity;
14
- domain: string | null;
15
12
  stage: FlowStage | null;
16
13
  origin_stage: FlowStage | null;
17
- origin_run: string | null;
18
14
  frequency: number;
19
- universality: KnowledgeEntryUniversality;
20
- maturity: KnowledgeEntryMaturity;
21
15
  created: string;
22
16
  first_seen_ts: string;
23
17
  last_seen_ts: string;
24
18
  project: string | null;
25
19
  source?: KnowledgeEntrySource | null;
26
- supersedes?: string[];
27
- superseded_by?: string;
28
20
  }
29
21
  export interface KnowledgeSeedEntry {
30
22
  type: KnowledgeEntryType;
@@ -32,27 +24,18 @@ export interface KnowledgeSeedEntry {
32
24
  action: string;
33
25
  confidence: KnowledgeEntryConfidence;
34
26
  severity?: KnowledgeEntrySeverity;
35
- domain?: string | null;
36
27
  stage?: FlowStage | null;
37
28
  origin_stage?: FlowStage | null;
38
- origin_run?: string | null;
39
- /** @deprecated Use `origin_run`. Accepted only for legacy JSONL/backfill inputs. */
40
- origin_feature?: string | null;
41
29
  frequency?: number;
42
- universality?: KnowledgeEntryUniversality;
43
- maturity?: KnowledgeEntryMaturity;
44
30
  created?: string;
45
31
  first_seen_ts?: string;
46
32
  last_seen_ts?: string;
47
33
  project?: string | null;
48
34
  source?: KnowledgeEntrySource | null;
49
- supersedes?: string[];
50
- superseded_by?: string;
51
35
  }
52
36
  export interface AppendKnowledgeDefaults {
53
37
  stage?: FlowStage | null;
54
38
  originStage?: FlowStage | null;
55
- originRun?: string | null;
56
39
  project?: string | null;
57
40
  source?: KnowledgeEntrySource | null;
58
41
  nowIso?: string;
@@ -100,8 +83,6 @@ export interface CompoundReadinessCluster {
100
83
  lastSeenTs: string;
101
84
  /** Entry types observed (rule/pattern/lesson/compound). */
102
85
  types: KnowledgeEntryType[];
103
- /** Distinct maturity values observed across the cluster. */
104
- maturity: KnowledgeEntryMaturity[];
105
86
  }
106
87
  export interface CompoundReadiness {
107
88
  schemaVersion: 2;
@@ -143,7 +124,7 @@ export interface ComputeCompoundReadinessOptions {
143
124
  maxReady?: number;
144
125
  now?: Date;
145
126
  /**
146
- * Count of archived runs under `.cclaw/runs/`. When supplied and
127
+ * Count of archived runs under `.cclaw/archive/`. When supplied and
147
128
  * `< SMALL_PROJECT_ARCHIVE_RUNS_THRESHOLD`, the effective threshold
148
129
  * is lowered to `min(threshold, SMALL_PROJECT_RECURRENCE_THRESHOLD)`.
149
130
  * Matches the rule documented in `docs/config.md`.
@@ -169,15 +150,11 @@ export declare function effectiveCompoundThreshold(baseThreshold: number, archiv
169
150
  *
170
151
  * Clustering key: `(type, normalizeText(trigger), normalizeText(action))`
171
152
  * which mirrors the compound readiness clustering in runtime state.
172
- * Entries with `maturity === "lifted-to-enforcement"` or `superseded_by`
173
- * are excluded they were already promoted/replaced and should not re-appear
174
- * as ready.
153
+ * The readiness surface intentionally stays simple: no maturity/supersede
154
+ * suppression logic in this pass.
175
155
  */
176
156
  export declare function computeCompoundReadiness(entries: KnowledgeEntry[], options?: ComputeCompoundReadinessOptions): CompoundReadiness;
177
- export interface ValidateKnowledgeEntryOptions {
178
- allowLegacyOriginFeature?: boolean;
179
- }
180
- export declare function validateKnowledgeEntry(entry: unknown, options?: ValidateKnowledgeEntryOptions): {
157
+ export declare function validateKnowledgeEntry(entry: unknown): {
181
158
  ok: boolean;
182
159
  errors: string[];
183
160
  };