cclaw-cli 0.49.0 → 0.51.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 (183) hide show
  1. package/README.md +57 -84
  2. package/dist/artifact-linter.d.ts +4 -0
  3. package/dist/artifact-linter.js +24 -3
  4. package/dist/cli.d.ts +1 -19
  5. package/dist/cli.js +49 -491
  6. package/dist/constants.d.ts +2 -13
  7. package/dist/constants.js +1 -43
  8. package/dist/content/closeout-guidance.d.ts +14 -0
  9. package/dist/content/closeout-guidance.js +42 -0
  10. package/dist/content/core-agents.js +55 -17
  11. package/dist/content/decision-protocol.d.ts +12 -0
  12. package/dist/content/decision-protocol.js +20 -0
  13. package/dist/content/diff-command.d.ts +1 -2
  14. package/dist/content/diff-command.js +8 -94
  15. package/dist/content/examples.d.ts +4 -10
  16. package/dist/content/examples.js +10 -20
  17. package/dist/content/hook-events.js +2 -2
  18. package/dist/content/hook-inline-snippets.d.ts +5 -2
  19. package/dist/content/hook-inline-snippets.js +33 -1
  20. package/dist/content/hook-manifest.d.ts +3 -4
  21. package/dist/content/hook-manifest.js +11 -12
  22. package/dist/content/hooks.js +44 -21
  23. package/dist/content/ideate-command.d.ts +2 -0
  24. package/dist/content/ideate-command.js +34 -25
  25. package/dist/content/iron-laws.d.ts +5 -5
  26. package/dist/content/iron-laws.js +5 -5
  27. package/dist/content/language-policy.d.ts +2 -0
  28. package/dist/content/language-policy.js +13 -0
  29. package/dist/content/learnings.d.ts +3 -4
  30. package/dist/content/learnings.js +26 -50
  31. package/dist/content/meta-skill.js +33 -22
  32. package/dist/content/next-command.js +41 -38
  33. package/dist/content/node-hooks.js +17 -345
  34. package/dist/content/opencode-plugin.js +5 -103
  35. package/dist/content/research-playbooks.js +14 -14
  36. package/dist/content/review-loop.d.ts +2 -0
  37. package/dist/content/review-loop.js +8 -0
  38. package/dist/content/session-hooks.js +15 -47
  39. package/dist/content/skills.d.ts +0 -5
  40. package/dist/content/skills.js +55 -128
  41. package/dist/content/stage-common-guidance.d.ts +0 -1
  42. package/dist/content/stage-common-guidance.js +17 -14
  43. package/dist/content/stage-schema.d.ts +26 -1
  44. package/dist/content/stage-schema.js +121 -40
  45. package/dist/content/stages/_lint-metadata/index.js +9 -15
  46. package/dist/content/stages/brainstorm.js +22 -43
  47. package/dist/content/stages/design.js +37 -57
  48. package/dist/content/stages/plan.js +22 -13
  49. package/dist/content/stages/review.js +24 -27
  50. package/dist/content/stages/scope.js +34 -46
  51. package/dist/content/stages/ship.js +7 -4
  52. package/dist/content/stages/spec.js +20 -9
  53. package/dist/content/stages/tdd.js +64 -44
  54. package/dist/content/start-command.js +13 -12
  55. package/dist/content/status-command.d.ts +2 -7
  56. package/dist/content/status-command.js +19 -146
  57. package/dist/content/subagents.d.ts +0 -5
  58. package/dist/content/subagents.js +51 -28
  59. package/dist/content/templates.d.ts +1 -1
  60. package/dist/content/templates.js +126 -135
  61. package/dist/content/track-render-context.d.ts +17 -0
  62. package/dist/content/track-render-context.js +44 -0
  63. package/dist/content/tree-command.d.ts +1 -2
  64. package/dist/content/tree-command.js +4 -87
  65. package/dist/content/utility-skills.d.ts +2 -29
  66. package/dist/content/utility-skills.js +2 -1534
  67. package/dist/content/view-command.js +31 -11
  68. package/dist/delegation.d.ts +1 -1
  69. package/dist/delegation.js +5 -15
  70. package/dist/doctor-registry.js +20 -21
  71. package/dist/doctor.js +88 -344
  72. package/dist/flow-state.d.ts +3 -0
  73. package/dist/flow-state.js +2 -0
  74. package/dist/harness-adapters.d.ts +1 -1
  75. package/dist/harness-adapters.js +51 -58
  76. package/dist/install.js +128 -358
  77. package/dist/internal/advance-stage.js +3 -9
  78. package/dist/internal/compound-readiness.d.ts +1 -1
  79. package/dist/internal/compound-readiness.js +1 -1
  80. package/dist/internal/tdd-loop-status.d.ts +1 -1
  81. package/dist/internal/tdd-loop-status.js +1 -1
  82. package/dist/knowledge-store.d.ts +16 -10
  83. package/dist/knowledge-store.js +51 -15
  84. package/dist/policy.js +16 -105
  85. package/dist/run-archive.d.ts +4 -6
  86. package/dist/run-archive.js +15 -20
  87. package/dist/run-persistence.d.ts +2 -2
  88. package/dist/run-persistence.js +3 -9
  89. package/package.json +1 -2
  90. package/dist/content/archive-command.d.ts +0 -2
  91. package/dist/content/archive-command.js +0 -124
  92. package/dist/content/compound-command.d.ts +0 -5
  93. package/dist/content/compound-command.js +0 -193
  94. package/dist/content/contexts.d.ts +0 -18
  95. package/dist/content/contexts.js +0 -24
  96. package/dist/content/contracts.d.ts +0 -2
  97. package/dist/content/contracts.js +0 -51
  98. package/dist/content/doctor-references.d.ts +0 -2
  99. package/dist/content/doctor-references.js +0 -150
  100. package/dist/content/eval-scaffold.d.ts +0 -15
  101. package/dist/content/eval-scaffold.js +0 -370
  102. package/dist/content/feature-command.d.ts +0 -2
  103. package/dist/content/feature-command.js +0 -123
  104. package/dist/content/flow-map.d.ts +0 -23
  105. package/dist/content/flow-map.js +0 -134
  106. package/dist/content/harness-doc.d.ts +0 -2
  107. package/dist/content/harness-doc.js +0 -202
  108. package/dist/content/harness-playbooks.d.ts +0 -24
  109. package/dist/content/harness-playbooks.js +0 -393
  110. package/dist/content/harness-tool-refs.d.ts +0 -20
  111. package/dist/content/harness-tool-refs.js +0 -268
  112. package/dist/content/ops-command.d.ts +0 -2
  113. package/dist/content/ops-command.js +0 -71
  114. package/dist/content/protocols.d.ts +0 -7
  115. package/dist/content/protocols.js +0 -215
  116. package/dist/content/retro-command.d.ts +0 -2
  117. package/dist/content/retro-command.js +0 -165
  118. package/dist/content/rewind-command.d.ts +0 -2
  119. package/dist/content/rewind-command.js +0 -106
  120. package/dist/content/tdd-log-command.d.ts +0 -2
  121. package/dist/content/tdd-log-command.js +0 -85
  122. package/dist/eval/agents/single-shot.d.ts +0 -27
  123. package/dist/eval/agents/single-shot.js +0 -79
  124. package/dist/eval/agents/with-tools.d.ts +0 -44
  125. package/dist/eval/agents/with-tools.js +0 -261
  126. package/dist/eval/agents/workflow.d.ts +0 -31
  127. package/dist/eval/agents/workflow.js +0 -155
  128. package/dist/eval/baseline.d.ts +0 -38
  129. package/dist/eval/baseline.js +0 -282
  130. package/dist/eval/config-loader.d.ts +0 -14
  131. package/dist/eval/config-loader.js +0 -395
  132. package/dist/eval/corpus.d.ts +0 -30
  133. package/dist/eval/corpus.js +0 -330
  134. package/dist/eval/cost-guard.d.ts +0 -102
  135. package/dist/eval/cost-guard.js +0 -190
  136. package/dist/eval/diff.d.ts +0 -64
  137. package/dist/eval/diff.js +0 -323
  138. package/dist/eval/llm-client.d.ts +0 -176
  139. package/dist/eval/llm-client.js +0 -267
  140. package/dist/eval/mode.d.ts +0 -28
  141. package/dist/eval/mode.js +0 -61
  142. package/dist/eval/progress.d.ts +0 -83
  143. package/dist/eval/progress.js +0 -59
  144. package/dist/eval/report.d.ts +0 -11
  145. package/dist/eval/report.js +0 -181
  146. package/dist/eval/rubric-loader.d.ts +0 -20
  147. package/dist/eval/rubric-loader.js +0 -143
  148. package/dist/eval/runner.d.ts +0 -81
  149. package/dist/eval/runner.js +0 -746
  150. package/dist/eval/runs.d.ts +0 -41
  151. package/dist/eval/runs.js +0 -114
  152. package/dist/eval/sandbox.d.ts +0 -38
  153. package/dist/eval/sandbox.js +0 -137
  154. package/dist/eval/tools/glob.d.ts +0 -2
  155. package/dist/eval/tools/glob.js +0 -163
  156. package/dist/eval/tools/grep.d.ts +0 -2
  157. package/dist/eval/tools/grep.js +0 -152
  158. package/dist/eval/tools/index.d.ts +0 -7
  159. package/dist/eval/tools/index.js +0 -35
  160. package/dist/eval/tools/read.d.ts +0 -2
  161. package/dist/eval/tools/read.js +0 -122
  162. package/dist/eval/tools/types.d.ts +0 -49
  163. package/dist/eval/tools/types.js +0 -41
  164. package/dist/eval/tools/write.d.ts +0 -2
  165. package/dist/eval/tools/write.js +0 -92
  166. package/dist/eval/types.d.ts +0 -561
  167. package/dist/eval/types.js +0 -47
  168. package/dist/eval/verifiers/judge.d.ts +0 -40
  169. package/dist/eval/verifiers/judge.js +0 -256
  170. package/dist/eval/verifiers/rules.d.ts +0 -24
  171. package/dist/eval/verifiers/rules.js +0 -218
  172. package/dist/eval/verifiers/structural.d.ts +0 -14
  173. package/dist/eval/verifiers/structural.js +0 -171
  174. package/dist/eval/verifiers/traceability.d.ts +0 -23
  175. package/dist/eval/verifiers/traceability.js +0 -84
  176. package/dist/eval/verifiers/workflow-consistency.d.ts +0 -21
  177. package/dist/eval/verifiers/workflow-consistency.js +0 -225
  178. package/dist/eval/workflow-corpus.d.ts +0 -7
  179. package/dist/eval/workflow-corpus.js +0 -207
  180. package/dist/feature-system.d.ts +0 -42
  181. package/dist/feature-system.js +0 -432
  182. package/dist/internal/knowledge-digest.d.ts +0 -7
  183. package/dist/internal/knowledge-digest.js +0 -93
