cclaw-cli 0.5.4 → 0.5.5

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.
package/dist/runs.js CHANGED
@@ -6,8 +6,6 @@ import { ensureDir, exists, withDirectoryLock, writeFileSafe } from "./fs-utils.
6
6
  const FLOW_STATE_REL_PATH = `${RUNTIME_ROOT}/state/flow-state.json`;
7
7
  const RUNS_DIR_REL_PATH = `${RUNTIME_ROOT}/runs`;
8
8
  const ACTIVE_ARTIFACTS_REL_PATH = `${RUNTIME_ROOT}/artifacts`;
9
- const RUN_META_FILE = "run.json";
10
- const RUN_HANDOFF_FILE = "handoff.md";
11
9
  const FLOW_STAGE_SET = new Set(COMMAND_FILE_ORDER);
12
10
  function flowStatePath(projectRoot) {
13
11
  return path.join(projectRoot, FLOW_STATE_REL_PATH);
@@ -21,65 +19,6 @@ function runsRoot(projectRoot) {
21
19
  function activeArtifactsPath(projectRoot) {
22
20
  return path.join(projectRoot, ACTIVE_ARTIFACTS_REL_PATH);
23
21
  }
24
- function runRoot(projectRoot, runId) {
25
- return path.join(runsRoot(projectRoot), requireSafeRunId(runId));
26
- }
27
- function runArtifactsPath(projectRoot, runId) {
28
- return path.join(runRoot(projectRoot, runId), "artifacts");
29
- }
30
- function runMetaPath(projectRoot, runId) {
31
- return path.join(runRoot(projectRoot, runId), RUN_META_FILE);
32
- }
33
- function runHandoffPath(projectRoot, runId) {
34
- return path.join(runRoot(projectRoot, runId), RUN_HANDOFF_FILE);
35
- }
36
- function nowIso() {
37
- return new Date().toISOString();
38
- }
39
- function pad2(value) {
40
- return value.toString().padStart(2, "0");
41
- }
42
- function buildRunId(date = new Date()) {
43
- const yyyy = date.getUTCFullYear();
44
- const mm = pad2(date.getUTCMonth() + 1);
45
- const dd = pad2(date.getUTCDate());
46
- const hh = pad2(date.getUTCHours());
47
- const min = pad2(date.getUTCMinutes());
48
- const ss = pad2(date.getUTCSeconds());
49
- const random = Math.random().toString(36).slice(2, 6);
50
- return `run-${yyyy}${mm}${dd}-${hh}${min}${ss}-${random}`;
51
- }
52
- function normalizeTitle(title) {
53
- const trimmed = (title ?? "").trim();
54
- if (trimmed.length === 0) {
55
- return "New feature run";
56
- }
57
- return trimmed;
58
- }
59
- function isSafeRunId(value) {
60
- return /^[A-Za-z0-9_-]{1,128}$/u.test(value);
61
- }
62
- function sanitizeRunId(value) {
63
- if (typeof value !== "string")
64
- return undefined;
65
- const trimmed = value.trim();
66
- return isSafeRunId(trimmed) ? trimmed : undefined;
67
- }
68
- function requireSafeRunId(runId) {
69
- const safe = sanitizeRunId(runId);
70
- if (!safe) {
71
- throw new Error(`Invalid run id "${runId}"`);
72
- }
73
- return safe;
74
- }
75
- function snapshotState(state) {
76
- return {
77
- currentStage: state.currentStage,
78
- completedStages: [...state.completedStages],
79
- guardEvidence: { ...state.guardEvidence },
80
- stageGateCatalog: JSON.parse(JSON.stringify(state.stageGateCatalog))
81
- };
82
- }
83
22
  function isFlowStage(value) {
84
23
  return typeof value === "string" && FLOW_STAGE_SET.has(value);
85
24
  }
@@ -144,300 +83,148 @@ function sanitizeStageGateCatalog(value, fallback) {
144
83
  }
145
84
  return next;
146
85
  }
147
- function coerceFlowState(parsed, activeRunIdOverride) {
148
- const overrideTrim = sanitizeRunId(activeRunIdOverride);
149
- const parsedActiveRun = sanitizeRunId(parsed.activeRunId);
150
- const seedRunId = overrideTrim ?? parsedActiveRun;
151
- const next = createInitialFlowState(seedRunId);
86
+ function coerceFlowState(parsed) {
87
+ const next = createInitialFlowState();
88
+ const activeRunIdRaw = parsed.activeRunId;
89
+ const activeRunId = typeof activeRunIdRaw === "string" && activeRunIdRaw.trim().length > 0
90
+ ? activeRunIdRaw.trim()
91
+ : next.activeRunId;
152
92
  return {
153
- activeRunId: overrideTrim ?? parsedActiveRun ?? next.activeRunId,
93
+ activeRunId,
154
94
  currentStage: isFlowStage(parsed.currentStage) ? parsed.currentStage : next.currentStage,
155
95
  completedStages: sanitizeCompletedStages(parsed.completedStages),
156
96
  guardEvidence: sanitizeGuardEvidence(parsed.guardEvidence),
157
97
  stageGateCatalog: sanitizeStageGateCatalog(parsed.stageGateCatalog, next.stageGateCatalog)
158
98
  };
159
99
  }
160
- function createdAtFromRunId(runId) {
161
- const match = /^run-(\d{4})(\d{2})(\d{2})-(\d{2})(\d{2})(\d{2})-[a-z0-9]+$/iu.exec(runId);
162
- if (!match) {
163
- return null;
100
+ function toArchiveDate(date = new Date()) {
101
+ const yyyy = date.getFullYear().toString();
102
+ const mm = (date.getMonth() + 1).toString().padStart(2, "0");
103
+ const dd = date.getDate().toString().padStart(2, "0");
104
+ return `${yyyy}-${mm}-${dd}`;
105
+ }
106
+ function slugifyFeatureName(value) {
107
+ const slug = value
108
+ .toLowerCase()
109
+ .trim()
110
+ .replace(/[^a-z0-9]+/gu, "-")
111
+ .replace(/^-+/u, "")
112
+ .replace(/-+$/u, "");
113
+ if (slug.length === 0) {
114
+ return "feature";
115
+ }
116
+ return slug.slice(0, 64);
117
+ }
118
+ async function inferFeatureNameFromArtifacts(projectRoot) {
119
+ const ideaPath = path.join(projectRoot, ACTIVE_ARTIFACTS_REL_PATH, "00-idea.md");
120
+ if (!(await exists(ideaPath))) {
121
+ return "feature";
164
122
  }
165
- const [, year, month, day, hour, minute, second] = match;
166
- const date = new Date(Date.UTC(Number(year), Number(month) - 1, Number(day), Number(hour), Number(minute), Number(second)));
167
- return Number.isNaN(date.getTime()) ? null : date.toISOString();
168
- }
169
- async function readJsonFile(filePath) {
170
- if (!(await exists(filePath)))
171
- return null;
172
123
  try {
173
- return JSON.parse(await fs.readFile(filePath, "utf8"));
124
+ const raw = await fs.readFile(ideaPath, "utf8");
125
+ const firstMeaningful = raw
126
+ .split(/\r?\n/gu)
127
+ .map((line) => line.trim())
128
+ .find((line) => line.length > 0);
129
+ if (!firstMeaningful) {
130
+ return "feature";
131
+ }
132
+ return firstMeaningful.replace(/^[-#*\s]+/u, "").trim() || "feature";
174
133
  }
175
134
  catch {
176
- return null;
135
+ return "feature";
177
136
  }
178
137
  }
179
- async function listImmediateFiles(dirPath) {
180
- if (!(await exists(dirPath)))
181
- return [];
182
- const entries = await fs.readdir(dirPath, { withFileTypes: true });
183
- return entries.filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
184
- }
185
- async function clearImmediateFiles(dirPath) {
186
- if (!(await exists(dirPath)))
187
- return;
188
- const entries = await fs.readdir(dirPath, { withFileTypes: true });
189
- for (const entry of entries) {
190
- if (entry.isFile()) {
191
- await fs.rm(path.join(dirPath, entry.name), { force: true });
192
- }
138
+ async function uniqueArchiveId(projectRoot, baseId) {
139
+ let index = 1;
140
+ let candidate = baseId;
141
+ while (await exists(path.join(runsRoot(projectRoot), candidate))) {
142
+ index += 1;
143
+ candidate = `${baseId}-${index}`;
193
144
  }
194
- }
195
- async function copyImmediateFiles(fromDir, toDir) {
196
- await ensureDir(toDir);
197
- const fileNames = await listImmediateFiles(fromDir);
198
- for (const fileName of fileNames) {
199
- const sourcePath = path.join(fromDir, fileName);
200
- const targetPath = path.join(toDir, fileName);
201
- await fs.copyFile(sourcePath, targetPath);
202
- }
203
- }
204
- function handoffMarkdown(runMeta, state) {
205
- return `# Run Handoff
206
-
207
- ## Run
208
- - ID: ${runMeta.id}
209
- - Title: ${runMeta.title}
210
- - Created: ${runMeta.createdAt}
211
- - Archived: ${runMeta.archivedAt ?? "active"}
212
-
213
- ## Flow Snapshot
214
- - Active stage: ${state.currentStage}
215
- - Completed stages: ${state.completedStages.join(", ") || "(none)"}
216
- - Active run ID in flow-state: ${state.activeRunId}
217
-
218
- ## Paths
219
- - Active artifacts: \`${RUNTIME_ROOT}/artifacts/\`
220
- - Canonical run artifacts: \`${RUNTIME_ROOT}/runs/${runMeta.id}/artifacts/\`
221
-
222
- ## Resume
223
- 1. Continue with the stage command for \`${state.currentStage}\`
224
- 2. If needed, sync artifacts from \`${RUNTIME_ROOT}/runs/${runMeta.id}/artifacts/\`
225
- `;
145
+ return candidate;
226
146
  }
227
147
  export async function readFlowState(projectRoot) {
228
148
  const statePath = flowStatePath(projectRoot);
229
- const parsed = await readJsonFile(statePath);
230
- if (!parsed || typeof parsed !== "object") {
149
+ if (!(await exists(statePath))) {
150
+ return createInitialFlowState();
151
+ }
152
+ try {
153
+ const parsed = JSON.parse(await fs.readFile(statePath, "utf8"));
154
+ return coerceFlowState(parsed);
155
+ }
156
+ catch {
231
157
  return createInitialFlowState();
232
158
  }
233
- return coerceFlowState(parsed);
234
159
  }
235
160
  export async function writeFlowState(projectRoot, state) {
236
161
  await withDirectoryLock(flowStateLockPath(projectRoot), async () => {
237
- const safe = coerceFlowState({ ...state }, state.activeRunId);
162
+ const safe = coerceFlowState({ ...state });
238
163
  await writeFileSafe(flowStatePath(projectRoot), `${JSON.stringify(safe, null, 2)}\n`);
239
164
  });
240
165
  }
166
+ export async function ensureRunSystem(projectRoot, _options = {}) {
167
+ await ensureDir(runsRoot(projectRoot));
168
+ await ensureDir(activeArtifactsPath(projectRoot));
169
+ const statePath = flowStatePath(projectRoot);
170
+ const state = await readFlowState(projectRoot);
171
+ if (!(await exists(statePath))) {
172
+ await writeFlowState(projectRoot, state);
173
+ }
174
+ return state;
175
+ }
241
176
  export async function listRuns(projectRoot) {
242
177
  const root = runsRoot(projectRoot);
243
- if (!(await exists(root)))
178
+ if (!(await exists(root))) {
244
179
  return [];
245
- const dirs = await fs.readdir(root, { withFileTypes: true });
246
- const metas = [];
247
- for (const dir of dirs) {
248
- if (!dir.isDirectory())
249
- continue;
250
- const runId = dir.name;
251
- if (!isSafeRunId(runId))
252
- continue;
253
- const meta = await readJsonFile(runMetaPath(projectRoot, runId));
254
- if (meta && typeof meta.id === "string" && meta.id === runId) {
255
- metas.push(meta);
180
+ }
181
+ const entries = await fs.readdir(root, { withFileTypes: true });
182
+ const runs = [];
183
+ for (const entry of entries) {
184
+ if (!entry.isDirectory()) {
256
185
  continue;
257
186
  }
258
- let fallbackCreatedAt = createdAtFromRunId(runId);
259
- if (!fallbackCreatedAt) {
260
- try {
261
- const stat = await fs.stat(path.join(root, runId));
262
- fallbackCreatedAt = stat.birthtime?.toISOString?.() ?? stat.mtime.toISOString();
263
- }
264
- catch {
265
- fallbackCreatedAt = null;
266
- }
187
+ const runPath = path.join(root, entry.name);
188
+ let createdAt = new Date().toISOString();
189
+ try {
190
+ const stat = await fs.stat(runPath);
191
+ createdAt = stat.birthtime?.toISOString?.() ?? stat.mtime.toISOString();
267
192
  }
268
- metas.push({
269
- id: runId,
270
- title: runId,
271
- createdAt: fallbackCreatedAt ?? nowIso()
272
- });
273
- }
274
- return metas.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
275
- }
276
- async function ensureRunMetadata(projectRoot, meta) {
277
- await writeFileSafe(runMetaPath(projectRoot, meta.id), `${JSON.stringify(meta, null, 2)}\n`);
278
- }
279
- async function persistRunStateSnapshot(projectRoot, runId, state) {
280
- const meta = await readJsonFile(runMetaPath(projectRoot, runId));
281
- if (!meta)
282
- return;
283
- const safeState = coerceFlowState({ ...state }, state.activeRunId);
284
- await ensureRunMetadata(projectRoot, {
285
- ...meta,
286
- stateSnapshot: snapshotState(safeState)
287
- });
288
- }
289
- async function syncActiveArtifactsToRun(projectRoot, runId) {
290
- const fromDir = activeArtifactsPath(projectRoot);
291
- const toDir = runArtifactsPath(projectRoot, runId);
292
- await ensureDir(toDir);
293
- await clearImmediateFiles(toDir);
294
- await copyImmediateFiles(fromDir, toDir);
295
- }
296
- async function loadRunArtifactsToActive(projectRoot, runId) {
297
- const fromDir = runArtifactsPath(projectRoot, runId);
298
- const toDir = activeArtifactsPath(projectRoot);
299
- await ensureDir(toDir);
300
- await clearImmediateFiles(toDir);
301
- await copyImmediateFiles(fromDir, toDir);
302
- }
303
- async function createRun(projectRoot, options) {
304
- const runId = buildRunId();
305
- const meta = {
306
- id: runId,
307
- title: normalizeTitle(options?.title),
308
- createdAt: nowIso()
309
- };
310
- await ensureDir(runRoot(projectRoot, runId));
311
- await ensureRunMetadata(projectRoot, meta);
312
- const runArtifactsDir = runArtifactsPath(projectRoot, runId);
313
- await ensureDir(runArtifactsDir);
314
- if (options?.seedFromActiveArtifacts && (await exists(activeArtifactsPath(projectRoot)))) {
315
- await copyImmediateFiles(activeArtifactsPath(projectRoot), runArtifactsDir);
316
- }
317
- return meta;
318
- }
319
- async function ensureRunHandoff(projectRoot, runId) {
320
- const state = await readFlowState(projectRoot);
321
- const meta = await readJsonFile(runMetaPath(projectRoot, runId));
322
- if (!meta)
323
- return;
324
- await writeFileSafe(runHandoffPath(projectRoot, runId), handoffMarkdown(meta, state));
325
- }
326
- export async function ensureRunSystem(projectRoot, options = {}) {
327
- await ensureDir(runsRoot(projectRoot));
328
- await ensureDir(activeArtifactsPath(projectRoot));
329
- let state = await readFlowState(projectRoot);
330
- let activeRunId = state.activeRunId;
331
- const createIfMissing = options.createIfMissing !== false;
332
- const activeRunExists = activeRunId.trim().length > 0 && (await exists(runArtifactsPath(projectRoot, activeRunId)));
333
- if (!activeRunExists) {
334
- if (!createIfMissing) {
335
- return state;
193
+ catch {
194
+ // keep fallback timestamp
336
195
  }
337
- const activeHasArtifacts = (await listImmediateFiles(activeArtifactsPath(projectRoot))).length > 0;
338
- const initialRun = await createRun(projectRoot, {
339
- title: activeHasArtifacts ? "Migrated active run" : "Initial feature run",
340
- seedFromActiveArtifacts: activeHasArtifacts
196
+ runs.push({
197
+ id: entry.name,
198
+ title: entry.name,
199
+ createdAt
341
200
  });
342
- activeRunId = initialRun.id;
343
- state = { ...state, activeRunId };
344
- await writeFlowState(projectRoot, state);
345
- }
346
- const runArtifactsDir = runArtifactsPath(projectRoot, activeRunId);
347
- await ensureDir(runArtifactsDir);
348
- if ((await listImmediateFiles(activeArtifactsPath(projectRoot))).length === 0) {
349
- await loadRunArtifactsToActive(projectRoot, activeRunId);
350
201
  }
351
- else {
352
- await syncActiveArtifactsToRun(projectRoot, activeRunId);
353
- }
354
- await persistRunStateSnapshot(projectRoot, activeRunId, state);
355
- await ensureRunHandoff(projectRoot, activeRunId);
356
- return state;
357
- }
358
- export async function startNewFeatureRun(projectRoot, title) {
359
- await ensureRunSystem(projectRoot);
360
- const state = await readFlowState(projectRoot);
361
- await syncActiveArtifactsToRun(projectRoot, state.activeRunId);
362
- await persistRunStateSnapshot(projectRoot, state.activeRunId, state);
363
- await ensureRunHandoff(projectRoot, state.activeRunId);
364
- const nextRun = await createRun(projectRoot, {
365
- title,
366
- seedFromActiveArtifacts: false
367
- });
368
- const nextState = {
369
- ...createInitialFlowState(nextRun.id),
370
- activeRunId: nextRun.id
371
- };
372
- await writeFlowState(projectRoot, nextState);
373
- await persistRunStateSnapshot(projectRoot, nextRun.id, nextState);
374
- await loadRunArtifactsToActive(projectRoot, nextRun.id);
375
- await ensureRunHandoff(projectRoot, nextRun.id);
376
- return nextRun;
202
+ return runs.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
377
203
  }
378
- export async function resumeRun(projectRoot, runId) {
204
+ export async function archiveRun(projectRoot, featureName) {
379
205
  await ensureRunSystem(projectRoot);
380
- const safeRunId = requireSafeRunId(runId);
381
- const targetMeta = await readJsonFile(runMetaPath(projectRoot, safeRunId));
382
- if (!targetMeta) {
383
- throw new Error(`Run "${safeRunId}" not found under ${RUNTIME_ROOT}/runs/`);
384
- }
385
- const state = await readFlowState(projectRoot);
386
- await syncActiveArtifactsToRun(projectRoot, state.activeRunId);
387
- await persistRunStateSnapshot(projectRoot, state.activeRunId, state);
388
- await ensureRunHandoff(projectRoot, state.activeRunId);
389
- const nextState = targetMeta.stateSnapshot
390
- ? coerceFlowState({
391
- ...createInitialFlowState(safeRunId),
392
- ...targetMeta.stateSnapshot,
393
- activeRunId: safeRunId
394
- }, safeRunId)
395
- : coerceFlowState({
396
- ...createInitialFlowState(safeRunId),
397
- activeRunId: safeRunId
398
- }, safeRunId);
399
- await writeFlowState(projectRoot, nextState);
400
- await persistRunStateSnapshot(projectRoot, safeRunId, nextState);
401
- await loadRunArtifactsToActive(projectRoot, safeRunId);
402
- await ensureRunHandoff(projectRoot, safeRunId);
403
- return targetMeta;
404
- }
405
- export async function archiveRun(projectRoot, runId) {
406
- await ensureRunSystem(projectRoot);
407
- const state = await readFlowState(projectRoot);
408
- const targetRunId = runId ? requireSafeRunId(runId) : state.activeRunId;
409
- const targetMeta = await readJsonFile(runMetaPath(projectRoot, targetRunId));
410
- if (!targetMeta) {
411
- throw new Error(`Run "${targetRunId}" not found under ${RUNTIME_ROOT}/runs/`);
412
- }
413
- if (targetRunId === state.activeRunId) {
414
- await syncActiveArtifactsToRun(projectRoot, targetRunId);
415
- await persistRunStateSnapshot(projectRoot, targetRunId, state);
416
- }
417
- const archivedMeta = {
418
- ...targetMeta,
419
- archivedAt: nowIso()
420
- };
421
- await ensureRunMetadata(projectRoot, archivedMeta);
422
- await ensureRunHandoff(projectRoot, targetRunId);
423
- if (targetRunId !== state.activeRunId) {
424
- const activeMeta = await readJsonFile(runMetaPath(projectRoot, state.activeRunId));
425
- if (!activeMeta) {
426
- throw new Error(`Active run "${state.activeRunId}" is missing metadata`);
427
- }
428
- return { archived: archivedMeta, active: activeMeta };
429
- }
430
- const nextRun = await createRun(projectRoot, {
431
- title: "Post-archive run",
432
- seedFromActiveArtifacts: false
433
- });
434
- const nextState = {
435
- ...createInitialFlowState(nextRun.id),
436
- activeRunId: nextRun.id
206
+ const artifactsDir = activeArtifactsPath(projectRoot);
207
+ const runsDir = runsRoot(projectRoot);
208
+ await ensureDir(runsDir);
209
+ await ensureDir(artifactsDir);
210
+ const feature = (featureName?.trim() && featureName.trim().length > 0)
211
+ ? featureName.trim()
212
+ : await inferFeatureNameFromArtifacts(projectRoot);
213
+ const archiveBaseId = `${toArchiveDate()}-${slugifyFeatureName(feature)}`;
214
+ const archiveId = await uniqueArchiveId(projectRoot, archiveBaseId);
215
+ const archivePath = path.join(runsDir, archiveId);
216
+ const archiveArtifactsPath = path.join(archivePath, "artifacts");
217
+ await ensureDir(archivePath);
218
+ await fs.rename(artifactsDir, archiveArtifactsPath);
219
+ await ensureDir(artifactsDir);
220
+ const resetState = createInitialFlowState();
221
+ await writeFlowState(projectRoot, resetState);
222
+ const archivedAt = new Date().toISOString();
223
+ return {
224
+ archiveId,
225
+ archivePath,
226
+ archivedAt,
227
+ featureName: feature,
228
+ resetState
437
229
  };
438
- await writeFlowState(projectRoot, nextState);
439
- await persistRunStateSnapshot(projectRoot, nextRun.id, nextState);
440
- await loadRunArtifactsToActive(projectRoot, nextRun.id);
441
- await ensureRunHandoff(projectRoot, nextRun.id);
442
- return { archived: archivedMeta, active: nextRun };
443
230
  }
@@ -2,22 +2,13 @@ import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { RUNTIME_ROOT } from "./constants.js";
4
4
  import { exists } from "./fs-utils.js";
5
- import { readFlowState } from "./runs.js";
6
5
  function activeArtifactPath(projectRoot, name) {
7
6
  return path.join(projectRoot, RUNTIME_ROOT, "artifacts", name);
8
7
  }
9
- function canonicalRunArtifactPath(projectRoot, runId, name) {
10
- return path.join(projectRoot, RUNTIME_ROOT, "runs", runId, "artifacts", name);
11
- }
12
- async function readArtifact(projectRoot, name, activeRunId) {
13
- const runId = activeRunId.trim();
14
- const candidates = runId.length > 0
15
- ? [canonicalRunArtifactPath(projectRoot, runId, name), activeArtifactPath(projectRoot, name)]
16
- : [activeArtifactPath(projectRoot, name)];
17
- for (const candidate of candidates) {
18
- if (await exists(candidate)) {
19
- return fs.readFile(candidate, "utf8");
20
- }
8
+ async function readArtifact(projectRoot, name) {
9
+ const candidate = activeArtifactPath(projectRoot, name);
10
+ if (await exists(candidate)) {
11
+ return fs.readFile(candidate, "utf8");
21
12
  }
22
13
  return null;
23
14
  }
@@ -120,11 +111,10 @@ function layer1LinesForCriterion(layer1, criterionId) {
120
111
  return out;
121
112
  }
122
113
  export async function buildTraceMatrix(projectRoot) {
123
- const { activeRunId } = await readFlowState(projectRoot);
124
- const spec = await readArtifact(projectRoot, "04-spec.md", activeRunId);
125
- const plan = await readArtifact(projectRoot, "05-plan.md", activeRunId);
126
- const tdd = await readArtifact(projectRoot, "06-tdd.md", activeRunId);
127
- const review = await readArtifact(projectRoot, "07-review.md", activeRunId);
114
+ const spec = await readArtifact(projectRoot, "04-spec.md");
115
+ const plan = await readArtifact(projectRoot, "05-plan.md");
116
+ const tdd = await readArtifact(projectRoot, "06-tdd.md");
117
+ const review = await readArtifact(projectRoot, "07-review.md");
128
118
  const criterionIds = spec ? parseAcceptanceCriterionIds(spec) : [];
129
119
  const taskToAcs = plan ? parsePlanTaskAcLinks(plan) : new Map();
130
120
  const allTaskIds = plan ? parsePlanTaskIds(plan) : [];
package/dist/types.d.ts CHANGED
@@ -8,10 +8,6 @@ export interface VibyConfig {
8
8
  harnesses: HarnessId[];
9
9
  /** When true, stage skills instruct the agent to continue to the following stage after gates pass. */
10
10
  autoAdvance?: boolean;
11
- /** Merge project bootstrap learnings with a global learnings file. */
12
- globalLearnings?: boolean;
13
- /** Optional absolute or project-relative path to global learnings JSONL. */
14
- globalLearningsPath?: string;
15
11
  /** Prompt guard behavior for runtime write-risk detection hooks. */
16
12
  promptGuardMode?: "advisory" | "strict";
17
13
  /** When true, cclaw installs managed git pre-commit/pre-push wrappers. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cclaw-cli",
3
- "version": "0.5.4",
3
+ "version": "0.5.5",
4
4
  "description": "Installer-first flow toolkit for coding agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,25 +0,0 @@
1
- export interface ObservationRecord {
2
- ts?: string;
3
- event?: string;
4
- tool?: string;
5
- phase?: string;
6
- stage?: string;
7
- runId?: string;
8
- data?: unknown;
9
- }
10
- export type LearningSource = "observed" | "user-stated" | "inferred";
11
- export type LearningType = "pitfall" | "pattern" | "preference";
12
- export interface LearningRecord {
13
- ts: string;
14
- skill: string;
15
- type: LearningType;
16
- key: string;
17
- insight: string;
18
- confidence: number;
19
- source: LearningSource;
20
- }
21
- export interface SummarizeOutcome {
22
- candidates: LearningRecord[];
23
- appendable: LearningRecord[];
24
- }
25
- export declare function summarizeObservationLearnings(observationJsonl: string, existingLearningsJsonl: string, timestamp: string): SummarizeOutcome;