block-no-verify 1.1.3 → 1.1.5

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.
Files changed (53) hide show
  1. package/README.md +45 -5
  2. package/dist/blocked-github-mcp-tool.d.ts +3 -0
  3. package/dist/blocked-github-mcp-tool.d.ts.map +1 -0
  4. package/dist/blocked-github-mcp-tool.js +2 -0
  5. package/dist/blocked-github-mcp-tool.js.map +1 -0
  6. package/dist/check-command-options.d.ts +11 -0
  7. package/dist/check-command-options.d.ts.map +1 -0
  8. package/dist/check-command-options.js +2 -0
  9. package/dist/check-command-options.js.map +1 -0
  10. package/dist/check-command.d.ts +9 -4
  11. package/dist/check-command.d.ts.map +1 -1
  12. package/dist/check-command.js +17 -4
  13. package/dist/check-command.js.map +1 -1
  14. package/dist/cli-help.d.ts +1 -1
  15. package/dist/cli-help.d.ts.map +1 -1
  16. package/dist/cli-help.js +6 -3
  17. package/dist/cli-help.js.map +1 -1
  18. package/dist/cli.js +4 -2
  19. package/dist/cli.js.map +1 -1
  20. package/dist/detect-github-mcp-tool.d.ts +12 -0
  21. package/dist/detect-github-mcp-tool.d.ts.map +1 -0
  22. package/dist/detect-github-mcp-tool.js +26 -0
  23. package/dist/detect-github-mcp-tool.js.map +1 -0
  24. package/dist/extract-from-json.d.ts +6 -0
  25. package/dist/extract-from-json.d.ts.map +1 -0
  26. package/dist/extract-from-json.js +73 -0
  27. package/dist/extract-from-json.js.map +1 -0
  28. package/dist/extracted-json.d.ts +8 -0
  29. package/dist/extracted-json.d.ts.map +1 -0
  30. package/dist/extracted-json.js +2 -0
  31. package/dist/extracted-json.js.map +1 -0
  32. package/dist/get-property.d.ts +5 -0
  33. package/dist/get-property.d.ts.map +1 -0
  34. package/dist/get-property.js +13 -0
  35. package/dist/get-property.js.map +1 -0
  36. package/dist/github-mcp-tools.d.ts +10 -0
  37. package/dist/github-mcp-tools.d.ts.map +1 -0
  38. package/dist/github-mcp-tools.js +18 -0
  39. package/dist/github-mcp-tools.js.map +1 -0
  40. package/dist/index.d.ts +4 -0
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +2 -0
  43. package/dist/index.js.map +1 -1
  44. package/dist/json-helpers.d.ts +5 -0
  45. package/dist/json-helpers.d.ts.map +1 -0
  46. package/dist/json-helpers.js +7 -0
  47. package/dist/json-helpers.js.map +1 -0
  48. package/dist/parse-input.d.ts.map +1 -1
  49. package/dist/parse-input.js +21 -102
  50. package/dist/parse-input.js.map +1 -1
  51. package/dist/parse-result.d.ts +6 -0
  52. package/dist/parse-result.d.ts.map +1 -1
  53. package/package.json +12 -12
package/README.md CHANGED
@@ -1,17 +1,36 @@
1
1
  # block-no-verify
2
2
 
3
- A platform-agnostic security tool that blocks the `--no-verify` flag in git commands. Designed to prevent AI agents from bypassing git hooks.
3
+ A platform-agnostic security tool that blocks ways AI agents can bypass local git hooks. It flags the `--no-verify` flag, `core.hooksPath` overrides, and GitHub MCP tool calls that write through the GitHub API.
4
4
 
5
5
  ## Why?
6
6
 
7
- When using AI coding assistants like Claude Code, Gemini CLI, Cursor, or others, you might have git hooks (pre-commit, pre-push) that enforce code quality, run tests, or perform security checks. The `--no-verify` flag allows bypassing these hooks, which could allow AI agents to skip important validations.
7
+ When using AI coding assistants like Claude Code, Gemini CLI, Cursor, or others, you might have git hooks (pre-commit, pre-push) that enforce code quality, run tests, or perform security checks. Agents can side-step those hooks in three common ways:
8
8
 
9
- This package provides a CLI that can block any git commands that include `--no-verify`, working with any AI tool that supports command hooks.
9
+ - passing `--no-verify` to a git command,
10
+ - overriding `core.hooksPath` (e.g. `git -c core.hooksPath=/dev/null ...`),
11
+ - calling GitHub MCP tools such as `mcp__github__push_files` that commit or merge directly through the GitHub API, skipping the local hook chain entirely.
12
+
13
+ This package provides a CLI that can block all three, working with any AI tool that supports command / tool-use hooks.
10
14
 
11
15
  ## Used By
12
16
 
13
17
  <a href="https://github.com/langgenius/dify">
