cclaw-cli 0.48.10 → 0.48.11
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/content/doctor-references.js +11 -7
- package/dist/content/node-hooks.js +11 -4
- package/dist/content/observe.js +4 -0
- package/dist/content/opencode-plugin.js +6 -3
- package/dist/doctor-registry.js +0 -9
- package/dist/doctor.js +3 -22
- package/dist/install.js +10 -1
- package/package.json +1 -1
|
@@ -13,7 +13,7 @@ Reference docs for \`cclaw doctor\` checks.
|
|
|
13
13
|
- \`state-and-gates.md\` - flow-state integrity and gate evidence contracts
|
|
14
14
|
- \`delegation-and-preamble.md\` - mandatory delegations and lightweight announce discipline
|
|
15
15
|
- \`traceability.md\` - spec/plan/tdd trace matrix expectations
|
|
16
|
-
- \`tooling-capabilities.md\` - local runtime prerequisites (
|
|
16
|
+
- \`tooling-capabilities.md\` - local runtime prerequisites (node only)
|
|
17
17
|
- \`config-and-policy.md\` - config schema, rules policy, and validation references
|
|
18
18
|
`,
|
|
19
19
|
"runtime-layout.md": `# Runtime Layout
|
|
@@ -116,17 +116,21 @@ Reference docs for \`cclaw doctor\` checks.
|
|
|
116
116
|
|
|
117
117
|
## Required
|
|
118
118
|
|
|
119
|
-
- \`
|
|
120
|
-
|
|
119
|
+
- \`node\` (>=20) — the only runtime dependency. All hooks, git-hook relays, and the
|
|
120
|
+
\`cclaw\` CLI itself run on Node.js. No \`bash\`, \`python3\`, or \`jq\` required.
|
|
121
|
+
- \`git\` — needed for worktree and pre-commit/pre-push relays.
|
|
121
122
|
|
|
122
|
-
##
|
|
123
|
+
## Not required (removed)
|
|
123
124
|
|
|
124
|
-
|
|
125
|
+
Earlier releases relied on \`bash\` to execute generated shell hooks and on
|
|
126
|
+
\`python3\`/\`jq\` as JSON fallback parsers. Node-only mode removes both: hooks
|
|
127
|
+
dispatch through \`node .cclaw/hooks/run-hook.mjs <hook-name>\`, so these tools
|
|
128
|
+
are no longer part of the supported runtime contract.
|
|
125
129
|
|
|
126
130
|
## Typical fixes
|
|
127
131
|
|
|
128
|
-
1. Install
|
|
129
|
-
2.
|
|
132
|
+
1. Install Node.js 20 or newer (matches \`package.json\` \`engines\`) and ensure \`node\` is on \`PATH\`.
|
|
133
|
+
2. Re-run \`cclaw sync\` to regenerate hook configs after upgrading Node.
|
|
130
134
|
`,
|
|
131
135
|
"config-and-policy.md": `# Config And Policy
|
|
132
136
|
|
|
@@ -186,12 +186,12 @@ async function detectRoot(env) {
|
|
|
186
186
|
try {
|
|
187
187
|
const runtimePath = path.join(candidate, RUNTIME_ROOT);
|
|
188
188
|
const stat = await fs.stat(runtimePath);
|
|
189
|
-
if (stat.isDirectory()) return candidate;
|
|
189
|
+
if (stat.isDirectory()) return { root: candidate, foundRuntime: true };
|
|
190
190
|
} catch {
|
|
191
191
|
// continue
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
|
-
return candidates[0] || process.cwd();
|
|
194
|
+
return { root: candidates[0] || process.cwd(), foundRuntime: false };
|
|
195
195
|
}
|
|
196
196
|
|
|
197
197
|
function toLower(value) {
|
|
@@ -1518,7 +1518,7 @@ async function handleVerifyCurrentState(runtime) {
|
|
|
1518
1518
|
: DEFAULT_WORKFLOW_GUARD_MODE;
|
|
1519
1519
|
const result = await runCclawInternal(runtime.root, ["verify-current-state", "--quiet"]);
|
|
1520
1520
|
if (result.missingBinary) {
|
|
1521
|
-
process.stderr.write("[cclaw]
|
|
1521
|
+
process.stderr.write("[cclaw] hook: cclaw binary is required for verify-current-state\\n");
|
|
1522
1522
|
return 1;
|
|
1523
1523
|
}
|
|
1524
1524
|
if (mode === "strict") {
|
|
@@ -1555,7 +1555,14 @@ async function main() {
|
|
|
1555
1555
|
}
|
|
1556
1556
|
|
|
1557
1557
|
const harness = detectHarness(process.env);
|
|
1558
|
-
const root = await detectRoot(process.env);
|
|
1558
|
+
const { root, foundRuntime } = await detectRoot(process.env);
|
|
1559
|
+
if (!foundRuntime) {
|
|
1560
|
+
// No .cclaw/ runtime in any candidate root — this directory is not
|
|
1561
|
+
// initialized for cclaw. Exit 0 silently so hooks never block harnesses
|
|
1562
|
+
// that run in unrelated repos; users initialize with \`cclaw init\`.
|
|
1563
|
+
process.exitCode = 0;
|
|
1564
|
+
return;
|
|
1565
|
+
}
|
|
1559
1566
|
const inputRaw = await readStdin();
|
|
1560
1567
|
const inputData = safeParseJson(inputRaw, {});
|
|
1561
1568
|
const runtime = {
|
package/dist/content/observe.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { RUNTIME_ROOT } from "../constants.js";
|
|
2
2
|
function hookDispatcherCommand(hookName) {
|
|
3
|
+
// RUNTIME_ROOT is a relative path (".cclaw") that currently contains no
|
|
4
|
+
// whitespace, so quoting is unnecessary inside the JSON-encoded command
|
|
5
|
+
// string. If RUNTIME_ROOT ever becomes configurable, wrap the path with
|
|
6
|
+
// JSON.stringify to survive spaces.
|
|
3
7
|
return `node ${RUNTIME_ROOT}/hooks/run-hook.mjs ${hookName}`;
|
|
4
8
|
}
|
|
5
9
|
export function claudeHooksJsonWithObservation() {
|
|
@@ -409,6 +409,12 @@ export default function cclawPlugin(ctx) {
|
|
|
409
409
|
: typeof payload;
|
|
410
410
|
console.error("[cclaw] opencode unknown event payload keys: " + keys);
|
|
411
411
|
}
|
|
412
|
+
// session.compacted must run pre-compact BEFORE refreshing the bootstrap
|
|
413
|
+
// cache, otherwise the injected system prompt still shows the pre-compact
|
|
414
|
+
// digest/state until the next lifecycle event.
|
|
415
|
+
if (eventType === "session.compacted") {
|
|
416
|
+
await runHookScript("pre-compact", eventData ?? {});
|
|
417
|
+
}
|
|
412
418
|
if (
|
|
413
419
|
eventType === "session.created" ||
|
|
414
420
|
eventType === "session.resumed" ||
|
|
@@ -424,9 +430,6 @@ export default function cclawPlugin(ctx) {
|
|
|
424
430
|
// until the next compaction or restart.
|
|
425
431
|
await refreshBootstrapCache(true);
|
|
426
432
|
}
|
|
427
|
-
if (eventType === "session.compacted") {
|
|
428
|
-
await runHookScript("pre-compact", eventData ?? {});
|
|
429
|
-
}
|
|
430
433
|
if (eventType === "session.idle") {
|
|
431
434
|
await runHookScript("stop-checkpoint", { loop_count: 0 });
|
|
432
435
|
}
|
package/dist/doctor-registry.js
CHANGED
|
@@ -30,15 +30,6 @@ const RULES = [
|
|
|
30
30
|
docRef: ref("runtime-layout.md")
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
|
-
{
|
|
34
|
-
test: /^capability:runtime:json_parser$/,
|
|
35
|
-
metadata: {
|
|
36
|
-
severity: "warning",
|
|
37
|
-
summary: "Optional JSON fallback parser availability.",
|
|
38
|
-
fix: "Install at least one of `python3` or `jq` for resilient fallback parsing.",
|
|
39
|
-
docRef: ref("tooling-capabilities.md")
|
|
40
|
-
}
|
|
41
|
-
},
|
|
42
33
|
{
|
|
43
34
|
test: /^capability:required:/,
|
|
44
35
|
metadata: {
|
package/dist/doctor.js
CHANGED
|
@@ -743,12 +743,9 @@ export async function doctorChecks(projectRoot, options = {}) {
|
|
|
743
743
|
}
|
|
744
744
|
}
|
|
745
745
|
}
|
|
746
|
-
// OpenCode plugin
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
ok: await exists(path.join(projectRoot, RUNTIME_ROOT, "hooks", "opencode-plugin.mjs")),
|
|
750
|
-
details: `${RUNTIME_ROOT}/hooks/opencode-plugin.mjs`
|
|
751
|
-
});
|
|
746
|
+
// OpenCode plugin deployed path. (Presence of the source under
|
|
747
|
+
// `${RUNTIME_ROOT}/hooks/opencode-plugin.mjs` is already asserted by the
|
|
748
|
+
// generic `hook:script:opencode-plugin.mjs` check above; avoid a duplicate.)
|
|
752
749
|
const opencodeEnabled = configuredHarnesses.includes("opencode");
|
|
753
750
|
const opencodeDeployed = await exists(path.join(projectRoot, ".opencode/plugins/cclaw-plugin.mjs"));
|
|
754
751
|
checks.push({
|
|
@@ -1009,27 +1006,11 @@ export async function doctorChecks(projectRoot, options = {}) {
|
|
|
1009
1006
|
});
|
|
1010
1007
|
}
|
|
1011
1008
|
const hasNode = await commandAvailable("node");
|
|
1012
|
-
const hasPython = await commandAvailable("python3");
|
|
1013
|
-
const hasJq = await commandAvailable("jq");
|
|
1014
1009
|
checks.push({
|
|
1015
1010
|
name: "capability:required:node",
|
|
1016
1011
|
ok: hasNode,
|
|
1017
1012
|
details: "node is required for cclaw runtime scripts and CLI wiring"
|
|
1018
1013
|
});
|
|
1019
|
-
checks.push({
|
|
1020
|
-
name: "warning:capability:jq",
|
|
1021
|
-
ok: true,
|
|
1022
|
-
details: hasJq
|
|
1023
|
-
? "jq available (optional)"
|
|
1024
|
-
: "warning: jq not found; Node hook runtime no longer depends on jq"
|
|
1025
|
-
});
|
|
1026
|
-
checks.push({
|
|
1027
|
-
name: "warning:capability:python3",
|
|
1028
|
-
ok: true,
|
|
1029
|
-
details: hasPython
|
|
1030
|
-
? "python3 available (optional)"
|
|
1031
|
-
: "warning: python3 not found; Node hook runtime no longer depends on python3"
|
|
1032
|
-
});
|
|
1033
1014
|
const windowsHookConfigCandidates = [
|
|
1034
1015
|
path.join(projectRoot, ".claude/hooks/hooks.json"),
|
|
1035
1016
|
path.join(projectRoot, ".cursor/hooks.json"),
|
package/dist/install.js
CHANGED
|
@@ -119,6 +119,11 @@ function resolveChangedFiles(root) {
|
|
|
119
119
|
const root = resolveRepoRoot();
|
|
120
120
|
const runtimeHook = path.join(root, RUNTIME_ROOT, "hooks", "run-hook.mjs");
|
|
121
121
|
if (!fs.existsSync(runtimeHook)) {
|
|
122
|
+
// cclaw git relay is installed but the runtime entrypoint is missing —
|
|
123
|
+
// warn visibly (without blocking the commit) so the drift is noticed.
|
|
124
|
+
process.stderr.write(
|
|
125
|
+
"[cclaw] " + HOOK_NAME + ": " + runtimeHook + " not found; run \`cclaw sync\` to reinstall\\n"
|
|
126
|
+
);
|
|
122
127
|
process.exit(0);
|
|
123
128
|
}
|
|
124
129
|
|
|
@@ -1428,7 +1433,11 @@ function stripManagedHookCommands(value) {
|
|
|
1428
1433
|
return { updated: root, changed: true };
|
|
1429
1434
|
}
|
|
1430
1435
|
function isManagedRuntimeHookCommand(command) {
|
|
1431
|
-
|
|
1436
|
+
// Normalize whitespace and collapse any Windows-style backslash path
|
|
1437
|
+
// separators to forward slashes so user-edited hook configs on Windows
|
|
1438
|
+
// (e.g. `node .cclaw\hooks\run-hook.mjs ...`) still round-trip through
|
|
1439
|
+
// sync without being duplicated alongside freshly generated entries.
|
|
1440
|
+
const normalized = command.trim().replace(/\s+/gu, " ").replace(/\\/gu, "/");
|
|
1432
1441
|
if (/(^|\s)(?:node\s+)?(?:"|')?(?:\.\/)?\.cclaw\/hooks\/run-hook\.mjs(?:"|')?\s+(?:session-start|stop-checkpoint|pre-compact|prompt-guard|workflow-guard|context-monitor|verify-current-state)(?:\s|$)/u.test(normalized)) {
|
|
1433
1442
|
return true;
|
|
1434
1443
|
}
|