cclaw-cli 0.48.6 → 0.48.8

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.
@@ -8,7 +8,8 @@
8
8
  export interface HookRuntimeOptions {
9
9
  }
10
10
  /** Shared bash preamble for generated hook scripts. */
11
- export declare const RUNTIME_SHELL_DETECT_ROOT = "HARNESS=\"codex\"\nif [ -n \"${CLAUDE_PROJECT_DIR:-}\" ]; then\n HARNESS=\"claude\"\nelif [ -n \"${CURSOR_PROJECT_DIR:-}\" ] || [ -n \"${CURSOR_PROJECT_ROOT:-}\" ]; then\n HARNESS=\"cursor\"\nelif [ -n \"${OPENCODE_PROJECT_DIR:-}\" ] || [ -n \"${OPENCODE_PROJECT_ROOT:-}\" ]; then\n HARNESS=\"opencode\"\nfi\n\nROOT=\"\"\nfor candidate in \"${CCLAW_PROJECT_ROOT:-}\" \"${CLAUDE_PROJECT_DIR:-}\" \"${CURSOR_PROJECT_DIR:-}\" \"${CURSOR_PROJECT_ROOT:-}\" \"${OPENCODE_PROJECT_DIR:-}\" \"${OPENCODE_PROJECT_ROOT:-}\" \"${PWD:-}\"; do\n if [ -n \"$candidate\" ] && [ -d \"$candidate/.cclaw\" ]; then\n ROOT=\"$candidate\"\n break\n fi\ndone\nif [ -z \"$ROOT\" ]; then\n ROOT=\"${CCLAW_PROJECT_ROOT:-${CLAUDE_PROJECT_DIR:-${CURSOR_PROJECT_DIR:-${CURSOR_PROJECT_ROOT:-${OPENCODE_PROJECT_DIR:-${OPENCODE_PROJECT_ROOT:-${PWD}}}}}}}\"\nfi";
11
+ export declare const RUNTIME_SHELL_DETECT_ROOT = "CCLAW_HOOK_LIB_PATH=\"\"\nfor candidate in \"${CCLAW_PROJECT_ROOT:-}\" \"${CLAUDE_PROJECT_DIR:-}\" \"${CURSOR_PROJECT_DIR:-}\" \"${CURSOR_PROJECT_ROOT:-}\" \"${OPENCODE_PROJECT_DIR:-}\" \"${OPENCODE_PROJECT_ROOT:-}\" \"${PWD:-}\"; do\n if [ -n \"$candidate\" ] && [ -f \"$candidate/.cclaw/hooks/_lib.sh\" ]; then\n CCLAW_HOOK_LIB_PATH=\"$candidate/.cclaw/hooks/_lib.sh\"\n break\n fi\ndone\nif [ -n \"$CCLAW_HOOK_LIB_PATH\" ] && [ -f \"$CCLAW_HOOK_LIB_PATH\" ]; then\n # shellcheck disable=SC1090\n . \"$CCLAW_HOOK_LIB_PATH\"\nfi\n\nif command -v cclaw_hook_detect_root >/dev/null 2>&1; then\n cclaw_hook_detect_root\nelse\n HARNESS=\"codex\"\n if [ -n \"${CLAUDE_PROJECT_DIR:-}\" ]; then\n HARNESS=\"claude\"\n elif [ -n \"${CURSOR_PROJECT_DIR:-}\" ] || [ -n \"${CURSOR_PROJECT_ROOT:-}\" ]; then\n HARNESS=\"cursor\"\n elif [ -n \"${OPENCODE_PROJECT_DIR:-}\" ] || [ -n \"${OPENCODE_PROJECT_ROOT:-}\" ]; then\n HARNESS=\"opencode\"\n fi\n\n ROOT=\"\"\n for candidate in \"${CCLAW_PROJECT_ROOT:-}\" \"${CLAUDE_PROJECT_DIR:-}\" \"${CURSOR_PROJECT_DIR:-}\" \"${CURSOR_PROJECT_ROOT:-}\" \"${OPENCODE_PROJECT_DIR:-}\" \"${OPENCODE_PROJECT_ROOT:-}\" \"${PWD:-}\"; do\n if [ -n \"$candidate\" ] && [ -d \"$candidate/.cclaw\" ]; then\n ROOT=\"$candidate\"\n break\n fi\n done\n if [ -z \"$ROOT\" ]; then\n ROOT=\"${CCLAW_PROJECT_ROOT:-${CLAUDE_PROJECT_DIR:-${CURSOR_PROJECT_DIR:-${CURSOR_PROJECT_ROOT:-${OPENCODE_PROJECT_DIR:-${OPENCODE_PROJECT_ROOT:-${PWD}}}}}}}\"\n fi\nfi";
12
+ export declare function hookLibScript(): string;
12
13
  export declare function sessionStartScript(_options?: HookRuntimeOptions): string;
