cclaw-cli 0.48.7 → 0.48.9
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/hooks.d.ts +1 -0
- package/dist/content/hooks.js +1 -0
- package/dist/content/node-hooks.d.ts +14 -0
- package/dist/content/node-hooks.js +1607 -0
- package/dist/content/observe.js +2 -2
- package/dist/content/opencode-plugin.js +5 -5
- package/dist/doctor.js +1 -1
- package/dist/install.js +13 -3
- package/dist/internal/advance-stage.js +53 -2
- package/package.json +1 -1
package/dist/content/observe.js
CHANGED
|
@@ -1660,7 +1660,7 @@ exit 0
|
|
|
1660
1660
|
* Updated hooks.json generators with PreToolUse/PostToolUse observation.
|
|
1661
1661
|
*/
|
|
1662
1662
|
function hookDispatcherCommand(scriptName) {
|
|
1663
|
-
return `
|
|
1663
|
+
return `node ${RUNTIME_ROOT}/hooks/run-hook.mjs ${scriptName}`;
|
|
1664
1664
|
}
|
|
1665
1665
|
export function claudeHooksJsonWithObservation() {
|
|
1666
1666
|
return JSON.stringify({
|
|
@@ -1799,7 +1799,7 @@ export function codexHooksJsonWithObservation() {
|
|
|
1799
1799
|
command: hookDispatcherCommand("workflow-guard.sh")
|
|
1800
1800
|
}, {
|
|
1801
1801
|
type: "command",
|
|
1802
|
-
command: "
|
|
1802
|
+
command: hookDispatcherCommand("verify-current-state")
|
|
1803
1803
|
}]
|
|
1804
1804
|
}],
|
|
1805
1805
|
PreToolUse: [{
|
|
@@ -272,9 +272,9 @@ export default function cclawPlugin(ctx) {
|
|
|
272
272
|
});
|
|
273
273
|
}
|
|
274
274
|
|
|
275
|
-
async function runHookScript(
|
|
275
|
+
async function runHookScript(hookName, payload = {}) {
|
|
276
276
|
const { spawn } = await import("node:child_process");
|
|
277
|
-
const
|
|
277
|
+
const hookRuntimePath = join(root, "${RUNTIME_ROOT}/hooks/run-hook.mjs");
|
|
278
278
|
const input = typeof payload === "string" ? payload : JSON.stringify(payload ?? {});
|
|
279
279
|
return scheduleHookTask(() => new Promise((resolve) => {
|
|
280
280
|
let stderr = "";
|
|
@@ -287,7 +287,7 @@ export default function cclawPlugin(ctx) {
|
|
|
287
287
|
|
|
288
288
|
let child;
|
|
289
289
|
try {
|
|
290
|
-
child = spawn(
|
|
290
|
+
child = spawn(process.execPath, [hookRuntimePath, hookName], {
|
|
291
291
|
cwd: root,
|
|
292
292
|
stdio: ["pipe", "ignore", "pipe"]
|
|
293
293
|
});
|
|
@@ -299,7 +299,7 @@ export default function cclawPlugin(ctx) {
|
|
|
299
299
|
const timer = setTimeout(() => {
|
|
300
300
|
child.kill("SIGKILL");
|
|
301
301
|
if (stderr.length > 0) {
|
|
302
|
-
console.error("[cclaw] opencode hook timeout: " +
|
|
302
|
+
console.error("[cclaw] opencode hook timeout: " + hookName + " stderr=" + stderr.slice(-1200));
|
|
303
303
|
}
|
|
304
304
|
finish(false);
|
|
305
305
|
}, 20_000);
|
|
@@ -318,7 +318,7 @@ export default function cclawPlugin(ctx) {
|
|
|
318
318
|
clearTimeout(timer);
|
|
319
319
|
const ok = code === 0;
|
|
320
320
|
if (!ok && stderr.length > 0) {
|
|
321
|
-
console.error("[cclaw] opencode hook failed: " +
|
|
321
|
+
console.error("[cclaw] opencode hook failed: " + hookName + " stderr=" + stderr.slice(-1200));
|
|
322
322
|
}
|
|
323
323
|
finish(ok);
|
|
324
324
|
});
|
package/dist/doctor.js
CHANGED
|
@@ -879,7 +879,7 @@ export async function doctorChecks(projectRoot, options = {}) {
|
|
|
879
879
|
const codexWiringOk = codexSessionCmds.some((cmd) => cmd.includes("session-start.sh")) &&
|
|
880
880
|
codexUserPromptCmds.some((cmd) => cmd.includes("prompt-guard.sh")) &&
|
|
881
881
|
codexUserPromptCmds.some((cmd) => cmd.includes("workflow-guard.sh")) &&
|
|
882
|
-
codexUserPromptCmds.some((cmd) => cmd.includes("verify-current-state
|
|
882
|
+
codexUserPromptCmds.some((cmd) => cmd.includes("verify-current-state")) &&
|
|
883
883
|
codexPreCmds.some((cmd) => cmd.includes("prompt-guard.sh")) &&
|
|
884
884
|
codexPreCmds.some((cmd) => cmd.includes("workflow-guard.sh")) &&
|
|
885
885
|
codexPostCmds.some((cmd) => cmd.includes("context-monitor.sh")) &&
|
package/dist/install.js
CHANGED
|
@@ -26,6 +26,7 @@ import { sessionHooksSkillMarkdown } from "./content/session-hooks.js";
|
|
|
26
26
|
import { ironLawRuntimeDocument, ironLawsSkillMarkdown } from "./content/iron-laws.js";
|
|
27
27
|
import { hookLibScript, sessionStartScript, stopCheckpointScript, runHookDispatcherScript, stageCompleteScript, preCompactScript, opencodePluginJs, claudeHooksJson, codexHooksJson, cursorHooksJson } from "./content/hooks.js";
|
|
28
28
|
import { contextMonitorScript, promptGuardScript, workflowGuardScript } from "./content/observe.js";
|
|
29
|
+
import { nodeHookRuntimeScript } from "./content/node-hooks.js";
|
|
29
30
|
import { META_SKILL_NAME, usingCclawSkillMarkdown } from "./content/meta-skill.js";
|
|
30
31
|
import { decisionProtocolMarkdown, completionProtocolMarkdown, ethosProtocolMarkdown } from "./content/protocols.js";
|
|
31
32
|
import { ARTIFACT_TEMPLATES, CURSOR_WORKFLOW_RULE_MDC, RULEBOOK_MARKDOWN, buildRulesJson } from "./content/templates.js";
|
|
@@ -646,6 +647,13 @@ async function writeHooks(projectRoot, config) {
|
|
|
646
647
|
tddProductionPathPatterns: config.tdd?.productionPathPatterns
|
|
647
648
|
}));
|
|
648
649
|
await writeFileSafe(path.join(hooksDir, "context-monitor.sh"), contextMonitorScript());
|
|
650
|
+
await writeFileSafe(path.join(hooksDir, "run-hook.mjs"), nodeHookRuntimeScript({
|
|
651
|
+
promptGuardMode: config.promptGuardMode ?? config.strictness ?? "advisory",
|
|
652
|
+
workflowGuardMode: config.strictness ?? "advisory",
|
|
653
|
+
tddEnforcementMode: config.tddEnforcement ?? config.strictness ?? "advisory",
|
|
654
|
+
tddTestPathPatterns: config.tdd?.testPathPatterns ?? config.tddTestGlobs,
|
|
655
|
+
tddProductionPathPatterns: config.tdd?.productionPathPatterns
|
|
656
|
+
}));
|
|
649
657
|
const opencodePluginSource = opencodePluginJs();
|
|
650
658
|
await writeFileSafe(path.join(hooksDir, "opencode-plugin.mjs"), opencodePluginSource);
|
|
651
659
|
try {
|
|
@@ -659,6 +667,7 @@ async function writeHooks(projectRoot, config) {
|
|
|
659
667
|
"prompt-guard.sh",
|
|
660
668
|
"workflow-guard.sh",
|
|
661
669
|
"context-monitor.sh",
|
|
670
|
+
"run-hook.mjs",
|
|
662
671
|
"opencode-plugin.mjs"
|
|
663
672
|
]) {
|
|
664
673
|
await fs.chmod(path.join(hooksDir, script), 0o755);
|
|
@@ -1347,12 +1356,13 @@ function stripManagedHookCommands(value) {
|
|
|
1347
1356
|
function isManagedRuntimeHookCommand(command) {
|
|
1348
1357
|
const normalized = command.trim().replace(/\s+/gu, " ");
|
|
1349
1358
|
if (/(^|\s)(?:bash\s+)?(?:\.\/)?\.cclaw\/hooks\/(?:session-start|stop-checkpoint|pre-compact|prompt-guard|workflow-guard|context-monitor)\.sh(?:\s|$)/u.test(normalized) ||
|
|
1350
|
-
/(^|\s)(?:bash\s+)?(?:\.\/)?\.cclaw\/hooks\/run-hook\.cmd\s+(?:session-start|stop-checkpoint|pre-compact|prompt-guard|workflow-guard|context-monitor)(?:\.sh)?(?:\s|$)/u.test(normalized)
|
|
1359
|
+
/(^|\s)(?:bash\s+)?(?:\.\/)?\.cclaw\/hooks\/run-hook\.cmd\s+(?:session-start|stop-checkpoint|pre-compact|prompt-guard|workflow-guard|context-monitor)(?:\.sh)?(?:\s|$)/u.test(normalized) ||
|
|
1360
|
+
/(^|\s)(?:node\s+)?(?:"|')?(?:\.\/)?\.cclaw\/hooks\/run-hook\.mjs(?:"|')?\s+(?:session-start|stop-checkpoint|pre-compact|prompt-guard|workflow-guard|context-monitor|verify-current-state)(?:\.sh)?(?:\s|$)/u.test(normalized)) {
|
|
1351
1361
|
return true;
|
|
1352
1362
|
}
|
|
1353
1363
|
// Codex UserPromptSubmit non-blocking state nudge:
|
|
1354
|
-
//
|
|
1355
|
-
return /internal verify-current-state
|
|
1364
|
+
// legacy shell and newer Node wrappers call this internal command.
|
|
1365
|
+
return /internal verify-current-state(?:\s|$)/u.test(normalized);
|
|
1356
1366
|
}
|
|
1357
1367
|
async function removeManagedHookEntries(hookFilePath) {
|
|
1358
1368
|
if (!(await exists(hookFilePath)))
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { spawn } from "node:child_process";
|
|
4
|
+
import process from "node:process";
|
|
3
5
|
import { RUNTIME_ROOT, SHIP_FINALIZATION_MODES } from "../constants.js";
|
|
4
6
|
import { stageSchema } from "../content/stage-schema.js";
|
|
5
7
|
import { appendDelegation, checkMandatoryDelegations } from "../delegation.js";
|
|
@@ -306,6 +308,17 @@ function parseVerifyCurrentStateArgs(tokens) {
|
|
|
306
308
|
}
|
|
307
309
|
return { quiet };
|
|
308
310
|
}
|
|
311
|
+
function parseHookArgs(tokens) {
|
|
312
|
+
const [hookName, ...rest] = tokens;
|
|
313
|
+
const normalizedHook = typeof hookName === "string" ? hookName.trim() : "";
|
|
314
|
+
if (normalizedHook.length === 0) {
|
|
315
|
+
throw new Error("internal hook requires a hook name: cclaw internal hook <name>.");
|
|
316
|
+
}
|
|
317
|
+
if (rest.length > 0) {
|
|
318
|
+
throw new Error(`Unknown arguments for internal hook: ${rest.join(" ")}`);
|
|
319
|
+
}
|
|
320
|
+
return { hookName: normalizedHook };
|
|
321
|
+
}
|
|
309
322
|
async function buildValidationReport(projectRoot, flowState) {
|
|
310
323
|
const delegation = await checkMandatoryDelegations(projectRoot, flowState.currentStage);
|
|
311
324
|
const gates = await verifyCurrentStageGateEvidence(projectRoot, flowState);
|
|
@@ -621,10 +634,45 @@ async function runVerifyCurrentState(projectRoot, args, io) {
|
|
|
621
634
|
}
|
|
622
635
|
return validation.ok ? 0 : 1;
|
|
623
636
|
}
|
|
637
|
+
async function runHookCommand(projectRoot, args, io) {
|
|
638
|
+
const runHookPath = path.join(projectRoot, RUNTIME_ROOT, "hooks", "run-hook.mjs");
|
|
639
|
+
try {
|
|
640
|
+
await fs.access(runHookPath);
|
|
641
|
+
}
|
|
642
|
+
catch {
|
|
643
|
+
io.stderr.write(`cclaw internal hook: missing hook runtime at ${runHookPath}. Run \`cclaw sync\` first.\n`);
|
|
644
|
+
return 1;
|
|
645
|
+
}
|
|
646
|
+
return await new Promise((resolve) => {
|
|
647
|
+
const child = spawn(process.execPath, [runHookPath, args.hookName], {
|
|
648
|
+
cwd: projectRoot,
|
|
649
|
+
env: process.env,
|
|
650
|
+
stdio: ["inherit", "pipe", "pipe"]
|
|
651
|
+
});
|
|
652
|
+
child.stdout.on("data", (chunk) => {
|
|
653
|
+
io.stdout.write(chunk);
|
|
654
|
+
});
|
|
655
|
+
child.stderr.on("data", (chunk) => {
|
|
656
|
+
io.stderr.write(chunk);
|
|
657
|
+
});
|
|
658
|
+
child.on("error", (err) => {
|
|
659
|
+
io.stderr.write(`cclaw internal hook: failed to launch runtime (${err instanceof Error ? err.message : String(err)}).\n`);
|
|
660
|
+
resolve(1);
|
|
661
|
+
});
|
|
662
|
+
child.on("close", (code, signal) => {
|
|
663
|
+
if (signal) {
|
|
664
|
+
io.stderr.write(`cclaw internal hook: runtime terminated by signal ${signal}.\n`);
|
|
665
|
+
resolve(1);
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
resolve(typeof code === "number" ? code : 1);
|
|
669
|
+
});
|
|
670
|
+
});
|
|
671
|
+
}
|
|
624
672
|
export async function runInternalCommand(projectRoot, argv, io) {
|
|
625
673
|
const [subcommand, ...tokens] = argv;
|
|
626
674
|
if (!subcommand) {
|
|
627
|
-
io.stderr.write("cclaw internal requires a subcommand: advance-stage | verify-flow-state-diff | verify-current-state | knowledge-digest | envelope-validate | tdd-red-evidence\n");
|
|
675
|
+
io.stderr.write("cclaw internal requires a subcommand: advance-stage | verify-flow-state-diff | verify-current-state | knowledge-digest | envelope-validate | tdd-red-evidence | hook\n");
|
|
628
676
|
return 1;
|
|
629
677
|
}
|
|
630
678
|
try {
|
|
@@ -646,7 +694,10 @@ export async function runInternalCommand(projectRoot, argv, io) {
|
|
|
646
694
|
if (subcommand === "tdd-red-evidence") {
|
|
647
695
|
return await runTddRedEvidenceCommand(projectRoot, tokens, io);
|
|
648
696
|
}
|
|
649
|
-
|
|
697
|
+
if (subcommand === "hook") {
|
|
698
|
+
return await runHookCommand(projectRoot, parseHookArgs(tokens), io);
|
|
699
|
+
}
|
|
700
|
+
io.stderr.write(`Unknown internal subcommand: ${subcommand}. Expected advance-stage | verify-flow-state-diff | verify-current-state | knowledge-digest | envelope-validate | tdd-red-evidence | hook\n`);
|
|
650
701
|
return 1;
|
|
651
702
|
}
|
|
652
703
|
catch (err) {
|