cclaw-cli 7.7.1 → 8.1.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 (282) hide show
  1. package/README.md +210 -134
  2. package/dist/artifact-frontmatter.d.ts +51 -0
  3. package/dist/artifact-frontmatter.js +131 -0
  4. package/dist/artifact-paths.d.ts +7 -27
  5. package/dist/artifact-paths.js +20 -249
  6. package/dist/cancel.d.ts +16 -0
  7. package/dist/cancel.js +66 -0
  8. package/dist/cli.d.ts +2 -27
  9. package/dist/cli.js +90 -508
  10. package/dist/compound.d.ts +26 -0
  11. package/dist/compound.js +96 -0
  12. package/dist/config.d.ts +14 -51
  13. package/dist/config.js +23 -359
  14. package/dist/constants.d.ts +11 -18
  15. package/dist/constants.js +19 -106
  16. package/dist/content/antipatterns.d.ts +1 -0
  17. package/dist/content/antipatterns.js +109 -0
  18. package/dist/content/artifact-templates.d.ts +10 -0
  19. package/dist/content/artifact-templates.js +550 -0
  20. package/dist/content/cancel-command.d.ts +2 -2
  21. package/dist/content/cancel-command.js +25 -17
  22. package/dist/content/core-agents.d.ts +9 -233
  23. package/dist/content/core-agents.js +39 -768
  24. package/dist/content/decision-protocol.d.ts +1 -12
  25. package/dist/content/decision-protocol.js +27 -20
  26. package/dist/content/examples.d.ts +8 -42
  27. package/dist/content/examples.js +293 -425
  28. package/dist/content/idea-command.d.ts +2 -0
  29. package/dist/content/idea-command.js +38 -0
  30. package/dist/content/iron-laws.d.ts +4 -138
  31. package/dist/content/iron-laws.js +18 -197
  32. package/dist/content/meta-skill.d.ts +1 -3
  33. package/dist/content/meta-skill.js +57 -134
  34. package/dist/content/node-hooks.d.ts +12 -8
  35. package/dist/content/node-hooks.js +188 -838
  36. package/dist/content/recovery.d.ts +8 -0
  37. package/dist/content/recovery.js +179 -0
  38. package/dist/content/reference-patterns.d.ts +4 -13
  39. package/dist/content/reference-patterns.js +260 -389
  40. package/dist/content/research-playbooks.d.ts +8 -8
  41. package/dist/content/research-playbooks.js +108 -121
  42. package/dist/content/review-loop.d.ts +6 -192
  43. package/dist/content/review-loop.js +29 -731
  44. package/dist/content/skills.d.ts +8 -38
  45. package/dist/content/skills.js +681 -732
  46. package/dist/content/specialist-prompts/architect.d.ts +1 -0
  47. package/dist/content/specialist-prompts/architect.js +225 -0
  48. package/dist/content/specialist-prompts/brainstormer.d.ts +1 -0
  49. package/dist/content/specialist-prompts/brainstormer.js +168 -0
  50. package/dist/content/specialist-prompts/index.d.ts +2 -0
  51. package/dist/content/specialist-prompts/index.js +14 -0
  52. package/dist/content/specialist-prompts/planner.d.ts +1 -0
  53. package/dist/content/specialist-prompts/planner.js +182 -0
  54. package/dist/content/specialist-prompts/reviewer.d.ts +1 -0
  55. package/dist/content/specialist-prompts/reviewer.js +193 -0
  56. package/dist/content/specialist-prompts/security-reviewer.d.ts +1 -0
  57. package/dist/content/specialist-prompts/security-reviewer.js +133 -0
  58. package/dist/content/specialist-prompts/slice-builder.d.ts +1 -0
  59. package/dist/content/specialist-prompts/slice-builder.js +232 -0
  60. package/dist/content/stage-playbooks.d.ts +8 -0
  61. package/dist/content/stage-playbooks.js +404 -0
  62. package/dist/content/start-command.d.ts +2 -12
  63. package/dist/content/start-command.js +221 -207
  64. package/dist/flow-state.d.ts +21 -178
  65. package/dist/flow-state.js +67 -170
  66. package/dist/fs-utils.d.ts +6 -26
  67. package/dist/fs-utils.js +29 -162
  68. package/dist/gitignore.d.ts +2 -1
  69. package/dist/gitignore.js +51 -34
  70. package/dist/harness-detect.d.ts +10 -0
  71. package/dist/harness-detect.js +29 -0
  72. package/dist/install.d.ts +27 -15
  73. package/dist/install.js +230 -1342
  74. package/dist/knowledge-store.d.ts +19 -163
  75. package/dist/knowledge-store.js +56 -590
  76. package/dist/logger.d.ts +8 -3
  77. package/dist/logger.js +13 -4
  78. package/dist/orchestrator-routing.d.ts +29 -0
  79. package/dist/orchestrator-routing.js +156 -0
  80. package/dist/run-persistence.d.ts +7 -118
  81. package/dist/run-persistence.js +29 -845
  82. package/dist/runtime/run-hook.entry.d.ts +1 -3
  83. package/dist/runtime/run-hook.entry.js +19 -4
  84. package/dist/runtime/run-hook.mjs +13 -1024
  85. package/dist/types.d.ts +25 -261
  86. package/dist/types.js +8 -36
  87. package/package.json +6 -3
  88. package/dist/artifact-linter/brainstorm.d.ts +0 -2
  89. package/dist/artifact-linter/brainstorm.js +0 -353
  90. package/dist/artifact-linter/design.d.ts +0 -18
  91. package/dist/artifact-linter/design.js +0 -444
  92. package/dist/artifact-linter/findings-dedup.d.ts +0 -56
  93. package/dist/artifact-linter/findings-dedup.js +0 -232
  94. package/dist/artifact-linter/plan.d.ts +0 -2
  95. package/dist/artifact-linter/plan.js +0 -826
  96. package/dist/artifact-linter/review-army.d.ts +0 -49
  97. package/dist/artifact-linter/review-army.js +0 -520
  98. package/dist/artifact-linter/review.d.ts +0 -2
  99. package/dist/artifact-linter/review.js +0 -113
  100. package/dist/artifact-linter/scope.d.ts +0 -2
  101. package/dist/artifact-linter/scope.js +0 -158
  102. package/dist/artifact-linter/shared.d.ts +0 -637
  103. package/dist/artifact-linter/shared.js +0 -2163
  104. package/dist/artifact-linter/ship.d.ts +0 -2
  105. package/dist/artifact-linter/ship.js +0 -250
  106. package/dist/artifact-linter/spec.d.ts +0 -2
  107. package/dist/artifact-linter/spec.js +0 -176
  108. package/dist/artifact-linter/tdd.d.ts +0 -118
  109. package/dist/artifact-linter/tdd.js +0 -1404
  110. package/dist/artifact-linter.d.ts +0 -15
  111. package/dist/artifact-linter.js +0 -517
  112. package/dist/codex-feature-flag.d.ts +0 -58
  113. package/dist/codex-feature-flag.js +0 -193
  114. package/dist/content/closeout-guidance.d.ts +0 -14
  115. package/dist/content/closeout-guidance.js +0 -44
  116. package/dist/content/diff-command.d.ts +0 -1
  117. package/dist/content/diff-command.js +0 -43
  118. package/dist/content/harness-doc.d.ts +0 -1
  119. package/dist/content/harness-doc.js +0 -65
  120. package/dist/content/hook-events.d.ts +0 -9
  121. package/dist/content/hook-events.js +0 -23
  122. package/dist/content/hook-manifest.d.ts +0 -81
  123. package/dist/content/hook-manifest.js +0 -156
  124. package/dist/content/hooks.d.ts +0 -11
  125. package/dist/content/hooks.js +0 -1972
  126. package/dist/content/idea.d.ts +0 -60
  127. package/dist/content/idea.js +0 -416
  128. package/dist/content/language-policy.d.ts +0 -2
  129. package/dist/content/language-policy.js +0 -13
  130. package/dist/content/learnings.d.ts +0 -6
  131. package/dist/content/learnings.js +0 -141
  132. package/dist/content/observe.d.ts +0 -19
  133. package/dist/content/observe.js +0 -86
  134. package/dist/content/opencode-plugin.d.ts +0 -1
  135. package/dist/content/opencode-plugin.js +0 -635
  136. package/dist/content/review-prompts.d.ts +0 -1
  137. package/dist/content/review-prompts.js +0 -104
  138. package/dist/content/runtime-shared-snippets.d.ts +0 -8
  139. package/dist/content/runtime-shared-snippets.js +0 -80
  140. package/dist/content/session-hooks.d.ts +0 -7
  141. package/dist/content/session-hooks.js +0 -107
  142. package/dist/content/skills-elicitation.d.ts +0 -1
  143. package/dist/content/skills-elicitation.js +0 -167
  144. package/dist/content/stage-command.d.ts +0 -2
  145. package/dist/content/stage-command.js +0 -17
  146. package/dist/content/stage-schema.d.ts +0 -117
  147. package/dist/content/stage-schema.js +0 -955
  148. package/dist/content/stages/_lint-metadata/index.d.ts +0 -2
  149. package/dist/content/stages/_lint-metadata/index.js +0 -97
  150. package/dist/content/stages/brainstorm.d.ts +0 -2
  151. package/dist/content/stages/brainstorm.js +0 -184
  152. package/dist/content/stages/design.d.ts +0 -2
  153. package/dist/content/stages/design.js +0 -288
  154. package/dist/content/stages/index.d.ts +0 -8
  155. package/dist/content/stages/index.js +0 -11
  156. package/dist/content/stages/plan.d.ts +0 -2
  157. package/dist/content/stages/plan.js +0 -191
  158. package/dist/content/stages/review.d.ts +0 -2
  159. package/dist/content/stages/review.js +0 -240
  160. package/dist/content/stages/schema-types.d.ts +0 -203
  161. package/dist/content/stages/schema-types.js +0 -1
  162. package/dist/content/stages/scope.d.ts +0 -2
  163. package/dist/content/stages/scope.js +0 -254
  164. package/dist/content/stages/ship.d.ts +0 -2
  165. package/dist/content/stages/ship.js +0 -159
  166. package/dist/content/stages/spec.d.ts +0 -2
  167. package/dist/content/stages/spec.js +0 -170
  168. package/dist/content/stages/tdd.d.ts +0 -4
  169. package/dist/content/stages/tdd.js +0 -273
  170. package/dist/content/state-contracts.d.ts +0 -1
  171. package/dist/content/state-contracts.js +0 -63
  172. package/dist/content/status-command.d.ts +0 -4
  173. package/dist/content/status-command.js +0 -109
  174. package/dist/content/subagent-context-skills.d.ts +0 -4
  175. package/dist/content/subagent-context-skills.js +0 -279
  176. package/dist/content/subagents.d.ts +0 -3
  177. package/dist/content/subagents.js +0 -997
  178. package/dist/content/templates.d.ts +0 -26
  179. package/dist/content/templates.js +0 -1692
  180. package/dist/content/track-render-context.d.ts +0 -18
  181. package/dist/content/track-render-context.js +0 -53
  182. package/dist/content/tree-command.d.ts +0 -1
  183. package/dist/content/tree-command.js +0 -64
  184. package/dist/content/utility-skills.d.ts +0 -30
  185. package/dist/content/utility-skills.js +0 -160
  186. package/dist/content/view-command.d.ts +0 -2
  187. package/dist/content/view-command.js +0 -92
  188. package/dist/delegation.d.ts +0 -649
  189. package/dist/delegation.js +0 -1539
  190. package/dist/early-loop.d.ts +0 -70
  191. package/dist/early-loop.js +0 -302
  192. package/dist/execution-topology.d.ts +0 -44
  193. package/dist/execution-topology.js +0 -95
  194. package/dist/gate-evidence.d.ts +0 -85
  195. package/dist/gate-evidence.js +0 -631
  196. package/dist/harness-adapters.d.ts +0 -151
  197. package/dist/harness-adapters.js +0 -756
  198. package/dist/harness-selection.d.ts +0 -31
  199. package/dist/harness-selection.js +0 -214
  200. package/dist/hook-schema.d.ts +0 -6
  201. package/dist/hook-schema.js +0 -114
  202. package/dist/hook-schemas/claude-hooks.v1.json +0 -10
  203. package/dist/hook-schemas/codex-hooks.v1.json +0 -10
  204. package/dist/hook-schemas/cursor-hooks.v1.json +0 -13
  205. package/dist/init-detect.d.ts +0 -2
  206. package/dist/init-detect.js +0 -50
  207. package/dist/internal/advance-stage/advance.d.ts +0 -89
  208. package/dist/internal/advance-stage/advance.js +0 -655
  209. package/dist/internal/advance-stage/cancel-run.d.ts +0 -8
  210. package/dist/internal/advance-stage/cancel-run.js +0 -19
  211. package/dist/internal/advance-stage/flow-state-coercion.d.ts +0 -3
  212. package/dist/internal/advance-stage/flow-state-coercion.js +0 -81
  213. package/dist/internal/advance-stage/helpers.d.ts +0 -14
  214. package/dist/internal/advance-stage/helpers.js +0 -145
  215. package/dist/internal/advance-stage/hook.d.ts +0 -8
  216. package/dist/internal/advance-stage/hook.js +0 -40
  217. package/dist/internal/advance-stage/parsers.d.ts +0 -72
  218. package/dist/internal/advance-stage/parsers.js +0 -357
  219. package/dist/internal/advance-stage/proactive-delegation-trace.d.ts +0 -24
  220. package/dist/internal/advance-stage/proactive-delegation-trace.js +0 -56
  221. package/dist/internal/advance-stage/review-loop.d.ts +0 -16
  222. package/dist/internal/advance-stage/review-loop.js +0 -199
  223. package/dist/internal/advance-stage/rewind.d.ts +0 -14
  224. package/dist/internal/advance-stage/rewind.js +0 -108
  225. package/dist/internal/advance-stage/start-flow.d.ts +0 -13
  226. package/dist/internal/advance-stage/start-flow.js +0 -241
  227. package/dist/internal/advance-stage/verify.d.ts +0 -21
  228. package/dist/internal/advance-stage/verify.js +0 -185
  229. package/dist/internal/advance-stage.d.ts +0 -7
  230. package/dist/internal/advance-stage.js +0 -138
  231. package/dist/internal/cohesion-contract-stub.d.ts +0 -24
  232. package/dist/internal/cohesion-contract-stub.js +0 -148
  233. package/dist/internal/compound-readiness.d.ts +0 -23
  234. package/dist/internal/compound-readiness.js +0 -102
  235. package/dist/internal/detect-public-api-changes.d.ts +0 -5
  236. package/dist/internal/detect-public-api-changes.js +0 -45
  237. package/dist/internal/detect-supply-chain-changes.d.ts +0 -6
  238. package/dist/internal/detect-supply-chain-changes.js +0 -138
  239. package/dist/internal/early-loop-status.d.ts +0 -7
  240. package/dist/internal/early-loop-status.js +0 -93
  241. package/dist/internal/envelope-validate.d.ts +0 -7
  242. package/dist/internal/envelope-validate.js +0 -66
  243. package/dist/internal/flow-state-repair.d.ts +0 -20
  244. package/dist/internal/flow-state-repair.js +0 -104
  245. package/dist/internal/plan-split-waves.d.ts +0 -190
  246. package/dist/internal/plan-split-waves.js +0 -764
  247. package/dist/internal/runtime-integrity.d.ts +0 -7
  248. package/dist/internal/runtime-integrity.js +0 -268
  249. package/dist/internal/slice-commit.d.ts +0 -7
  250. package/dist/internal/slice-commit.js +0 -619
  251. package/dist/internal/tdd-loop-status.d.ts +0 -14
  252. package/dist/internal/tdd-loop-status.js +0 -68
  253. package/dist/internal/tdd-red-evidence.d.ts +0 -7
  254. package/dist/internal/tdd-red-evidence.js +0 -153
  255. package/dist/internal/waiver-grant.d.ts +0 -62
  256. package/dist/internal/waiver-grant.js +0 -294
  257. package/dist/internal/wave-status.d.ts +0 -74
  258. package/dist/internal/wave-status.js +0 -506
  259. package/dist/managed-resources.d.ts +0 -53
  260. package/dist/managed-resources.js +0 -313
  261. package/dist/policy.d.ts +0 -10
  262. package/dist/policy.js +0 -167
  263. package/dist/retro-gate.d.ts +0 -9
  264. package/dist/retro-gate.js +0 -47
  265. package/dist/run-archive.d.ts +0 -61
  266. package/dist/run-archive.js +0 -391
  267. package/dist/runs.d.ts +0 -2
  268. package/dist/runs.js +0 -2
  269. package/dist/stack-detection.d.ts +0 -116
  270. package/dist/stack-detection.js +0 -489
  271. package/dist/streaming/event-stream.d.ts +0 -31
  272. package/dist/streaming/event-stream.js +0 -114
  273. package/dist/tdd-cycle.d.ts +0 -107
  274. package/dist/tdd-cycle.js +0 -289
  275. package/dist/tdd-verification-evidence.d.ts +0 -17
  276. package/dist/tdd-verification-evidence.js +0 -122
  277. package/dist/track-heuristics.d.ts +0 -27
  278. package/dist/track-heuristics.js +0 -154
  279. package/dist/util/slice-id.d.ts +0 -58
  280. package/dist/util/slice-id.js +0 -89
  281. package/dist/worktree-manager.d.ts +0 -20
  282. package/dist/worktree-manager.js +0 -108