13
14
  export declare function stopCheckpointScript(): string;
14
15
  export declare function runHookDispatcherScript(): string;
@@ -17,5 +18,5 @@ export declare function preCompactScript(): string;
17
18
  export { claudeHooksJsonWithObservation as claudeHooksJson } from "./observe.js";
18
19
  export { cursorHooksJsonWithObservation as cursorHooksJson } from "./observe.js";
19
20
  export { codexHooksJsonWithObservation as codexHooksJson } from "./observe.js";
21
+ export { nodeHookRuntimeScript } from "./node-hooks.js";
20
22
  export { opencodePluginJs } from "./opencode-plugin.js";
21
- export declare function hooksAgentsMdBlock(): string;
@@ -15,34 +15,195 @@ const ESCAPE_FN = `escape_json() {
15
15
  str=\${str//$'\\n'/\\\\n}
16
16
  printf '%s' "$str"
17
17
  }`;
18
- const DETECT_ROOT = `HARNESS="codex"
19
- if [ -n "\${CLAUDE_PROJECT_DIR:-}" ]; then
20
- HARNESS="claude"
21
- elif [ -n "\${CURSOR_PROJECT_DIR:-}" ] || [ -n "\${CURSOR_PROJECT_ROOT:-}" ]; then
22
- HARNESS="cursor"
23
- elif [ -n "\${OPENCODE_PROJECT_DIR:-}" ] || [ -n "\${OPENCODE_PROJECT_ROOT:-}" ]; then
24
- HARNESS="opencode"
25
- fi
26
-
27
- ROOT=""
18
+ const HOOK_LIB_FILE = "_lib.sh";
19
+ /** Shared bash preamble for generated hook scripts. */
20
+ export const RUNTIME_SHELL_DETECT_ROOT = `CCLAW_HOOK_LIB_PATH=""
28
21
  for candidate in "\${CCLAW_PROJECT_ROOT:-}" "\${CLAUDE_PROJECT_DIR:-}" "\${CURSOR_PROJECT_DIR:-}" "\${CURSOR_PROJECT_ROOT:-}" "\${OPENCODE_PROJECT_DIR:-}" "\${OPENCODE_PROJECT_ROOT:-}" "\${PWD:-}"; do
29
- if [ -n "$candidate" ] && [ -d "$candidate/${RUNTIME_ROOT}" ]; then
30
- ROOT="$candidate"
22
+ if [ -n "$candidate" ] && [ -f "$candidate/${RUNTIME_ROOT}/hooks/${HOOK_LIB_FILE}" ]; then
23
+ CCLAW_HOOK_LIB_PATH="$candidate/${RUNTIME_ROOT}/hooks/${HOOK_LIB_FILE}"
31
24
  break
32
25
  fi
33
26
  done
