cclaw-cli 7.7.1 → 8.1.1

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 (284) hide show
  1. package/README.md +211 -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 +107 -511
  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/harness-prompt.d.ts +26 -0
  73. package/dist/harness-prompt.js +142 -0
  74. package/dist/install.d.ts +35 -15
  75. package/dist/install.js +238 -1347
  76. package/dist/knowledge-store.d.ts +19 -163
  77. package/dist/knowledge-store.js +56 -590
  78. package/dist/logger.d.ts +8 -3
  79. package/dist/logger.js +13 -4
  80. package/dist/orchestrator-routing.d.ts +29 -0
  81. package/dist/orchestrator-routing.js +156 -0
  82. package/dist/run-persistence.d.ts +7 -118
  83. package/dist/run-persistence.js +29 -845
  84. package/dist/runtime/run-hook.entry.d.ts +1 -3
  85. package/dist/runtime/run-hook.entry.js +19 -4
  86. package/dist/runtime/run-hook.mjs +13 -1024
  87. package/dist/types.d.ts +25 -261
  88. package/dist/types.js +8 -36
  89. package/package.json +6 -3
  90. package/dist/artifact-linter/brainstorm.d.ts +0 -2
  91. package/dist/artifact-linter/brainstorm.js +0 -353
  92. package/dist/artifact-linter/design.d.ts +0 -18
  93. package/dist/artifact-linter/design.js +0 -444
  94. package/dist/artifact-linter/findings-dedup.d.ts +0 -56
  95. package/dist/artifact-linter/findings-dedup.js +0 -232
  96. package/dist/artifact-linter/plan.d.ts +0 -2
  97. package/dist/artifact-linter/plan.js +0 -826
  98. package/dist/artifact-linter/review-army.d.ts +0 -49
  99. package/dist/artifact-linter/review-army.js +0 -520
  100. package/dist/artifact-linter/review.d.ts +0 -2
  101. package/dist/artifact-linter/review.js +0 -113
  102. package/dist/artifact-linter/scope.d.ts +0 -2
  103. package/dist/artifact-linter/scope.js +0 -158
  104. package/dist/artifact-linter/shared.d.ts +0 -637
  105. package/dist/artifact-linter/shared.js +0 -2163
  106. package/dist/artifact-linter/ship.d.ts +0 -2
  107. package/dist/artifact-linter/ship.js +0 -250
  108. package/dist/artifact-linter/spec.d.ts +0 -2
  109. package/dist/artifact-linter/spec.js +0 -176
  110. package/dist/artifact-linter/tdd.d.ts +0 -118
  111. package/dist/artifact-linter/tdd.js +0 -1404
  112. package/dist/artifact-linter.d.ts +0 -15
  113. package/dist/artifact-linter.js +0 -517
  114. package/dist/codex-feature-flag.d.ts +0 -58
  115. package/dist/codex-feature-flag.js +0 -193
  116. package/dist/content/closeout-guidance.d.ts +0 -14
  117. package/dist/content/closeout-guidance.js +0 -44
  118. package/dist/content/diff-command.d.ts +0 -1
  119. package/dist/content/diff-command.js +0 -43
  120. package/dist/content/harness-doc.d.ts +0 -1
  121. package/dist/content/harness-doc.js +0 -65
  122. package/dist/content/hook-events.d.ts +0 -9
  123. package/dist/content/hook-events.js +0 -23
  124. package/dist/content/hook-manifest.d.ts +0 -81
  125. package/dist/content/hook-manifest.js +0 -156
  126. package/dist/content/hooks.d.ts +0 -11
  127. package/dist/content/hooks.js +0 -1972
  128. package/dist/content/idea.d.ts +0 -60
  129. package/dist/content/idea.js +0 -416
  130. package/dist/content/language-policy.d.ts +0 -2
  131. package/dist/content/language-policy.js +0 -13
  132. package/dist/content/learnings.d.ts +0 -6
  133. package/dist/content/learnings.js +0 -141
  134. package/dist/content/observe.d.ts +0 -19
  135. package/dist/content/observe.js +0 -86
  136. package/dist/content/opencode-plugin.d.ts +0 -1
  137. package/dist/content/opencode-plugin.js +0 -635
  138. package/dist/content/review-prompts.d.ts +0 -1
  139. package/dist/content/review-prompts.js +0 -104
  140. package/dist/content/runtime-shared-snippets.d.ts +0 -8
  141. package/dist/content/runtime-shared-snippets.js +0 -80
  142. package/dist/content/session-hooks.d.ts +0 -7
  143. package/dist/content/session-hooks.js +0 -107
  144. package/dist/content/skills-elicitation.d.ts +0 -1
  145. package/dist/content/skills-elicitation.js +0 -167
  146. package/dist/content/stage-command.d.ts +0 -2
  147. package/dist/content/stage-command.js +0 -17
  148. package/dist/content/stage-schema.d.ts +0 -117
  149. package/dist/content/stage-schema.js +0 -955
  150. package/dist/content/stages/_lint-metadata/index.d.ts +0 -2
  151. package/dist/content/stages/_lint-metadata/index.js +0 -97
  152. package/dist/content/stages/brainstorm.d.ts +0 -2
  153. package/dist/content/stages/brainstorm.js +0 -184
  154. package/dist/content/stages/design.d.ts +0 -2
  155. package/dist/content/stages/design.js +0 -288
  156. package/dist/content/stages/index.d.ts +0 -8
  157. package/dist/content/stages/index.js +0 -11
  158. package/dist/content/stages/plan.d.ts +0 -2
  159. package/dist/content/stages/plan.js +0 -191
  160. package/dist/content/stages/review.d.ts +0 -2
  161. package/dist/content/stages/review.js +0 -240
  162. package/dist/content/stages/schema-types.d.ts +0 -203
  163. package/dist/content/stages/schema-types.js +0 -1
  164. package/dist/content/stages/scope.d.ts +0 -2
  165. package/dist/content/stages/scope.js +0 -254
  166. package/dist/content/stages/ship.d.ts +0 -2
  167. package/dist/content/stages/ship.js +0 -159
  168. package/dist/content/stages/spec.d.ts +0 -2
  169. package/dist/content/stages/spec.js +0 -170
  170. package/dist/content/stages/tdd.d.ts +0 -4
  171. package/dist/content/stages/tdd.js +0 -273
  172. package/dist/content/state-contracts.d.ts +0 -1
  173. package/dist/content/state-contracts.js +0 -63
  174. package/dist/content/status-command.d.ts +0 -4
  175. package/dist/content/status-command.js +0 -109
  176. package/dist/content/subagent-context-skills.d.ts +0 -4
  177. package/dist/content/subagent-context-skills.js +0 -279
  178. package/dist/content/subagents.d.ts +0 -3
  179. package/dist/content/subagents.js +0 -997
  180. package/dist/content/templates.d.ts +0 -26
  181. package/dist/content/templates.js +0 -1692
  182. package/dist/content/track-render-context.d.ts +0 -18
  183. package/dist/content/track-render-context.js +0 -53
  184. package/dist/content/tree-command.d.ts +0 -1
  185. package/dist/content/tree-command.js +0 -64
  186. package/dist/content/utility-skills.d.ts +0 -30
  187. package/dist/content/utility-skills.js +0 -160
  188. package/dist/content/view-command.d.ts +0 -2
  189. package/dist/content/view-command.js +0 -92
  190. package/dist/delegation.d.ts +0 -649
  191. package/dist/delegation.js +0 -1539
  192. package/dist/early-loop.d.ts +0 -70
  193. package/dist/early-loop.js +0 -302
  194. package/dist/execution-topology.d.ts +0 -44
  195. package/dist/execution-topology.js +0 -95
  196. package/dist/gate-evidence.d.ts +0 -85
  197. package/dist/gate-evidence.js +0 -631
  198. package/dist/harness-adapters.d.ts +0 -151
  199. package/dist/harness-adapters.js +0 -756
  200. package/dist/harness-selection.d.ts +0 -31
  201. package/dist/harness-selection.js +0 -214
  202. package/dist/hook-schema.d.ts +0 -6
  203. package/dist/hook-schema.js +0 -114
  204. package/dist/hook-schemas/claude-hooks.v1.json +0 -10
  205. package/dist/hook-schemas/codex-hooks.v1.json +0 -10
  206. package/dist/hook-schemas/cursor-hooks.v1.json +0 -13
  207. package/dist/init-detect.d.ts +0 -2
  208. package/dist/init-detect.js +0 -50
  209. package/dist/internal/advance-stage/advance.d.ts +0 -89
  210. package/dist/internal/advance-stage/advance.js +0 -655
  211. package/dist/internal/advance-stage/cancel-run.d.ts +0 -8
  212. package/dist/internal/advance-stage/cancel-run.js +0 -19
  213. package/dist/internal/advance-stage/flow-state-coercion.d.ts +0 -3
  214. package/dist/internal/advance-stage/flow-state-coercion.js +0 -81
  215. package/dist/internal/advance-stage/helpers.d.ts +0 -14
  216. package/dist/internal/advance-stage/helpers.js +0 -145
  217. package/dist/internal/advance-stage/hook.d.ts +0 -8
  218. package/dist/internal/advance-stage/hook.js +0 -40
  219. package/dist/internal/advance-stage/parsers.d.ts +0 -72
  220. package/dist/internal/advance-stage/parsers.js +0 -357
  221. package/dist/internal/advance-stage/proactive-delegation-trace.d.ts +0 -24
  222. package/dist/internal/advance-stage/proactive-delegation-trace.js +0 -56
  223. package/dist/internal/advance-stage/review-loop.d.ts +0 -16
  224. package/dist/internal/advance-stage/review-loop.js +0 -199
  225. package/dist/internal/advance-stage/rewind.d.ts +0 -14
  226. package/dist/internal/advance-stage/rewind.js +0 -108
  227. package/dist/internal/advance-stage/start-flow.d.ts +0 -13
  228. package/dist/internal/advance-stage/start-flow.js +0 -241
  229. package/dist/internal/advance-stage/verify.d.ts +0 -21
  230. package/dist/internal/advance-stage/verify.js +0 -185
  231. package/dist/internal/advance-stage.d.ts +0 -7
  232. package/dist/internal/advance-stage.js +0 -138
  233. package/dist/internal/cohesion-contract-stub.d.ts +0 -24
  234. package/dist/internal/cohesion-contract-stub.js +0 -148
  235. package/dist/internal/compound-readiness.d.ts +0 -23
  236. package/dist/internal/compound-readiness.js +0 -102
  237. package/dist/internal/detect-public-api-changes.d.ts +0 -5
  238. package/dist/internal/detect-public-api-changes.js +0 -45
  239. package/dist/internal/detect-supply-chain-changes.d.ts +0 -6
  240. package/dist/internal/detect-supply-chain-changes.js +0 -138
  241. package/dist/internal/early-loop-status.d.ts +0 -7
  242. package/dist/internal/early-loop-status.js +0 -93
  243. package/dist/internal/envelope-validate.d.ts +0 -7
  244. package/dist/internal/envelope-validate.js +0 -66
  245. package/dist/internal/flow-state-repair.d.ts +0 -20
  246. package/dist/internal/flow-state-repair.js +0 -104
  247. package/dist/internal/plan-split-waves.d.ts +0 -190
  248. package/dist/internal/plan-split-waves.js +0 -764
  249. package/dist/internal/runtime-integrity.d.ts +0 -7
  250. package/dist/internal/runtime-integrity.js +0 -268
  251. package/dist/internal/slice-commit.d.ts +0 -7
  252. package/dist/internal/slice-commit.js +0 -619
  253. package/dist/internal/tdd-loop-status.d.ts +0 -14
  254. package/dist/internal/tdd-loop-status.js +0 -68
  255. package/dist/internal/tdd-red-evidence.d.ts +0 -7
  256. package/dist/internal/tdd-red-evidence.js +0 -153
  257. package/dist/internal/waiver-grant.d.ts +0 -62
  258. package/dist/internal/waiver-grant.js +0 -294
  259. package/dist/internal/wave-status.d.ts +0 -74
  260. package/dist/internal/wave-status.js +0 -506
  261. package/dist/managed-resources.d.ts +0 -53
  262. package/dist/managed-resources.js +0 -313
  263. package/dist/policy.d.ts +0 -10
  264. package/dist/policy.js +0 -167
  265. package/dist/retro-gate.d.ts +0 -9
  266. package/dist/retro-gate.js +0 -47
  267. package/dist/run-archive.d.ts +0 -61
  268. package/dist/run-archive.js +0 -391
  269. package/dist/runs.d.ts +0 -2
  270. package/dist/runs.js +0 -2
  271. package/dist/stack-detection.d.ts +0 -116
  272. package/dist/stack-detection.js +0 -489
  273. package/dist/streaming/event-stream.d.ts +0 -31
  274. package/dist/streaming/event-stream.js +0 -114
  275. package/dist/tdd-cycle.d.ts +0 -107
  276. package/dist/tdd-cycle.js +0 -289
  277. package/dist/tdd-verification-evidence.d.ts +0 -17
  278. package/dist/tdd-verification-evidence.js +0 -122
  279. package/dist/track-heuristics.d.ts +0 -27
  280. package/dist/track-heuristics.js +0 -154
  281. package/dist/util/slice-id.d.ts +0 -58
  282. package/dist/util/slice-id.js +0 -89
  283. package/dist/worktree-manager.d.ts +0 -20
  284. 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
- };