cclaw-cli 0.55.2 → 2.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 (92) hide show
  1. package/README.md +3 -3
  2. package/dist/artifact-linter/brainstorm.js +59 -1
  3. package/dist/artifact-linter/design.js +46 -1
  4. package/dist/artifact-linter/plan.js +22 -1
  5. package/dist/artifact-linter/review.js +35 -1
  6. package/dist/artifact-linter/scope.js +33 -9
  7. package/dist/artifact-linter/shared.d.ts +12 -10
  8. package/dist/artifact-linter/shared.js +102 -41
  9. package/dist/artifact-linter/ship.js +36 -0
  10. package/dist/artifact-linter/spec.js +23 -1
  11. package/dist/artifact-linter/tdd.js +74 -0
  12. package/dist/artifact-linter.d.ts +1 -1
  13. package/dist/artifact-linter.js +11 -1
  14. package/dist/constants.d.ts +1 -1
  15. package/dist/constants.js +1 -0
  16. package/dist/content/closeout-guidance.d.ts +1 -1
  17. package/dist/content/closeout-guidance.js +10 -11
  18. package/dist/content/core-agents.d.ts +35 -36
  19. package/dist/content/core-agents.js +189 -99
  20. package/dist/content/diff-command.js +1 -1
  21. package/dist/content/examples.d.ts +0 -3
  22. package/dist/content/examples.js +197 -752
  23. package/dist/content/hook-events.js +1 -2
  24. package/dist/content/hook-manifest.d.ts +3 -4
  25. package/dist/content/hook-manifest.js +22 -25
  26. package/dist/content/hooks.js +54 -14
  27. package/dist/content/idea.d.ts +60 -0
  28. package/dist/content/idea.js +404 -0
  29. package/dist/content/learnings.d.ts +2 -4
  30. package/dist/content/learnings.js +10 -26
  31. package/dist/content/meta-skill.js +4 -3
  32. package/dist/content/node-hooks.js +368 -164
  33. package/dist/content/observe.js +3 -3
  34. package/dist/content/opencode-plugin.js +12 -32
  35. package/dist/content/reference-patterns.js +2 -2
  36. package/dist/content/runtime-shared-snippets.d.ts +8 -0
  37. package/dist/content/runtime-shared-snippets.js +80 -0
  38. package/dist/content/session-hooks.js +1 -1
  39. package/dist/content/skills-elicitation.d.ts +1 -0
  40. package/dist/content/skills-elicitation.js +123 -0
  41. package/dist/content/skills.d.ts +1 -0
  42. package/dist/content/skills.js +54 -2
  43. package/dist/content/stage-schema.js +107 -63
  44. package/dist/content/stages/brainstorm.js +7 -3
  45. package/dist/content/stages/design.js +4 -0
  46. package/dist/content/stages/review.js +8 -8
  47. package/dist/content/stages/schema-types.d.ts +2 -2
  48. package/dist/content/stages/scope.js +7 -3
  49. package/dist/content/stages/ship.js +1 -1
  50. package/dist/content/start-command.js +4 -4
  51. package/dist/content/status-command.js +3 -3
  52. package/dist/content/subagent-context-skills.js +156 -1
  53. package/dist/content/subagents.d.ts +0 -5
  54. package/dist/content/subagents.js +12 -82
  55. package/dist/content/templates.js +108 -6
  56. package/dist/content/utility-skills.js +26 -97
  57. package/dist/flow-state.d.ts +12 -6
  58. package/dist/flow-state.js +5 -6
  59. package/dist/gate-evidence.d.ts +0 -31
  60. package/dist/gate-evidence.js +3 -181
  61. package/dist/harness-adapters.js +1 -1
  62. package/dist/hook-schemas/claude-hooks.v1.json +2 -3
  63. package/dist/hook-schemas/codex-hooks.v1.json +1 -1
  64. package/dist/hook-schemas/cursor-hooks.v1.json +1 -1
  65. package/dist/install.js +50 -7
  66. package/dist/internal/advance-stage/advance.js +22 -2
  67. package/dist/internal/advance-stage/parsers.d.ts +1 -0
  68. package/dist/internal/advance-stage/parsers.js +6 -0
  69. package/dist/internal/advance-stage/review-loop.js +1 -10
  70. package/dist/knowledge-store.d.ts +2 -20
  71. package/dist/knowledge-store.js +43 -57
  72. package/dist/policy.js +3 -3
  73. package/dist/retro-gate.js +8 -90
  74. package/dist/run-archive.js +1 -4
  75. package/dist/run-persistence.d.ts +1 -1
  76. package/dist/run-persistence.js +43 -111
  77. package/dist/runtime/run-hook.entry.d.ts +3 -0
  78. package/dist/runtime/run-hook.entry.js +5 -0
  79. package/dist/runtime/run-hook.mjs +9647 -0
  80. package/dist/track-heuristics.d.ts +7 -1
  81. package/dist/track-heuristics.js +12 -0
  82. package/package.json +4 -2
  83. package/dist/content/hook-inline-snippets.d.ts +0 -96
  84. package/dist/content/hook-inline-snippets.js +0 -515
  85. package/dist/content/idea-command.d.ts +0 -8
  86. package/dist/content/idea-command.js +0 -322
  87. package/dist/content/idea-frames.d.ts +0 -31
  88. package/dist/content/idea-frames.js +0 -140
  89. package/dist/content/idea-ranking.d.ts +0 -25
  90. package/dist/content/idea-ranking.js +0 -65
  91. package/dist/trace-matrix.d.ts +0 -27
  92. package/dist/trace-matrix.js +0 -226