34
- if [ -z "$ROOT" ]; then
35
- ROOT="\${CCLAW_PROJECT_ROOT:-\${CLAUDE_PROJECT_DIR:-\${CURSOR_PROJECT_DIR:-\${CURSOR_PROJECT_ROOT:-\${OPENCODE_PROJECT_DIR:-\${OPENCODE_PROJECT_ROOT:-\${PWD}}}}}}}"
27
+ if [ -n "$CCLAW_HOOK_LIB_PATH" ] && [ -f "$CCLAW_HOOK_LIB_PATH" ]; then
28
+ # shellcheck disable=SC1090
29
+ . "$CCLAW_HOOK_LIB_PATH"
30
+ fi
31
+
32
+ if command -v cclaw_hook_detect_root >/dev/null 2>&1; then
33
+ cclaw_hook_detect_root
34
+ else
35
+ HARNESS="codex"
36
+ if [ -n "\${CLAUDE_PROJECT_DIR:-}" ]; then
37
+ HARNESS="claude"
38
+ elif [ -n "\${CURSOR_PROJECT_DIR:-}" ] || [ -n "\${CURSOR_PROJECT_ROOT:-}" ]; then
39
+ HARNESS="cursor"
40
+ elif [ -n "\${OPENCODE_PROJECT_DIR:-}" ] || [ -n "\${OPENCODE_PROJECT_ROOT:-}" ]; then
41
+ HARNESS="opencode"
42
+ fi
43
+
44
+ ROOT=""
45
+ for candidate in "\${CCLAW_PROJECT_ROOT:-}" "\${CLAUDE_PROJECT_DIR:-}" "\${CURSOR_PROJECT_DIR:-}" "\${CURSOR_PROJECT_ROOT:-}" "\${OPENCODE_PROJECT_DIR:-}" "\${OPENCODE_PROJECT_ROOT:-}" "\${PWD:-}"; do
46
+ if [ -n "$candidate" ] && [ -d "$candidate/${RUNTIME_ROOT}" ]; then
47
+ ROOT="$candidate"
48
+ break
49
+ fi
50
+ done
51
+ if [ -z "$ROOT" ]; then
52
+ ROOT="\${CCLAW_PROJECT_ROOT:-\${CLAUDE_PROJECT_DIR:-\${CURSOR_PROJECT_DIR:-\${CURSOR_PROJECT_ROOT:-\${OPENCODE_PROJECT_DIR:-\${OPENCODE_PROJECT_ROOT:-\${PWD}}}}}}}"
53
+ fi
36
54
  fi`;
37
- /** Shared bash preamble for generated hook scripts. */
38
- export const RUNTIME_SHELL_DETECT_ROOT = DETECT_ROOT;
55
+ export function hookLibScript() {
56
+ return `#!/usr/bin/env bash
57
+ # cclaw shared hook library — generated by cclaw sync
58
+ # Shared helper functions for root detection and lightweight JSON parsing.
59
+
60
+ cclaw_hook_detect_root() {
61
+ HARNESS="codex"
62
+ if [ -n "\${CLAUDE_PROJECT_DIR:-}" ]; then
63
+ HARNESS="claude"
64
+ elif [ -n "\${CURSOR_PROJECT_DIR:-}" ] || [ -n "\${CURSOR_PROJECT_ROOT:-}" ]; then
65
+ HARNESS="cursor"
66
+ elif [ -n "\${OPENCODE_PROJECT_DIR:-}" ] || [ -n "\${OPENCODE_PROJECT_ROOT:-}" ]; then
67
+ HARNESS="opencode"
68
+ fi
69
+
70
+ ROOT=""
71
+ for candidate in "\${CCLAW_PROJECT_ROOT:-}" "\${CLAUDE_PROJECT_DIR:-}" "\${CURSOR_PROJECT_DIR:-}" "\${CURSOR_PROJECT_ROOT:-}" "\${OPENCODE_PROJECT_DIR:-}" "\${OPENCODE_PROJECT_ROOT:-}" "\${PWD:-}"; do
72
+ if [ -n "$candidate" ] && [ -d "$candidate/${RUNTIME_ROOT}" ]; then
73
+ ROOT="$candidate"
74
+ break
75
+ fi
76
+ done
77
+ if [ -z "$ROOT" ]; then
78
+ ROOT="\${CCLAW_PROJECT_ROOT:-\${CLAUDE_PROJECT_DIR:-\${CURSOR_PROJECT_DIR:-\${CURSOR_PROJECT_ROOT:-\${OPENCODE_PROJECT_DIR:-\${OPENCODE_PROJECT_ROOT:-\${PWD}}}}}}}"
79
+ fi
80
+ }
81
+
82
+ cclaw_hook_lower() {
83
+ printf '%s' "$1" | tr '[:upper:]' '[:lower:]'
84
+ }
85
+
86
+ cclaw_hook_extract_tool_and_payload() {
87
+ local input_json="$1"
88
+ CCLAW_HOOK_TOOL="unknown"
89
+ CCLAW_HOOK_PAYLOAD=""
90
+ if command -v jq >/dev/null 2>&1; then
91
+ CCLAW_HOOK_TOOL=$(printf '%s' "$input_json" | jq -r '.tool_name // .tool // .toolName // .name // .id // .command // .tool.name // .tool.id // .input.tool_name // .input.tool // .input.toolName // .input.name // .input.id // .input.command // .input.tool.name // .input.tool.id // "unknown"' 2>/dev/null || echo "unknown")
92
+ CCLAW_HOOK_PAYLOAD=$(printf '%s' "$input_json" | jq -r '.tool_input // .input // .arguments // .params // .payload // {} | tostring' 2>/dev/null || echo "")
93
+ elif command -v python3 >/dev/null 2>&1; then
94
+ CCLAW_HOOK_TOOL=$(INPUT_JSON="$input_json" python3 - <<'PY'
95
+ import json
96
+ import os
97
+ try:
98
+ value = json.loads(os.environ.get("INPUT_JSON", "{}"))
99
+ except Exception:
100
+ value = {}
101
+
102
+ def pick_tool(payload):
103
+ if not isinstance(payload, dict):
104
+ return "unknown"
105
+ candidates = [
106
+ payload.get("tool_name"),
107
+ payload.get("tool"),
108
+ payload.get("toolName"),
109
+ payload.get("name"),
110
+ payload.get("id"),
111
+ payload.get("command")
112
+ ]
113
+ top_tool = payload.get("tool")
114
+ if isinstance(top_tool, dict):
115
+ candidates.extend([top_tool.get("name"), top_tool.get("id")])
116
+ nested = payload.get("input")
117
+ if isinstance(nested, dict):
118
+ candidates.extend([
119
+ nested.get("tool_name"),
120
+ nested.get("tool"),
121
+ nested.get("toolName"),
122
+ nested.get("name"),
123
+ nested.get("id"),
124
+ nested.get("command")
125
+ ])
126
+ nested_tool = nested.get("tool")
127
+ if isinstance(nested_tool, dict):
128
+ candidates.extend([nested_tool.get("name"), nested_tool.get("id")])
129
+ for candidate in candidates:
130
+ if isinstance(candidate, str) and candidate.strip():
131
+ return candidate.strip()
132
+ return "unknown"
133
+
134
+ print(pick_tool(value))
135
+ PY
136
+ )
137
+ CCLAW_HOOK_PAYLOAD=$(printf '%s' "$input_json")
138
+ else
139
+ CCLAW_HOOK_PAYLOAD=$(printf '%s' "$input_json")
140
+ fi
141
+ [ -n "$CCLAW_HOOK_PAYLOAD" ] || CCLAW_HOOK_PAYLOAD=$(printf '%s' "$input_json")
142
+ [ -n "$CCLAW_HOOK_TOOL" ] || CCLAW_HOOK_TOOL="unknown"
143
+ }
144
+
145
+ cclaw_hook_read_flow_state_minimal() {
146
+ local flow_state_file="$1"
147
+ CCLAW_HOOK_FLOW_STAGE="none"
148
+ CCLAW_HOOK_FLOW_RUN_ID="active"
149
+ CCLAW_HOOK_FLOW_COMPLETED="0"
150
+ [ -f "$flow_state_file" ] || return 0
151
+
152
+ if command -v jq >/dev/null 2>&1; then
153
+ CCLAW_HOOK_FLOW_STAGE=$(jq -r '.currentStage // "none"' "$flow_state_file" 2>/dev/null || echo "none")
154
+ CCLAW_HOOK_FLOW_RUN_ID=$(jq -r '.activeRunId // "active"' "$flow_state_file" 2>/dev/null || echo "active")
155
+ CCLAW_HOOK_FLOW_COMPLETED=$(jq -r '(.completedStages // []) | length' "$flow_state_file" 2>/dev/null || echo "0")
156
+ return 0
157
+ fi
158
+
159
+ if command -v python3 >/dev/null 2>&1; then
160
+ local flow_meta
161
+ flow_meta=$(python3 - "$flow_state_file" <<'PY'
162
+ import json
163
+ import sys
164
+ stage = "none"
165
+ run_id = "active"
166
+ completed = 0
167
+ try:
168
+ with open(sys.argv[1], "r", encoding="utf-8") as fh:
169
+ payload = json.load(fh)
170
+ stage_value = payload.get("currentStage")
171
+ run_value = payload.get("activeRunId")
172
+ completed_value = payload.get("completedStages")
173
+ if isinstance(stage_value, str) and stage_value:
174
+ stage = stage_value
175
+ if isinstance(run_value, str) and run_value:
176
+ run_id = run_value
177
+ if isinstance(completed_value, list):
178
+ completed = len(completed_value)
179
+ except Exception:
180
+ pass
181
+ print(stage)
182
+ print(run_id)
183
+ print(completed)
184
+ PY
185
+ )
186
+ {
187
+ IFS= read -r CCLAW_HOOK_FLOW_STAGE
188
+ IFS= read -r CCLAW_HOOK_FLOW_RUN_ID
189
+ IFS= read -r CCLAW_HOOK_FLOW_COMPLETED
190
+ } <<EOF
191
+ $flow_meta
192
+ EOF
193
+ [ -n "$CCLAW_HOOK_FLOW_STAGE" ] || CCLAW_HOOK_FLOW_STAGE="none"
194
+ [ -n "$CCLAW_HOOK_FLOW_RUN_ID" ] || CCLAW_HOOK_FLOW_RUN_ID="active"
195
+ [ -n "$CCLAW_HOOK_FLOW_COMPLETED" ] || CCLAW_HOOK_FLOW_COMPLETED="0"
196
+ fi
197
+ }
198
+ `;
199
+ }
39
200
  export function sessionStartScript(_options = {}) {
40
201
  return `#!/usr/bin/env bash