14
- <img src="https://github.com/langgenius.png" width="50" height="50" alt="Dify" title="Dify - Open-source LLM app development platform">
18
+ <img src="https://github.com/langgenius.png" width="50" height="50" alt="Dify" title="Dify - Open-source LLM app development platform (133k★)">
19
+ </a>
20
+ <a href="https://github.com/nicolargo/glances">
21
+ <img src="https://github.com/nicolargo.png" width="50" height="50" alt="Glances" title="Glances - Cross-platform system monitoring tool (32k★)">
22
+ </a>
23
+ <a href="https://github.com/pubkey/rxdb">
24
+ <img src="https://github.com/pubkey.png" width="50" height="50" alt="RxDB" title="RxDB - Local-first database for JavaScript applications (23k★)">
25
+ </a>
26
+ <a href="https://github.com/promptfoo/promptfoo">
27
+ <img src="https://github.com/promptfoo.png" width="50" height="50" alt="Promptfoo" title="Promptfoo - LLM testing and evaluation framework (18k★)">
28
+ </a>
29
+ <a href="https://github.com/YFGaia/dify-plus">
30
+ <img src="https://github.com/YFGaia.png" width="50" height="50" alt="Dify Plus" title="Dify Plus - Enhanced Dify distribution (2k★)">
31
+ </a>
32
+ <a href="https://github.com/forcedotcom/salesforcedx-vscode">
33
+ <img src="https://github.com/forcedotcom.png" width="50" height="50" alt="Salesforce Extensions for VS Code" title="Salesforce Extensions for VS Code (1k★)">
15
34
  </a>
16
35
  <a href="https://centy.io">
17
36
  <img src="https://github.com/centy-io.png" width="50" height="50" alt="Centy" title="Centy">
@@ -52,7 +71,7 @@ echo "git push --no-verify" | block-no-verify
52
71
 
53
72
  ### Claude Code
54
73
 
55
- Add to your `.claude/settings.json`:
74
+ Add to your `.claude/settings.json`. The first matcher handles shell commands (`--no-verify`, `core.hooksPath`); the second matches any GitHub MCP tool so direct-to-API writes can also be blocked:
56
75
 