@@ -17,11 +17,6 @@ export class InvalidStageTransitionError extends Error {
17
17
  const FLOW_STATE_REL_PATH = `${RUNTIME_ROOT}/state/flow-state.json`;
18
18
  const ARCHIVE_DIR_REL_PATH = `${RUNTIME_ROOT}/archive`;
19
19
  const ACTIVE_ARTIFACTS_REL_PATH = `${RUNTIME_ROOT}/artifacts`;
20
- const RECONCILIATION_NOTICES_REL_PATH = `${RUNTIME_ROOT}/state/reconciliation-notices.json`;
21
- const RECONCILIATION_NOTICES_LOCK_REL_PATH = `${RUNTIME_ROOT}/state/.reconciliation-notices.lock`;
22
- const RECONCILIATION_NOTICES_SCHEMA_VERSION = 1;
23
- const CLOSEOUT_SUBSTATE_DEMOTION_KIND = "closeout_substate_demotion";
24
- const CLOSEOUT_SUBSTATE_GATE_ID = "closeout.shipSubstate";
25
20
  const FLOW_STAGE_SET = new Set(FLOW_STAGES);
26
21
  function validateFlowTransition(prev, next) {
27
22
  if (prev.activeRunId !== next.activeRunId) {
@@ -74,88 +69,12 @@ function flowStatePath(projectRoot) {
74
69
  function flowStateLockPath(projectRoot) {
75
70
  return path.join(projectRoot, RUNTIME_ROOT, "state", ".flow-state.lock");
76
71
  }
77
- function reconciliationNoticesPath(projectRoot) {
78
- return path.join(projectRoot, RECONCILIATION_NOTICES_REL_PATH);
79
- }
80
- function reconciliationNoticesLockPath(projectRoot) {
81
- return path.join(projectRoot, RECONCILIATION_NOTICES_LOCK_REL_PATH);
82
- }
83
72
  function archiveRoot(projectRoot) {
84
73
  return path.join(projectRoot, ARCHIVE_DIR_REL_PATH);
85
74
  }
86
75
  function activeArtifactsPath(projectRoot) {
87
76
  return path.join(projectRoot, ACTIVE_ARTIFACTS_REL_PATH);
88
77
  }
89
- function asObjectRecord(value) {
90
- if (!value || typeof value !== "object" || Array.isArray(value))
91
- return null;
92
- return value;
93
- }
94
- async function appendCloseoutSubstateDemotionNotice(projectRoot, state, demotion) {
95
- await withDirectoryLock(reconciliationNoticesLockPath(projectRoot), async () => {
96
- const filePath = reconciliationNoticesPath(projectRoot);
97
- const existingNotices = [];
98
- if (await exists(filePath)) {
99
- try {
100
- const raw = JSON.parse(await fs.readFile(filePath, "utf8"));
101
- const parsed = asObjectRecord(raw);
102
- const noticesRaw = parsed?.notices;
103
- if (Array.isArray(noticesRaw)) {
104
- for (const notice of noticesRaw) {
105
- const typed = asObjectRecord(notice);
106
- if (typed)
107
- existingNotices.push(typed);
108
- }
109
- }
110
- }
111
- catch {
112
- // Keep going with an empty payload; sync can still report parse errors.
113
- }
114
- }
115
- const alreadyRecorded = existingNotices.some((notice) => {
116
- if (notice.runId !== state.activeRunId)
117
- return false;
118
- if (notice.kind !== CLOSEOUT_SUBSTATE_DEMOTION_KIND)
119
- return false;
120
- const payload = asObjectRecord(notice.payload);
121
- return payload?.previous === demotion.previous &&
122
- payload?.next === demotion.next &&
123
- payload?.reason === demotion.reason;
124
- });
125
- if (alreadyRecorded)
126
- return;
127
- const ts = new Date().toISOString();
128
- existingNotices.push({
129
- id: `${state.activeRunId}:${state.currentStage}:${CLOSEOUT_SUBSTATE_GATE_ID}:${CLOSEOUT_SUBSTATE_DEMOTION_KIND}:${ts}`,
130
- runId: state.activeRunId,
131
- stage: state.currentStage,
132
- gateId: CLOSEOUT_SUBSTATE_GATE_ID,
133
- reason: demotion.reason,
134
- demotedAt: ts,
135
- kind: CLOSEOUT_SUBSTATE_DEMOTION_KIND,
136
- payload: {
137
- previous: demotion.previous,
138
- next: demotion.next,
139
- reason: demotion.reason
140
- }
141
- });
142
- existingNotices.sort((left, right) => {
143
- const leftTs = typeof left.demotedAt === "string" ? left.demotedAt : "";
144
- const rightTs = typeof right.demotedAt === "string" ? right.demotedAt : "";
145
- if (leftTs === rightTs) {
146
- const leftId = typeof left.id === "string" ? left.id : "";
147
- const rightId = typeof right.id === "string" ? right.id : "";
148
- return leftId.localeCompare(rightId);
149
- }
150
- return leftTs.localeCompare(rightTs);
151
- });
152
- await ensureDir(path.dirname(filePath));
153
- await writeFileSafe(filePath, `${JSON.stringify({
154
- schemaVersion: RECONCILIATION_NOTICES_SCHEMA_VERSION,
155
- notices: existingNotices
156
- }, null, 2)}\n`, { mode: 0o600 });
157
- });
158
- }
159
78
  function isFlowStage(value) {
160
79
  return typeof value === "string" && FLOW_STAGE_SET.has(value);
161
80
  }
@@ -313,6 +232,31 @@ function sanitizeRewinds(value) {
313
232
  }
314
233
  return out;
315
234
  }
235
+ function sanitizeInteractionHints(value) {
236
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
237
+ return {};
238
+ }
239
+ const out = {};
240
+ for (const [stage, raw] of Object.entries(value)) {
241
+ if (!isFlowStage(stage))
242
+ continue;
243
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
244
+ continue;
245
+ const typed = raw;
246
+ const skipQuestions = typed.skipQuestions === true ? true : undefined;
247
+ const sourceStage = isFlowStage(typed.sourceStage) ? typed.sourceStage : undefined;
248
+ const recordedAt = typeof typed.recordedAt === "string" ? typed.recordedAt : undefined;
249
+ if (skipQuestions !== true && !sourceStage && !recordedAt) {
250
+ continue;
251
+ }
252
+ out[stage] = {
253
+ ...(skipQuestions ? { skipQuestions } : {}),
254
+ ...(sourceStage ? { sourceStage } : {}),
255
+ ...(recordedAt ? { recordedAt } : {})
256
+ };
257
+ }
258
+ return out;
259
+ }
316
260
  function sanitizeRetroState(value) {
317
261
  const fallback = {
318
262
  required: false,
@@ -338,14 +282,20 @@ function sanitizeRetroState(value) {
338
282
  function isShipSubstate(value) {
339
283
  return typeof value === "string" && SHIP_SUBSTATES.includes(value);
340
284
  }
341
- function sanitizeCloseoutState(value, onDemotion) {
285
+ function sanitizeCloseoutState(value) {
342
286
  const fallback = createInitialCloseoutState();
343
287
  if (!value || typeof value !== "object" || Array.isArray(value)) {
344
288
  return fallback;
345
289
  }
346
290
  const typed = value;
347
- let shipSubstate = isShipSubstate(typed.shipSubstate) ? typed.shipSubstate : fallback.shipSubstate;
348
- const previousShipSubstate = shipSubstate;
291
+ const rawShipSubstate = typeof typed.shipSubstate === "string" ? typed.shipSubstate : undefined;
292
+ let shipSubstate;
293
+ if (rawShipSubstate === "retro_review" || rawShipSubstate === "compound_review") {
294
+ shipSubstate = "post_ship_review";
295
+ }
296
+ else {
297
+ shipSubstate = isShipSubstate(rawShipSubstate) ? rawShipSubstate : fallback.shipSubstate;
298
+ }
349
299
  const retroDraftedAt = typeof typed.retroDraftedAt === "string" ? typed.retroDraftedAt : undefined;
350
300
  const retroAcceptedAt = typeof typed.retroAcceptedAt === "string" ? typed.retroAcceptedAt : undefined;
351
301
  const retroSkipReason = typeof typed.retroSkipReason === "string"
@@ -370,21 +320,8 @@ function sanitizeCloseoutState(value, onDemotion) {
370
320
  // the compound leg, which would let `archive` skip durable closeout proof.
371
321
  const retroDone = retroAcceptedAt !== undefined || retroSkipped === true;
372
322
  const compoundDone = compoundCompletedAt !== undefined || compoundPromoted > 0 || compoundSkipped === true;
373
- let demotionReason;
374
- if (!retroDone && (shipSubstate === "ready_to_archive" || shipSubstate === "compound_review")) {
375
- shipSubstate = "retro_review";
376
- demotionReason = "retro closeout leg is incomplete (missing retroAcceptedAt or explicit retro skip).";
377
- }
378
- else if (shipSubstate === "ready_to_archive" && !compoundDone) {
379
- shipSubstate = "compound_review";
380
- demotionReason = "compound closeout leg is incomplete (missing compound proof).";
381
- }
382
- if (demotionReason && previousShipSubstate !== shipSubstate) {
383
- onDemotion?.({
384
- previous: previousShipSubstate,
385
- next: shipSubstate,
386
- reason: demotionReason
387
- });
323
+ if (shipSubstate === "ready_to_archive" && (!retroDone || !compoundDone)) {
324
+ shipSubstate = "post_ship_review";
388
325
  }
389
326
  return {
390
327
  shipSubstate,
@@ -405,7 +342,6 @@ function coerceFlowState(parsed) {
405
342
  const activeRunId = typeof activeRunIdRaw === "string" && activeRunIdRaw.trim().length > 0
406
343
  ? activeRunIdRaw.trim()
407
344
  : next.activeRunId;
408
- let closeoutDemotion;
409
345
  const state = {
410
346
  schemaVersion: FLOW_STATE_SCHEMA_VERSION,
411
347
  activeRunId,
@@ -417,12 +353,11 @@ function coerceFlowState(parsed) {
417
353
  skippedStages: sanitizeSkippedStages(parsed.skippedStages, track),
418
354
  staleStages: sanitizeStaleStages(parsed.staleStages),
419
355
  rewinds: sanitizeRewinds(parsed.rewinds),
356
+ interactionHints: sanitizeInteractionHints(parsed.interactionHints),
420
357
  retro: sanitizeRetroState(parsed.retro),
421
- closeout: sanitizeCloseoutState(parsed.closeout, (demotion) => {
422
- closeoutDemotion = demotion;
423
- })
358
+ closeout: sanitizeCloseoutState(parsed.closeout)
424
359
  };
425
- return { state, closeoutDemotion };
360
+ return { state };
426
361
  }
427
362
  export class CorruptFlowStateError extends Error {
428
363
  statePath;
@@ -484,11 +419,7 @@ export async function readFlowState(projectRoot, options = {}) {
484
419
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
485
420
  await quarantineCorruptState(statePath, new Error("flow-state.json did not deserialize to a JSON object"));
486
421
  }
487
- const coerced = coerceFlowState(parsed);
488
- if (coerced.closeoutDemotion) {
489
- await appendCloseoutSubstateDemotionNotice(projectRoot, coerced.state, coerced.closeoutDemotion);
490
- }
491
- return coerced.state;
422
+ return coerceFlowState(parsed).state;
492
423
  }
493
424
  export async function writeFlowState(projectRoot, state, options = {}) {
494
425
  const doWrite = async () => {
@@ -527,12 +458,13 @@ export async function writeFlowState(projectRoot, state, options = {}) {
527
458
  export function flowStateLockPathFor(projectRoot) {
528
459
  return flowStateLockPath(projectRoot);
529
460
  }
530
- export async function ensureRunSystem(projectRoot, _options = {}) {
461
+ export async function ensureRunSystem(projectRoot, options = {}) {
531
462
  await ensureDir(archiveRoot(projectRoot));
532
463
  await ensureDir(activeArtifactsPath(projectRoot));
533
464
  const statePath = flowStatePath(projectRoot);
534
465
  const state = await readFlowState(projectRoot);
535
- if (!(await exists(statePath))) {
466
+ const createIfMissing = options.createIfMissing !== false;
467
+ if (createIfMissing && !(await exists(statePath))) {
536
468
  await writeFlowState(projectRoot, state, { allowReset: true });
537
469
  }
538
470
  return state;
@@ -0,0 +1,3 @@
1
+ import { type NodeHookRuntimeOptions } from "../content/node-hooks.js";
2
+ export declare function buildRunHookRuntimeScript(options?: NodeHookRuntimeOptions): string;
3
+ export default buildRunHookRuntimeScript;
@@ -0,0 +1,5 @@
1
+ import { nodeHookRuntimeScript } from "../content/node-hooks.js";
2
+ export function buildRunHookRuntimeScript(options = {}) {
3
+ return nodeHookRuntimeScript(options);
4
+ }
5
+ export default buildRunHookRuntimeScript;