@@ -1,107 +0,0 @@
1
- export type TddCyclePhase = "red" | "green" | "refactor";
2
- export interface TddCycleEntry {
3
- ts: string;
4
- runId: string;
5
- stage: string;
6
- slice: string;
7
- phase: TddCyclePhase;
8
- command: string;
9
- files?: string[];
10
- exitCode?: number;
11
- note?: string;
12
- /**
13
- * Optional acceptance-criterion IDs this log line relates to (e.g. `["AC-1"]`).
14
- * Used by the Ralph Loop status summary to surface how many ACs have been
15
- * closed by a GREEN cycle without forcing the user to track them manually.
16
- */
17
- acIds?: string[];
18
- }
19
- export interface TddCycleValidation {
20
- ok: boolean;
21
- issues: string[];
22
- openRedSlices: string[];
23
- sliceCount: number;
24
- }
25
- export interface TddCycleParseIssue {
26
- lineNumber: number;
27
- reason: string;
28
- rawLine: string;
29
- }
30
- export interface ParseTddCycleLogOptions {
31
- /**
32
- * Collect one issue per dropped/malformed line. Callers that care
33
- * (sync/runtime checks, red-evidence) can surface them; hooks keep soft-fail.
34
- */
35
- issues?: TddCycleParseIssue[];
36
- /**
37
- * When true, reject lines that omit required fields instead of
38
- * back-filling them with defaults. Used by validation paths
39
- * (`validateTddCycleOrder`, `npx cclaw-cli sync` fail-fast) to avoid silently
40
- * bucketing unscoped rows into "runId=active, stage=tdd". Soft paths
41
- * (generated hooks) keep the legacy defaults so a half-written file
42
- * never takes the session down.
43
- */
44
- strict?: boolean;
45
- }
46
- export declare function parseTddCycleLog(text: string, options?: ParseTddCycleLogOptions): TddCycleEntry[];
47
- export declare function validateTddCycleOrder(entries: TddCycleEntry[], options?: {
48
- runId?: string;
49
- }): TddCycleValidation;
50
- /**
51
- * Canonical path normalization used by ALL TDD path-matching layers
52
- * (cycle-log analysis, internal CLI `tdd-red-evidence`, and the
53
- * inline runtime hook). Previously each layer had its own near-copy,
54
- * which produced subtle drift (e.g. `./src/app.ts` vs `src/app.ts`
55
- * differing between hook and CLI). Keep this function in one place
56
- * so all callers agree.
57
- */
58
- export declare function normalizeTddPath(value: string): string;
59
- /**
60
- * Shared "does the recorded file path refer to the target" matcher.
61
- * Uses canonical normalization plus the traditional `endsWith('/'+x)`
62
- * rule so a recorded `src/app.ts` matches either `src/app.ts` or
63
- * `subdir/src/app.ts` but NOT `src/app.test.ts`. All TDD path checks
64
- * MUST go through this helper.
65
- */
66
- export declare function pathMatchesTarget(candidate: string, target: string): boolean;
67
- export interface RalphLoopSliceState {
68
- slice: string;
69
- redCount: number;
70
- greenCount: number;
71
- refactorCount: number;
72
- redOpen: boolean;
73
- acIds: string[];
74
- }
75
- export interface RalphLoopStatus {
76
- schemaVersion: 1;
77
- runId: string;
78
- /**
79
- * Number of RED -> GREEN cycles observed for the run — a rough "Ralph Loop"
80
- * iteration counter that mirrors how many passing tests the loop has
81
- * delivered so far.
82
- */
83
- loopIteration: number;
84
- redOpen: boolean;
85
- redOpenSlices: string[];
86
- acClosed: string[];
87
- sliceCount: number;
88
- slices: RalphLoopSliceState[];
89
- lastUpdatedAt: string;
90
- }
91
- /**
92
- * Derive a lightweight Ralph Loop summary from parsed tdd-cycle-log entries.
93
- * The goal is to give the model a single source of truth for "am I done
94
- * iterating?" — it collapses per-slice progress and distinct closed AC IDs
95
- * (from GREEN rows) into a single artifact the progression contract reads.
96
- */
97
- export declare function computeRalphLoopStatus(entries: TddCycleEntry[], options?: {
98
- runId?: string;
99
- now?: Date;
100
- }): RalphLoopStatus;
101
- /**
102
- * Checks whether the log contains a failing RED record associated with
103
- * `productionPath` for the active run.
104
- */
105
- export declare function hasFailingTestForPath(entries: TddCycleEntry[], productionPath: string, options?: {
106
- runId?: string;
107
- }): boolean;
package/dist/tdd-cycle.js DELETED
@@ -1,289 +0,0 @@
1
- import { isSliceId } from "./util/slice-id.js";
2
- export function parseTddCycleLog(text, options = {}) {
3
- const issues = options.issues;
4
- const strict = options.strict === true;
5
- const out = [];
6
- // Strip a leading UTF-8 BOM on the whole blob so the first line parses
7
- // cleanly; `trim()` handles BOM on subsequent lines through the same
8
- // codepath (empty/whitespace-only lines are skipped).
9
- const normalized = text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;
10
- const lines = normalized.split(/\r?\n/);
11
- for (let index = 0; index < lines.length; index += 1) {
12
- const raw = lines[index] ?? "";
13
- const line = raw.trim();
14
- if (!line)
15
- continue;
16
- const lineNumber = index + 1;
17
- let parsed;
18
- try {
19
- parsed = JSON.parse(line);
20
- }
21
- catch (err) {
22
- issues?.push({
23
- lineNumber,
24
- reason: `json-parse-failed: ${err instanceof Error ? err.message : String(err)}`,
25
- rawLine: raw
26
- });
27
- continue;
28
- }
29
- const phase = parsed.phase;
30
- if (phase !== "red" && phase !== "green" && phase !== "refactor") {
31
- issues?.push({
32
- lineNumber,
33
- reason: `invalid-phase: ${JSON.stringify(parsed.phase)}`,
34
- rawLine: raw
35
- });
36
- continue;
37
- }
38
- const runIdField = typeof parsed.runId === "string" ? parsed.runId : null;
39
- const stageField = typeof parsed.stage === "string" ? parsed.stage : null;
40
- const sliceField = typeof parsed.slice === "string" ? parsed.slice : null;
41
- if (strict) {
42
- const missing = [];
43
- if (!runIdField)
44
- missing.push("runId");
45
- if (!stageField)
46
- missing.push("stage");
47
- if (!sliceField)
48
- missing.push("slice");
49
- if (missing.length > 0) {
50
- issues?.push({
51
- lineNumber,
52
- reason: `missing-required-fields: ${missing.join(",")}`,
53
- rawLine: raw
54
- });
55
- continue;
56
- }
57
- }
58
- const entry = {
59
- ts: typeof parsed.ts === "string" ? parsed.ts : "",
60
- runId: runIdField ?? "active",
61
- stage: stageField ?? "tdd",
62
- slice: sliceField ?? "S-unknown",
63
- phase,
64
- command: typeof parsed.command === "string" ? parsed.command : "",
65
- files: Array.isArray(parsed.files)
66
- ? parsed.files.filter((item) => typeof item === "string")
67
- : undefined,
68
- exitCode: typeof parsed.exitCode === "number" ? parsed.exitCode : undefined,
69
- note: typeof parsed.note === "string" ? parsed.note : undefined,
70
- acIds: Array.isArray(parsed.acIds)
71
- ? parsed.acIds
72
- .filter((item) => typeof item === "string" && item.length > 0)
73
- : undefined
74
- };
75
- out.push(entry);
76
- }
77
- return out;
78
- }
79
- export function validateTddCycleOrder(entries, options = {}) {
80
- const targetRun = options.runId;
81
- const filtered = targetRun
82
- ? entries.filter((entry) => entry.runId === targetRun)
83
- : entries;
84
- const bySlice = new Map();
85
- for (const entry of filtered) {
86
- const list = bySlice.get(entry.slice) ?? [];
87
- list.push(entry);
88
- bySlice.set(entry.slice, list);
89
- }
90
- const issues = [];
91
- const openRedSlices = [];
92
- // Reject slices whose ID does not match the stable slice-id contract.
93
- // Entries that drop the slice field entirely were previously coerced to
94
- // `S-unknown` and silently bucketed together, which means multiple distinct
95
- // cycles could appear to share a RED/GREEN pair. 7.6.0 relaxed the shape
96
- // to allow lettered sub-slice ids (e.g. `S-36a`) so plan amendments can
97
- // insert work between numeric slices without renumbering.
98
- for (const slice of bySlice.keys()) {
99
- if (!isSliceId(slice)) {
100
- issues.push(`slice "${slice}": id must match S-<number>(<letter><suffix>)? (e.g. S-1, S-36a); repair by re-logging RED/GREEN/REFACTOR with a stable slice id.`);
101
- }
102
- }
103
- for (const [slice, sliceEntries] of bySlice.entries()) {
104
- let state = "need_red";
105
- for (const entry of sliceEntries) {
106
- if (entry.phase === "red") {
107
- if (entry.exitCode === undefined) {
108
- issues.push(`slice ${slice}: RED repair needed: red entry must record a non-zero exitCode from a failing test.`);
109
- continue;
110
- }
111
- if (entry.exitCode === 0) {
112
- issues.push(`slice ${slice}: RED repair needed: red entry exitCode must be non-zero; passing output is not RED evidence.`);
113
- continue;
114
- }
115
- if (state === "red_open") {
116
- issues.push(`slice ${slice}: RED/GREEN repair needed: duplicate RED before GREEN; record the GREEN pass that closes the prior RED or split into a new slice.`);
117
- continue;
118
- }
119
- state = "red_open";
120
- continue;
121
- }
122
- if (entry.phase === "green") {
123
- if (entry.exitCode === undefined) {
124
- issues.push(`slice ${slice}: GREEN repair needed: green entry must record exitCode 0 from the verification command.`);
125
- continue;
126
- }
127
- if (entry.exitCode !== 0) {
128
- issues.push(`slice ${slice}: GREEN repair needed: green entry exitCode must be 0; fix regressions before advancing.`);
129
- continue;
130
- }
131
- if (state !== "red_open") {
132
- issues.push(`slice ${slice}: GREEN repair needed: green logged before RED; add the failing RED test evidence first.`);
133
- continue;
134
- }
135
- state = "green_done";
136
- continue;
137
- }
138
- // refactor — must preserve the passing state established by green.
139
- if (entry.exitCode === undefined) {
140
- issues.push(`slice ${slice}: REFACTOR repair needed: refactor entry must record exitCode 0 proving behavior stayed green.`);
141
- continue;
142
- }
143
- if (entry.exitCode !== 0) {
144
- issues.push(`slice ${slice}: REFACTOR repair needed: tests must stay green after cleanup; rerun/fix before closing the slice.`);
145
- continue;
146
- }
147
- if (state !== "green_done") {
148
- issues.push(`slice ${slice}: REFACTOR repair needed: refactor logged before GREEN; prove GREEN first, then cleanup.`);
149
- continue;
150
- }
151
- }
152
- if (state === "red_open") {
153
- openRedSlices.push(slice);
154
- }
155
- }
156
- return {
157
- ok: issues.length === 0 && openRedSlices.length === 0,
158
- issues,
159
- openRedSlices,
160
- sliceCount: bySlice.size
161
- };
162
- }
163
- /**
164
- * Canonical path normalization used by ALL TDD path-matching layers
165
- * (cycle-log analysis, internal CLI `tdd-red-evidence`, and the
166
- * inline runtime hook). Previously each layer had its own near-copy,
167
- * which produced subtle drift (e.g. `./src/app.ts` vs `src/app.ts`
168
- * differing between hook and CLI). Keep this function in one place
169
- * so all callers agree.
170
- */
171
- export function normalizeTddPath(value) {
172
- const trimmed = String(value ?? "").trim();
173
- return trimmed
174
- .replace(/\\/gu, "/")
175
- .replace(/^\.\//u, "")
176
- .toLowerCase();
177
- }
178
- // Legacy alias kept for local callers below.
179
- function normalizePath(value) {
180
- return normalizeTddPath(value);
181
- }
182
- /**
183
- * Shared "does the recorded file path refer to the target" matcher.
184
- * Uses canonical normalization plus the traditional `endsWith('/'+x)`
185
- * rule so a recorded `src/app.ts` matches either `src/app.ts` or
186
- * `subdir/src/app.ts` but NOT `src/app.test.ts`. All TDD path checks
187
- * MUST go through this helper.
188
- */
189
- export function pathMatchesTarget(candidate, target) {
190
- const normalizedCandidate = normalizeTddPath(candidate);
191
- const normalizedTarget = normalizeTddPath(target);
192
- if (normalizedCandidate.length === 0 || normalizedTarget.length === 0) {
193
- return false;
194
- }
195
- if (normalizedCandidate === normalizedTarget) {
196
- return true;
197
- }
198
- // Only allow suffix matching for multi-segment targets. A bare basename
199
- // like `app.ts` is too broad and can match unrelated files in any folder.
200
- return normalizedTarget.includes("/") && normalizedCandidate.endsWith(`/${normalizedTarget}`);
201
- }
202
- /**
203
- * Derive a lightweight Ralph Loop summary from parsed tdd-cycle-log entries.
204
- * The goal is to give the model a single source of truth for "am I done
205
- * iterating?" — it collapses per-slice progress and distinct closed AC IDs
206
- * (from GREEN rows) into a single artifact the progression contract reads.
207
- */
208
- export function computeRalphLoopStatus(entries, options = {}) {
209
- const runId = options.runId ?? "active";
210
- const filtered = entries.filter((entry) => options.runId ? entry.runId === options.runId : true);
211
- const slicesMap = new Map();
212
- const acClosedSet = new Set();
213
- let loopIteration = 0;
214
- const redOpenSlices = [];
215
- for (const slice of Array.from(new Set(filtered.map((entry) => entry.slice)))) {
216
- slicesMap.set(slice, {
217
- slice,
218
- redCount: 0,
219
- greenCount: 0,
220
- refactorCount: 0,
221
- redOpen: false,
222
- acIds: []
223
- });
224
- }
225
- for (const entry of filtered) {
226
- const state = slicesMap.get(entry.slice);
227
- if (!state)
228
- continue;
229
- if (entry.phase === "red") {
230
- state.redCount += 1;
231
- if (entry.exitCode !== undefined && entry.exitCode !== 0) {
232
- state.redOpen = true;
233
- }
234
- continue;
235
- }
236
- if (entry.phase === "green") {
237
- state.greenCount += 1;
238
- state.redOpen = false;
239
- loopIteration += 1;
240
- if (Array.isArray(entry.acIds)) {
241
- for (const acId of entry.acIds) {
242
- acClosedSet.add(acId);
243
- if (!state.acIds.includes(acId))
244
- state.acIds.push(acId);
245
- }
246
- }
247
- continue;
248
- }
249
- state.refactorCount += 1;
250
- }
251
- for (const state of slicesMap.values()) {
252
- if (state.redOpen)
253
- redOpenSlices.push(state.slice);
254
- }
255
- const slices = Array.from(slicesMap.values()).sort((a, b) => a.slice.localeCompare(b.slice, "en"));
256
- return {
257
- schemaVersion: 1,
258
- runId,
259
- loopIteration,
260
- redOpen: redOpenSlices.length > 0,
261
- redOpenSlices,
262
- acClosed: Array.from(acClosedSet).sort(),
263
- sliceCount: slices.length,
264
- slices,
265
- lastUpdatedAt: (options.now ?? new Date()).toISOString()
266
- };
267
- }
268
- /**
269
- * Checks whether the log contains a failing RED record associated with
270
- * `productionPath` for the active run.
271
- */
272
- export function hasFailingTestForPath(entries, productionPath, options = {}) {
273
- const filtered = options.runId
274
- ? entries.filter((entry) => entry.runId === options.runId)
275
- : entries;
276
- for (const entry of filtered) {
277
- if (entry.phase !== "red")
278
- continue;
279
- if (entry.exitCode === undefined || entry.exitCode === 0)
280
- continue;
281
- if (!Array.isArray(entry.files) || entry.files.length === 0)
282
- continue;
283
- const hasMatch = entry.files.some((filePath) => pathMatchesTarget(filePath, productionPath));
284
- if (hasMatch) {
285
- return true;
286
- }
287
- }
288
- return false;
289
- }
@@ -1,17 +0,0 @@
1
- export declare const TEST_COMMAND_HINT_PATTERN: RegExp;
2
- export declare const SHA_WITH_LABEL_PATTERN: RegExp;
3
- export declare const PASS_STATUS_PATTERN: RegExp;
4
- export declare const NO_VCS_ATTESTATION_PATTERN: RegExp;
5
- export declare const NO_VCS_HASH_PATTERN: RegExp;
6
- export type TddVerificationRefMode = "auto" | "required" | "disabled";
7
- export interface TddVerificationEvidenceOptions {
8
- requireCommand?: boolean;
9
- requirePassStatus?: boolean;
10
- }
11
- export interface TddVerificationEvidenceResult {
12
- ok: boolean;
13
- issues: string[];
14
- mode: TddVerificationRefMode;
15
- gitPresent: boolean;
16
- }
17
- export declare function validateTddVerificationEvidence(projectRoot: string, evidence: string, options?: TddVerificationEvidenceOptions): Promise<TddVerificationEvidenceResult>;
@@ -1,122 +0,0 @@
1
- import { execFile } from "node:child_process";
2
- import path from "node:path";
3
- import { promisify } from "node:util";
4
- import { readConfig, resolveTddCommitMode } from "./config.js";
5
- import { readDelegationLedger } from "./delegation.js";
6
- import { exists } from "./fs-utils.js";
7
- const execFileAsync = promisify(execFile);
8
- export const TEST_COMMAND_HINT_PATTERN = /\b(?:npm test|npm run test(?::[\w:-]+)?|pnpm test|pnpm [\w:-]*test[\w:-]*|yarn test|yarn [\w:-]*test[\w:-]*|bun test|bun run test(?::[\w:-]+)?|vitest|jest|pytest|go test|cargo test|mvn test|gradle test|\.\/gradlew test|dotnet test)\b/iu;
9
- export const SHA_WITH_LABEL_PATTERN = /\b(?:sha|commit)(?:\s*[:=]|\s+)\s*[0-9a-f]{7,40}\b/iu;
10
- export const PASS_STATUS_PATTERN = /\b(?:pass|passed|green|ok)\b/iu;
11
- export const NO_VCS_ATTESTATION_PATTERN = /\b(?:no[-_ ]?vcs|no git|not a git repo|vcs\s*[:=]\s*none)\b/iu;
12
- export const NO_VCS_HASH_PATTERN = /\b(?:content|artifact)[-_ ]?hash\s*[:=]\s*(?:sha256:)?[0-9a-f]{16,64}\b|\bsha256\s*[:=]\s*[0-9a-f]{16,64}\b/iu;
13
- function escapeRegex(value) {
14
- return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
15
- }
16
- function hasRefactorCoverage(entries) {
17
- const phases = new Set(entries
18
- .filter((e) => e.status === "completed" && typeof e.phase === "string")
19
- .map((e) => e.phase));
20
- if (phases.has("refactor") || phases.has("refactor-deferred")) {
21
- return true;
22
- }
23
- const greenWithOutcome = entries.find((entry) => entry.status === "completed" &&
24
- entry.phase === "green" &&
25
- entry.refactorOutcome &&
26
- (entry.refactorOutcome.mode === "inline" || entry.refactorOutcome.mode === "deferred"));
27
- if (!greenWithOutcome?.refactorOutcome)
28
- return false;
29
- if (greenWithOutcome.refactorOutcome.mode === "inline")
30
- return true;
31
- const rationale = greenWithOutcome.refactorOutcome.rationale;
32
- if (typeof rationale === "string" && rationale.trim().length > 0)
33
- return true;
34
- if (!Array.isArray(greenWithOutcome.evidenceRefs))
35
- return false;
36
- return greenWithOutcome.evidenceRefs.some((ref) => typeof ref === "string" && ref.trim().length > 0);
37
- }
38
- function collectClosedSlices(entries, runId) {
39
- const bySlice = new Map();
40
- for (const entry of entries) {
41
- if (entry.runId !== runId)
42
- continue;
43
- if (entry.stage !== "tdd")
44
- continue;
45
- if (entry.status !== "completed")
46
- continue;
47
- if (typeof entry.sliceId !== "string" || entry.sliceId.length === 0)
48
- continue;
49
- if (typeof entry.spanId !== "string" || entry.spanId.length === 0)
50
- continue;
51
- const bySpan = bySlice.get(entry.sliceId) ?? new Map();
52
- const rows = bySpan.get(entry.spanId) ?? [];
53
- rows.push(entry);
54
- bySpan.set(entry.spanId, rows);
55
- bySlice.set(entry.sliceId, bySpan);
56
- }
57
- const closedSlices = new Set();
58
- for (const [sliceId, bySpan] of bySlice.entries()) {
59
- for (const rows of bySpan.values()) {
60
- const phases = new Set(rows
61
- .filter((row) => row.status === "completed" && typeof row.phase === "string")
62
- .map((row) => row.phase));
63
- const hasRed = phases.has("red");
64
- const hasGreen = phases.has("green");
65
- const hasDoc = phases.has("doc");
66
- if (hasRed && hasGreen && hasDoc && hasRefactorCoverage(rows)) {
67
- closedSlices.add(sliceId);
68
- break;
69
- }
70
- }
71
- }
72
- return [...closedSlices].sort();
73
- }
74
- async function hasManagedCommitForSlice(projectRoot, sliceId) {
75
- const grep = `^${escapeRegex(sliceId)}/`;
76
- const { stdout } = await execFileAsync("git", ["log", "--format=%s%n%b", "--grep", grep], { cwd: projectRoot });
77
- return stdout.trim().length > 0;
78
- }
79
- export async function validateTddVerificationEvidence(projectRoot, evidence, options = {}) {
80
- const normalized = evidence.trim();
81
- const config = await readConfig(projectRoot).catch(() => null);
82
- const commitMode = resolveTddCommitMode(config);
83
- const mode = commitMode === "off" ? "disabled" : "auto";
84
- const gitPresent = await exists(path.join(projectRoot, ".git"));
85
- const issues = [];
86
- if (options.requireCommand !== false && !TEST_COMMAND_HINT_PATTERN.test(normalized)) {
87
- issues.push("GREEN repair needed: include the fresh verification command that was run (for example `npm test`, `pytest`, `go test`, or equivalent).");
88
- }
89
- if (options.requirePassStatus !== false && !PASS_STATUS_PATTERN.test(normalized)) {
90
- issues.push("GREEN repair needed: include explicit success status (for example `PASS` or `GREEN`).");
91
- }
92
- if (mode !== "disabled" && commitMode === "managed-per-slice" && gitPresent) {
93
- const ledger = await readDelegationLedger(projectRoot).catch(() => null);
94
- if (ledger && typeof ledger.runId === "string" && ledger.runId.length > 0) {
95
- const closedSlices = collectClosedSlices(ledger.entries, ledger.runId);
96
- const missing = [];
97
- for (const sliceId of closedSlices) {
98
- const hasCommit = await hasManagedCommitForSlice(projectRoot, sliceId).catch(() => false);
99
- if (!hasCommit) {
100
- missing.push(sliceId);
101
- }
102
- }
103
- if (missing.length > 0) {
104
- issues.push(`managed-per-slice commit check failed: missing git commit(s) for closed slice(s): ${missing.join(", ")}.`);
105
- }
106
- }
107
- }
108
- else if (mode === "auto") {
109
- const hasSha = SHA_WITH_LABEL_PATTERN.test(normalized);
110
- const hasNoVcs = NO_VCS_ATTESTATION_PATTERN.test(normalized);
111
- if (gitPresent && !hasSha) {
112
- issues.push("must include a commit SHA token prefixed with `sha` or `commit` (for example `sha: abc1234`).");
113
- }
114
- else if (!gitPresent && !hasSha && !hasNoVcs) {
115
- issues.push("must include either a commit SHA or an explicit no-VCS attestation (for example `no-vcs: project has no .git directory`).");
116
- }
117
- else if (!gitPresent && hasNoVcs && !NO_VCS_HASH_PATTERN.test(normalized)) {
118
- issues.push("NO_VCS_MODE repair needed: include a content/artifact hash for no-VCS TDD evidence (for example `artifact-hash: sha256:<hash>`).");
119
- }
120
- }
121
- return { ok: issues.length === 0, issues, mode, gitPresent };
122
- }
@@ -1,27 +0,0 @@
1
- import type { DiscoveryMode, FlowStage, FlowTrack, TrackHeuristicRule, TrackHeuristicsConfig } from "./types.js";
2
- export interface TrackResolution {
3
- track: FlowTrack;
4
- reason: string;
5
- matchedTokens: string[];
6
- confidence: "high" | "medium" | "low";
7
- overrideGuidance: string;
8
- }
9
- export interface QuestionBudgetHint {
10
- min: number;
11
- recommended: number;
12
- hardCapWarning: number;
13
- }
14
- /**
15
- * Reference implementation of the track classifier the /cc skill prose
16
- * describes. Tests pin its behavior so the built-in defaults stay honest.
17
- * This function is not called from cclaw runtime — `/cc` routing happens in
18
- * the LLM. If you wire this in later, update README to drop the
19
- * "advisory" language.
20
- */
21
- export declare function resolveTrackFromPrompt(prompt: string, config: TrackHeuristicsConfig | undefined): TrackResolution;
22
- export declare function questionBudgetHint(modeOrTrack: DiscoveryMode | FlowTrack, stage: FlowStage): QuestionBudgetHint;
23
- export declare const TRACK_HEURISTICS_DEFAULTS: {
24
- readonly fallback: "standard";
25
- readonly evaluationOrder: readonly ("quick" | "medium" | "standard")[];
26
- readonly tracks: Record<"quick" | "medium" | "standard", TrackHeuristicRule>;
27
- };