oh-my-customcode 1.1.55 → 1.1.57
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/cli/index.js +5 -1
- package/dist/index.js +5 -1
- package/package.json +1 -1
- package/templates/.claude/hooks/hooks.json +21 -21
- package/templates/.claude/hooks/scripts/agent-start-recorder.sh +5 -5
- package/templates/.claude/hooks/scripts/agent-teams-advisor.sh +4 -4
- package/templates/.claude/hooks/scripts/audit-log.sh +6 -6
- package/templates/.claude/hooks/scripts/auto-continue-guard.sh +1 -1
- package/templates/.claude/hooks/scripts/auto-dev-token-summary.sh +6 -6
- package/templates/.claude/hooks/scripts/auto-dev-token-tracker.sh +6 -6
- package/templates/.claude/hooks/scripts/claude-md-reinject.sh +9 -4
- package/templates/.claude/hooks/scripts/content-hash-validator.sh +4 -4
- package/templates/.claude/hooks/scripts/context-budget-advisor.sh +3 -3
- package/templates/.claude/hooks/scripts/cost-cap-advisor.sh +6 -6
- package/templates/.claude/hooks/scripts/cwd-change-detector.sh +3 -3
- package/templates/.claude/hooks/scripts/destructive-git-guard.sh +2 -2
- package/templates/.claude/hooks/scripts/eval-core-batch-save.sh +2 -2
- package/templates/.claude/hooks/scripts/feedback-collector.sh +7 -7
- package/templates/.claude/hooks/scripts/file-change-validator.sh +4 -4
- package/templates/.claude/hooks/scripts/git-delegation-guard.sh +3 -3
- package/templates/.claude/hooks/scripts/model-escalation-advisor.sh +4 -4
- package/templates/.claude/hooks/scripts/omcustom-auto-update.sh +6 -6
- package/templates/.claude/hooks/scripts/playwright-compress.sh +4 -4
- package/templates/.claude/hooks/scripts/plugin-cache-check.sh +2 -2
- package/templates/.claude/hooks/scripts/rtk-intercept.sh +9 -9
- package/templates/.claude/hooks/scripts/rule-deletion-guard.sh +5 -5
- package/templates/.claude/hooks/scripts/schema-validator.sh +10 -10
- package/templates/.claude/hooks/scripts/secret-filter.sh +4 -4
- package/templates/.claude/hooks/scripts/session-autofix-prompt.sh +3 -3
- package/templates/.claude/hooks/scripts/session-autofix.sh +1 -1
- package/templates/.claude/hooks/scripts/session-env-check.sh +1 -1
- package/templates/.claude/hooks/scripts/session-reflection.sh +15 -15
- package/templates/.claude/hooks/scripts/skill-extractor-analyzer.sh +2 -2
- package/templates/.claude/hooks/scripts/stale-todo-scanner.sh +1 -1
- package/templates/.claude/hooks/scripts/stall-detection-advisor.sh +11 -11
- package/templates/.claude/hooks/scripts/stop-console-audit.sh +1 -1
- package/templates/.claude/hooks/scripts/stuck-detector.sh +5 -5
- package/templates/.claude/hooks/scripts/subagent-failure-advisor.sh +36 -0
- package/templates/.claude/hooks/scripts/task-outcome-recorder.sh +8 -8
- package/templates/.claude/hooks/scripts/task-state-precompact.sh +1 -1
- package/templates/.claude/settings.json +21 -21
- package/templates/manifest.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -243,7 +243,7 @@ var init_package = __esm(() => {
|
|
|
243
243
|
workspaces: [
|
|
244
244
|
"packages/*"
|
|
245
245
|
],
|
|
246
|
-
version: "1.1.
|
|
246
|
+
version: "1.1.57",
|
|
247
247
|
description: "Batteries-included agent harness for Claude Code",
|
|
248
248
|
type: "module",
|
|
249
249
|
bin: {
|
|
@@ -28198,10 +28198,14 @@ function analyzeMixedAndExpr(ast, raw) {
|
|
|
28198
28198
|
const fieldNode = fieldParts.reduce((acc, part) => acc === null ? part : { kind: "and", left: acc, right: part }, null);
|
|
28199
28199
|
return { toolRegex, fieldNode };
|
|
28200
28200
|
}
|
|
28201
|
+
var BARE_LITERAL_MATCHER = /^[A-Za-z_][A-Za-z0-9_-]*$/;
|
|
28201
28202
|
function analyzeMatcher(raw) {
|
|
28202
28203
|
if (raw === undefined || raw === "*" || raw.trim() === "") {
|
|
28203
28204
|
return { toolRegex: "*", fieldNode: null };
|
|
28204
28205
|
}
|
|
28206
|
+
if (BARE_LITERAL_MATCHER.test(raw)) {
|
|
28207
|
+
return { toolRegex: raw, fieldNode: null };
|
|
28208
|
+
}
|
|
28205
28209
|
let ast;
|
|
28206
28210
|
try {
|
|
28207
28211
|
ast = parseMatcherExpr(raw);
|
package/dist/index.js
CHANGED
|
@@ -1556,10 +1556,14 @@ function analyzeMixedAndExpr(ast, raw) {
|
|
|
1556
1556
|
const fieldNode = fieldParts.reduce((acc, part) => acc === null ? part : { kind: "and", left: acc, right: part }, null);
|
|
1557
1557
|
return { toolRegex, fieldNode };
|
|
1558
1558
|
}
|
|
1559
|
+
var BARE_LITERAL_MATCHER = /^[A-Za-z_][A-Za-z0-9_-]*$/;
|
|
1559
1560
|
function analyzeMatcher(raw) {
|
|
1560
1561
|
if (raw === undefined || raw === "*" || raw.trim() === "") {
|
|
1561
1562
|
return { toolRegex: "*", fieldNode: null };
|
|
1562
1563
|
}
|
|
1564
|
+
if (BARE_LITERAL_MATCHER.test(raw)) {
|
|
1565
|
+
return { toolRegex: raw, fieldNode: null };
|
|
1566
|
+
}
|
|
1563
1567
|
let ast;
|
|
1564
1568
|
try {
|
|
1565
1569
|
ast = parseMatcherExpr(raw);
|
|
@@ -2535,7 +2539,7 @@ var package_default = {
|
|
|
2535
2539
|
workspaces: [
|
|
2536
2540
|
"packages/*"
|
|
2537
2541
|
],
|
|
2538
|
-
version: "1.1.
|
|
2542
|
+
version: "1.1.57",
|
|
2539
2543
|
description: "Batteries-included agent harness for Claude Code",
|
|
2540
2544
|
type: "module",
|
|
2541
2545
|
bin: {
|
package/package.json
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"hooks": [
|
|
18
18
|
{
|
|
19
19
|
"type": "command",
|
|
20
|
-
"command": "#!/bin/bash\ninput=$(cat)\ncmd=$(
|
|
20
|
+
"command": "#!/bin/bash\ninput=$(cat)\ncmd=$(printf '%s\\n' \"$input\" | jq -r '.tool_input.command // \"\"')\n\n# Block dev servers that aren't run in tmux\necho '[Hook] BLOCKED: Dev server must run in tmux for log access' >&2\necho '[Hook] Use this command instead:' >&2\necho \"[Hook] tmux new-session -d -s dev 'npm run dev'\" >&2\necho '[Hook] Then: tmux attach -t dev' >&2\nexit 1"
|
|
21
21
|
}
|
|
22
22
|
],
|
|
23
23
|
"description": "Block dev servers outside tmux - ensures you can access logs"
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"hooks": [
|
|
28
28
|
{
|
|
29
29
|
"type": "command",
|
|
30
|
-
"command": "#!/bin/bash\ninput=$(cat)\nif [ -z \"$TMUX\" ]; then\n echo '[Hook] Consider running in tmux for session persistence' >&2\n echo '[Hook] tmux new -s dev | tmux attach -t dev' >&2\nfi\
|
|
30
|
+
"command": "#!/bin/bash\ninput=$(cat)\nif [ -z \"$TMUX\" ]; then\n echo '[Hook] Consider running in tmux for session persistence' >&2\n echo '[Hook] tmux new -s dev | tmux attach -t dev' >&2\nfi\nprintf '%s\\n' \"$input\""
|
|
31
31
|
}
|
|
32
32
|
],
|
|
33
33
|
"description": "Reminder to use tmux for long-running commands"
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"hooks": [
|
|
48
48
|
{
|
|
49
49
|
"type": "command",
|
|
50
|
-
"command": "#!/bin/bash\ninput=$(cat)\nfile_path=$(
|
|
50
|
+
"command": "#!/bin/bash\ninput=$(cat)\nfile_path=$(printf '%s\\n' \"$input\" | jq -r '.tool_input.file_path // \"\"')\n\nif [[ \"$file_path\" =~ \\.(md|txt)$ ]] && [[ ! \"$file_path\" =~ (README|CLAUDE|AGENT|SKILL)\\.md$ ]]; then\n echo \"[Hook] BLOCKED: Unnecessary documentation file creation\" >&2\n echo \"[Hook] File: $file_path\" >&2\n echo \"[Hook] Use README.md or AGENT.md for documentation instead\" >&2\n exit 1\nfi\n\nprintf '%s\\n' \"$input\""
|
|
51
51
|
}
|
|
52
52
|
],
|
|
53
53
|
"description": "Block creation of random .md files - keeps docs consolidated"
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
"hooks": [
|
|
118
118
|
{
|
|
119
119
|
"type": "command",
|
|
120
|
-
"command": "#!/bin/bash\ninput=$(cat)\nagent_type=$(
|
|
120
|
+
"command": "#!/bin/bash\ninput=$(cat)\nagent_type=$(printf '%s\\n' \"$input\" | jq -r '.tool_input.subagent_type // \"unknown\"')\nmodel=$(printf '%s\\n' \"$input\" | jq -r '.tool_input.model // \"inherit\"')\ndesc=$(printf '%s\\n' \"$input\" | jq -r '.tool_input.description // \"\"' | head -c 40)\nresume=$(printf '%s\\n' \"$input\" | jq -r '.tool_input.resume // empty')\nif [ -n \"$resume\" ]; then\n echo \"─── [Resume] ${agent_type}:${model} | ${desc} ───\" >&2\nelse\n echo \"─── [Spawn] ${agent_type}:${model} | ${desc} ───\" >&2\nfi\nprintf '%s\\n' \"$input\""
|
|
121
121
|
},
|
|
122
122
|
{
|
|
123
123
|
"type": "command",
|
|
@@ -197,14 +197,14 @@
|
|
|
197
197
|
"description": "Advisory check for plugin cache directories missing node_modules (#1207)"
|
|
198
198
|
},
|
|
199
199
|
{
|
|
200
|
-
"matcher": "
|
|
200
|
+
"matcher": "compact",
|
|
201
201
|
"hooks": [
|
|
202
202
|
{
|
|
203
203
|
"type": "command",
|
|
204
204
|
"command": "bash .claude/hooks/scripts/claude-md-reinject.sh"
|
|
205
205
|
}
|
|
206
206
|
],
|
|
207
|
-
"description": "Re-inject project CLAUDE.md into model context on
|
|
207
|
+
"description": "Re-inject project CLAUDE.md into model context on compact re-entry only — CC already natively auto-loads CLAUDE.md on startup/resume/clear, so re-injecting there is pure duplication (~13.8KB/session); matcher narrowed to \"compact\" to keep the original #1617 purpose (post-compact amnesia defense) without the startup double-injection (#1626)"
|
|
208
208
|
}
|
|
209
209
|
],
|
|
210
210
|
"UserPromptSubmit": [
|
|
@@ -255,7 +255,7 @@
|
|
|
255
255
|
"hooks": [
|
|
256
256
|
{
|
|
257
257
|
"type": "command",
|
|
258
|
-
"command": "#!/bin/bash\ninput=$(cat)\nagent_type=$(
|
|
258
|
+
"command": "#!/bin/bash\ninput=$(cat)\nagent_type=$(printf '%s\\n' \"$input\" | jq -r '.agent_type // \"unknown\"')\nmodel=$(printf '%s\\n' \"$input\" | jq -r '.model // \"inherit\"')\ndesc=$(printf '%s\\n' \"$input\" | jq -r '.description // \"\"' | head -c 40)\necho \"─── [SubagentStart] ${agent_type}:${model} | ${desc} ───\" >&2\nprintf '%s\\n' \"$input\""
|
|
259
259
|
},
|
|
260
260
|
{
|
|
261
261
|
"type": "command",
|
|
@@ -286,11 +286,11 @@
|
|
|
286
286
|
"command": "bash .claude/hooks/scripts/r007-r008-drift-advisor.sh"
|
|
287
287
|
},
|
|
288
288
|
{
|
|
289
|
-
"type": "
|
|
290
|
-
"
|
|
289
|
+
"type": "command",
|
|
290
|
+
"command": "bash .claude/hooks/scripts/subagent-failure-advisor.sh"
|
|
291
291
|
}
|
|
292
292
|
],
|
|
293
|
-
"description": "Record agent outcomes + auto-continue workflow + R007/R008 drift advisory on subagent completion (autonomous-loop re-entry, #1545)"
|
|
293
|
+
"description": "Record agent outcomes + auto-continue workflow + R007/R008 drift advisory + failure advisory on subagent completion (autonomous-loop re-entry, #1545; #1631 replaced the self-referential prompt-type judge hook with an advisory-only command hook)"
|
|
294
294
|
}
|
|
295
295
|
],
|
|
296
296
|
"CwdChanged": [
|
|
@@ -323,7 +323,7 @@
|
|
|
323
323
|
"hooks": [
|
|
324
324
|
{
|
|
325
325
|
"type": "command",
|
|
326
|
-
"command": "#!/bin/bash\ninput=$(cat)\nmsg=$(
|
|
326
|
+
"command": "#!/bin/bash\ninput=$(cat)\nmsg=$(printf '%s\\n' \"$input\" | jq -r '.message // \"\"' 2>/dev/null)\nif [ -n \"$msg\" ]; then\n echo \"[Hook] Notification: $msg\" >&2\nfi\nprintf '%s\\n' \"$input\""
|
|
327
327
|
}
|
|
328
328
|
],
|
|
329
329
|
"description": "Display notifications for long-running operation completions"
|
|
@@ -335,7 +335,7 @@
|
|
|
335
335
|
"hooks": [
|
|
336
336
|
{
|
|
337
337
|
"type": "command",
|
|
338
|
-
"command": "#!/bin/bash\ninput=$(cat)\nteammate=$(
|
|
338
|
+
"command": "#!/bin/bash\ninput=$(cat)\nteammate=$(printf '%s\\n' \"$input\" | jq -r '.teammate_id // \"unknown\"' 2>/dev/null)\necho \"[Hook] TeammateIdle: $teammate — available for reassignment\" >&2\nprintf '%s\\n' \"$input\""
|
|
339
339
|
}
|
|
340
340
|
],
|
|
341
341
|
"description": "Track idle Agent Teams members for work reassignment"
|
|
@@ -347,7 +347,7 @@
|
|
|
347
347
|
"hooks": [
|
|
348
348
|
{
|
|
349
349
|
"type": "command",
|
|
350
|
-
"command": "#!/bin/bash\ninput=$(cat)\ntask_id=$(
|
|
350
|
+
"command": "#!/bin/bash\ninput=$(cat)\ntask_id=$(printf '%s\\n' \"$input\" | jq -r '.task_id // \"\"' 2>/dev/null)\ndesc=$(printf '%s\\n' \"$input\" | jq -r '.description // \"\"' 2>/dev/null | head -c 60)\necho \"[Hook] TaskCreated: $task_id — $desc\" >&2\nprintf '%s\\n' \"$input\""
|
|
351
351
|
}
|
|
352
352
|
],
|
|
353
353
|
"description": "Log task creation events for Agent Teams coordination"
|
|
@@ -359,7 +359,7 @@
|
|
|
359
359
|
"hooks": [
|
|
360
360
|
{
|
|
361
361
|
"type": "command",
|
|
362
|
-
"command": "#!/bin/bash\ninput=$(cat)\ntask_id=$(
|
|
362
|
+
"command": "#!/bin/bash\ninput=$(cat)\ntask_id=$(printf '%s\\n' \"$input\" | jq -r '.task_id // \"\"' 2>/dev/null)\nresult=$(printf '%s\\n' \"$input\" | jq -r '.result // \"\"' 2>/dev/null | head -c 60)\necho \"[Hook] TaskCompleted: $task_id — $result\" >&2\nprintf '%s\\n' \"$input\""
|
|
363
363
|
}
|
|
364
364
|
],
|
|
365
365
|
"description": "Log task completion events for Agent Teams coordination"
|
|
@@ -395,7 +395,7 @@
|
|
|
395
395
|
"hooks": [
|
|
396
396
|
{
|
|
397
397
|
"type": "command",
|
|
398
|
-
"command": "#!/bin/bash\ninput=$(cat)\ncmd=$(
|
|
398
|
+
"command": "#!/bin/bash\ninput=$(cat)\ncmd=$(printf '%s\\n' \"$input\" | jq -r '.tool_input.command')\n\nif echo \"$cmd\" | grep -qE 'gh pr create'; then\n output=$(printf '%s\\n' \"$input\" | jq -r '.tool_output.output // \"\"')\n pr_url=$(echo \"$output\" | grep -oE 'https://github.com/[^/]+/[^/]+/pull/[0-9]+')\n \n if [ -n \"$pr_url\" ]; then\n echo \"[Hook] PR created: $pr_url\" >&2\n echo \"[Hook] Checking GitHub Actions status...\" >&2\n repo=$(echo \"$pr_url\" | sed -E 's|https://github.com/([^/]+/[^/]+)/pull/[0-9]+|\\1|')\n pr_num=$(echo \"$pr_url\" | sed -E 's|.*/pull/([0-9]+)|\\1|')\n echo \"[Hook] To review PR: gh pr review $pr_num --repo $repo\" >&2\n fi\nfi\n\nprintf '%s\\n' \"$input\""
|
|
399
399
|
}
|
|
400
400
|
],
|
|
401
401
|
"description": "Log PR URL and provide review command after PR creation"
|
|
@@ -405,7 +405,7 @@
|
|
|
405
405
|
"hooks": [
|
|
406
406
|
{
|
|
407
407
|
"type": "command",
|
|
408
|
-
"command": "#!/bin/bash\ninput=$(cat)\nfile_path=$(
|
|
408
|
+
"command": "#!/bin/bash\ninput=$(cat)\nfile_path=$(printf '%s\\n' \"$input\" | jq -r '.tool_input.file_path // \"\"')\n\nif [ -n \"$file_path\" ] && [ -f \"$file_path\" ]; then\n if command -v prettier >/dev/null 2>&1; then\n prettier --write \"$file_path\" 2>&1 | head -5 >&2\n fi\nfi\n\nprintf '%s\\n' \"$input\""
|
|
409
409
|
}
|
|
410
410
|
],
|
|
411
411
|
"description": "Auto-format JS/TS files with Prettier after edits"
|
|
@@ -415,7 +415,7 @@
|
|
|
415
415
|
"hooks": [
|
|
416
416
|
{
|
|
417
417
|
"type": "command",
|
|
418
|
-
"command": "#!/bin/bash\ninput=$(cat)\nfile_path=$(
|
|
418
|
+
"command": "#!/bin/bash\ninput=$(cat)\nfile_path=$(printf '%s\\n' \"$input\" | jq -r '.tool_input.file_path // \"\"')\n\nif [ -n \"$file_path\" ] && [ -f \"$file_path\" ]; then\n dir=$(dirname \"$file_path\")\n project_root=\"$dir\"\n while [ \"$project_root\" != \"/\" ] && [ ! -f \"$project_root/package.json\" ]; do\n project_root=$(dirname \"$project_root\")\n done\n \n if [ -f \"$project_root/tsconfig.json\" ]; then\n cd \"$project_root\" && npx tsc --noEmit --pretty false 2>&1 | grep \"$file_path\" | head -10 >&2 || true\n fi\nfi\n\nprintf '%s\\n' \"$input\"",
|
|
419
419
|
"continueOnBlock": true
|
|
420
420
|
}
|
|
421
421
|
],
|
|
@@ -426,7 +426,7 @@
|
|
|
426
426
|
"hooks": [
|
|
427
427
|
{
|
|
428
428
|
"type": "command",
|
|
429
|
-
"command": "#!/bin/bash\ninput=$(cat)\nfile_path=$(
|
|
429
|
+
"command": "#!/bin/bash\ninput=$(cat)\nfile_path=$(printf '%s\\n' \"$input\" | jq -r '.tool_input.file_path // \"\"')\n\nif [ -n \"$file_path\" ] && [ -f \"$file_path\" ]; then\n console_logs=$(grep -n \"console\\\\.log\" \"$file_path\" 2>/dev/null || true)\n \n if [ -n \"$console_logs\" ]; then\n echo \"[Hook] WARNING: console.log found in $file_path\" >&2\n echo \"$console_logs\" | head -5 >&2\n echo \"[Hook] Remove console.log before committing\" >&2\n fi\nfi\n\nprintf '%s\\n' \"$input\"",
|
|
430
430
|
"continueOnBlock": true
|
|
431
431
|
}
|
|
432
432
|
],
|
|
@@ -437,7 +437,7 @@
|
|
|
437
437
|
"hooks": [
|
|
438
438
|
{
|
|
439
439
|
"type": "command",
|
|
440
|
-
"command": "#!/bin/bash\ninput=$(cat)\nfile_path=$(
|
|
440
|
+
"command": "#!/bin/bash\ninput=$(cat)\nfile_path=$(printf '%s\\n' \"$input\" | jq -r '.tool_input.file_path // \"\"')\n\nif [ -n \"$file_path\" ] && [ -f \"$file_path\" ]; then\n if command -v gofmt >/dev/null 2>&1; then\n gofmt -w \"$file_path\" 2>&1 >&2\n fi\nfi\n\nprintf '%s\\n' \"$input\""
|
|
441
441
|
}
|
|
442
442
|
],
|
|
443
443
|
"description": "Auto-format Go files with gofmt after edits"
|
|
@@ -447,7 +447,7 @@
|
|
|
447
447
|
"hooks": [
|
|
448
448
|
{
|
|
449
449
|
"type": "command",
|
|
450
|
-
"command": "#!/bin/bash\ninput=$(cat)\nfile_path=$(
|
|
450
|
+
"command": "#!/bin/bash\ninput=$(cat)\nfile_path=$(printf '%s\\n' \"$input\" | jq -r '.tool_input.file_path // \"\"')\n\nif [ -n \"$file_path\" ] && [ -f \"$file_path\" ]; then\n # Format with ruff\n if command -v ruff >/dev/null 2>&1; then\n ruff format --quiet \"$file_path\" 2>&1 >&2\n ruff check --fix --quiet \"$file_path\" 2>&1 >&2 || true\n echo \"[Hook] Python formatted with ruff\" >&2\n fi\nfi\n\nprintf '%s\\n' \"$input\"",
|
|
451
451
|
"continueOnBlock": true
|
|
452
452
|
}
|
|
453
453
|
],
|
|
@@ -458,7 +458,7 @@
|
|
|
458
458
|
"hooks": [
|
|
459
459
|
{
|
|
460
460
|
"type": "command",
|
|
461
|
-
"command": "#!/bin/bash\ninput=$(cat)\nfile_path=$(
|
|
461
|
+
"command": "#!/bin/bash\ninput=$(cat)\nfile_path=$(printf '%s\\n' \"$input\" | jq -r '.tool_input.file_path // \"\"')\n\nif [ -n \"$file_path\" ] && [ -f \"$file_path\" ]; then\n # Type check with ty\n if command -v ty >/dev/null 2>&1; then\n dir=$(dirname \"$file_path\")\n project_root=\"$dir\"\n while [ \"$project_root\" != \"/\" ] && [ ! -f \"$project_root/pyproject.toml\" ]; do\n project_root=$(dirname \"$project_root\")\n done\n \n if [ -f \"$project_root/pyproject.toml\" ]; then\n cd \"$project_root\" && ty check \"$file_path\" 2>&1 | head -10 >&2 || true\n else\n ty check \"$file_path\" 2>&1 | head -10 >&2 || true\n fi\n fi\nfi\n\nprintf '%s\\n' \"$input\"",
|
|
462
462
|
"continueOnBlock": true
|
|
463
463
|
}
|
|
464
464
|
],
|
|
@@ -10,9 +10,9 @@ command -v jq >/dev/null 2>&1 || { cat; exit 0; }
|
|
|
10
10
|
|
|
11
11
|
input=$(cat)
|
|
12
12
|
|
|
13
|
-
agent_type=$(
|
|
14
|
-
model=$(
|
|
15
|
-
description=$(
|
|
13
|
+
agent_type=$(printf '%s\n' "$input" | jq -r '.agent_type // "unknown"')
|
|
14
|
+
model=$(printf '%s\n' "$input" | jq -r '.model // "inherit"')
|
|
15
|
+
description=$(printf '%s\n' "$input" | jq -r '.description // ""' | head -c 80)
|
|
16
16
|
|
|
17
17
|
AGENT_START_FILE="/tmp/.claude-agent-starts-${PPID}"
|
|
18
18
|
|
|
@@ -25,7 +25,7 @@ entry=$(jq -cn \
|
|
|
25
25
|
--arg desc "$description" \
|
|
26
26
|
'{start_epoch: $ts, agent_type: $agent, model: $model, description: $desc}')
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
printf '%s\n' "$entry" >> "$AGENT_START_FILE"
|
|
29
29
|
|
|
30
30
|
# Ring buffer: 50 max
|
|
31
31
|
if [ -f "$AGENT_START_FILE" ]; then
|
|
@@ -36,5 +36,5 @@ if [ -f "$AGENT_START_FILE" ]; then
|
|
|
36
36
|
fi
|
|
37
37
|
fi
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
printf '%s\n' "$input"
|
|
40
40
|
exit 0
|
|
@@ -21,7 +21,7 @@ ENV_STATUS="/tmp/.claude-env-status-${PPID}"
|
|
|
21
21
|
if [ -f "$ENV_STATUS" ]; then
|
|
22
22
|
teams_status=$(grep "agent_teams=" "$ENV_STATUS" 2>/dev/null | cut -d= -f2 || echo "unknown")
|
|
23
23
|
if [ "$teams_status" != "enabled" ]; then
|
|
24
|
-
|
|
24
|
+
printf '%s\n' "$input"
|
|
25
25
|
exit 0
|
|
26
26
|
fi
|
|
27
27
|
fi
|
|
@@ -43,8 +43,8 @@ if [ -f "$RELEASE_PLAN" ]; then
|
|
|
43
43
|
fi
|
|
44
44
|
|
|
45
45
|
# Extract task info from input
|
|
46
|
-
agent_type=$(
|
|
47
|
-
prompt_preview=$(
|
|
46
|
+
agent_type=$(printf '%s\n' "$input" | jq -r '.tool_input.subagent_type // "unknown"')
|
|
47
|
+
prompt_preview=$(printf '%s\n' "$input" | jq -r '.tool_input.description // ""' | head -c 60)
|
|
48
48
|
|
|
49
49
|
# Session-scoped counter using parent PID as session identifier
|
|
50
50
|
COUNTER_FILE="/tmp/.claude-task-count-${PPID}"
|
|
@@ -77,5 +77,5 @@ elif [ "$COUNT" -ge 2 ]; then
|
|
|
77
77
|
fi
|
|
78
78
|
|
|
79
79
|
# Always pass through -- advisory only, never blocks
|
|
80
|
-
|
|
80
|
+
printf '%s\n' "$input"
|
|
81
81
|
exit 0
|
|
@@ -14,11 +14,11 @@ command -v jq >/dev/null 2>&1 || exit 0
|
|
|
14
14
|
input=$(cat)
|
|
15
15
|
|
|
16
16
|
# Extract fields from hook input
|
|
17
|
-
tool_name=$(
|
|
18
|
-
file_path=$(
|
|
19
|
-
agent_type=$(
|
|
20
|
-
model=$(
|
|
21
|
-
is_error=$(
|
|
17
|
+
tool_name=$(printf '%s\n' "$input" | jq -r '.tool_name // "unknown"')
|
|
18
|
+
file_path=$(printf '%s\n' "$input" | jq -r '.tool_input.file_path // .tool_input.command // ""' | head -c 200)
|
|
19
|
+
agent_type=$(printf '%s\n' "$input" | jq -r '.agent_type // "unknown"')
|
|
20
|
+
model=$(printf '%s\n' "$input" | jq -r '.model // "unknown"')
|
|
21
|
+
is_error=$(printf '%s\n' "$input" | jq -r '.tool_output.is_error // false')
|
|
22
22
|
timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
23
23
|
|
|
24
24
|
# Determine outcome
|
|
@@ -55,7 +55,7 @@ if [ -f "$AUDIT_LOG" ]; then
|
|
|
55
55
|
fi
|
|
56
56
|
|
|
57
57
|
# Pass through
|
|
58
|
-
|
|
58
|
+
printf '%s\n' "$input"
|
|
59
59
|
HOOK_END=$(date +%s%N 2>/dev/null || echo 0)
|
|
60
60
|
if [ "$HOOK_START" != "0" ] && [ "$HOOK_END" != "0" ]; then
|
|
61
61
|
HOOK_MS=$(( (HOOK_END - HOOK_START) / 1000000 ))
|
|
@@ -32,7 +32,7 @@ summary=$(jq -s -r '
|
|
|
32
32
|
[ "$summary" = "[]" ] && exit 0
|
|
33
33
|
|
|
34
34
|
# Totals
|
|
35
|
-
totals=$(
|
|
35
|
+
totals=$(printf '%s\n' "$summary" | jq -r '
|
|
36
36
|
{
|
|
37
37
|
total_calls: (map(.calls) | add),
|
|
38
38
|
total_in: (map(.tokens_in) | add),
|
|
@@ -40,10 +40,10 @@ totals=$(echo "$summary" | jq -r '
|
|
|
40
40
|
grand: (map(.total) | add)
|
|
41
41
|
}
|
|
42
42
|
')
|
|
43
|
-
total_calls=$(
|
|
44
|
-
total_in=$(
|
|
45
|
-
total_out=$(
|
|
46
|
-
grand=$(
|
|
43
|
+
total_calls=$(printf '%s\n' "$totals" | jq -r '.total_calls')
|
|
44
|
+
total_in=$(printf '%s\n' "$totals" | jq -r '.total_in')
|
|
45
|
+
total_out=$(printf '%s\n' "$totals" | jq -r '.total_out')
|
|
46
|
+
grand=$(printf '%s\n' "$totals" | jq -r '.grand')
|
|
47
47
|
|
|
48
48
|
{
|
|
49
49
|
echo ""
|
|
@@ -52,7 +52,7 @@ grand=$(echo "$totals" | jq -r '.grand')
|
|
|
52
52
|
echo ""
|
|
53
53
|
printf "| %-32s | %5s | %10s | %10s | %10s |\n" "Phase" "Calls" "Tokens In" "Tokens Out" "Total"
|
|
54
54
|
printf "| %-32s | %5s | %10s | %10s | %10s |\n" "--------------------------------" "-----" "----------" "----------" "----------"
|
|
55
|
-
|
|
55
|
+
printf '%s\n' "$summary" | jq -r '.[] | "\(.phase)\t\(.calls)\t\(.tokens_in)\t\(.tokens_out)\t\(.total)"' | \
|
|
56
56
|
while IFS=$'\t' read -r phase calls tin tout tot; do
|
|
57
57
|
phase_trunc=$(printf "%s" "$phase" | head -c 32)
|
|
58
58
|
printf "| %-32s | %5s | %10s | %10s | %10s |\n" "$phase_trunc" "$calls" "$tin" "$tout" "$tot"
|
|
@@ -9,7 +9,7 @@ set -euo pipefail
|
|
|
9
9
|
|
|
10
10
|
# Always pass through input no matter what
|
|
11
11
|
input=$(cat)
|
|
12
|
-
trap '
|
|
12
|
+
trap 'printf "%s\n" "$input"' EXIT
|
|
13
13
|
|
|
14
14
|
# Gate: only active during auto-dev pipeline
|
|
15
15
|
PIPELINE_STATE="/tmp/.claude-pipeline-auto-dev-${PPID}.json"
|
|
@@ -21,10 +21,10 @@ command -v jq >/dev/null 2>&1 || exit 0
|
|
|
21
21
|
LOG_FILE="/tmp/auto-dev-spend-${PPID}.json"
|
|
22
22
|
|
|
23
23
|
# Extract fields (PostToolUse Agent shape)
|
|
24
|
-
agent_type=$(
|
|
25
|
-
description=$(
|
|
26
|
-
prompt_text=$(
|
|
27
|
-
output_text=$(
|
|
24
|
+
agent_type=$(printf '%s\n' "$input" | jq -r '.tool_input.subagent_type // "unknown"' 2>/dev/null || echo "unknown")
|
|
25
|
+
description=$(printf '%s\n' "$input" | jq -r '.tool_input.description // ""' 2>/dev/null || echo "")
|
|
26
|
+
prompt_text=$(printf '%s\n' "$input" | jq -r '.tool_input.prompt // ""' 2>/dev/null || echo "")
|
|
27
|
+
output_text=$(printf '%s\n' "$input" | jq -r '.tool_output.output // .tool_output // ""' 2>/dev/null || echo "")
|
|
28
28
|
|
|
29
29
|
# Derive phase from pipeline state (current_phase) or fallback to description prefix
|
|
30
30
|
phase=$(jq -r '.current_phase // .phase // "unknown"' "$PIPELINE_STATE" 2>/dev/null || echo "unknown")
|
|
@@ -52,6 +52,6 @@ entry=$(jq -n -c \
|
|
|
52
52
|
--argjson tout "$tokens_out" \
|
|
53
53
|
'{ts: $ts, phase: $phase, agent: $agent, tokens_in: $tin, tokens_out: $tout}' 2>/dev/null) || exit 0
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
printf '%s\n' "$entry" >> "$LOG_FILE" 2>/dev/null || true
|
|
56
56
|
|
|
57
57
|
exit 0
|
|
@@ -6,13 +6,18 @@
|
|
|
6
6
|
# 규칙 amnesia가 재발한다. 기존 PostCompact 훅(hooks.json)은 "prompt" 타입으로 요약 지침만
|
|
7
7
|
# 재주입할 뿐, CLAUDE.md 원문 전체를 재주입하지 않는다.
|
|
8
8
|
#
|
|
9
|
-
# 배선 이벤트 (Phase 1 판단, #1617):
|
|
9
|
+
# 배선 이벤트 (Phase 1 판단, #1617 / matcher 협소화 #1626):
|
|
10
10
|
# R006 실측 기준(이 저장소 rules/MUST-agent-design.md) additionalContext 지원 이벤트 목록에
|
|
11
11
|
# SessionStart는 있고 PostCompact는 없다. 한편 공식 문서(hooks.md, 2026-08-29 재확인)의
|
|
12
12
|
# SessionStart matcher는 startup / resume / clear / compact 네 가지이며, "compact"는
|
|
13
|
-
# auto/manual compact 직후를
|
|
14
|
-
#
|
|
15
|
-
#
|
|
13
|
+
# auto/manual compact 직후를 가리킨다. 별도 PostCompact 배선은 불필요 — 공식 문서 이벤트
|
|
14
|
+
# 목록(### 헤더 스캔)에 PostCompact 자체가 없다(PreCompact만 존재).
|
|
15
|
+
#
|
|
16
|
+
# #1626 실측: startup 시점 재주입은 CC의 네이티브 CLAUDE.md 자동 로드와 중복(13,817 B/세션
|
|
17
|
+
# 순수 낭비)이며, resume/clear는 이전 컨텍스트가 그대로 복원되므로 재주입이 불요하다.
|
|
18
|
+
# 원 목적(#1617 — compact 후 규칙 amnesia 방지)은 "compact" 소스만으로 충분히 달성되므로,
|
|
19
|
+
# hooks.json의 matcher를 "*" → "compact"로 좁혔다. 이 스크립트 자체는 source 필터링을
|
|
20
|
+
# 하지 않으므로(아래 source_field는 로그 헤더용) hooks.json matcher가 유일한 게이트다.
|
|
16
21
|
#
|
|
17
22
|
# 동작:
|
|
18
23
|
# stdin JSON의 .source(startup/resume/clear/compact/기타)를 로그 헤더에 포함해
|
|
@@ -15,12 +15,12 @@ input=$(cat)
|
|
|
15
15
|
# Hash store (PPID-scoped, session-only)
|
|
16
16
|
HASH_STORE="/tmp/.claude-content-hashes-${PPID}"
|
|
17
17
|
|
|
18
|
-
tool_name=$(
|
|
18
|
+
tool_name=$(printf '%s\n' "$input" | jq -r '.tool_name // "unknown"')
|
|
19
19
|
|
|
20
20
|
case "$tool_name" in
|
|
21
21
|
"Read")
|
|
22
22
|
# Store content hash for the file that was just read
|
|
23
|
-
file_path=$(
|
|
23
|
+
file_path=$(printf '%s\n' "$input" | jq -r '.tool_input.file_path // ""')
|
|
24
24
|
|
|
25
25
|
if [ -n "$file_path" ] && [ -f "$file_path" ]; then
|
|
26
26
|
content_hash=$(md5 -q "$file_path" 2>/dev/null || md5sum "$file_path" 2>/dev/null | cut -d' ' -f1 || echo "unknown")
|
|
@@ -43,7 +43,7 @@ case "$tool_name" in
|
|
|
43
43
|
|
|
44
44
|
"Edit")
|
|
45
45
|
# Validate that file hasn't changed since last Read
|
|
46
|
-
file_path=$(
|
|
46
|
+
file_path=$(printf '%s\n' "$input" | jq -r '.tool_input.file_path // ""')
|
|
47
47
|
|
|
48
48
|
if [ -n "$file_path" ] && [ -f "$HASH_STORE" ] && [ -f "$file_path" ]; then
|
|
49
49
|
stored_hash=$(grep "\"path\":\"${file_path}\"" "$HASH_STORE" 2>/dev/null | tail -1 | jq -r '.hash // ""' 2>/dev/null || echo "")
|
|
@@ -71,5 +71,5 @@ if [ -f "$HASH_STORE" ]; then
|
|
|
71
71
|
fi
|
|
72
72
|
|
|
73
73
|
# Always pass through
|
|
74
|
-
|
|
74
|
+
printf '%s\n' "$input"
|
|
75
75
|
exit 0
|
|
@@ -33,7 +33,7 @@ read_count=${read_count:-0}
|
|
|
33
33
|
agent_count=${agent_count:-0}
|
|
34
34
|
|
|
35
35
|
# Determine tool type from input
|
|
36
|
-
TOOL=$(
|
|
36
|
+
TOOL=$(printf '%s\n' "$input" | jq -r '.tool_name // ""' 2>/dev/null || echo "")
|
|
37
37
|
tool_count=$((tool_count + 1))
|
|
38
38
|
|
|
39
39
|
case "$TOOL" in
|
|
@@ -95,7 +95,7 @@ if [ "$tool_count" -ge "$THRESHOLD" ] && [ ! -f "$BLOCK_FILE" ]; then
|
|
|
95
95
|
HOOK_MS=$(( (HOOK_END - HOOK_START) / 1000000 ))
|
|
96
96
|
echo "[Hook Perf] $(basename "$0"): ${HOOK_MS}ms" >> "/tmp/.claude-hook-perf-${PPID}.log"
|
|
97
97
|
fi
|
|
98
|
-
|
|
98
|
+
printf '%s\n' "$input"
|
|
99
99
|
exit 2
|
|
100
100
|
fi
|
|
101
101
|
|
|
@@ -112,7 +112,7 @@ if [ "$tool_count" -gt 0 ] && [ $((tool_count % 50)) -eq 0 ]; then
|
|
|
112
112
|
fi
|
|
113
113
|
|
|
114
114
|
# Pass through
|
|
115
|
-
|
|
115
|
+
printf '%s\n' "$input"
|
|
116
116
|
HOOK_END=$(date +%s%N 2>/dev/null || echo 0)
|
|
117
117
|
if [ "$HOOK_START" != "0" ] && [ "$HOOK_END" != "0" ]; then
|
|
118
118
|
HOOK_MS=$(( (HOOK_END - HOOK_START) / 1000000 ))
|
|
@@ -15,19 +15,19 @@ COST_CAP="${CLAUDE_COST_CAP:-5.00}"
|
|
|
15
15
|
|
|
16
16
|
# Check if cost data is available
|
|
17
17
|
if [ ! -f "$COST_FILE" ]; then
|
|
18
|
-
|
|
18
|
+
printf '%s\n' "$input"
|
|
19
19
|
exit 0
|
|
20
20
|
fi
|
|
21
21
|
|
|
22
22
|
# TSV: cost_usd, ctx_pct, timestamp, rl_5h_pct, rl_7d_pct, rl_5h_resets, rl_7d_resets
|
|
23
23
|
IFS=$'\t' read -r cost_usd ctx_pct timestamp _rl_5h _rl_7d _rl_5h_resets _rl_7d_resets < "$COST_FILE" 2>/dev/null || {
|
|
24
|
-
|
|
24
|
+
printf '%s\n' "$input"
|
|
25
25
|
exit 0
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
# Validate cost_usd is a number
|
|
29
29
|
if ! printf '%f' "$cost_usd" >/dev/null 2>&1; then
|
|
30
|
-
|
|
30
|
+
printf '%s\n' "$input"
|
|
31
31
|
exit 0
|
|
32
32
|
fi
|
|
33
33
|
|
|
@@ -39,7 +39,7 @@ cost_pct=$(echo "scale=0; $cost_usd * 100 / $COST_CAP" | bc 2>/dev/null || echo
|
|
|
39
39
|
now=$(date +%s)
|
|
40
40
|
age=$((now - ${timestamp:-0}))
|
|
41
41
|
if [ "$age" -gt 60 ]; then
|
|
42
|
-
|
|
42
|
+
printf '%s\n' "$input"
|
|
43
43
|
exit 0
|
|
44
44
|
fi
|
|
45
45
|
|
|
@@ -54,7 +54,7 @@ if [ "$cost_pct" -ge 100 ] && [ "$last_level" != "100" ]; then
|
|
|
54
54
|
echo "[Cost Cap] Session cost \$${cost_usd} has reached cap \$${COST_CAP} (${cost_pct}%)" >&2
|
|
55
55
|
echo "[Cost Cap] Consider wrapping up or increasing CLAUDE_COST_CAP" >&2
|
|
56
56
|
echo "100" > "$ADVISORY_FILE"
|
|
57
|
-
|
|
57
|
+
printf '%s\n' "$input"
|
|
58
58
|
exit 2
|
|
59
59
|
elif [ "$cost_pct" -ge 90 ] && [ "$last_level" != "90" ] && [ "$last_level" != "100" ]; then
|
|
60
60
|
echo "[Cost Cap] Session cost \$${cost_usd} at 90% of cap \$${COST_CAP}" >&2
|
|
@@ -69,5 +69,5 @@ elif [ "$cost_pct" -ge 50 ] && [ -z "$last_level" ]; then
|
|
|
69
69
|
fi
|
|
70
70
|
|
|
71
71
|
# Pass through — advisory only
|
|
72
|
-
|
|
72
|
+
printf '%s\n' "$input"
|
|
73
73
|
exit 0
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
# Advisory only — provides context hints when cwd changes
|
|
4
4
|
|
|
5
5
|
input=$(cat)
|
|
6
|
-
new_cwd=$(
|
|
6
|
+
new_cwd=$(printf '%s\n' "$input" | jq -r '.new_cwd // ""' 2>/dev/null)
|
|
7
7
|
|
|
8
8
|
if [ -z "$new_cwd" ] || [ ! -d "$new_cwd" ]; then
|
|
9
|
-
|
|
9
|
+
printf '%s\n' "$input"
|
|
10
10
|
exit 0
|
|
11
11
|
fi
|
|
12
12
|
|
|
@@ -33,4 +33,4 @@ if [ -n "$hints" ]; then
|
|
|
33
33
|
printf "%b" "$hints" >&2
|
|
34
34
|
fi
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
printf '%s\n' "$input"
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
input=$(cat)
|
|
11
11
|
if command -v jq >/dev/null 2>&1; then
|
|
12
|
-
command_text=$(
|
|
12
|
+
command_text=$(printf '%s\n' "$input" | jq -r '.tool_input.command // ""' 2>/dev/null)
|
|
13
13
|
elif command -v python3 >/dev/null 2>&1; then
|
|
14
14
|
command_text=$(INPUT_JSON="$input" python3 - <<'PY' 2>/dev/null
|
|
15
15
|
import json, os
|
|
@@ -57,4 +57,4 @@ if [ -n "$matched" ]; then
|
|
|
57
57
|
fi
|
|
58
58
|
|
|
59
59
|
# Always pass through - this hook is advisory only.
|
|
60
|
-
|
|
60
|
+
printf '%s\n' "$input"
|
|
@@ -14,7 +14,7 @@ PPID_FILE="/tmp/.claude-task-outcomes-${PPID}"
|
|
|
14
14
|
|
|
15
15
|
# Only attempt collection if outcome file exists
|
|
16
16
|
if [ ! -f "$PPID_FILE" ]; then
|
|
17
|
-
|
|
17
|
+
printf '%s\n' "$input"
|
|
18
18
|
exit 0
|
|
19
19
|
fi
|
|
20
20
|
|
|
@@ -42,5 +42,5 @@ if [ -n "$EVAL_CORE" ]; then
|
|
|
42
42
|
fi
|
|
43
43
|
|
|
44
44
|
# Always pass through input and exit 0 (advisory only)
|
|
45
|
-
|
|
45
|
+
printf '%s\n' "$input"
|
|
46
46
|
exit 0
|