@@ -13,7 +13,7 @@ interface InternalIo {
13
13
  */
14
14
  export declare function countArchivedRunsSafely(projectRoot: string): Promise<number | undefined>;
15
15
  /**
16
- * Compact one-liner for session-digest / bootstrap surfaces.
16
+ * Compact one-liner for bootstrap surfaces.
17
17
  *
18
18
  * Example: `Compound readiness: clusters=12, ready=2 (critical=1)`.
19
19
  * When `ready === 0`, emit `Compound readiness: no candidates`.
@@ -65,7 +65,7 @@ export async function countArchivedRunsSafely(projectRoot) {
65
65
  }
66
66
  }
67
67
  /**
68
- * Compact one-liner for session-digest / bootstrap surfaces.
68
+ * Compact one-liner for bootstrap surfaces.
69
69
  *
70
70
  * Example: `Compound readiness: clusters=12, ready=2 (critical=1)`.
71
71
  * When `ready === 0`, emit `Compound readiness: no candidates`.
@@ -6,7 +6,7 @@ interface InternalIo {
6
6
  }
7
7
  /**
8
8
  * Produces a one-line "Ralph Loop: iter=X, slices=Y, acClosed=Z, redOpen=..."
9
- * summary — suitable for session-digest / bootstrap surfaces where the user
9
+ * summary — suitable for bootstrap surfaces where the user
10
10
  * just needs a progress indicator, not the full slice breakdown.
11
11
  */
12
12
  export declare function formatRalphLoopStatusLine(status: RalphLoopStatus): string;
@@ -36,7 +36,7 @@ async function readCycleLog(projectRoot) {
36
36
  }
37
37
  /**
38
38
  * Produces a one-line "Ralph Loop: iter=X, slices=Y, acClosed=Z, redOpen=..."
39
- * summary — suitable for session-digest / bootstrap surfaces where the user
39
+ * summary — suitable for bootstrap surfaces where the user
40
40
  * just needs a progress indicator, not the full slice breakdown.
41
41
  */
42
42
  export function formatRalphLoopStatusLine(status) {
@@ -14,7 +14,7 @@ export interface KnowledgeEntry {
14
14
  domain: string | null;
15
15
  stage: FlowStage | null;
16
16
  origin_stage: FlowStage | null;
17
- origin_feature: string | null;
17
+ origin_run: string | null;
18
18
  frequency: number;
19
19
  universality: KnowledgeEntryUniversality;
20
20
  maturity: KnowledgeEntryMaturity;
@@ -23,6 +23,8 @@ export interface KnowledgeEntry {
23
23
  last_seen_ts: string;
24
24
  project: string | null;
25
25
  source?: KnowledgeEntrySource | null;
26
+ supersedes?: string[];
27
+ superseded_by?: string;
26
28
  }
27
29
  export interface KnowledgeSeedEntry {
28
30
  type: KnowledgeEntryType;
@@ -33,6 +35,8 @@ export interface KnowledgeSeedEntry {
33
35
  domain?: string | null;
34
36
  stage?: FlowStage | null;
35
37
  origin_stage?: FlowStage | null;
38
+ origin_run?: string | null;
39
+ /** @deprecated Use `origin_run`. Accepted only for legacy JSONL/backfill inputs. */
36
40
  origin_feature?: string | null;
37
41
  frequency?: number;
38
42
  universality?: KnowledgeEntryUniversality;
@@ -42,11 +46,13 @@ export interface KnowledgeSeedEntry {
42
46
  last_seen_ts?: string;
43
47
  project?: string | null;
44
48
  source?: KnowledgeEntrySource | null;
49
+ supersedes?: string[];
50
+ superseded_by?: string;
45
51
  }
46
52
  export interface AppendKnowledgeDefaults {
47
53
  stage?: FlowStage | null;
48
54
  originStage?: FlowStage | null;
49
- originFeature?: string | null;
55
+ originRun?: string | null;
50
56
  project?: string | null;
51
57
  source?: KnowledgeEntrySource | null;
52
58
  nowIso?: string;
@@ -84,7 +90,7 @@ export interface CompoundReadinessCluster {
84
90
  action: string;
85
91
  /**
86
92
  * Sum of `frequency` across entries in the cluster — matches the
87
- * recurrence count used by `/cc-ops compound`.
93
+ * recurrence count used by compound readiness analysis.
88
94
  */
89
95
  recurrence: number;
90
96
  /** Distinct entry lines contributing to this cluster. */
@@ -140,16 +146,15 @@ export interface ComputeCompoundReadinessOptions {
140
146
  * Count of archived runs under `.cclaw/runs/`. When supplied and
141
147
  * `< SMALL_PROJECT_ARCHIVE_RUNS_THRESHOLD`, the effective threshold
142
148
  * is lowered to `min(threshold, SMALL_PROJECT_RECURRENCE_THRESHOLD)`.
143
- * Matches the rule documented in `src/content/compound-command.ts`
144
- * and `docs/config.md`.
149
+ * Matches the rule documented in `docs/config.md`.
145
150
  */
146
151
  archivedRunsCount?: number;
147
152
  }
148
153
  /**
149
154
  * Single source of truth for the small-project relaxation rule.
150
155
  *
151
- * Kept exported so the inline hook mirror, the CLI command, and
152
- * the `/cc-ops compound` skill all agree on the same numbers.
156
+ * Kept exported so the inline hook mirror and CLI/runtime paths all agree on
157
+ * the same numbers.
153
158
  */
154
159
  export declare const SMALL_PROJECT_ARCHIVE_RUNS_THRESHOLD = 5;
155
160
  export declare const SMALL_PROJECT_RECURRENCE_THRESHOLD = 2;
@@ -163,9 +168,10 @@ export declare function effectiveCompoundThreshold(baseThreshold: number, archiv
163
168
  * for persisting to `.cclaw/state/compound-readiness.json`.
164
169
  *
165
170
  * Clustering key: `(type, normalizeText(trigger), normalizeText(action))`
166
- * which mirrors the clustering used by the `/cc-ops compound` skill.
167
- * Entries with `maturity === "lifted-to-enforcement"` are excluded —
168
- * they were already promoted and should not re-appear as ready.
171
+ * which mirrors the compound readiness clustering in runtime state.
172
+ * Entries with `maturity === "lifted-to-enforcement"` or `superseded_by`
173
+ * are excluded — they were already promoted/replaced and should not re-appear
174
+ * as ready.
169
175
  */
170
176
  export declare function computeCompoundReadiness(entries: KnowledgeEntry[], options?: ComputeCompoundReadinessOptions): CompoundReadiness;
171
177
  export declare function validateKnowledgeEntry(entry: unknown): {
@@ -8,8 +8,8 @@ const DEFAULT_COMPOUND_READINESS_MAX_READY = 10;
8
8
  /**
9
9
  * Single source of truth for the small-project relaxation rule.
10
10
  *
11
- * Kept exported so the inline hook mirror, the CLI command, and
12
- * the `/cc-ops compound` skill all agree on the same numbers.
11
+ * Kept exported so the inline hook mirror and CLI/runtime paths all agree on
12
+ * the same numbers.
13
13
  */
14
14
  export const SMALL_PROJECT_ARCHIVE_RUNS_THRESHOLD = 5;
15
15
  export const SMALL_PROJECT_RECURRENCE_THRESHOLD = 2;
@@ -31,9 +31,10 @@ export function effectiveCompoundThreshold(baseThreshold, archivedRunsCount) {
31
31
  * for persisting to `.cclaw/state/compound-readiness.json`.
32
32
  *
33
33
  * Clustering key: `(type, normalizeText(trigger), normalizeText(action))`
34
- * which mirrors the clustering used by the `/cc-ops compound` skill.
35
- * Entries with `maturity === "lifted-to-enforcement"` are excluded —
36
- * they were already promoted and should not re-appear as ready.
34
+ * which mirrors the compound readiness clustering in runtime state.
35
+ * Entries with `maturity === "lifted-to-enforcement"` or `superseded_by`
36
+ * are excluded — they were already promoted/replaced and should not re-appear
37
+ * as ready.
37
38
  */
38
39
  export function computeCompoundReadiness(entries, options = {}) {
39
40
  const thresholdRaw = options.threshold ?? DEFAULT_COMPOUND_RECURRENCE_THRESHOLD;
@@ -53,7 +54,7 @@ export function computeCompoundReadiness(entries, options = {}) {
53
54
  const { threshold, relaxationApplied } = effectiveCompoundThreshold(baseThreshold, archivedRunsCount);
54
55
  const buckets = new Map();
55
56
  for (const entry of entries) {
56
- if (entry.maturity === "lifted-to-enforcement")
57
+ if (entry.maturity === "lifted-to-enforcement" || entry.superseded_by !== undefined)
57
58
  continue;
58
59
  const key = [
59
60
  entry.type,
@@ -160,7 +161,7 @@ const KNOWLEDGE_REQUIRED_KEYS = [
160
161
  "domain",
161
162
  "stage",
162
163
  "origin_stage",
163
- "origin_feature",
164
+ "origin_run",
164
165
  "frequency",
165
166
  "universality",
166
167
  "maturity",
@@ -170,8 +171,11 @@ const KNOWLEDGE_REQUIRED_KEYS = [
170
171
  "project"
171
172
  ];
172
173
  const KNOWLEDGE_ALLOWED_KEYS = new Set(KNOWLEDGE_REQUIRED_KEYS);
174
+ KNOWLEDGE_ALLOWED_KEYS.add("origin_feature");
173
175
  KNOWLEDGE_ALLOWED_KEYS.add("source");
174
176
  KNOWLEDGE_ALLOWED_KEYS.add("severity");
177
+ KNOWLEDGE_ALLOWED_KEYS.add("supersedes");
178
+ KNOWLEDGE_ALLOWED_KEYS.add("superseded_by");
175
179
  function knowledgePath(projectRoot) {
176
180
  return path.join(projectRoot, RUNTIME_ROOT, "knowledge.jsonl");
177
181
  }
@@ -195,11 +199,13 @@ function dedupeKey(entry) {
195
199
  entry.domain === null ? "null" : normalizeText(entry.domain),
196
200
  entry.stage ?? "null",
197
201
  entry.origin_stage ?? "null",
198
- entry.origin_feature === null ? "null" : normalizeText(entry.origin_feature),
202
+ entry.origin_run === null ? "null" : normalizeText(entry.origin_run),
199
203
  entry.universality,
200
204
  entry.project === null ? "null" : normalizeText(entry.project),
201
205
  entry.source === undefined || entry.source === null ? "null" : entry.source,
202
- entry.severity === undefined ? "none" : entry.severity
206
+ entry.severity === undefined ? "none" : entry.severity,
207
+ Array.isArray(entry.supersedes) ? entry.supersedes.map(normalizeText).sort().join(",") : "none",
208
+ entry.superseded_by === undefined ? "none" : normalizeText(entry.superseded_by)
203
209
  ].join("|");
204
210
  }
205
211
  function emptyKnowledgeSnapshot() {
@@ -211,6 +217,13 @@ function emptyKnowledgeSnapshot() {
211
217
  entryByIndex: new Map()
212
218
  };
213
219
  }
220
+ function normalizeLegacyKnowledgeEntry(entry) {
221
+ const { origin_feature: legacyOriginRun, ...rest } = entry;
222
+ return {
223
+ ...rest,
224
+ origin_run: entry.origin_run ?? legacyOriginRun ?? null
225
+ };
226
+ }
214
227
  function parseKnowledgeSnapshot(raw) {
215
228
  const lines = stripBom(raw).split(/\r?\n/u);
216
229
  const entries = [];
@@ -228,7 +241,7 @@ function parseKnowledgeSnapshot(raw) {
228
241
  malformedLines += 1;
229
242
  continue;
230
243
  }
231
- const entry = parsed;
244
+ const entry = normalizeLegacyKnowledgeEntry(parsed);
232
245
  entries.push(entry);
233
246
  const key = dedupeKey(entry);
234
247
  if (!keyToIndex.has(key)) {
@@ -294,7 +307,9 @@ export function validateKnowledgeEntry(entry) {
294
307
  }
295
308
  for (const key of KNOWLEDGE_REQUIRED_KEYS) {
296
309
  if (!Object.prototype.hasOwnProperty.call(obj, key)) {
297
- errors.push(`Missing required key "${key}".`);
310
+ if (key !== "origin_run" || !Object.prototype.hasOwnProperty.call(obj, "origin_feature")) {
311
+ errors.push(`Missing required key "${key}".`);
312
+ }
298
313
  }
299
314
  }
300
315
  if (!KNOWLEDGE_TYPE_SET.has(obj.type)) {
@@ -322,8 +337,11 @@ export function validateKnowledgeEntry(entry) {
322
337
  if (!isNullableStage(obj.origin_stage)) {
323
338
  errors.push(`origin_stage must be one of ${FLOW_STAGES.join(", ")} or null.`);
324
339
  }
325
- if (!isNullableString(obj.origin_feature)) {
326
- errors.push("origin_feature must be string or null.");
340
+ const originRun = Object.prototype.hasOwnProperty.call(obj, "origin_run")
341
+ ? obj.origin_run
342
+ : obj.origin_feature;
343
+ if (!isNullableString(originRun)) {
344
+ errors.push("origin_run must be string or null.");
327
345
  }
328
346
  if (typeof obj.frequency !== "number" ||
329
347
  !Number.isInteger(obj.frequency) ||
@@ -345,6 +363,17 @@ export function validateKnowledgeEntry(entry) {
345
363
  if (!isNullableString(obj.project)) {
346
364
  errors.push("project must be string or null.");
347
365
  }
366
+ if (obj.supersedes !== undefined) {
367
+ if (!Array.isArray(obj.supersedes) ||
368
+ obj.supersedes.length === 0 ||
369
+ obj.supersedes.some((value) => typeof value !== "string" || value.trim().length === 0)) {
370
+ errors.push("supersedes must be a non-empty array of strings when present.");
371
+ }
372
+ }
373
+ if (obj.superseded_by !== undefined &&
374
+ (typeof obj.superseded_by !== "string" || obj.superseded_by.trim().length === 0)) {
375
+ errors.push("superseded_by must be a non-empty string when present.");
376
+ }
348
377
  if (obj.source !== undefined &&
349
378
  obj.source !== null &&
350
379
  (typeof obj.source !== "string" || !KNOWLEDGE_SOURCE_SET.has(obj.source))) {
@@ -356,6 +385,7 @@ export function materializeKnowledgeEntry(seed, defaults = {}) {
356
385
  const now = normalizeUtcIso(defaults.nowIso ?? nowUtcIso());
357
386
  const stage = seed.stage ?? defaults.stage ?? null;
358
387
  const originStage = seed.origin_stage ?? defaults.originStage ?? stage ?? null;
388
+ const originRun = seed.origin_run ?? seed.origin_feature ?? defaults.originRun ?? null;
359
389
  const source = seed.source ?? defaults.source ?? null;
360
390
  const entry = {
361
391
  type: seed.type,
@@ -365,7 +395,7 @@ export function materializeKnowledgeEntry(seed, defaults = {}) {
365
395
  domain: seed.domain ?? null,
366
396
  stage,
367
397
  origin_stage: originStage,
368
- origin_feature: seed.origin_feature ?? defaults.originFeature ?? null,
398
+ origin_run: originRun,
369
399
  frequency: seed.frequency ?? 1,
370
400
  universality: seed.universality ?? "project",
371
401
  maturity: seed.maturity ?? "raw",
@@ -377,6 +407,12 @@ export function materializeKnowledgeEntry(seed, defaults = {}) {
377
407
  if (seed.severity !== undefined) {
378
408
  entry.severity = seed.severity;
379
409
  }
410
+ if (seed.supersedes !== undefined) {
411
+ entry.supersedes = seed.supersedes.map((value) => value.trim());
412
+ }
413
+ if (seed.superseded_by !== undefined) {
414
+ entry.superseded_by = seed.superseded_by.trim();
415
+ }
380
416
  if (source !== null) {
381
417
  entry.source = source;
382
418
  }
@@ -521,7 +557,7 @@ export async function selectRelevantLearnings(projectRoot, options = {}) {
521
557
  ...tokenizeText(entry.domain),
522
558
  ...tokenizeText(entry.trigger),
523
559
  ...tokenizeText(entry.action),
524
- ...tokenizeText(entry.origin_feature),
560
+ ...tokenizeText(entry.origin_run),
525
561
  ...tokenizeText(entry.project)
526
562
  ];
527
563
  const searchSet = new Set(searchable);
package/dist/policy.js CHANGED
@@ -2,7 +2,7 @@ import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { RUNTIME_ROOT } from "./constants.js";
4
4
  import { FLOW_STAGES } from "./types.js";
5
- import { stageSchema, stagePolicyNeedles } from "./content/stage-schema.js";
5
+ import { stageSchema } from "./content/stage-schema.js";
6
6
  import { stageSkillFolder } from "./content/skills.js";
7
7
  import { exists } from "./fs-utils.js";
8
8
  const POLICY_RULES = [];
@@ -14,32 +14,11 @@ export async function policyChecks(projectRoot, options = {}) {
14
14
  for (const stage of FLOW_STAGES) {
15
15
  const folder = stageSkillFolder(stage);
16
16
  const schema = stageSchema(stage);
17
- const commandFile = `${RUNTIME_ROOT}/commands/${stage}.md`;
18
17
  const skillFile = `${RUNTIME_ROOT}/skills/${folder}/SKILL.md`;
19
- // --- thin command mandatory sections ---
20
- for (const heading of [
21
- "## HARD-GATE",
22
- "## Gates",
23
- "## Exit",
24
- "## Anchors",
25
- "## Context Hydration"
26
- ]) {
27
- rules.push({
28
- filePath: commandFile,
29
- needle: heading,
30
- name: `command:${stage}:section:${heading.replace(/^## /, "").toLowerCase().replace(/[^a-z0-9]+/g, "_")}`
31
- });
32
- }
33
- // --- command must reference the skill ---
34
- rules.push({
35
- filePath: commandFile,
36
- needle: `${folder}/SKILL.md`,
37
- name: `command:${stage}:skill_ref`
38
- });
39
18
  // --- skill mandatory sections ---
40
19
  for (const heading of [
41
20
  "## Process",
42
- "## Verification",
21
+ "## Exit Criteria",
43
22
  "## Interaction Protocol",
44
23
  "## Anti-Patterns & Red Flags",
45
24
  "## HARD-GATE",
@@ -73,50 +52,25 @@ export async function policyChecks(projectRoot, options = {}) {
73
52
  name: `skill:${stage}:section:verification_before_completion`
74
53
  });
75
54
  }
76
- // --- policy needles in commands ---
77
- for (const needle of stagePolicyNeedles(stage)) {
78
- rules.push({
79
- filePath: commandFile,
80
- needle,
81
- name: `command:${stage}:anchor:${needle.toLowerCase().replace(/[^a-z0-9]+/g, "_")}`
82
- });
83
- }
84
55
  }
85
56
  // --- utility skill checks ---
86
57
  const runtimeFile = (relativePath) => `${RUNTIME_ROOT}/${relativePath}`;
87
58
  const utilitySkillChecks = [
88
59
  { file: runtimeFile("skills/learnings/SKILL.md"), needle: "strict JSONL schema", name: "utility_skill:learnings:jsonl_schema" },
89
60
  { file: runtimeFile("skills/learnings/SKILL.md"), needle: "knowledge.jsonl", name: "utility_skill:learnings:jsonl_store" },
90
- { file: runtimeFile("skills/learnings/SKILL.md"), needle: "type, trigger, action, confidence, domain, stage, origin_stage, origin_feature, frequency, universality, maturity, created, first_seen_ts, last_seen_ts, project", name: "utility_skill:learnings:field_order" },
91
- { file: runtimeFile("skills/learnings/SKILL.md"), needle: "## Subcommands", name: "utility_skill:learnings:subcommands" },
61
+ { file: runtimeFile("skills/learnings/SKILL.md"), needle: "type, trigger, action, confidence, domain, stage, origin_stage, origin_run, frequency, universality, maturity, created, first_seen_ts, last_seen_ts, project", name: "utility_skill:learnings:field_order" },
62
+ { file: runtimeFile("skills/learnings/SKILL.md"), needle: "## Manual Actions", name: "utility_skill:learnings:manual_actions" },
92
63
  { file: runtimeFile("skills/learnings/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:learnings:hard_gate" },
93
- { file: runtimeFile("commands/learn.md"), needle: "## Subcommands", name: "utility_command:learn:subcommands" },
64
+ { file: runtimeFile("commands/start.md"), needle: "## Algorithm", name: "utility_command:start:algorithm" },
65
+ { file: runtimeFile("commands/next.md"), needle: "## Algorithm", name: "utility_command:next:algorithm" },
66
+ { file: runtimeFile("commands/next.md"), needle: "closeout.shipSubstate", name: "utility_command:next:closeout_chain" },
94
67
  { file: runtimeFile("commands/ideate.md"), needle: "## Algorithm", name: "utility_command:ideate:algorithm" },
95
68
  { file: runtimeFile("skills/flow-ideate/SKILL.md"), needle: "## Protocol", name: "utility_skill:ideate:protocol" },
96
69
  { file: runtimeFile("skills/flow-ideate/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:ideate:hard_gate" },
97
- { file: runtimeFile("commands/status.md"), needle: "bar:", name: "utility_command:status:visual_bar" },
98
- { file: runtimeFile("commands/status.md"), needle: "/cc-view tree · /cc-view diff", name: "utility_command:status:tree_diff_link" },
99
- { file: runtimeFile("commands/tree.md"), needle: "## Algorithm", name: "utility_command:tree:algorithm" },
100
- { file: runtimeFile("skills/flow-tree/SKILL.md"), needle: "## Protocol", name: "utility_skill:tree:protocol" },
101
- { file: runtimeFile("skills/flow-tree/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:tree:hard_gate" },
102
- { file: runtimeFile("commands/diff.md"), needle: "## Algorithm", name: "utility_command:diff:algorithm" },
103
- { file: runtimeFile("skills/flow-diff/SKILL.md"), needle: "## Protocol", name: "utility_skill:diff:protocol" },
104
- { file: runtimeFile("skills/flow-diff/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:diff:hard_gate" },
105
- { file: runtimeFile("commands/feature.md"), needle: "## Subcommands", name: "utility_command:feature:subcommands" },
106
- { file: runtimeFile("skills/using-git-worktrees/SKILL.md"), needle: "## Protocol", name: "utility_skill:feature:protocol" },
107
- { file: runtimeFile("skills/using-git-worktrees/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:feature:hard_gate" },
108
- { file: runtimeFile("commands/tdd-log.md"), needle: "## Subcommands", name: "utility_command:tdd_log:subcommands" },
109
- { file: runtimeFile("skills/tdd-cycle-log/SKILL.md"), needle: "## Protocol", name: "utility_skill:tdd_log:protocol" },
110
- { file: runtimeFile("skills/tdd-cycle-log/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:tdd_log:hard_gate" },
111
- { file: runtimeFile("commands/retro.md"), needle: "## Algorithm", name: "utility_command:retro:algorithm" },
112
- { file: runtimeFile("skills/flow-retro/SKILL.md"), needle: "## Protocol", name: "utility_skill:retro:protocol" },
113
- { file: runtimeFile("skills/flow-retro/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:retro:hard_gate" },
114
- { file: runtimeFile("commands/compound.md"), needle: "## Algorithm", name: "utility_command:compound:algorithm" },
115
- { file: runtimeFile("skills/flow-compound/SKILL.md"), needle: "## Protocol", name: "utility_skill:compound:protocol" },
116
- { file: runtimeFile("skills/flow-compound/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:compound:hard_gate" },
117
- { file: runtimeFile("commands/rewind.md"), needle: "## Algorithm", name: "utility_command:rewind:algorithm" },
118
- { file: runtimeFile("skills/flow-rewind/SKILL.md"), needle: "## Protocol", name: "utility_skill:rewind:protocol" },
119
- { file: runtimeFile("skills/flow-rewind/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:rewind:hard_gate" },
70
+ { file: runtimeFile("commands/view.md"), needle: "## Routing", name: "utility_command:view:routing" },
71
+ { file: runtimeFile("skills/flow-view/SKILL.md"), needle: "## Status Subcommand", name: "utility_skill:view:status_section" },
72
+ { file: runtimeFile("skills/flow-view/SKILL.md"), needle: "## Tree Subcommand", name: "utility_skill:view:tree_section" },
73
+ { file: runtimeFile("skills/flow-view/SKILL.md"), needle: "## Diff Subcommand", name: "utility_skill:view:diff_section" },
120
74
  { file: runtimeFile("skills/subagent-dev/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:sdd:hard_gate" },
121
75
  { file: runtimeFile("skills/subagent-dev/SKILL.md"), needle: "## Status Contract", name: "utility_skill:sdd:status_contract" },
122
76
  { file: runtimeFile("skills/subagent-dev/SKILL.md"), needle: "Implementer", name: "utility_skill:sdd:implementer_template" },
@@ -136,57 +90,14 @@ export async function policyChecks(projectRoot, options = {}) {
136
90
  { file: runtimeFile("skills/using-cclaw/SKILL.md"), needle: "## Routing flow", name: "meta_skill:routing_flow" },
137
91
  { file: runtimeFile("skills/using-cclaw/SKILL.md"), needle: "## Task classification", name: "meta_skill:task_classification" },
138
92
  { file: runtimeFile("skills/using-cclaw/SKILL.md"), needle: "## Stage quick map", name: "meta_skill:stage_quick_map" },
139
- { file: runtimeFile("skills/using-cclaw/SKILL.md"), needle: "## Contextual skill activation", name: "meta_skill:contextual_skills" },
140
- { file: runtimeFile("skills/using-cclaw/SKILL.md"), needle: "## Protocol references", name: "meta_skill:protocol_refs" },
93
+ { file: runtimeFile("skills/using-cclaw/SKILL.md"), needle: "## Whole flow map", name: "meta_skill:whole_flow_map" },
94
+ { file: runtimeFile("skills/using-cclaw/SKILL.md"), needle: "retro -> compound -> archive", name: "meta_skill:closeout_chain" },
95
+ { file: runtimeFile("skills/using-cclaw/SKILL.md"), needle: "## Contextual Skill Activation", name: "meta_skill:contextual_skills" },
96
+ { file: runtimeFile("skills/using-cclaw/SKILL.md"), needle: "## Protocol Behavior", name: "meta_skill:protocol_behavior" },
141
97
  { file: runtimeFile("skills/using-cclaw/SKILL.md"), needle: "## Failure guardrails", name: "meta_skill:failure_guardrails" },
142
- { file: runtimeFile("references/protocols/decision.md"), needle: "# Decision Protocol", name: "protocol:decision" },
143
- { file: runtimeFile("references/protocols/completion.md"), needle: "# Stage Completion Protocol", name: "protocol:completion" },
144
- { file: runtimeFile("references/protocols/ethos.md"), needle: "# Engineering Ethos", name: "protocol:ethos" },
145
- { file: runtimeFile("references/flow-map.md"), needle: "# cclaw Flow Map", name: "reference:flow_map:header" },
146
- { file: runtimeFile("references/flow-map.md"), needle: "## Stages (8)", name: "reference:flow_map:stages" },
147
- { file: runtimeFile("references/flow-map.md"), needle: "## Ralph Loop", name: "reference:flow_map:ralph_loop" },
148
- { file: runtimeFile("references/flow-map.md"), needle: "## Key state files", name: "reference:flow_map:state_files" },
149
- { file: runtimeFile("references/flow-map.md"), needle: "## Compound readiness", name: "reference:flow_map:compound_readiness" },
150
98
  { file: runtimeFile("skills/session/SKILL.md"), needle: "## Session Resume Protocol", name: "utility_skill:session:resume" },
151
- { file: runtimeFile("skills/brainstorming/SKILL.md"), needle: "common-guidance.md", name: "stage_skill:shared_guidance_reference" },
152
- { file: runtimeFile("skills/security/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:security:hard_gate" },
153
- { file: runtimeFile("skills/security/SKILL.md"), needle: "## Checklist", name: "utility_skill:security:checklist" },
154
- { file: runtimeFile("skills/security/SKILL.md"), needle: "## Severity Classification", name: "utility_skill:security:severity" },
155
- { file: runtimeFile("skills/debugging/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:debugging:hard_gate" },
156
- { file: runtimeFile("skills/debugging/SKILL.md"), needle: "## The Protocol", name: "utility_skill:debugging:protocol" },
157
- { file: runtimeFile("skills/debugging/SKILL.md"), needle: "Step 1 — Reproduce", name: "utility_skill:debugging:reproduce" },
158
- { file: runtimeFile("skills/debugging/SKILL.md"), needle: "## Testing-Specific Anti-Patterns", name: "utility_skill:debugging:test_antipatterns" },
159
- { file: runtimeFile("skills/performance/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:performance:hard_gate" },
160
- { file: runtimeFile("skills/performance/SKILL.md"), needle: "## Workflow", name: "utility_skill:performance:workflow" },
161
- { file: runtimeFile("skills/performance/SKILL.md"), needle: "## Core Web Vitals Reference", name: "utility_skill:performance:cwv" },
162
- { file: runtimeFile("skills/ci-cd/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:cicd:hard_gate" },
163
- { file: runtimeFile("skills/ci-cd/SKILL.md"), needle: "## Quality Gate Pipeline", name: "utility_skill:cicd:pipeline" },
164
- { file: runtimeFile("skills/ci-cd/SKILL.md"), needle: "## CI Debugging Protocol", name: "utility_skill:cicd:debugging" },
165
- { file: runtimeFile("skills/docs/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:docs:hard_gate" },
166
- { file: runtimeFile("skills/docs/SKILL.md"), needle: "## ADR (Architecture Decision Record)", name: "utility_skill:docs:adr" },
167
- { file: runtimeFile("skills/docs/SKILL.md"), needle: "## README Guidance", name: "utility_skill:docs:readme" },
168
- { file: runtimeFile("skills/executing-plans/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:executing_plans:hard_gate" },
169
- { file: runtimeFile("skills/executing-plans/SKILL.md"), needle: "## Execution Protocol", name: "utility_skill:executing_plans:protocol" },
170
- { file: runtimeFile("skills/executing-plans/SKILL.md"), needle: "## Batch Checklist", name: "utility_skill:executing_plans:batches" },
171
- { file: runtimeFile("skills/verification-before-completion/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:verification_before_completion:hard_gate" },
172
- { file: runtimeFile("skills/verification-before-completion/SKILL.md"), needle: "## Protocol", name: "utility_skill:verification_before_completion:protocol" },
173
- { file: runtimeFile("skills/finishing-a-development-branch/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:finishing_branch:hard_gate" },
174
- { file: runtimeFile("skills/finishing-a-development-branch/SKILL.md"), needle: "## Protocol", name: "utility_skill:finishing_branch:protocol" },
175
- { file: runtimeFile("skills/context-engineering/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:context_engineering:hard_gate" },
176
- { file: runtimeFile("skills/context-engineering/SKILL.md"), needle: "## Context Modes", name: "utility_skill:context_engineering:modes" },
177
- { file: runtimeFile("skills/context-engineering/SKILL.md"), needle: "## Mode Switching Protocol", name: "utility_skill:context_engineering:switch" },
178
- { file: runtimeFile("skills/source-driven-development/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:source_driven:hard_gate" },
179
- { file: runtimeFile("skills/source-driven-development/SKILL.md"), needle: "## Protocol", name: "utility_skill:source_driven:protocol" },
180
- { file: runtimeFile("skills/source-driven-development/SKILL.md"), needle: "## Selection Heuristics", name: "utility_skill:source_driven:heuristics" },
181
- { file: runtimeFile("skills/frontend-accessibility/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:frontend_accessibility:hard_gate" },
182
- { file: runtimeFile("skills/frontend-accessibility/SKILL.md"), needle: "## Checklist", name: "utility_skill:frontend_accessibility:checklist" },
183
- { file: runtimeFile("skills/frontend-accessibility/SKILL.md"), needle: "## Anti-Patterns", name: "utility_skill:frontend_accessibility:anti_patterns" },
99
+ { file: runtimeFile("skills/brainstorming/SKILL.md"), needle: "## Shared Stage Guidance", name: "stage_skill:shared_guidance_inline" },
184
100
  { file: runtimeFile("hooks/run-hook.mjs"), needle: "activeRunId", name: "hooks:session_start:active_run" },
185
- { file: runtimeFile("hooks/run-hook.mjs"), needle: "checkpoint.json", name: "hooks:session_start:checkpoint_ref" },
186
- { file: runtimeFile("hooks/run-hook.mjs"), needle: "stage-activity.jsonl", name: "hooks:session_start:activity_ref" },
187
- { file: runtimeFile("hooks/run-hook.mjs"), needle: "suggestion-memory.json", name: "hooks:session_start:suggestion_memory" },
188
- { file: runtimeFile("hooks/run-hook.mjs"), needle: "context-warnings.jsonl", name: "hooks:session_start:context_warning_ref" },
189
- { file: runtimeFile("hooks/run-hook.mjs"), needle: "checkpoint.json", name: "hooks:stop:checkpoint_write" },
190
101
  { file: runtimeFile("hooks/run-hook.mjs"), needle: "write_to_cclaw_runtime", name: "hooks:guard:risky_write_advisory" },
191
102
  { file: runtimeFile("hooks/run-hook.mjs"), needle: "stage_invocation_without_recent_flow_read", name: "hooks:workflow_guard:flow_read_reason" },
192
103
  { file: runtimeFile("hooks/run-hook.mjs"), needle: "stage_jump_", name: "hooks:workflow_guard:stage_jump_reason" },
@@ -9,8 +9,7 @@ export interface ArchiveRunResult {
9
9
  archiveId: string;
10
10
  archivePath: string;
11
11
  archivedAt: string;
12
- featureName: string;
13
- activeFeature: string;
12
+ runName: string;
14
13
  resetState: FlowState;
15
14
  snapshottedStateFiles: string[];
16
15
  /** Knowledge curation hint: total active entries + soft threshold (50). */
@@ -29,11 +28,10 @@ export interface ArchiveRunResult {
29
28
  };
30
29
  }
31
30
  export interface ArchiveManifest {
32
- version: 1;
31
+ version: 2;
33
32
  archiveId: string;
34
33
  archivedAt: string;
35
- featureName: string;
36
- activeFeature: string;
34
+ runName: string;
37
35
  sourceRunId: string;
38
36
  sourceCurrentStage: FlowStage;
39
37
  sourceCompletedStages: FlowStage[];
@@ -45,7 +43,7 @@ export interface ArchiveRunOptions {
45
43
  skipRetroReason?: string;
46
44
  }
47
45
  export declare function listRuns(projectRoot: string): Promise<CclawRunMeta[]>;
48
- export declare function archiveRun(projectRoot: string, featureName?: string, options?: ArchiveRunOptions): Promise<ArchiveRunResult>;
46
+ export declare function archiveRun(projectRoot: string, runName?: string, options?: ArchiveRunOptions): Promise<ArchiveRunResult>;
49
47
  /**
50
48
  * Counts entries in the canonical JSONL knowledge store. An "active" entry is one
51
49
  * non-empty line that parses as JSON with the required `type` field belonging to the
@@ -2,7 +2,6 @@ import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { RUNTIME_ROOT } from "./constants.js";
4
4
  import { createInitialFlowState } from "./flow-state.js";
5
- import { readActiveFeature, syncActiveFeatureSnapshot } from "./feature-system.js";
6
5
  import { ensureDir, exists, withDirectoryLock, writeFileSafe } from "./fs-utils.js";
7
6
  import { readKnowledgeSafely } from "./knowledge-store.js";
8
7
  import { evaluateRetroGate } from "./retro-gate.js";
@@ -90,7 +89,7 @@ function toArchiveDate(date = new Date()) {
90
89
  const dd = date.getDate().toString().padStart(2, "0");
91
90
  return `${yyyy}-${mm}-${dd}`;
92
91
  }
93
- function slugifyFeatureName(value) {
92
+ function slugifyRunName(value) {
94
93
  const slug = value
95
94
  .toLowerCase()
96
95
  .trim()
@@ -98,14 +97,14 @@ function slugifyFeatureName(value) {
98
97
  .replace(/^-+/u, "")
99
98
  .replace(/-+$/u, "");
100
99
  if (slug.length === 0) {
101
- return "feature";
100
+ return "run";
102
101
  }
103
102
  return slug.slice(0, 64);
104
103
  }
105
- async function inferFeatureNameFromArtifacts(projectRoot) {
104
+ async function inferRunNameFromArtifacts(projectRoot) {
106
105
  const ideaPath = path.join(projectRoot, ACTIVE_ARTIFACTS_REL_PATH, "00-idea.md");
107
106
  if (!(await exists(ideaPath))) {
108
- return "feature";
107
+ return "run";
109
108
  }
110
109
  try {
111
110
  const raw = await fs.readFile(ideaPath, "utf8");
@@ -114,12 +113,12 @@ async function inferFeatureNameFromArtifacts(projectRoot) {
114
113
  .map((line) => line.trim())
115
114
  .find((line) => line.length > 0);
116
115
  if (!firstMeaningful) {
117
- return "feature";
116
+ return "run";
118
117
  }
119
- return firstMeaningful.replace(/^[-#*\s]+/u, "").trim() || "feature";
118
+ return firstMeaningful.replace(/^[-#*\s]+/u, "").trim() || "run";
120
119
  }
121
120
  catch {
122
- return "feature";
121
+ return "run";
123
122
  }
124
123
  }
125
124
  async function uniqueArchiveId(projectRoot, baseId) {
@@ -159,7 +158,7 @@ export async function listRuns(projectRoot) {
159
158
  }
160
159
  return runs.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
161
160
  }
162
- export async function archiveRun(projectRoot, featureName, options = {}) {
161
+ export async function archiveRun(projectRoot, runName, options = {}) {
163
162
  await ensureRunSystem(projectRoot);
164
163
  // Hold BOTH archive.lock and flow-state.lock for the entire archive:
165
164
  // the outer archive lock serializes two concurrent archives; the
@@ -168,15 +167,14 @@ export async function archiveRun(projectRoot, featureName, options = {}) {
168
167
  // which used to cause lost-update races.
169
168
  return withDirectoryLock(archiveLockPath(projectRoot), async () => {
170
169
  return withDirectoryLock(flowStateLockPathFor(projectRoot), async () => {
171
- const activeFeature = await readActiveFeature(projectRoot);
172
170
  const artifactsDir = activeArtifactsPath(projectRoot);
173
171
  const runsDir = runsRoot(projectRoot);
174
172
  await ensureDir(runsDir);
175
173
  await ensureDir(artifactsDir);
176
- const feature = (featureName?.trim() && featureName.trim().length > 0)
177
- ? featureName.trim()
178
- : await inferFeatureNameFromArtifacts(projectRoot);
179
- const archiveBaseId = `${toArchiveDate()}-${slugifyFeatureName(feature)}`;
174
+ const archiveRunName = (runName?.trim() && runName.trim().length > 0)
175
+ ? runName.trim()
176
+ : await inferRunNameFromArtifacts(projectRoot);
177
+ const archiveBaseId = `${toArchiveDate()}-${slugifyRunName(archiveRunName)}`;
180
178
  const archiveId = await uniqueArchiveId(projectRoot, archiveBaseId);
181
179
  const archivePath = path.join(runsDir, archiveId);
182
180
  const archiveArtifactsPath = path.join(archivePath, "artifacts");
@@ -256,11 +254,10 @@ export async function archiveRun(projectRoot, featureName, options = {}) {
256
254
  stateReset = true;
257
255
  await resetCarryoverStateFiles(projectRoot, resetState.activeRunId);
258
256
  const manifest = {
259
- version: 1,
257
+ version: 2,
260
258
  archiveId,
261
259
  archivedAt,
262
- featureName: feature,
263
- activeFeature,
260
+ runName: archiveRunName,
264
261
  sourceRunId: sourceState.activeRunId,
265
262
  sourceCurrentStage: sourceState.currentStage,
266
263
  sourceCompletedStages: sourceState.completedStages,
@@ -271,13 +268,11 @@ export async function archiveRun(projectRoot, featureName, options = {}) {
271
268
  // Manifest landed — sentinel is no longer needed.
272
269
  await fs.unlink(sentinelPath).catch(() => undefined);
273
270
  const knowledgeStats = await readKnowledgeStats(projectRoot);
274
- await syncActiveFeatureSnapshot(projectRoot);
275
271
  return {
276
272
  archiveId,
277
273
  archivePath,
278
274
  archivedAt,
279
- featureName: feature,
280
- activeFeature,
275
+ runName: archiveRunName,
281
276
  resetState,
282
277
  snapshottedStateFiles,
283
278
  knowledge: knowledgeStats,
@@ -21,8 +21,8 @@ export interface WriteFlowStateOptions {
21
21
  }
22
22
  export interface ReadFlowStateOptions {
23
23
  /**
24
- * When false, skip feature-system auto-repair writes and read flow-state in
25
- * pure diagnostic mode.
24
+ * Reserved compatibility switch from older runtimes. The repair layer was removed,
25
+ * so this flag is now a no-op and only preserved for API stability.
26
26
  */
27
27
  repairFeatureSystem?: boolean;
28
28
  }