cclaw-cli 0.51.29 → 0.55.2
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/README.md +22 -16
- package/dist/artifact-linter/brainstorm.d.ts +2 -0
- package/dist/artifact-linter/brainstorm.js +245 -0
- package/dist/artifact-linter/design.d.ts +2 -0
- package/dist/artifact-linter/design.js +323 -0
- package/dist/artifact-linter/plan.d.ts +2 -0
- package/dist/artifact-linter/plan.js +162 -0
- package/dist/artifact-linter/review-army.d.ts +24 -0
- package/dist/artifact-linter/review-army.js +365 -0
- package/dist/artifact-linter/review.d.ts +2 -0
- package/dist/artifact-linter/review.js +65 -0
- package/dist/artifact-linter/scope.d.ts +2 -0
- package/dist/artifact-linter/scope.js +115 -0
- package/dist/artifact-linter/shared.d.ts +246 -0
- package/dist/artifact-linter/shared.js +1488 -0
- package/dist/artifact-linter/ship.d.ts +2 -0
- package/dist/artifact-linter/ship.js +46 -0
- package/dist/artifact-linter/spec.d.ts +2 -0
- package/dist/artifact-linter/spec.js +108 -0
- package/dist/artifact-linter/tdd.d.ts +2 -0
- package/dist/artifact-linter/tdd.js +124 -0
- package/dist/artifact-linter.d.ts +4 -76
- package/dist/artifact-linter.js +56 -2949
- package/dist/cli.d.ts +2 -18
- package/dist/cli.js +8 -246
- package/dist/codex-feature-flag.d.ts +1 -1
- package/dist/codex-feature-flag.js +1 -1
- package/dist/config.d.ts +3 -2
- package/dist/config.js +67 -3
- package/dist/constants.d.ts +1 -7
- package/dist/constants.js +9 -15
- package/dist/content/cancel-command.js +2 -2
- package/dist/content/closeout-guidance.js +13 -10
- package/dist/content/core-agents.d.ts +18 -0
- package/dist/content/core-agents.js +51 -7
- package/dist/content/decision-protocol.d.ts +1 -1
- package/dist/content/decision-protocol.js +1 -1
- package/dist/content/examples.js +6 -6
- package/dist/content/harness-doc.js +20 -2
- package/dist/content/hook-inline-snippets.d.ts +17 -4
- package/dist/content/hook-inline-snippets.js +218 -5
- package/dist/content/hook-manifest.d.ts +2 -2
- package/dist/content/hook-manifest.js +2 -2
- package/dist/content/hooks.d.ts +1 -0
- package/dist/content/hooks.js +32 -137
- package/dist/content/idea-command.d.ts +8 -0
- package/dist/content/{ideate-command.js → idea-command.js} +57 -50
- package/dist/content/idea-frames.d.ts +31 -0
- package/dist/content/{ideate-frames.js → idea-frames.js} +9 -9
- package/dist/content/idea-ranking.d.ts +25 -0
- package/dist/content/{ideate-ranking.js → idea-ranking.js} +5 -5
- package/dist/content/iron-laws.d.ts +0 -1
- package/dist/content/iron-laws.js +31 -16
- package/dist/content/learnings.js +1 -1
- package/dist/content/meta-skill.js +11 -13
- package/dist/content/node-hooks.d.ts +10 -0
- package/dist/content/node-hooks.js +45 -11
- package/dist/content/opencode-plugin.js +3 -3
- package/dist/content/session-hooks.js +1 -1
- package/dist/content/skills.js +19 -7
- package/dist/content/stage-command.js +1 -1
- package/dist/content/stage-schema.js +44 -2
- package/dist/content/stages/_lint-metadata/index.js +26 -2
- package/dist/content/stages/brainstorm.js +13 -7
- package/dist/content/stages/design.js +16 -11
- package/dist/content/stages/plan.js +9 -6
- package/dist/content/stages/review.js +4 -4
- package/dist/content/stages/schema-types.d.ts +1 -1
- package/dist/content/stages/scope.js +15 -12
- package/dist/content/stages/ship.js +2 -2
- package/dist/content/stages/spec.js +9 -3
- package/dist/content/stages/tdd.js +14 -4
- package/dist/content/start-command.d.ts +2 -2
- package/dist/content/start-command.js +24 -21
- package/dist/content/status-command.js +8 -8
- package/dist/content/subagents.js +61 -7
- package/dist/content/templates.d.ts +1 -1
- package/dist/content/templates.js +104 -152
- package/dist/content/tree-command.js +2 -2
- package/dist/content/utility-skills.d.ts +2 -2
- package/dist/content/utility-skills.js +2 -2
- package/dist/content/view-command.js +4 -2
- package/dist/delegation.d.ts +2 -0
- package/dist/delegation.js +2 -1
- package/dist/early-loop.d.ts +66 -0
- package/dist/early-loop.js +275 -0
- package/dist/flow-state.d.ts +1 -1
- package/dist/flow-state.js +1 -1
- package/dist/gate-evidence.d.ts +8 -0
- package/dist/gate-evidence.js +141 -5
- package/dist/harness-adapters.d.ts +2 -2
- package/dist/harness-adapters.js +54 -122
- package/dist/harness-selection.d.ts +31 -0
- package/dist/harness-selection.js +214 -0
- package/dist/install.js +166 -38
- package/dist/internal/advance-stage/advance.d.ts +50 -0
- package/dist/internal/advance-stage/advance.js +480 -0
- package/dist/internal/advance-stage/cancel-run.d.ts +8 -0
- package/dist/internal/advance-stage/cancel-run.js +19 -0
- package/dist/internal/advance-stage/flow-state-coercion.d.ts +3 -0
- package/dist/internal/advance-stage/flow-state-coercion.js +81 -0
- package/dist/internal/advance-stage/helpers.d.ts +14 -0
- package/dist/internal/advance-stage/helpers.js +145 -0
- package/dist/internal/advance-stage/hook.d.ts +8 -0
- package/dist/internal/advance-stage/hook.js +40 -0
- package/dist/internal/advance-stage/parsers.d.ts +54 -0
- package/dist/internal/advance-stage/parsers.js +307 -0
- package/dist/internal/advance-stage/review-loop.d.ts +7 -0
- package/dist/internal/advance-stage/review-loop.js +170 -0
- package/dist/internal/advance-stage/rewind.d.ts +14 -0
- package/dist/internal/advance-stage/rewind.js +108 -0
- package/dist/internal/advance-stage/start-flow.d.ts +11 -0
- package/dist/internal/advance-stage/start-flow.js +136 -0
- package/dist/internal/advance-stage/verify.d.ts +29 -0
- package/dist/internal/advance-stage/verify.js +225 -0
- package/dist/internal/advance-stage.js +21 -1470
- package/dist/internal/compound-readiness.d.ts +1 -1
- package/dist/internal/compound-readiness.js +2 -2
- package/dist/internal/early-loop-status.d.ts +7 -0
- package/dist/internal/early-loop-status.js +90 -0
- package/dist/internal/runtime-integrity.d.ts +7 -0
- package/dist/internal/runtime-integrity.js +288 -0
- package/dist/internal/tdd-red-evidence.js +1 -1
- package/dist/knowledge-store.d.ts +3 -8
- package/dist/knowledge-store.js +16 -29
- package/dist/managed-resources.js +24 -2
- package/dist/policy.js +5 -7
- package/dist/run-archive.d.ts +1 -1
- package/dist/run-archive.js +16 -16
- package/dist/run-persistence.js +112 -12
- package/dist/tdd-cycle.d.ts +3 -3
- package/dist/tdd-cycle.js +1 -1
- package/dist/types.d.ts +18 -10
- package/package.json +1 -1
- package/dist/content/finish-command.d.ts +0 -2
- package/dist/content/finish-command.js +0 -26
- package/dist/content/ideate-command.d.ts +0 -8
- package/dist/content/ideate-frames.d.ts +0 -31
- package/dist/content/ideate-ranking.d.ts +0 -25
- package/dist/content/next-command.d.ts +0 -20
- package/dist/content/next-command.js +0 -298
- package/dist/content/seed-shelf.d.ts +0 -36
- package/dist/content/seed-shelf.js +0 -301
- package/dist/content/stage-common-guidance.d.ts +0 -1
- package/dist/content/stage-common-guidance.js +0 -106
- package/dist/doctor-registry.d.ts +0 -10
- package/dist/doctor-registry.js +0 -186
- package/dist/doctor.d.ts +0 -17
- package/dist/doctor.js +0 -2206
- package/dist/internal/hook-manifest.d.ts +0 -16
- package/dist/internal/hook-manifest.js +0 -77
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
* `src/knowledge-store.ts::computeCompoundReadiness`.
|
|
11
11
|
* 2. `computeRalphLoopStatusInline` mirrors
|
|
12
12
|
* `src/tdd-cycle.ts::computeRalphLoopStatus`.
|
|
13
|
+
* 3. `computeEarlyLoopStatusInline` mirrors
|
|
14
|
+
* `src/early-loop.ts::computeEarlyLoopStatus`.
|
|
13
15
|
*
|
|
14
16
|
* Previously those bodies lived inline in `src/content/node-hooks.ts` — a
|
|
15
17
|
* ~2000-line file — next to unrelated hook-handler code. Any silent drift
|
|
@@ -25,11 +27,12 @@
|
|
|
25
27
|
* longer owns their source code.
|
|
26
28
|
*
|
|
27
29
|
* Parity with the TypeScript canonical implementations is enforced by
|
|
28
|
-
* `tests/unit/ralph-loop-parity.test.ts
|
|
30
|
+
* `tests/unit/ralph-loop-parity.test.ts` and
|
|
31
|
+
* `tests/unit/early-loop-parity.test.ts`. Any structural change to the
|
|
29
32
|
* canonical TS code MUST:
|
|
30
33
|
*
|
|
31
34
|
* 1. Update the matching snippet below.
|
|
32
|
-
* 2. Re-run
|
|
35
|
+
* 2. Re-run parity tests for the touched snippet.
|
|
33
36
|
*
|
|
34
37
|
* DO NOT inline tests here — keep the parity check in its dedicated test
|
|
35
38
|
* file.
|
|
@@ -43,7 +46,7 @@
|
|
|
43
46
|
* timestamp so the hook-written `compound-readiness.json` is byte-equal
|
|
44
47
|
* to the CLI-written version for the same input.
|
|
45
48
|
* - `countArchivedRunsInline` counts immediate subdirectories of
|
|
46
|
-
* `<root>/.cclaw/
|
|
49
|
+
* `<root>/.cclaw/archive/` so both the hook and the CLI see the same
|
|
47
50
|
* `archivedRunsCount` for the small-project relaxation.
|
|
48
51
|
* - `formatCompoundReadinessLineInline` mirrors the one-line summary shape
|
|
49
52
|
* used by `src/internal/compound-readiness.ts::formatCompoundReadinessLine`
|
|
@@ -54,11 +57,11 @@ function normalizeCompoundLastUpdatedAt(date) {
|
|
|
54
57
|
return date.toISOString().replace(/\\.\\d{3}Z$/u, "Z");
|
|
55
58
|
}
|
|
56
59
|
|
|
57
|
-
// Count archived runs as sub-directories under \`.cclaw/
|
|
60
|
+
// Count archived runs as sub-directories under \`.cclaw/archive/\`. Missing
|
|
58
61
|
// dir returns 0; unexpected errors return undefined so the caller can
|
|
59
62
|
// skip the small-project relaxation rather than guess.
|
|
60
63
|
async function countArchivedRunsInline(root) {
|
|
61
|
-
const dir = path.join(root, RUNTIME_ROOT, "
|
|
64
|
+
const dir = path.join(root, RUNTIME_ROOT, "archive");
|
|
62
65
|
try {
|
|
63
66
|
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
64
67
|
return entries.filter((entry) => entry.isDirectory()).length;
|
|
@@ -300,3 +303,213 @@ async function computeRalphLoopStatusInline(stateDir, runId) {
|
|
|
300
303
|
};
|
|
301
304
|
}
|
|
302
305
|
`;
|
|
306
|
+
/**
|
|
307
|
+
* Inline mirror of `src/early-loop.ts::computeEarlyLoopStatus`.
|
|
308
|
+
*
|
|
309
|
+
* Parity enforced by
|
|
310
|
+
* `tests/unit/early-loop-parity.test.ts::early-loop parity`.
|
|
311
|
+
*
|
|
312
|
+
* Signature contract:
|
|
313
|
+
* async function computeEarlyLoopStatusInline(stateDir, stageId, runId, maxIterations) -> EarlyLoopStatus
|
|
314
|
+
*/
|
|
315
|
+
export const EARLY_LOOP_INLINE_SOURCE = `
|
|
316
|
+
function normalizeEarlyLoopSeverityInline(value) {
|
|
317
|
+
if (value === "critical" || value === "important" || value === "suggestion") {
|
|
318
|
+
return value;
|
|
319
|
+
}
|
|
320
|
+
return "important";
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function normalizeEarlyLoopTextInline(value, fallback) {
|
|
324
|
+
if (typeof value !== "string") return fallback;
|
|
325
|
+
const trimmed = value.trim();
|
|
326
|
+
return trimmed.length > 0 ? trimmed : fallback;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function stableConcernFallbackIdInline(locator, summary) {
|
|
330
|
+
const seed = (String(locator) + "::" + String(summary)).trim().toLowerCase();
|
|
331
|
+
let hash = 0;
|
|
332
|
+
for (let index = 0; index < seed.length; index += 1) {
|
|
333
|
+
hash = (Math.imul(31, hash) + seed.charCodeAt(index)) >>> 0;
|
|
334
|
+
}
|
|
335
|
+
return "C-" + hash.toString(16).padStart(8, "0");
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function normalizeEarlyLoopConcernInline(row) {
|
|
339
|
+
if (!row || typeof row !== "object" || Array.isArray(row)) return null;
|
|
340
|
+
const locator = normalizeEarlyLoopTextInline(row.locator, "unknown-location");
|
|
341
|
+
const summary = normalizeEarlyLoopTextInline(row.summary, "missing-summary");
|
|
342
|
+
const id = typeof row.id === "string" && row.id.trim().length > 0
|
|
343
|
+
? row.id.trim()
|
|
344
|
+
: stableConcernFallbackIdInline(locator, summary);
|
|
345
|
+
return {
|
|
346
|
+
id,
|
|
347
|
+
severity: normalizeEarlyLoopSeverityInline(row.severity),
|
|
348
|
+
locator,
|
|
349
|
+
summary
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function normalizeEarlyLoopMaxIterationsInline(value) {
|
|
354
|
+
return Number.isInteger(value) && value >= 1 ? value : 3;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function earlyLoopSeverityWeightInline(value) {
|
|
358
|
+
if (value === "critical") return 3;
|
|
359
|
+
if (value === "important") return 2;
|
|
360
|
+
return 1;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function sortEarlyLoopConcernsInline(a, b) {
|
|
364
|
+
const severityDiff = earlyLoopSeverityWeightInline(b.severity) - earlyLoopSeverityWeightInline(a.severity);
|
|
365
|
+
if (severityDiff !== 0) return severityDiff;
|
|
366
|
+
if (a.firstSeenIteration !== b.firstSeenIteration) {
|
|
367
|
+
return a.firstSeenIteration - b.firstSeenIteration;
|
|
368
|
+
}
|
|
369
|
+
if (a.lastSeenIteration !== b.lastSeenIteration) {
|
|
370
|
+
return a.lastSeenIteration - b.lastSeenIteration;
|
|
371
|
+
}
|
|
372
|
+
return String(a.id).localeCompare(String(b.id), "en");
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function formatEarlyLoopStatusLineInline(status) {
|
|
376
|
+
if (!status || typeof status !== "object") return "";
|
|
377
|
+
const convergence = status.convergenceTripped ? "tripped" : "clear";
|
|
378
|
+
return "Early Loop: stage=" + String(status.stage) +
|
|
379
|
+
", iter=" + String(status.iteration) + "/" + String(status.maxIterations) +
|
|
380
|
+
", open=" + String(Array.isArray(status.openConcerns) ? status.openConcerns.length : 0) +
|
|
381
|
+
", convergence=" + convergence;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
async function computeEarlyLoopStatusInline(stateDir, stageId, runId, maxIterations) {
|
|
385
|
+
const filePath = path.join(stateDir, "early-loop-log.jsonl");
|
|
386
|
+
const raw = await readTextFile(filePath, "");
|
|
387
|
+
const maxIters = normalizeEarlyLoopMaxIterationsInline(maxIterations);
|
|
388
|
+
const concernsMap = new Map();
|
|
389
|
+
let previousSnapshotKey = "";
|
|
390
|
+
let sameConcernStreak = 0;
|
|
391
|
+
let convergenceTripped = false;
|
|
392
|
+
let escalationReason = undefined;
|
|
393
|
+
let currentIteration = 0;
|
|
394
|
+
let lastSeenConcernIds = [];
|
|
395
|
+
|
|
396
|
+
for (const rawLine of raw.split(/\\r?\\n/gu)) {
|
|
397
|
+
const line = rawLine.trim();
|
|
398
|
+
if (line.length === 0) continue;
|
|
399
|
+
let parsed;
|
|
400
|
+
try {
|
|
401
|
+
parsed = JSON.parse(line);
|
|
402
|
+
} catch {
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) continue;
|
|
406
|
+
const rowRunId = typeof parsed.runId === "string" && parsed.runId.trim().length > 0
|
|
407
|
+
? parsed.runId.trim()
|
|
408
|
+
: "active";
|
|
409
|
+
const rowStage = typeof parsed.stage === "string" && parsed.stage.trim().length > 0
|
|
410
|
+
? parsed.stage.trim()
|
|
411
|
+
: "brainstorm";
|
|
412
|
+
if (rowRunId !== runId || rowStage !== stageId) continue;
|
|
413
|
+
|
|
414
|
+
currentIteration += 1;
|
|
415
|
+
const iteration = Number.isInteger(parsed.iteration) && parsed.iteration >= 1
|
|
416
|
+
? parsed.iteration
|
|
417
|
+
: currentIteration;
|
|
418
|
+
const seenThisIteration = new Set();
|
|
419
|
+
const concerns = Array.isArray(parsed.concerns) ? parsed.concerns : [];
|
|
420
|
+
for (const rawConcern of concerns) {
|
|
421
|
+
const concern = normalizeEarlyLoopConcernInline(rawConcern);
|
|
422
|
+
if (!concern) continue;
|
|
423
|
+
seenThisIteration.add(concern.id);
|
|
424
|
+
const existing = concernsMap.get(concern.id);
|
|
425
|
+
if (!existing) {
|
|
426
|
+
concernsMap.set(concern.id, {
|
|
427
|
+
id: concern.id,
|
|
428
|
+
severity: concern.severity,
|
|
429
|
+
locator: concern.locator,
|
|
430
|
+
summary: concern.summary,
|
|
431
|
+
firstSeenIteration: iteration,
|
|
432
|
+
lastSeenIteration: iteration
|
|
433
|
+
});
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
existing.lastSeenIteration = iteration;
|
|
437
|
+
existing.locator = concern.locator;
|
|
438
|
+
existing.summary = concern.summary;
|
|
439
|
+
if (earlyLoopSeverityWeightInline(concern.severity) >= earlyLoopSeverityWeightInline(existing.severity)) {
|
|
440
|
+
existing.severity = concern.severity;
|
|
441
|
+
}
|
|
442
|
+
delete existing.resolvedAtIteration;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
const resolvedConcernIds = Array.isArray(parsed.resolvedConcernIds)
|
|
446
|
+
? parsed.resolvedConcernIds
|
|
447
|
+
.filter((entry) => typeof entry === "string" && entry.trim().length > 0)
|
|
448
|
+
.map((entry) => entry.trim())
|
|
449
|
+
: [];
|
|
450
|
+
for (const concernId of resolvedConcernIds) {
|
|
451
|
+
const existing = concernsMap.get(concernId);
|
|
452
|
+
if (!existing) continue;
|
|
453
|
+
if (seenThisIteration.has(concernId)) continue;
|
|
454
|
+
if (existing.resolvedAtIteration === undefined) {
|
|
455
|
+
existing.resolvedAtIteration = iteration;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
for (const concern of concernsMap.values()) {
|
|
460
|
+
if (concern.resolvedAtIteration !== undefined) continue;
|
|
461
|
+
if (seenThisIteration.has(concern.id)) continue;
|
|
462
|
+
concern.resolvedAtIteration = iteration;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const openConcernIds = Array.from(concernsMap.values())
|
|
466
|
+
.filter((concern) => concern.resolvedAtIteration === undefined)
|
|
467
|
+
.map((concern) => concern.id)
|
|
468
|
+
.sort((a, b) => String(a).localeCompare(String(b), "en"));
|
|
469
|
+
lastSeenConcernIds = openConcernIds;
|
|
470
|
+
const snapshotKey = openConcernIds.join("|");
|
|
471
|
+
if (snapshotKey.length > 0 && snapshotKey === previousSnapshotKey) {
|
|
472
|
+
sameConcernStreak += 1;
|
|
473
|
+
if (!convergenceTripped && sameConcernStreak >= 2) {
|
|
474
|
+
convergenceTripped = true;
|
|
475
|
+
escalationReason = "same concerns " + String(sameConcernStreak) + " iterations in a row";
|
|
476
|
+
}
|
|
477
|
+
} else {
|
|
478
|
+
sameConcernStreak = snapshotKey.length > 0 ? 1 : 0;
|
|
479
|
+
}
|
|
480
|
+
previousSnapshotKey = snapshotKey;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const openConcerns = Array.from(concernsMap.values())
|
|
484
|
+
.filter((concern) => concern.resolvedAtIteration === undefined)
|
|
485
|
+
.sort(sortEarlyLoopConcernsInline);
|
|
486
|
+
const resolvedConcerns = Array.from(concernsMap.values())
|
|
487
|
+
.filter((concern) => concern.resolvedAtIteration !== undefined)
|
|
488
|
+
.sort((a, b) => {
|
|
489
|
+
if (a.resolvedAtIteration !== b.resolvedAtIteration) {
|
|
490
|
+
return a.resolvedAtIteration - b.resolvedAtIteration;
|
|
491
|
+
}
|
|
492
|
+
return sortEarlyLoopConcernsInline(a, b);
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
if (!convergenceTripped && openConcerns.length > 0 && currentIteration >= maxIters) {
|
|
496
|
+
convergenceTripped = true;
|
|
497
|
+
escalationReason = "max iterations " + String(maxIters) +
|
|
498
|
+
" reached with " + String(openConcerns.length) + " open concern(s)";
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
return {
|
|
502
|
+
schemaVersion: 1,
|
|
503
|
+
stage: stageId,
|
|
504
|
+
runId,
|
|
505
|
+
iteration: currentIteration,
|
|
506
|
+
maxIterations: maxIters,
|
|
507
|
+
openConcerns,
|
|
508
|
+
resolvedConcerns,
|
|
509
|
+
lastSeenConcernIds,
|
|
510
|
+
convergenceTripped,
|
|
511
|
+
...(escalationReason ? { escalationReason } : {}),
|
|
512
|
+
lastUpdatedAt: new Date().toISOString()
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
`;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* - the per-harness JSON generators in `./observe.ts`
|
|
7
7
|
* (claude/cursor/codex hook documents),
|
|
8
|
-
* - the semantic coverage map in `./hook-events.ts` (docs +
|
|
8
|
+
* - the semantic coverage map in `./hook-events.ts` (docs + sync/runtime checks),
|
|
9
9
|
* - the `requiredEvents` list embedded in `src/hook-schemas/*.v1.json`
|
|
10
10
|
* (enforced by a parity test).
|
|
11
11
|
*
|
|
@@ -74,6 +74,6 @@ export declare function groupBindingsByEvent(harness: HookManifestHarness): Even
|
|
|
74
74
|
/** Distinct harness-native event names covered by the manifest. */
|
|
75
75
|
export declare function requiredEventsFor(harness: HookManifestHarness): string[];
|
|
76
76
|
/**
|
|
77
|
-
* Human-readable per-harness semantic coverage used by docs and
|
|
77
|
+
* Human-readable per-harness semantic coverage used by docs and sync/runtime diagnostics.
|
|
78
78
|
*/
|
|
79
79
|
export declare function semanticEventCoverage(harness: HookManifestHarness): Partial<Record<HookSemanticEvent, string>>;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* - the per-harness JSON generators in `./observe.ts`
|
|
7
7
|
* (claude/cursor/codex hook documents),
|
|
8
|
-
* - the semantic coverage map in `./hook-events.ts` (docs +
|
|
8
|
+
* - the semantic coverage map in `./hook-events.ts` (docs + sync/runtime checks),
|
|
9
9
|
* - the `requiredEvents` list embedded in `src/hook-schemas/*.v1.json`
|
|
10
10
|
* (enforced by a parity test).
|
|
11
11
|
*
|
|
@@ -177,7 +177,7 @@ export function requiredEventsFor(harness) {
|
|
|
177
177
|
return ordered;
|
|
178
178
|
}
|
|
179
179
|
/**
|
|
180
|
-
* Human-readable per-harness semantic coverage used by docs and
|
|
180
|
+
* Human-readable per-harness semantic coverage used by docs and sync/runtime diagnostics.
|
|
181
181
|
*/
|
|
182
182
|
export function semanticEventCoverage(harness) {
|
|
183
183
|
const out = {};
|
package/dist/content/hooks.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export declare function startFlowScript(): string;
|
|
2
|
+
export declare function cancelRunScript(): string;
|
|
2
3
|
export declare function stageCompleteScript(): string;
|
|
3
4
|
export declare function delegationRecordScript(): string;
|
|
4
5
|
export declare function runHookCmdScript(): string;
|
package/dist/content/hooks.js
CHANGED
|
@@ -26,7 +26,7 @@ function resolveCliRuntimeForGeneratedHook() {
|
|
|
26
26
|
}
|
|
27
27
|
return { entrypoint: null, argsPrefix: [] };
|
|
28
28
|
}
|
|
29
|
-
function internalHelperScript(helperName, internalSubcommand, usage) {
|
|
29
|
+
function internalHelperScript(helperName, internalSubcommand, usage, options) {
|
|
30
30
|
const cliRuntime = resolveCliRuntimeForGeneratedHook();
|
|
31
31
|
return `#!/usr/bin/env node
|
|
32
32
|
import fs from "node:fs/promises";
|
|
@@ -40,6 +40,8 @@ const CCLAW_CLI_ARGS_PREFIX = ${JSON.stringify(cliRuntime.argsPrefix)};
|
|
|
40
40
|
const HELPER_NAME = ${JSON.stringify(helperName)};
|
|
41
41
|
const INTERNAL_SUBCOMMAND = ${JSON.stringify(internalSubcommand)};
|
|
42
42
|
const USAGE = ${JSON.stringify(usage)};
|
|
43
|
+
const POSITIONAL_ARG_NAME = ${JSON.stringify(options?.positionalArgName ?? null)};
|
|
44
|
+
const POSITIONAL_ARG_REQUIRED = ${JSON.stringify(options?.positionalArgRequired === true)};
|
|
43
45
|
|
|
44
46
|
async function detectRoot() {
|
|
45
47
|
const candidates = [
|
|
@@ -69,11 +71,22 @@ function printUsage() {
|
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
async function main() {
|
|
72
|
-
const [, , ...
|
|
73
|
-
if (
|
|
74
|
+
const [, , ...argvTokens] = process.argv;
|
|
75
|
+
if (argvTokens.includes("--help") || argvTokens.includes("-h")) {
|
|
74
76
|
printUsage();
|
|
75
77
|
return;
|
|
76
78
|
}
|
|
79
|
+
let positionalArg = "";
|
|
80
|
+
let flags = argvTokens;
|
|
81
|
+
if (POSITIONAL_ARG_NAME !== null) {
|
|
82
|
+
positionalArg = (argvTokens[0] ?? "").trim();
|
|
83
|
+
flags = argvTokens.slice(1);
|
|
84
|
+
if (POSITIONAL_ARG_REQUIRED && positionalArg.length === 0) {
|
|
85
|
+
printUsage();
|
|
86
|
+
process.exitCode = 1;
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
77
90
|
|
|
78
91
|
const root = await detectRoot();
|
|
79
92
|
const runtimePath = path.join(root, RUNTIME_ROOT);
|
|
@@ -112,7 +125,12 @@ async function main() {
|
|
|
112
125
|
return;
|
|
113
126
|
}
|
|
114
127
|
|
|
115
|
-
const
|
|
128
|
+
const internalArgs =
|
|
129
|
+
POSITIONAL_ARG_NAME !== null
|
|
130
|
+
? [INTERNAL_SUBCOMMAND, positionalArg, ...flags]
|
|
131
|
+
: [INTERNAL_SUBCOMMAND, ...flags];
|
|
132
|
+
|
|
133
|
+
const child = spawn(process.execPath, [cliEntrypoint, ...cliArgsPrefix, "internal", ...internalArgs], {
|
|
116
134
|
cwd: root,
|
|
117
135
|
env: process.env,
|
|
118
136
|
stdio: "inherit"
|
|
@@ -124,7 +142,7 @@ async function main() {
|
|
|
124
142
|
const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
|
|
125
143
|
if (code === "ENOENT") {
|
|
126
144
|
process.stderr.write(
|
|
127
|
-
"[cclaw] " + HELPER_NAME + ": node executable not found while invoking local runtime. Re-run npx cclaw-cli
|
|
145
|
+
"[cclaw] " + HELPER_NAME + ": node executable not found while invoking local runtime. Re-run npx cclaw-cli sync.\\n"
|
|
128
146
|
);
|
|
129
147
|
} else {
|
|
130
148
|
process.stderr.write(
|
|
@@ -155,137 +173,14 @@ void main();
|
|
|
155
173
|
export function startFlowScript() {
|
|
156
174
|
return internalHelperScript("start-flow", "start-flow", "Usage: node " + RUNTIME_ROOT + "/hooks/start-flow.mjs --track=<standard|medium|quick> [--class=...] [--prompt=...] [--stack=...] [--reason=...] [--reclassify] [--force-reset]");
|
|
157
175
|
}
|
|
158
|
-
export function
|
|
159
|
-
|
|
160
|
-
return `#!/usr/bin/env node
|
|
161
|
-
import fs from "node:fs/promises";
|
|
162
|
-
import path from "node:path";
|
|
163
|
-
import process from "node:process";
|
|
164
|
-
import { spawn } from "node:child_process";
|
|
165
|
-
|
|
166
|
-
const RUNTIME_ROOT = ${JSON.stringify(RUNTIME_ROOT)};
|
|
167
|
-
const CCLAW_CLI_ENTRYPOINT = ${JSON.stringify(cliRuntime.entrypoint)};
|
|
168
|
-
const CCLAW_CLI_ARGS_PREFIX = ${JSON.stringify(cliRuntime.argsPrefix)};
|
|
169
|
-
|
|
170
|
-
async function detectRoot() {
|
|
171
|
-
const candidates = [
|
|
172
|
-
process.env.CCLAW_PROJECT_ROOT,
|
|
173
|
-
process.env.CLAUDE_PROJECT_DIR,
|
|
174
|
-
process.env.CURSOR_PROJECT_DIR,
|
|
175
|
-
process.env.CURSOR_PROJECT_ROOT,
|
|
176
|
-
process.env.OPENCODE_PROJECT_DIR,
|
|
177
|
-
process.env.OPENCODE_PROJECT_ROOT,
|
|
178
|
-
process.cwd()
|
|
179
|
-
].filter((value) => typeof value === "string" && value.length > 0);
|
|
180
|
-
|
|
181
|
-
for (const candidate of candidates) {
|
|
182
|
-
try {
|
|
183
|
-
const runtimePath = path.join(candidate, RUNTIME_ROOT);
|
|
184
|
-
const stat = await fs.stat(runtimePath);
|
|
185
|
-
if (stat.isDirectory()) return candidate;
|
|
186
|
-
} catch {
|
|
187
|
-
// continue
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
return candidates[0] || process.cwd();
|
|
176
|
+
export function cancelRunScript() {
|
|
177
|
+
return internalHelperScript("cancel-run", "cancel-run", "Usage: node " + RUNTIME_ROOT + "/hooks/cancel-run.mjs --reason=<text> [--disposition=<cancelled|abandoned>] [--name=<slug>]");
|
|
191
178
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
"/hooks/stage-complete.mjs <stage> [--passed=...] [--evidence-json=...] [--waive-delegation=...] [--waiver-reason=...] [--json]\\n"
|
|
198
|
-
);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
async function main() {
|
|
202
|
-
const [, , stage, ...flags] = process.argv;
|
|
203
|
-
if (!stage || stage.trim().length === 0) {
|
|
204
|
-
printUsage();
|
|
205
|
-
process.exitCode = 1;
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
const root = await detectRoot();
|
|
210
|
-
const runtimePath = path.join(root, RUNTIME_ROOT);
|
|
211
|
-
try {
|
|
212
|
-
const stat = await fs.stat(runtimePath);
|
|
213
|
-
if (!stat.isDirectory()) throw new Error("not-dir");
|
|
214
|
-
} catch {
|
|
215
|
-
process.stderr.write("[cclaw] stage-complete: runtime root not found at " + runtimePath + "\\n");
|
|
216
|
-
process.exitCode = 1;
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
const cliEntrypoint = process.env.CCLAW_CLI_JS || CCLAW_CLI_ENTRYPOINT;
|
|
221
|
-
const cliArgsPrefix = process.env.CCLAW_CLI_JS ? [] : CCLAW_CLI_ARGS_PREFIX;
|
|
222
|
-
if (!cliEntrypoint || cliEntrypoint.trim().length === 0) {
|
|
223
|
-
process.stderr.write(
|
|
224
|
-
"[cclaw] stage-complete: local Node runtime entrypoint is missing. Re-run npx cclaw-cli sync, or set CCLAW_CLI_JS=/absolute/path/to/dist/cli.js for this session.\\n"
|
|
225
|
-
);
|
|
226
|
-
process.exitCode = 1;
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
try {
|
|
231
|
-
const stat = await fs.stat(cliEntrypoint);
|
|
232
|
-
if (!stat.isFile()) throw new Error("not-file");
|
|
233
|
-
for (const argPath of cliArgsPrefix) {
|
|
234
|
-
if (typeof argPath !== "string" || argPath.startsWith("-")) continue;
|
|
235
|
-
const argStat = await fs.stat(argPath);
|
|
236
|
-
if (!argStat.isFile()) throw new Error("arg-not-file");
|
|
237
|
-
}
|
|
238
|
-
} catch {
|
|
239
|
-
process.stderr.write(
|
|
240
|
-
"[cclaw] stage-complete: local Node runtime entrypoint not found at " + cliEntrypoint + ". Re-run npx cclaw-cli sync, or set CCLAW_CLI_JS=/absolute/path/to/dist/cli.js for this session.\\n"
|
|
241
|
-
);
|
|
242
|
-
process.exitCode = 1;
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const child = spawn(
|
|
247
|
-
process.execPath,
|
|
248
|
-
[cliEntrypoint, ...cliArgsPrefix, "internal", "advance-stage", stage, ...flags],
|
|
249
|
-
{
|
|
250
|
-
cwd: root,
|
|
251
|
-
env: process.env,
|
|
252
|
-
stdio: "inherit"
|
|
253
|
-
}
|
|
254
|
-
);
|
|
255
|
-
let spawnErrored = false;
|
|
256
|
-
|
|
257
|
-
child.on("error", (error) => {
|
|
258
|
-
spawnErrored = true;
|
|
259
|
-
const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
|
|
260
|
-
if (code === "ENOENT") {
|
|
261
|
-
process.stderr.write(
|
|
262
|
-
"[cclaw] stage-complete: node executable not found while invoking local runtime. Re-run npx cclaw-cli doctor.\\n"
|
|
263
|
-
);
|
|
264
|
-
} else {
|
|
265
|
-
process.stderr.write(
|
|
266
|
-
"[cclaw] stage-complete: failed to invoke local Node advance-stage runtime (" +
|
|
267
|
-
(error instanceof Error ? error.message : String(error)) +
|
|
268
|
-
").\\n"
|
|
269
|
-
);
|
|
270
|
-
}
|
|
271
|
-
process.exitCode = 1;
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
child.on("close", (code, signal) => {
|
|
275
|
-
if (spawnErrored) {
|
|
276
|
-
process.exitCode = 1;
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
if (signal) {
|
|
280
|
-
process.exitCode = 1;
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
process.exitCode = typeof code === "number" && code >= 0 ? code : 1;
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
void main();
|
|
288
|
-
`;
|
|
179
|
+
export function stageCompleteScript() {
|
|
180
|
+
return internalHelperScript("stage-complete", "advance-stage", "Usage: node " + RUNTIME_ROOT + "/hooks/stage-complete.mjs <stage> [--passed=...] [--evidence-json=...] [--waive-delegation=...] [--waiver-reason=...] [--accept-proactive-waiver] [--accept-proactive-waiver-reason=...] [--json]", {
|
|
181
|
+
positionalArgName: "stage",
|
|
182
|
+
positionalArgRequired: true
|
|
183
|
+
});
|
|
289
184
|
}
|
|
290
185
|
export function delegationRecordScript() {
|
|
291
186
|
return `#!/usr/bin/env node
|
|
@@ -669,7 +564,7 @@ set "RUNTIME=%HOOK_DIR%run-hook.mjs"
|
|
|
669
564
|
where node >nul 2>nul
|
|
670
565
|
if %ERRORLEVEL% neq 0 (
|
|
671
566
|
REM Best-effort: missing node should not block harness execution loops.
|
|
672
|
-
echo [cclaw] run-hook.cmd: node not found; cclaw hook skipped. Run npx cclaw-cli
|
|
567
|
+
echo [cclaw] run-hook.cmd: node not found; cclaw hook skipped. Run npx cclaw-cli sync. >&2
|
|
673
568
|
exit /b 0
|
|
674
569
|
)
|
|
675
570
|
node "%RUNTIME%" %*
|
|
@@ -681,7 +576,7 @@ if [ "$#" -lt 1 ]; then
|
|
|
681
576
|
exit 1
|
|
682
577
|
fi
|
|
683
578
|
if ! command -v node >/dev/null 2>&1; then
|
|
684
|
-
echo "[cclaw] run-hook.cmd: node not found; cclaw hook skipped. Run npx cclaw-cli
|
|
579
|
+
echo "[cclaw] run-hook.cmd: node not found; cclaw hook skipped. Run npx cclaw-cli sync." >&2
|
|
685
580
|
exit 0
|
|
686
581
|
fi
|
|
687
582
|
exec node "\${SCRIPT_DIR}/run-hook.mjs" "$@"
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type IdeaFrameId } from "./idea-frames.js";
|
|
2
|
+
export interface IdeaCommandOptions {
|
|
3
|
+
frameIds?: readonly IdeaFrameId[];
|
|
4
|
+
mode?: "repo-grounded" | "elsewhere-software" | "elsewhere-non-software" | "narrow";
|
|
5
|
+
}
|
|
6
|
+
export declare function minimumDistinctIdeaFrames(frameCount: number, mode?: IdeaCommandOptions["mode"]): number;
|
|
7
|
+
export declare function ideaCommandContract(options?: IdeaCommandOptions): string;
|
|
8
|
+
export declare function ideaCommandSkillMarkdown(options?: IdeaCommandOptions): string;
|