@webpieces/ai-hook-rules 0.3.281 → 0.3.283
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpieces/ai-hook-rules",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.283",
|
|
4
4
|
"description": "Pluggable write-time validation framework for AI coding agents (@webpieces/ai-hook-rules). Claude Code PreToolUse + openclaw before_tool_call adapters share one rule engine.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"directory": "packages/tooling/ai-hook-rules"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@webpieces/rules-config": "0.3.
|
|
38
|
+
"@webpieces/rules-config": "0.3.283"
|
|
39
39
|
},
|
|
40
40
|
"publishConfig": {
|
|
41
41
|
"access": "public"
|
|
@@ -51,6 +51,10 @@ function denyJson(reason, toolName) {
|
|
|
51
51
|
}
|
|
52
52
|
// Block the tool call and surface `reason` to both the user (terminal UI) and the model. `toolName`
|
|
53
53
|
// selects whether the red `systemMessage` is added (Bash) or omitted (file tools) — see denyJson.
|
|
54
|
+
// NOTE: emitDeny/emitAllow are the hook's designated terminal boundary — the exit code IS the
|
|
55
|
+
// Claude Code PreToolUse protocol (exit 0 + JSON = the contract). When the
|
|
56
|
+
// @webpieces/no-process-exit-outside-main rule is activated repo-wide (after the tooling release
|
|
57
|
+
// carrying it), add its eslint-disable-next-line above each process.exit below.
|
|
54
58
|
function emitDeny(reason, toolName) {
|
|
55
59
|
process.stdout.write(denyJson(reason, toolName) + '\n');
|
|
56
60
|
process.exit(0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-code-response.js","sourceRoot":"","sources":["../../../../../../packages/tooling/ai-hook-rules/src/adapters/claude-code-response.ts"],"names":[],"mappings":";AAAA,+FAA+F;AAC/F,sFAAsF;AACtF,yGAAyG;AACzG,EAAE;AACF,gGAAgG;AAChG,kGAAkG;AAClG,uGAAuG;AACvG,oDAAoD;AACpD,EAAE;AACF,oGAAoG;AACpG,oDAAoD;AACpD,EAAE;AACF,8GAA8G;AAC9G,8GAA8G;AAC9G,8GAA8G;AAC9G,8GAA8G;AAC9G,8GAA8G;AAC9G,EAAE;AACF,mGAAmG;AACnG,qFAAqF;AACrF,qGAAqG;AACrG,mGAAmG;AACnG,mGAAmG;AACnG,oGAAoG;AACpG,8FAA8F;AAC9F,yCAAyC;AACzC,6FAA6F;;AAS7F,4BAYC;
|
|
1
|
+
{"version":3,"file":"claude-code-response.js","sourceRoot":"","sources":["../../../../../../packages/tooling/ai-hook-rules/src/adapters/claude-code-response.ts"],"names":[],"mappings":";AAAA,+FAA+F;AAC/F,sFAAsF;AACtF,yGAAyG;AACzG,EAAE;AACF,gGAAgG;AAChG,kGAAkG;AAClG,uGAAuG;AACvG,oDAAoD;AACpD,EAAE;AACF,oGAAoG;AACpG,oDAAoD;AACpD,EAAE;AACF,8GAA8G;AAC9G,8GAA8G;AAC9G,8GAA8G;AAC9G,8GAA8G;AAC9G,8GAA8G;AAC9G,EAAE;AACF,mGAAmG;AACnG,qFAAqF;AACrF,qGAAqG;AACrG,mGAAmG;AACnG,mGAAmG;AACnG,oGAAoG;AACpG,8FAA8F;AAC9F,yCAAyC;AACzC,6FAA6F;;AAS7F,4BAYC;AAQD,4BAGC;AAGD,8BAEC;AAnCD,qGAAqG;AACrG,uGAAuG;AACvG,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;AACtC,SAAS,gBAAgB,CAAC,MAAc;IACpC,OAAO,GAAG,GAAG,YAAY,MAAM,GAAG,GAAG,KAAK,CAAC;AAC/C,CAAC;AAED,SAAgB,QAAQ,CAAC,MAAc,EAAE,QAAgB;IACrD,MAAM,kBAAkB,GAAG;QACvB,aAAa,EAAE,YAAY;QAC3B,kBAAkB,EAAE,MAAM;QAC1B,wBAAwB,EAAE,MAAM;KACnC,CAAC;IACF,yFAAyF;IACzF,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,aAAa,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC3F,CAAC;IACD,2FAA2F;IAC3F,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,kBAAkB,EAAE,CAAC,CAAC;AAClD,CAAC;AAED,oGAAoG;AACpG,kGAAkG;AAClG,8FAA8F;AAC9F,2EAA2E;AAC3E,iGAAiG;AACjG,gFAAgF;AAChF,SAAgB,QAAQ,CAAC,MAAc,EAAE,QAAgB;IACrD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC;IACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC;AAED,+FAA+F;AAC/F,SAAgB,SAAS;IACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC","sourcesContent":["// The single place that knows Claude Code's PreToolUse decision protocol, so every deny in the\n// Claude Code adapter is emitted identically — and identically to the checked-in shim\n// (.claude/webpieces/ai-hook.sh, rendered by renderShim() in ../bin/shim.ts), which emits the same JSON.\n//\n// A block is signalled by `permissionDecision: \"deny\"` JSON on STDOUT with exit 0 — NOT exit 2.\n// Claude Code only parses the JSON on exit 0; exit 2 would ignore stdout and the reason would not\n// surface in the terminal UI. \"deny\" still blocks the tool, so this remains fail-closed: it is not the\n// silent-allow a bare exit 0 with no JSON would be.\n//\n// WHY the tool-conditional `systemMessage` (verified by live tests against Claude Code v2.1.x — the\n// docs are wrong here; do NOT re-derive from them):\n//\n// | deny field | Bash tool | Write/Edit/MultiEdit tool |\n// |-----------------------------------|-----------------------------------|-------------------------------|\n// | permissionDecisionReason (plain) | model sees it; USER SEES NOTHING | model + RED \"Error:\" block ok |\n// | systemMessage | ONLY user-visible field; grey | grey extra line (redundant) |\n// | systemMessage wrapped in ANSI red | RED + visible to the user (fix) | redundant 2nd red line |\n//\n// So: on a **Bash** deny we ALSO emit a top-level `systemMessage` wrapped in ANSI red (ESC[31;1m …\n// ESC[0m) — it is the only field a Bash deny shows the human, and it honors ANSI. On\n// Write/Edit/MultiEdit we add NO `systemMessage` (the reason already renders red natively — a second\n// line is just noise). `permissionDecisionReason` is always plain text (never ANSI): it's what the\n// model reads and what Write/Edit renders red. JSON.stringify serializes the ESC char as the valid\n// \\u escape, so the payload stays valid JSON — we build the ESC via String.fromCharCode(0x1b) so no\n// raw ESC (0x1b) byte ever lives in this source file. Do NOT use exit 2 (stdout JSON ignored;\n// stderr invisible to the user on Bash).\n// Refs: Claude Code GitHub issues #31592, #40380, #17356 (asymmetry \"closed / not planned\").\n\n// ANSI escape (0x1b) built at runtime so no raw ESC byte sits in source. ANSI red is a *bonus* — the\n// 🛑 prefix + reason stay meaningful if a future/CI renderer strips the color. One place = one escape.\nconst ESC = String.fromCharCode(0x1b);\nfunction redSystemMessage(reason: string): string {\n return `${ESC}[31;1m🛑 ${reason}${ESC}[0m`;\n}\n\nexport function denyJson(reason: string, toolName: string): string {\n const hookSpecificOutput = {\n hookEventName: 'PreToolUse',\n permissionDecision: 'deny',\n permissionDecisionReason: reason,\n };\n // Bash only: permissionDecisionReason is NOT user-visible, so add the red systemMessage.\n if (toolName === 'Bash') {\n return JSON.stringify({ systemMessage: redSystemMessage(reason), hookSpecificOutput });\n }\n // Write/Edit/MultiEdit (and anything else): reason renders red natively; no systemMessage.\n return JSON.stringify({ hookSpecificOutput });\n}\n\n// Block the tool call and surface `reason` to both the user (terminal UI) and the model. `toolName`\n// selects whether the red `systemMessage` is added (Bash) or omitted (file tools) — see denyJson.\n// NOTE: emitDeny/emitAllow are the hook's designated terminal boundary — the exit code IS the\n// Claude Code PreToolUse protocol (exit 0 + JSON = the contract). When the\n// @webpieces/no-process-exit-outside-main rule is activated repo-wide (after the tooling release\n// carrying it), add its eslint-disable-next-line above each process.exit below.\nexport function emitDeny(reason: string, toolName: string): never {\n process.stdout.write(denyJson(reason, toolName) + '\\n');\n process.exit(0);\n}\n\n// Allow the tool call. No JSON needed — a silent exit 0 is \"allow\" in the PreToolUse protocol.\nexport function emitAllow(): never {\n process.exit(0);\n}\n"]}
|