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.
- package/dist/content/hooks.d.ts +3 -2
- package/dist/content/hooks.js +183 -47
- package/dist/content/iron-laws.d.ts +8 -0
- package/dist/content/iron-laws.js +9 -0
- package/dist/content/node-hooks.d.ts +14 -0
- package/dist/content/node-hooks.js +1527 -0
- package/dist/content/observe.js +381 -56
- package/dist/content/stages/review.js +2 -2
- package/dist/content/templates.js +8 -0
- package/dist/doctor.js +6 -2
- package/dist/install.js +12 -1
- package/dist/internal/advance-stage.js +57 -2
- package/dist/internal/tdd-red-evidence.d.ts +7 -0
- package/dist/internal/tdd-red-evidence.js +130 -0
- package/package.json +1 -1
package/dist/content/hooks.d.ts
CHANGED
|
@@ -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\"\
|
|
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;
|
package/dist/content/hooks.js
CHANGED
|
@@ -15,34 +15,195 @@ const ESCAPE_FN = `escape_json() {
|
|
|
15
15
|
str=\${str//$'\\n'/\\\\n}
|
|
16
16
|
printf '%s' "$str"
|
|
17
17
|
}`;
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
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" ] && [ -
|
|
30
|
-
|
|
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 [ -
|
|
35
|
-
|
|
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
|
-
|
|
38
|
-
|
|
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
|
-
${
|
|
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
|
-
${
|
|
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
|
-
${
|
|
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
|
-
${
|
|
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
|
-
${
|
|
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;
|