57
76
  ```json
58
77
  {
@@ -66,6 +85,15 @@ Add to your `.claude/settings.json`:
66
85
  "command": "pnpm exec block-no-verify"
67
86
  }
68
87
  ]
88
+ },
89
+ {
90
+ "matcher": "mcp__github__.*",
91
+ "hooks": [
92
+ {
93
+ "type": "command",
94
+ "command": "pnpm exec block-no-verify"
95
+ }
96
+ ]
69
97
  }
70
98
  ]
71
99
  }
@@ -167,6 +195,18 @@ The following git commands are monitored for `--no-verify`:
167
195
  - `git rebase`
168
196
  - `git am`
169
197
 
198
+ ## Blocked GitHub MCP Tools
199
+
200
+ When a Claude Code / MCP-compatible payload includes a `tool_name`, the following GitHub MCP tools are blocked because they write through the GitHub API and therefore skip local git hooks:
201
+
202
+ - `mcp__github__create_or_update_file`
203
+ - `mcp__github__delete_file`
204
+ - `mcp__github__push_files`
205
+ - `mcp__github__merge_pull_request`
206
+ - `mcp__github__update_pull_request_branch`
207
+
208
+ Read-only GitHub MCP tools (e.g. `mcp__github__get_file_contents`, `mcp__github__list_pull_requests`) are not blocked.
209
+
170
210
  ## Behavior
171
211
 
172
212
  | Command | Blocked? | Notes |
@@ -0,0 +1,3 @@
1
+ import { BLOCKED_GITHUB_MCP_TOOLS } from './github-mcp-tools.js';
2
+ export type BlockedGithubMcpTool = (typeof BLOCKED_GITHUB_MCP_TOOLS)[number];
3
+ //# sourceMappingURL=blocked-github-mcp-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blocked-github-mcp-tool.d.ts","sourceRoot":"","sources":["../src/blocked-github-mcp-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAA;AAEhE,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=blocked-github-mcp-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blocked-github-mcp-tool.js","sourceRoot":"","sources":["../src/blocked-github-mcp-tool.ts"],"names":[],"mappings":""}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Optional context for {@link checkCommand}.
3
+ */
4
+ export interface CheckCommandOptions {
5
+ /**
6
+ * Name of the tool being invoked, when available. Used to detect GitHub
7
+ * MCP tool calls that would bypass local git hooks.
8
+ */
9
+ toolName?: string;
10
+ }
11
+ //# sourceMappingURL=check-command-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-command-options.d.ts","sourceRoot":"","sources":["../src/check-command-options.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=check-command-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-command-options.js","sourceRoot":"","sources":["../src/check-command-options.ts"],"names":[],"mappings":""}
@@ -1,9 +1,14 @@
1
+ import type { CheckCommandOptions } from './check-command-options.js';
1
2
  import type { CheckResult } from './check-result.js';
2
3
  /**
3
- * Checks a command input for --no-verify flag usage or hooks path override
4
+ * Checks a command input for --no-verify flag usage, hooks path override, or
5
+ * a direct GitHub MCP tool invocation that would bypass local git hooks.
4
6
  *
5
- * @param input - The command input to check (typically from stdin in Claude Code hooks)
6
- * @returns CheckResult indicating whether the command should be blocked
7
+ * @param input - The command input to check (typically from stdin in AI agent
8
+ * hooks). May be an empty string when the invocation is a non-shell tool
9
+ * call (e.g. an MCP tool).
10
+ * @param options - Optional context such as the invoked tool name.
11
+ * @returns CheckResult indicating whether the command should be blocked.
7
12
  */
8
- export declare function checkCommand(input: string): CheckResult;
13
+ export declare function checkCommand(input: string, options?: CheckCommandOptions): CheckResult;
9
14
  //# sourceMappingURL=check-command.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"check-command.d.ts","sourceRoot":"","sources":["../src/check-command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAKpD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAwBvD"}
1
+ {"version":3,"file":"check-command.d.ts","sourceRoot":"","sources":["../src/check-command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAMpD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,mBAAmB,GAC5B,WAAW,CAkCb"}
@@ -1,13 +1,26 @@
1
1
  import { detectGitCommand } from './detect-git-command.js';
2
+ import { detectBlockedGithubMcpTool } from './detect-github-mcp-tool.js';
2
3
  import { hasNoVerifyFlag } from './has-no-verify-flag.js';
3
4
  import { hasHooksPathOverride } from './has-hooks-path-override.js';
4
5
  /**
5
- * Checks a command input for --no-verify flag usage or hooks path override
6
+ * Checks a command input for --no-verify flag usage, hooks path override, or
7
+ * a direct GitHub MCP tool invocation that would bypass local git hooks.
6
8
  *
7
- * @param input - The command input to check (typically from stdin in Claude Code hooks)
8
- * @returns CheckResult indicating whether the command should be blocked
9
+ * @param input - The command input to check (typically from stdin in AI agent
10
+ * hooks). May be an empty string when the invocation is a non-shell tool
11
+ * call (e.g. an MCP tool).
12
+ * @param options - Optional context such as the invoked tool name.
13
+ * @returns CheckResult indicating whether the command should be blocked.
9
14
  */
10
- export function checkCommand(input) {
15
+ export function checkCommand(input, options) {
16
+ const toolName = options === undefined || options === null ? undefined : options.toolName;
17
+ const blockedMcpTool = detectBlockedGithubMcpTool(toolName);
18
+ if (blockedMcpTool !== null) {
19
+ return {
20
+ blocked: true,
21
+ reason: `BLOCKED: ${blockedMcpTool} bypasses local git hooks by writing through the GitHub API. Use local git commands so hooks can run.`,
22
+ };
23
+ }
11
24
  const gitCommand = detectGitCommand(input);
12
25
  if (!gitCommand) {
13
26
  return { blocked: false };
@@ -1 +1 @@
1
- {"version":3,"file":"check-command.js","sourceRoot":"","sources":["../src/check-command.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAA;AAEnE;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,MAAM,UAAU,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAA;IAE1C,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAA;IAC3B,CAAC;IAED,IAAI,eAAe,CAAC,KAAK,EAAE,UAAU,CAAC,EAAE,CAAC;QACvC,OAAO;YACL,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,qDAAqD,UAAU,mCAAmC;YAC1G,UAAU;SACX,CAAA;IACH,CAAC;IAED,IAAI,oBAAoB,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO;YACL,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,8DAA8D,UAAU,mCAAmC;YACnH,UAAU;SACX,CAAA;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAA;AACvC,CAAC"}
1
+ {"version":3,"file":"check-command.js","sourceRoot":"","sources":["../src/check-command.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAA;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAA;AAEnE;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAC1B,KAAa,EACb,OAA6B;IAE7B,MAAM,QAAQ,GACZ,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAA;IAC1E,MAAM,cAAc,GAAG,0BAA0B,CAAC,QAAQ,CAAC,CAAA;IAC3D,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;QAC5B,OAAO;YACL,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,YAAY,cAAc,uGAAuG;SAC1I,CAAA;IACH,CAAC;IAED,MAAM,UAAU,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAA;IAE1C,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAA;IAC3B,CAAC;IAED,IAAI,eAAe,CAAC,KAAK,EAAE,UAAU,CAAC,EAAE,CAAC;QACvC,OAAO;YACL,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,qDAAqD,UAAU,mCAAmC;YAC1G,UAAU;SACX,CAAA;IACH,CAAC;IAED,IAAI,oBAAoB,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO;YACL,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,8DAA8D,UAAU,mCAAmC;YACnH,UAAU;SACX,CAAA;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAA;AACvC,CAAC"}
@@ -1,5 +1,5 @@
1
1
  /**
2
2
  * CLI help text
3
3
  */
4
- export declare const HELP_TEXT = "block-no-verify - Block --no-verify flags in git commands\n\nUSAGE:\n block-no-verify [options] [command]\n\nOPTIONS:\n --format <type> Input format: auto, plain, claude-code, json (default: auto)\n --help, -h Show this help message\n --version, -v Show version number\n\nINPUT METHODS:\n 1. Command argument:\n block-no-verify \"git commit --no-verify -m 'test'\"\n\n 2. Stdin (plain text):\n echo \"git commit --no-verify\" | block-no-verify\n\n 3. Stdin (JSON - auto-detected):\n echo '{\"command\":\"git commit --no-verify\"}' | block-no-verify\n\n 4. Stdin (Claude Code format):\n echo '{\"tool_input\":{\"command\":\"git commit\"}}' | block-no-verify --format claude-code\n\nSUPPORTED JSON FIELDS:\n When using JSON input, the following fields are recognized:\n - tool_input.command (Claude Code format)\n - command\n - cmd\n - input\n - shell\n - script\n\nEXIT CODES:\n 0 - Command is allowed\n 2 - Command is blocked (contains --no-verify)\n 1 - An error occurred\n\nEXAMPLES:\n # Claude Code hook (.claude/settings.json)\n {\n \"hooks\": {\n \"PreToolUse\": [{\n \"matcher\": \"Bash\",\n \"hooks\": [{ \"type\": \"command\", \"command\": \"block-no-verify\" }]\n }]\n }\n }\n\n # Cursor hook (.cursor/hooks.json)\n {\n \"hooks\": {\n \"beforeShellExecution\": [{\n \"command\": \"pnpm dlx block-no-verify\"\n }]\n }\n }\n\n # Generic AI tool integration\n block-no-verify --format plain \"git push --no-verify\"\n\n # Pipe from another command\n your-ai-tool get-command | block-no-verify";
4
+ export declare const HELP_TEXT = "block-no-verify - Block ways to bypass local git hooks\n\nBlocks --no-verify flags, core.hooksPath overrides, and GitHub MCP tool calls\nthat write through the GitHub API (e.g. mcp__github__push_files).\n\nUSAGE:\n block-no-verify [options] [command]\n\nOPTIONS:\n --format <type> Input format: auto, plain, claude-code, json (default: auto)\n --help, -h Show this help message\n --version, -v Show version number\n\nINPUT METHODS:\n 1. Command argument:\n block-no-verify \"git commit --no-verify -m 'test'\"\n\n 2. Stdin (plain text):\n echo \"git commit --no-verify\" | block-no-verify\n\n 3. Stdin (JSON - auto-detected):\n echo '{\"command\":\"git commit --no-verify\"}' | block-no-verify\n\n 4. Stdin (Claude Code format):\n echo '{\"tool_input\":{\"command\":\"git commit\"}}' | block-no-verify --format claude-code\n\nSUPPORTED JSON FIELDS:\n When using JSON input, the following fields are recognized:\n - tool_input.command (Claude Code format)\n - command\n - cmd\n - input\n - shell\n - script\n\nEXIT CODES:\n 0 - Command / tool call is allowed\n 2 - Command / tool call is blocked (bypasses git hooks)\n 1 - An error occurred\n\nEXAMPLES:\n # Claude Code hook (.claude/settings.json)\n {\n \"hooks\": {\n \"PreToolUse\": [{\n \"matcher\": \"Bash\",\n \"hooks\": [{ \"type\": \"command\", \"command\": \"block-no-verify\" }]\n }]\n }\n }\n\n # Cursor hook (.cursor/hooks.json)\n {\n \"hooks\": {\n \"beforeShellExecution\": [{\n \"command\": \"pnpm dlx block-no-verify\"\n }]\n }\n }\n\n # Generic AI tool integration\n block-no-verify --format plain \"git push --no-verify\"\n\n # Pipe from another command\n your-ai-tool get-command | block-no-verify";
5
5
  //# sourceMappingURL=cli-help.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cli-help.d.ts","sourceRoot":"","sources":["../src/cli-help.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,SAAS,8kDA6DuB,CAAA"}
1
+ {"version":3,"file":"cli-help.d.ts","sourceRoot":"","sources":["../src/cli-help.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,SAAS,qvDAgEuB,CAAA"}
package/dist/cli-help.js CHANGED
@@ -1,7 +1,10 @@
1
1
  /**
2
2
  * CLI help text
3
3
  */
4
- export const HELP_TEXT = `block-no-verify - Block --no-verify flags in git commands
4
+ export const HELP_TEXT = `block-no-verify - Block ways to bypass local git hooks
5
+
6
+ Blocks --no-verify flags, core.hooksPath overrides, and GitHub MCP tool calls
7
+ that write through the GitHub API (e.g. mcp__github__push_files).
5
8
 
6
9
  USAGE:
7
10
  block-no-verify [options] [command]
@@ -34,8 +37,8 @@ SUPPORTED JSON FIELDS:
34
37
  - script
35
38
 
36
39
  EXIT CODES:
37
- 0 - Command is allowed
38
- 2 - Command is blocked (contains --no-verify)
40
+ 0 - Command / tool call is allowed
41
+ 2 - Command / tool call is blocked (bypasses git hooks)
39
42
  1 - An error occurred
40
43
 
41
44
  EXAMPLES:
@@ -1 +1 @@
1
- {"version":3,"file":"cli-help.js","sourceRoot":"","sources":["../src/cli-help.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6CA6DoB,CAAA"}
1
+ {"version":3,"file":"cli-help.js","sourceRoot":"","sources":["../src/cli-help.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6CAgEoB,CAAA"}
package/dist/cli.js CHANGED
@@ -56,8 +56,10 @@ async function main() {
56
56
  if (!rawInput.trim()) {
57
57
  process.exit(EXIT_CODES.ALLOWED);
58
58
  }
59
- const { command } = parseInput(rawInput, args.format);
60
- const result = checkCommand(command);
59
+ const { command, toolName } = parseInput(rawInput, args.format);
60
+ const result = toolName === undefined
61
+ ? checkCommand(command)
62
+ : checkCommand(command, { toolName });
61
63
  if (result.blocked) {
62
64
  console.error(result.reason);
63
65
  process.exit(EXIT_CODES.BLOCKED);
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAErD,MAAM,OAAO,GAAG,OAAO,CAAA;AAEvB,KAAK,UAAU,SAAS;IACtB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,IAAI,GAAG,EAAE,CAAA;QAEb,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;QAEjC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE;YAC/B,IAAI,IAAI,KAAK,CAAA;QACf,CAAC,CAAC,CAAA;QAEF,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YAC3B,OAAO,CAAC,IAAI,CAAC,CAAA;QACf,CAAC,CAAC,CAAA;QAEF,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE;YAC9B,MAAM,CAAC,GAAG,CAAC,CAAA;QACb,CAAC,CAAC,CAAA;QAEF,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACxB,OAAO,CAAC,EAAE,CAAC,CAAA;QACb,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,OAAe;IAClC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IACtB,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAC9D,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAA;IACjD,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;AAChC,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAA;QAE1D,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;YACtB,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;QAClC,CAAC;QAED,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;YACpB,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;QAClC,CAAC;QAED,mCAAmC;QACnC,IAAI,QAAgB,CAAA;QACpB,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;YAC1B,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAA;QACzB,CAAC;aAAM,CAAC;YACN,QAAQ,GAAG,MAAM,SAAS,EAAE,CAAA;QAC9B,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;YACrB,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;QAClC,CAAC;QAED,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;QAC/D,MAAM,MAAM,GACV,QAAQ,KAAK,SAAS;YACpB,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC;YACvB,CAAC,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAA;QAEzC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YAC5B,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;QAClC,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QACtE,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;QAChC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;IAChC,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAA"}
@@ -0,0 +1,12 @@
1
+ import type { BlockedGithubMcpTool } from './blocked-github-mcp-tool.js';
2
+ /**
3
+ * Checks whether a tool name refers to a GitHub MCP tool that bypasses local
4
+ * git hooks.
5
+ *
6
+ * @param toolName - The tool name reported by the AI agent (e.g. from a
7
+ * Claude Code `PreToolUse` payload).
8
+ * @returns The matched blocked tool name, or null when the tool is not a
9
+ * blocked GitHub MCP tool.
10
+ */
11
+ export declare function detectBlockedGithubMcpTool(toolName: string | undefined | null): BlockedGithubMcpTool | null;
12
+ //# sourceMappingURL=detect-github-mcp-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-github-mcp-tool.d.ts","sourceRoot":"","sources":["../src/detect-github-mcp-tool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAA;AAGxE;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAClC,oBAAoB,GAAG,IAAI,CAiB7B"}
@@ -0,0 +1,26 @@
1
+ import { BLOCKED_GITHUB_MCP_TOOLS } from './github-mcp-tools.js';
2
+ /**
3
+ * Checks whether a tool name refers to a GitHub MCP tool that bypasses local
4
+ * git hooks.
5
+ *
6
+ * @param toolName - The tool name reported by the AI agent (e.g. from a
7
+ * Claude Code `PreToolUse` payload).
8
+ * @returns The matched blocked tool name, or null when the tool is not a
9
+ * blocked GitHub MCP tool.
10
+ */
11
+ export function detectBlockedGithubMcpTool(toolName) {
12
+ if (toolName === undefined || toolName === null) {
13
+ return null;
14
+ }
15
+ const trimmed = toolName.trim();
16
+ if (trimmed === '') {
17
+ return null;
18
+ }
19
+ for (const blocked of BLOCKED_GITHUB_MCP_TOOLS) {
20
+ if (trimmed === blocked) {
21
+ return blocked;
22
+ }
23
+ }
24
+ return null;
25
+ }
26
+ //# sourceMappingURL=detect-github-mcp-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-github-mcp-tool.js","sourceRoot":"","sources":["../src/detect-github-mcp-tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAA;AAEhE;;;;;;;;GAQG;AACH,MAAM,UAAU,0BAA0B,CACxC,QAAmC;IAEnC,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QAChD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAA;IAC/B,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;QACnB,OAAO,IAAI,CAAA;IACb,CAAC;IAED,KAAK,MAAM,OAAO,IAAI,wBAAwB,EAAE,CAAC;QAC/C,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;YACxB,OAAO,OAAO,CAAA;QAChB,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { ExtractedJson } from './extracted-json.js';
2
+ /**
3
+ * Attempts to parse input as JSON and extract the command + tool name.
4
+ */
5
+ export declare function tryExtractFromJson(input: string): ExtractedJson | null;
6
+ //# sourceMappingURL=extract-from-json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-from-json.d.ts","sourceRoot":"","sources":["../src/extract-from-json.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAuDxD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CA6BtE"}
@@ -0,0 +1,73 @@
1
+ import { getProperty } from './get-property.js';
2
+ import { hasProperty } from './json-helpers.js';
3
+ /**
4
+ * Extracts a `tool_name` field when present at the top level of the JSON
5
+ * payload (Claude Code / Gemini CLI shape).
6
+ */
7
+ function extractToolName(parsed) {
8
+ if (!hasProperty(parsed, 'tool_name')) {
9
+ return null;
10
+ }
11
+ const value = getProperty(parsed, 'tool_name');
12
+ if (typeof value === 'string') {
13
+ return value;
14
+ }
15
+ return null;
16
+ }
17
+ function extractClaudeCodeCommand(parsed, toolName) {
18
+ if (!hasProperty(parsed, 'tool_input')) {
19
+ return null;
20
+ }
21
+ const toolInput = getProperty(parsed, 'tool_input');
22
+ if (typeof toolInput === 'object' && toolInput !== null) {
23
+ if (hasProperty(toolInput, 'command')) {
24
+ const command = getProperty(toolInput, 'command');
25
+ if (typeof command === 'string') {
26
+ return { command, toolName };
27
+ }
28
+ }
29
+ }
30
+ // tool_input present without a string command (e.g. MCP tool invocation).
31
+ return { command: null, toolName };
32
+ }
33
+ function extractGenericCommand(parsed, toolName) {
34
+ const genericKeys = ['command', 'cmd', 'input', 'shell', 'script'];
35
+ for (const key of genericKeys) {
36
+ if (hasProperty(parsed, key)) {
37
+ const value = getProperty(parsed, key);
38
+ if (typeof value === 'string') {
39
+ return { command: value, toolName };
40
+ }
41
+ }
42
+ }
43
+ return null;
44
+ }
45
+ /**
46
+ * Attempts to parse input as JSON and extract the command + tool name.
47
+ */
48
+ export function tryExtractFromJson(input) {
49
+ try {
50
+ const parsed = JSON.parse(input);
51
+ if (typeof parsed !== 'object' || parsed === null) {
52
+ return null;
53
+ }
54
+ const toolName = extractToolName(parsed);
55
+ const claudeCode = extractClaudeCodeCommand(parsed, toolName);
56
+ if (claudeCode !== null) {
57
+ return claudeCode;
58
+ }
59
+ const generic = extractGenericCommand(parsed, toolName);
60
+ if (generic !== null) {
61
+ return generic;
62
+ }
63
+ // JSON parsed but no recognized command field. Still surface tool name.
64
+ if (toolName !== null) {
65
+ return { command: null, toolName };
66
+ }
67
+ return null;
68
+ }
69
+ catch {
70
+ return null;
71
+ }
72
+ }
73
+ //# sourceMappingURL=extract-from-json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-from-json.js","sourceRoot":"","sources":["../src/extract-from-json.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Extracted pieces from a JSON payload.
3
+ */
4
+ export interface ExtractedJson {
5
+ command: string | null;
6
+ toolName: string | null;
7
+ }
8
+ //# sourceMappingURL=extracted-json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extracted-json.d.ts","sourceRoot":"","sources":["../src/extracted-json.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=extracted-json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extracted-json.js","sourceRoot":"","sources":["../src/extracted-json.ts"],"names":[],"mappings":""}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Type-safe property access using Object.entries
3
+ */
4
+ export declare function getProperty(obj: object, key: string): unknown;
5
+ //# sourceMappingURL=get-property.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-property.d.ts","sourceRoot":"","sources":["../src/get-property.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAQ7D"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Type-safe property access using Object.entries
3
+ */
4
+ export function getProperty(obj, key) {
5
+ const entries = Object.entries(obj);
6
+ for (const entry of entries) {
7
+ if (entry[0] === key) {
8
+ return entry[1];
9
+ }
10
+ }
11
+ return undefined;
12
+ }
13
+ //# sourceMappingURL=get-property.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-property.js","sourceRoot":"","sources":["../src/get-property.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,GAAW;IAClD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IACnC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACrB,OAAO,KAAK,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * GitHub MCP tools that bypass local git hooks.
3
+ *
4
+ * These MCP tools communicate directly with the GitHub API, meaning they do
5
+ * not trigger local pre-commit, pre-push, commit-msg, or other client-side
6
+ * hooks. Blocking them prevents AI agents from side-stepping the validations
7
+ * enforced by those hooks.
8
+ */
9
+ export declare const BLOCKED_GITHUB_MCP_TOOLS: readonly ["mcp__github__create_or_update_file", "mcp__github__delete_file", "mcp__github__push_files", "mcp__github__merge_pull_request", "mcp__github__update_pull_request_branch"];
10
+ //# sourceMappingURL=github-mcp-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-mcp-tools.d.ts","sourceRoot":"","sources":["../src/github-mcp-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,sLAQ3B,CAAA"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * GitHub MCP tools that bypass local git hooks.
3
+ *
4
+ * These MCP tools communicate directly with the GitHub API, meaning they do
5
+ * not trigger local pre-commit, pre-push, commit-msg, or other client-side
6
+ * hooks. Blocking them prevents AI agents from side-stepping the validations
7
+ * enforced by those hooks.
8
+ */
9
+ export const BLOCKED_GITHUB_MCP_TOOLS = [
10
+ // Content writes that bypass pre-commit / commit-msg hooks
11
+ 'mcp__github__create_or_update_file',
12
+ 'mcp__github__delete_file',
13
+ 'mcp__github__push_files',
14
+ // Branch / merge operations that bypass pre-push hooks
15
+ 'mcp__github__merge_pull_request',
16
+ 'mcp__github__update_pull_request_branch',
17
+ ];
18
+ //# sourceMappingURL=github-mcp-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-mcp-tools.js","sourceRoot":"","sources":["../src/github-mcp-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,2DAA2D;IAC3D,oCAAoC;IACpC,0BAA0B;IAC1B,yBAAyB;IACzB,uDAAuD;IACvD,iCAAiC;IACjC,yCAAyC;CACjC,CAAA"}
package/dist/index.d.ts CHANGED
@@ -11,7 +11,11 @@ export { EXIT_CODES } from './exit-codes.js';
11
11
  export { detectGitCommand } from './detect-git-command.js';
12
12
  export { hasNoVerifyFlag } from './has-no-verify-flag.js';
13
13
  export { hasHooksPathOverride } from './has-hooks-path-override.js';
14
+ export { detectBlockedGithubMcpTool } from './detect-github-mcp-tool.js';
15
+ export { BLOCKED_GITHUB_MCP_TOOLS } from './github-mcp-tools.js';
16
+ export type { BlockedGithubMcpTool } from './blocked-github-mcp-tool.js';
14
17
  export { checkCommand } from './check-command.js';
18
+ export type { CheckCommandOptions } from './check-command-options.js';
15
19
  export { parseInput } from './parse-input.js';
16
20
  export type { InputFormat } from './input-format.js';
17
21
  export type { ParseResult } from './parse-result.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAA;AACxD,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAA;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAA;AACxD,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAA;AACnE,OAAO,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAA;AACxE,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAA;AAChE,YAAY,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAA;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,YAAY,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA"}
package/dist/index.js CHANGED
@@ -9,6 +9,8 @@ export { EXIT_CODES } from './exit-codes.js';
9
9
  export { detectGitCommand } from './detect-git-command.js';
10
10
  export { hasNoVerifyFlag } from './has-no-verify-flag.js';
11
11
  export { hasHooksPathOverride } from './has-hooks-path-override.js';
12
+ export { detectBlockedGithubMcpTool } from './detect-github-mcp-tool.js';
13
+ export { BLOCKED_GITHUB_MCP_TOOLS } from './github-mcp-tools.js';
12
14
  export { checkCommand } from './check-command.js';
13
15
  export { parseInput } from './parse-input.js';
14
16
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAA;AAGxD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAA;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAA;AAGxD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAA;AACnE,OAAO,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAA;AACxE,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAA;AAEhE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Type-safe property check
3
+ */
4
+ export declare function hasProperty(obj: object, key: string): boolean;
5
+ //# sourceMappingURL=json-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-helpers.d.ts","sourceRoot":"","sources":["../src/json-helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAE7D"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Type-safe property check
3
+ */
4
+ export function hasProperty(obj, key) {
5
+ return Object.prototype.hasOwnProperty.call(obj, key);
6
+ }
7
+ //# sourceMappingURL=json-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-helpers.js","sourceRoot":"","sources":["../src/json-helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,GAAW;IAClD,OAAO,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;AACvD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"parse-input.d.ts","sourceRoot":"","sources":["../src/parse-input.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAyHpD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,WAAW,CAkB3E"}
1
+ {"version":3,"file":"parse-input.d.ts","sourceRoot":"","sources":["../src/parse-input.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AA8CpD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,WAAW,CAmB3E"}
@@ -1,111 +1,29 @@
1
- /**
2
- * Attempts to parse input as JSON and extract the command
3
- */
4
- function tryParseJson(input) {
5
- try {
6
- const parsed = JSON.parse(input);
7
- if (typeof parsed !== 'object' || parsed === null) {
8
- return null;
9
- }
10
- // Check for Claude Code format: { tool_input: { command: "..." } }
11
- if (hasProperty(parsed, 'tool_input')) {
12
- const toolInput = getProperty(parsed, 'tool_input');
13
- if (typeof toolInput === 'object' && toolInput !== null) {
14
- if (hasProperty(toolInput, 'command')) {
15
- const command = getProperty(toolInput, 'command');
16
- if (typeof command === 'string') {
17
- return command;
18
- }
19
- }
20
- }
21
- }
22
- // Generic JSON formats
23
- const genericKeys = ['command', 'cmd', 'input', 'shell', 'script'];
24
- for (const key of genericKeys) {
25
- if (hasProperty(parsed, key)) {
26
- const value = getProperty(parsed, key);
27
- if (typeof value === 'string') {
28
- return value;
29
- }
30
- }
31
- }
32
- // If JSON but no recognized command field, return null
33
- return null;
34
- }
35
- catch {
36
- // Not valid JSON
37
- return null;
1
+ import { tryExtractFromJson } from './extract-from-json.js';
2
+ function resolveExtracted(input) {
3
+ const extracted = tryExtractFromJson(input);
4
+ if (extracted === null) {
5
+ return { command: input, toolName: null };
38
6
  }
7
+ return {
8
+ command: extracted.command === null ? input : extracted.command,
9
+ toolName: extracted.toolName,
10
+ };
39
11
  }
40
- /**
41
- * Type-safe property check
42
- */
43
- function hasProperty(obj, key) {
44
- return Object.prototype.hasOwnProperty.call(obj, key);
45
- }
46
- /**
47
- * Type-safe property access using Object.entries
48
- */
49
- function getProperty(obj, key) {
50
- const entries = Object.entries(obj);
51
- for (const entry of entries) {
52
- if (entry[0] === key) {
53
- return entry[1];
54
- }
12
+ function buildResult(command, format, toolName) {
13
+ if (toolName === null) {
14
+ return { command, format };
55
15
  }
56
- return undefined;
16
+ return { command, format, toolName };
57
17
  }
58
- /**
59
- * Parses input in Claude Code format
60
- */
61
- function parseClaudeCode(input) {
62
- try {
63
- const parsed = JSON.parse(input);
64
- if (typeof parsed !== 'object' || parsed === null) {
65
- return input;
66
- }
67
- if (hasProperty(parsed, 'tool_input')) {
68
- const toolInput = getProperty(parsed, 'tool_input');
69
- if (typeof toolInput === 'object' && toolInput !== null) {
70
- if (hasProperty(toolInput, 'command')) {
71
- const command = getProperty(toolInput, 'command');
72
- if (typeof command === 'string') {
73
- return command;
74
- }
75
- }
76
- }
77
- }
78
- return input;
79
- }
80
- catch {
81
- // If not valid JSON, treat as plain text
82
- return input;
83
- }
84
- }
85
- /**
86
- * Parses input in generic JSON format
87
- */
88
- function parseJson(input) {
89
- const command = tryParseJson(input);
90
- if (command !== null) {
91
- return command;
92
- }
93
- return input;
94
- }
95
- /**
96
- * Auto-detects format and parses input
97
- */
98
18
  function parseAuto(input) {
99
19
  const trimmed = input.trim();
100
- // Try JSON first if it looks like JSON
101
20
  if (trimmed.startsWith('{')) {
102
- const command = tryParseJson(trimmed);
103
- if (command !== null) {
104
- return { command, format: 'json' };
21
+ const extracted = tryExtractFromJson(trimmed);
22
+ if (extracted !== null) {
23
+ return buildResult(extracted.command === null ? input : extracted.command, 'json', extracted.toolName);
105
24
  }
106
25
  }
107
- // Otherwise treat as plain text
108
- return { command: input, format: 'plain' };
26
+ return buildResult(input, 'plain', null);
109
27
  }
110
28
  /**
111
29
  * Parses input according to the specified format
@@ -135,12 +53,13 @@ export function parseInput(input, format) {
135
53
  return { command: input, format: 'plain' };
136
54
  }
137
55
  if (resolvedFormat === 'claude-code') {
138
- return { command: parseClaudeCode(input), format: 'claude-code' };
56
+ const extracted = resolveExtracted(input);
57
+ return buildResult(extracted.command, 'claude-code', extracted.toolName);
139
58
  }
140
59
  if (resolvedFormat === 'json') {
141
- return { command: parseJson(input), format: 'json' };
60
+ const extracted = resolveExtracted(input);
61
+ return buildResult(extracted.command, 'json', extracted.toolName);
142
62
  }
143
- // resolvedFormat === 'auto'
144
63
  return parseAuto(input);
145
64
  }
146
65
  //# sourceMappingURL=parse-input.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"parse-input.js","sourceRoot":"","sources":["../src/parse-input.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"parse-input.js","sourceRoot":"","sources":["../src/parse-input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAS3D,SAAS,gBAAgB,CAAC,KAAa;IACrC,MAAM,SAAS,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAA;IAC3C,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;QACvB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAA;IAC3C,CAAC;IACD,OAAO;QACL,OAAO,EAAE,SAAS,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO;QAC/D,QAAQ,EAAE,SAAS,CAAC,QAAQ;KAC7B,CAAA;AACH,CAAC;AAED,SAAS,WAAW,CAClB,OAAe,EACf,MAAmB,EACnB,QAAuB;IAEvB,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAA;IAC5B,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAA;AACtC,CAAC;AAED,SAAS,SAAS,CAAC,KAAa;IAC9B,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;IAE5B,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5B,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAA;QAC7C,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;YACvB,OAAO,WAAW,CAChB,SAAS,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,EACtD,MAAM,EACN,SAAS,CAAC,QAAQ,CACnB,CAAA;QACH,CAAC;IACH,CAAC;IAED,OAAO,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;AAC1C,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa,EAAE,MAAoB;IAC5D,MAAM,cAAc,GAClB,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAA;IAE3D,IAAI,cAAc,KAAK,OAAO,EAAE,CAAC;QAC/B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAA;IAC5C,CAAC;IAED,IAAI,cAAc,KAAK,aAAa,EAAE,CAAC;QACrC,MAAM,SAAS,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAA;QACzC,OAAO,WAAW,CAAC,SAAS,CAAC,OAAO,EAAE,aAAa,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAA;IAC1E,CAAC;IAED,IAAI,cAAc,KAAK,MAAM,EAAE,CAAC;QAC9B,MAAM,SAAS,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAA;QACzC,OAAO,WAAW,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAA;IACnE,CAAC;IAED,OAAO,SAAS,CAAC,KAAK,CAAC,CAAA;AACzB,CAAC"}
@@ -5,5 +5,11 @@ import type { InputFormat } from './input-format.js';
5
5
  export interface ParseResult {
6
6
  command: string;
7
7
  format: InputFormat;
8
+ /**
9
+ * Name of the tool being invoked, when the input format exposes it (e.g.
10
+ * Claude Code's `tool_name` field). Used to detect direct GitHub MCP calls
11
+ * that would bypass local git hooks.
12
+ */
13
+ toolName?: string;
8
14
  }
9
15
  //# sourceMappingURL=parse-result.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"parse-result.d.ts","sourceRoot":"","sources":["../src/parse-result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEpD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,WAAW,CAAA;CACpB"}
1
+ {"version":3,"file":"parse-result.d.ts","sourceRoot":"","sources":["../src/parse-result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEpD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,WAAW,CAAA;IACnB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "block-no-verify",
3
- "version": "1.1.3",
3
+ "version": "1.1.5",
4
4
  "description": "CLI tool to block --no-verify flag in git commands. Prevents AI agents from bypassing git hooks.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -61,23 +61,23 @@
61
61
  },
62
62
  "homepage": "https://github.com/tupe12334/block-no-verify#readme",
63
63
  "devDependencies": {
64
- "@commitlint/cli": "^20.3.1",
65
- "@commitlint/config-conventional": "^20.3.1",
64
+ "@commitlint/cli": "^20.5.0",
65
+ "@commitlint/config-conventional": "^20.5.0",
66
66
  "@cspell/dict-he": "^4.0.5",
67
67
  "@release-it/conventional-changelog": "^10.0.6",
68
- "@types/node": "^25.0.3",
69
- "@vitest/coverage-v8": "^4.0.16",
70
- "cspell": "^9.4.0",
71
- "eslint": "^9.39.2",
68
+ "@types/node": "^25.5.0",
69
+ "@vitest/coverage-v8": "^4.1.1",
70
+ "cspell": "^9.7.0",
71
+ "eslint": "^9.39.4",
72
72
  "eslint-config-agent": "^1.9.3",
73
73
  "eslint-config-publishable-package-json": "^1.0.0",
74
74
  "eslint-import-resolver-typescript": "^4.4.4",
75
75
  "husky": "^9.1.7",
76
- "knip": "^5.80.2",
77
- "lint-staged": "^16.2.7",
78
- "prettier": "^3.7.4",
79
- "release-it": "^19.2.3",
76
+ "knip": "^5.88.1",
77
+ "lint-staged": "^16.4.0",
78
+ "prettier": "^3.8.1",
79
+ "release-it": "^19.2.4",
80
80
  "typescript": "^5.9.3",
81
- "vitest": "^4.0.16"
81
+ "vitest": "^4.1.1"
82
82
  }
83
83
  }