41
202
  # cclaw session-start hook — generated by cclaw sync
42
203
  # Injects using-cclaw + flow status + active artifacts + compact knowledge digest + checkpoint/activity summary.
43
204
  set -euo pipefail
44
205
 
45
- ${DETECT_ROOT}
206
+ ${RUNTIME_SHELL_DETECT_ROOT}
46
207
 
47
208
  STATE_FILE="$ROOT/${RUNTIME_ROOT}/state/flow-state.json"
48
209
  ACTIVE_FEATURE_FILE="$ROOT/${RUNTIME_ROOT}/state/active-feature.json"
@@ -567,7 +728,7 @@ export function stopCheckpointScript() {
567
728
  # Writes checkpoint state and reminds agent about flow/session consistency.
568
729
  set -euo pipefail
569
730
 
570
- ${DETECT_ROOT}
731
+ ${RUNTIME_SHELL_DETECT_ROOT}
571
732
 
572
733
  INPUT=$(cat 2>/dev/null || echo '{}')
573
734
 
@@ -844,7 +1005,7 @@ export function runHookDispatcherScript() {
844
1005
  # Single entrypoint used by harness hook JSON wiring.
845
1006
  set -euo pipefail
846
1007
 
847
- ${DETECT_ROOT}
1008
+ ${RUNTIME_SHELL_DETECT_ROOT}
848
1009
 
849
1010
  if [ "$#" -lt 1 ]; then
850
1011
  printf 'Usage: bash ${RUNTIME_ROOT}/hooks/run-hook.cmd <session-start|stop-checkpoint|pre-compact|prompt-guard|workflow-guard|context-monitor>\\n' >&2
@@ -895,7 +1056,7 @@ export function stageCompleteScript() {
895
1056
  # mutation to \`cclaw internal advance-stage\`.
896
1057
  set -euo pipefail
897
1058
 
898
- ${DETECT_ROOT}
1059
+ ${RUNTIME_SHELL_DETECT_ROOT}
899
1060
 
900
1061
  if [ "$#" -lt 1 ]; then
901
1062
  printf 'Usage: bash ${RUNTIME_ROOT}/hooks/stage-complete.sh <stage> [--passed=...] [--evidence-json=...] [--waive-delegation=...] [--waiver-reason=...]\\n' >&2
@@ -926,9 +1087,7 @@ export function preCompactScript() {
926
1087
  # having to re-derive it from scratch.
927
1088
  set -uo pipefail
928
1089
 
929
- ${DETECT_ROOT}
930
-
931
- INPUT=$(cat 2>/dev/null || echo '{}')
1090
+ ${RUNTIME_SHELL_DETECT_ROOT}
932
1091
 
933
1092
  STATE_DIR="$ROOT/${RUNTIME_ROOT}/state"
934
1093
  STATE_FILE="$STATE_DIR/flow-state.json"
@@ -1069,31 +1228,8 @@ exit 0
1069
1228
  export { claudeHooksJsonWithObservation as claudeHooksJson } from "./observe.js";
1070
1229
  export { cursorHooksJsonWithObservation as cursorHooksJson } from "./observe.js";
1071
1230
  export { codexHooksJsonWithObservation as codexHooksJson } from "./observe.js";
1231
+ export { nodeHookRuntimeScript } from "./node-hooks.js";
1072
1232
  // ---------------------------------------------------------------------------
1073
1233
  // OpenCode plugin — JS module
1074
1234
  // ---------------------------------------------------------------------------
1075
1235
  export { opencodePluginJs } from "./opencode-plugin.js";
1076
- // ---------------------------------------------------------------------------
1077
- // AGENTS.md block for hooks
1078
- // ---------------------------------------------------------------------------
1079
- export function hooksAgentsMdBlock() {
1080
- return `### Hooks (real lifecycle integration)
1081
-
1082
- Cclaw generates real hook integrations for every harness that exposes a
1083
- hook primitive:
1084
- - **Claude/Cursor:** lifecycle rehydration + PreToolUse/PostToolUse + Stop
1085
- - **OpenCode:** session lifecycle + system transform rehydration + bootstrap parity (digest/warnings/knowledge snapshot)
1086
- - **Codex:** Codex CLI ≥ v0.114 exposes lifecycle hooks at \`.codex/hooks.json\`, gated behind \`[features] codex_hooks = true\` in \`~/.codex/config.toml\`. \`PreToolUse\`/\`PostToolUse\` intercept **only the \`Bash\` tool** in Codex; \`Write\`/\`Edit\`/\`WebSearch\`/MCP calls are substituted via the \`/cc\` skill bodies under \`.agents/skills/cc*/SKILL.md\` and explicit in-turn agent steps. See \`.cclaw/references/harnesses/codex-playbook.md\` for the coverage matrix.
1087
-
1088
- | Harness | Hook file | Events |
1089
- |---------|-----------|--------|
1090
- | Claude Code | \`.claude/hooks/hooks.json\` | SessionStart(startup/resume/clear/compact), PreToolUse, PostToolUse, Stop |
1091
- | Cursor | \`.cursor/hooks.json\` | sessionStart/sessionResume/sessionClear/sessionCompact, preToolUse, postToolUse, stop |
1092
- | OpenCode | \`${RUNTIME_ROOT}/hooks/opencode-plugin.mjs\` | session.created/updated/resumed/cleared/compacted/idle, tool.execute.before/after, system transform |
1093
- | Codex | \`.codex/hooks.json\` | SessionStart(startup/resume), UserPromptSubmit, PreToolUse(Bash), PostToolUse(Bash), Stop (feature-gated by \`codex_hooks = true\`) |
1094
-
1095
- Hook state files:
1096
- - \`${RUNTIME_ROOT}/state/stage-activity.jsonl\`
1097
- - \`${RUNTIME_ROOT}/state/checkpoint.json\`
1098
- `;
1099
- }
@@ -98,6 +98,14 @@ export declare const IRON_LAWS: readonly [{
98
98
  readonly enforcement: "PreToolUse";
99
99
  readonly severity: "hard-gate";
100
100
  readonly appliesTo: ["ship"];
101
+ }, {
102
+ readonly id: "review-coverage-complete-before-ship";
103
+ readonly title: "Review layer coverage before ship";
104
+ readonly rule: "Block ship finalization when review-army does not confirm full Layer 1/2 coverage map.";
105
+ readonly rationale: "Prevents finalization when multi-pass review evidence is incomplete or partially missing.";
106
+ readonly enforcement: "PreToolUse";
107
+ readonly severity: "hard-gate";
108
+ readonly appliesTo: ["ship"];
101
109
  }, {
102
110
  readonly id: "subagent-task-self-contained";
103
111
  readonly title: "Subagent tasks are self-contained";
@@ -71,6 +71,15 @@ export const IRON_LAWS = [
71
71
  severity: "hard-gate",
72
72
  appliesTo: ["ship"]
73
73
  },
74
+ {
75
+ id: "review-coverage-complete-before-ship",
76
+ title: "Review layer coverage before ship",
77
+ rule: "Block ship finalization when review-army does not confirm full Layer 1/2 coverage map.",
78
+ rationale: "Prevents finalization when multi-pass review evidence is incomplete or partially missing.",
79
+ enforcement: "PreToolUse",
80
+ severity: "hard-gate",
81
+ appliesTo: ["ship"]
82
+ },
74
83
  {
75
84
  id: "subagent-task-self-contained",
76
85
  title: "Subagent tasks are self-contained",
@@ -0,0 +1,14 @@
1
+ export interface NodeHookRuntimeOptions {
2
+ promptGuardMode?: "advisory" | "strict";
3
+ workflowGuardMode?: "advisory" | "strict";
4
+ tddEnforcementMode?: "advisory" | "strict";
5
+ tddTestPathPatterns?: string[];
6
+ tddProductionPathPatterns?: string[];
7
+ }
8
+ /**
9
+ * Node-only hook runtime (single entrypoint).
10
+ *
11
+ * Generated into `.cclaw/hooks/run-hook.mjs` and used by all harnesses to avoid
12
+ * bash/python/jq runtime dependencies.
13
+ */
14
+ export declare function nodeHookRuntimeScript(options?: NodeHookRuntimeOptions): string;