cclaw-cli 0.48.8 → 0.48.10

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.
@@ -58,7 +58,7 @@ Knowledge capture is now stage-native:
58
58
  - Allowed payloads:
59
59
  - \`- None this stage.\` (explicit no-op)
60
60
  - JSON bullets with required keys \`type\`, \`trigger\`, \`action\`, \`confidence\` (optional keys may mirror the full JSONL schema fields).
61
- - During \`bash .cclaw/hooks/stage-complete.sh <stage>\`, cclaw:
61
+ - During \`node .cclaw/hooks/stage-complete.mjs <stage>\`, cclaw:
62
62
  1. validates \`## Learnings\`,
63
63
  2. appends deduped entries to \`${KNOWLEDGE_PATH}\`,
64
64
  3. writes a harvest marker into the artifact.
@@ -157,7 +157,7 @@ Manage the project knowledge store. One canonical file, strict JSONL:
157
157
  - \`${KNOWLEDGE_ARCHIVE_PATH}\` — soft-archive target written only by curate.
158
158
 
159
159
  Stage-native pipeline:
160
- - During \`stage-complete.sh\`, cclaw harvests \`## Learnings\` from the current
160
+ - During \`stage-complete.mjs\`, cclaw harvests \`## Learnings\` from the current
161
161
  stage artifact into \`${KNOWLEDGE_PATH}\` automatically.
162
162
  - Use \`/cc-learn\` for query, backfill, and curation workflows.
163
163
 
@@ -58,7 +58,7 @@ This is the only progression command the user needs to drive the entire flow. St
58
58
 
59
59
  → Load **\`${RUNTIME_ROOT}/skills/<skillFolder>/SKILL.md\`** and **\`${RUNTIME_ROOT}/commands/<currentStage>.md\`** for the current stage.
60
60
  → Execute that stage's protocol. The stage skill handles the full interaction including STOP points and gate tracking.
61
- → Stage completion must use \`bash .cclaw/hooks/stage-complete.sh <currentStage>\` (canonical), which validates delegations + gate evidence before mutating \`flow-state.json\`.
61
+ → Stage completion must use \`node .cclaw/hooks/stage-complete.mjs <currentStage>\` (canonical), which validates delegations + gate evidence before mutating \`flow-state.json\`.
62
62
 
63
63
  ### Path B: Current stage IS complete (all gates passed, all delegations satisfied)
64
64
 
@@ -188,7 +188,7 @@ Load the current stage's skill and command contract:
188
188
  - \`${RUNTIME_ROOT}/skills/<skillFolder>/SKILL.md\`
189
189
  - \`${RUNTIME_ROOT}/commands/<currentStage>.md\`
190
190
 
191
- Execute the stage protocol. The stage skill handles interaction, STOP points, gate tracking, and stage completion via \`bash .cclaw/hooks/stage-complete.sh <stage>\` (canonical flow-state mutation path).
191
+ Execute the stage protocol. The stage skill handles interaction, STOP points, gate tracking, and stage completion via \`node .cclaw/hooks/stage-complete.mjs <stage>\` (canonical flow-state mutation path).
192
192
 
193
193
  Special-case for review: if \`review_criticals_resolved\` is in \`blocked\`, route to rework instead of looping review forever — recommend \`/cc-ops rewind tdd "review_blocked_by_critical"\`.
194
194
 
@@ -99,6 +99,72 @@ async function readStdin() {
99
99
  });
100
100
  }
101
101
 
102
+ async function runCclawInternal(root, args) {
103
+ return await new Promise((resolve) => {
104
+ const isWindows = process.platform === "win32";
105
+ let settled = false;
106
+ let stderr = "";
107
+ const finalize = (value) => {
108
+ if (settled) return;
109
+ settled = true;
110
+ resolve(value);
111
+ };
112
+ let child;
113
+ try {
114
+ child = spawn(
115
+ isWindows ? "cmd.exe" : "cclaw",
116
+ isWindows ? ["/d", "/s", "/c", "cclaw", "internal", ...args] : ["internal", ...args],
117
+ {
118
+ cwd: root,
119
+ env: process.env,
120
+ stdio: ["ignore", "ignore", "pipe"]
121
+ }
122
+ );
123
+ } catch (error) {
124
+ const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
125
+ finalize({
126
+ code: 1,
127
+ stderr,
128
+ missingBinary: code === "ENOENT" || (isWindows && code === "EINVAL")
129
+ });
130
+ return;
131
+ }
132
+ child.stderr?.on("data", (chunk) => {
133
+ stderr += String(chunk ?? "");
134
+ if (stderr.length > 8000) {
135
+ stderr = stderr.slice(-8000);
136
+ }
137
+ });
138
+ child.on("error", (error) => {
139
+ const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
140
+ finalize({
141
+ code: 1,
142
+ stderr,
143
+ missingBinary: code === "ENOENT" || (isWindows && code === "EINVAL")
144
+ });
145
+ });
146
+ child.on("close", (code, signal) => {
147
+ if (signal) {
148
+ finalize({
149
+ code: 1,
150
+ stderr,
151
+ missingBinary: false
152
+ });
153
+ return;
154
+ }
155
+ const stderrLower = stderr.toLowerCase();
156
+ const missingBinary = isWindows
157
+ ? stderrLower.includes("is not recognized as an internal or external command")
158
+ : false;
159
+ finalize({
160
+ code: typeof code === "number" ? code : 1,
161
+ stderr,
162
+ missingBinary
163
+ });
164
+ });
165
+ });
166
+ }
167
+
102
168
  function detectHarness(env) {
103
169
  if (env.CLAUDE_PROJECT_DIR) return "claude";
104
170
  if (env.CURSOR_PROJECT_DIR || env.CURSOR_PROJECT_ROOT) return "cursor";
@@ -1446,14 +1512,33 @@ async function handleContextMonitor(runtime) {
1446
1512
  return 0;
1447
1513
  }
1448
1514
 
1515
+ async function handleVerifyCurrentState(runtime) {
1516
+ const mode = process.env.CCLAW_WORKFLOW_GUARD_MODE === "strict"
1517
+ ? "strict"
1518
+ : DEFAULT_WORKFLOW_GUARD_MODE;
1519
+ const result = await runCclawInternal(runtime.root, ["verify-current-state", "--quiet"]);
1520
+ if (result.missingBinary) {
1521
+ process.stderr.write("[cclaw] codex hook: cclaw binary is required for verify-current-state\\n");
1522
+ return 1;
1523
+ }
1524
+ if (mode === "strict") {
1525
+ if (result.code !== 0 && result.stderr.trim().length > 0) {
1526
+ process.stderr.write(result.stderr);
1527
+ }
1528
+ return result.code === 0 ? 0 : 1;
1529
+ }
1530
+ return 0;
1531
+ }
1532
+
1449
1533
  function normalizeHookName(rawName) {
1450
1534
  const value = normalizeText(rawName).toLowerCase();
1451
- if (value === "session-start" || value === "session-start.sh") return "session-start";
1452
- if (value === "stop-checkpoint" || value === "stop-checkpoint.sh") return "stop-checkpoint";
1453
- if (value === "pre-compact" || value === "pre-compact.sh") return "pre-compact";
1454
- if (value === "prompt-guard" || value === "prompt-guard.sh") return "prompt-guard";
1455
- if (value === "workflow-guard" || value === "workflow-guard.sh") return "workflow-guard";
1456
- if (value === "context-monitor" || value === "context-monitor.sh") return "context-monitor";
1535
+ if (value === "session-start") return "session-start";
1536
+ if (value === "stop-checkpoint") return "stop-checkpoint";
1537
+ if (value === "pre-compact") return "pre-compact";
1538
+ if (value === "prompt-guard") return "prompt-guard";
1539
+ if (value === "workflow-guard") return "workflow-guard";
1540
+ if (value === "context-monitor") return "context-monitor";
1541
+ if (value === "verify-current-state") return "verify-current-state";
1457
1542
  return "";
1458
1543
  }
1459
1544
 
@@ -1463,7 +1548,7 @@ async function main() {
1463
1548
  process.stderr.write(
1464
1549
  "[cclaw] run-hook: usage: node " +
1465
1550
  RUNTIME_ROOT +
1466
- "/hooks/run-hook.mjs <session-start|stop-checkpoint|pre-compact|prompt-guard|workflow-guard|context-monitor>\\n"
1551
+ "/hooks/run-hook.mjs <session-start|stop-checkpoint|pre-compact|prompt-guard|workflow-guard|context-monitor|verify-current-state>\\n"
1467
1552
  );
1468
1553
  process.exitCode = 1;
1469
1554
  return;
@@ -1508,6 +1593,10 @@ async function main() {
1508
1593
  process.exitCode = await handleContextMonitor(runtime);
1509
1594
  return;
1510
1595
  }
1596
+ if (hookName === "verify-current-state") {
1597
+ process.exitCode = await handleVerifyCurrentState(runtime);
1598
+ return;
1599
+ }
1511
1600
  process.stderr.write("[cclaw] run-hook: unsupported hook " + hookName + "\\n");
1512
1601
  process.exitCode = 1;
1513
1602
  } catch (error) {
@@ -1,41 +1,3 @@
1
- /**
2
- * Hook helper scripts and harness hook JSON generators.
3
- *
4
- * This module still provides prompt/workflow/context guard scripts and
5
- * cross-harness hook wiring. Observation pipeline scripts are retained only
6
- * for backward compatibility and are not wired by default runtime generation.
7
- */
8
- export interface PromptGuardOptions {
9
- strictMode?: boolean;
10
- }
11
- export declare function promptGuardScript(options?: PromptGuardOptions): string;
12
- export interface WorkflowGuardOptions {
13
- workflowGuardMode?: "advisory" | "strict";
14
- tddEnforcementMode?: "advisory" | "strict";
15
- tddTestPathPatterns?: string[];
16
- tddProductionPathPatterns?: string[];
17
- }
18
- export declare function workflowGuardScript(options?: WorkflowGuardOptions): string;
19
- export declare function contextMonitorScript(): string;
20
1
  export declare function claudeHooksJsonWithObservation(): string;
21
2
  export declare function cursorHooksJsonWithObservation(): string;
22
- /**
23
- * Codex CLI ≥ v0.114 hooks. Differences vs. the Claude shape:
24
- *
25
- * - `SessionStart` matcher is limited to `startup|resume` — Codex does
26
- * not emit `clear` or `compact` lifecycle phases.
27
- * - `PreToolUse` / `PostToolUse` fire **only for the `Bash` tool**
28
- * (documented Codex limitation, v0.114/v0.115). We match both `Bash`
29
- * and `bash` variants to tolerate casing drift across Codex builds.
30
- * - `UserPromptSubmit` is supported and is the closest analogue to
31
- * Cursor's `preToolUse` for non-Bash tooling — we run prompt-guard
32
- * there so workflow/prompt checks still fire when the tool being
33
- * used is `Write` or `Edit` rather than `Bash`.
34
- * - There is no `PreCompact` event in Codex CLI — pre-compact
35
- * semantics are carried by the agent itself inside `/cc-ops retro`.
36
- *
37
- * The entire file is inert unless the user opts into
38
- * `[features] codex_hooks = true` in `~/.codex/config.toml`; cclaw
39
- * doctor and the init prompt handle that flag.
40
- */
41
3
  export declare function codexHooksJsonWithObservation(): string;