block-no-verify 1.0.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,119 @@
1
+ # block-no-verify
2
+
3
+ A security tool that blocks the `--no-verify` flag in git commands. Designed to prevent AI agents from bypassing git hooks.
4
+
5
+ ## Why?
6
+
7
+ When using AI coding assistants like Claude Code, 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.
8
+
9
+ This package provides a CLI that can be used as a Claude Code hook to block any git commands that include `--no-verify`.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ npm install -g block-no-verify
15
+ # or
16
+ pnpm add -g block-no-verify
17
+ ```
18
+
19
+ ## Usage with Claude Code
20
+
21
+ Add this to your `.claude/settings.json`:
22
+
23
+ ```json
24
+ {
25
+ "hooks": {
26
+ "PreToolUse": [
27
+ {
28
+ "matcher": "Bash",
29
+ "hooks": [
30
+ {
31
+ "type": "command",
32
+ "command": "block-no-verify"
33
+ }
34
+ ]
35
+ }
36
+ ]
37
+ }
38
+ }
39
+ ```
40
+
41
+ This will block any Bash commands that contain `--no-verify` with supported git commands.
42
+
43
+ ## Supported Git Commands
44
+
45
+ The following git commands are monitored for `--no-verify`:
46
+
47
+ - `git commit`
48
+ - `git push`
49
+ - `git merge`
50
+ - `git cherry-pick`
51
+ - `git rebase`
52
+ - `git am`
53
+
54
+ ## Behavior
55
+
56
+ | Command | Blocked? | Notes |
57
+ | ------------------------ | -------- | --------------------------------------------- |
58
+ | `git commit --no-verify` | Yes | |
59
+ | `git commit -n` | Yes | `-n` is shorthand for `--no-verify` in commit |
60
+ | `git push --no-verify` | Yes | |
61
+ | `git push -n` | No | `-n` means `--dry-run` in push |
62
+ | `git merge --no-verify` | Yes | |
63
+ | `git merge -n` | No | `-n` means `--no-commit` in merge |
64
+ | `git commit -m "msg"` | No | No `--no-verify` flag |
65
+
66
+ ## Exit Codes
67
+
68
+ - `0` - Command is allowed
69
+ - `2` - Command is blocked (contains `--no-verify`)
70
+ - `1` - An error occurred
71
+
72
+ ## Programmatic Usage
73
+
74
+ ```typescript
75
+ import {
76
+ checkCommand,
77
+ detectGitCommand,
78
+ hasNoVerifyFlag,
79
+ } from 'block-no-verify'
80
+
81
+ // Check if a command should be blocked
82
+ const result = checkCommand('git commit --no-verify -m "test"')
83
+ console.log(result.blocked) // true
84
+ console.log(result.reason) // "BLOCKED: --no-verify flag is not allowed..."
85
+
86
+ // Detect git command type
87
+ const cmd = detectGitCommand('git push origin main')
88
+ console.log(cmd) // "push"
89
+
90
+ // Check for no-verify flag
91
+ const hasFlag = hasNoVerifyFlag('git commit -n -m "test"', 'commit')
92
+ console.log(hasFlag) // true
93
+ ```
94
+
95
+ ## Development
96
+
97
+ ```bash
98
+ # Install dependencies
99
+ pnpm install
100
+
101
+ # Build
102
+ pnpm build
103
+
104
+ # Run tests
105
+ pnpm test
106
+
107
+ # Run tests with coverage
108
+ pnpm test:coverage
109
+
110
+ # Lint
111
+ pnpm lint
112
+
113
+ # Format
114
+ pnpm format
115
+ ```
116
+
117
+ ## License
118
+
119
+ MIT
@@ -0,0 +1,9 @@
1
+ import type { CheckResult } from './check-result.js';
2
+ /**
3
+ * Checks a command input for --no-verify flag usage
4
+ *
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
+ */
8
+ export declare function checkCommand(input: string): CheckResult;
9
+ //# sourceMappingURL=check-command.d.ts.map
@@ -0,0 +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;AAIpD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAgBvD"}
@@ -0,0 +1,23 @@
1
+ import { detectGitCommand } from './detect-git-command.js';
2
+ import { hasNoVerifyFlag } from './has-no-verify-flag.js';
3
+ /**
4
+ * Checks a command input for --no-verify flag usage
5
+ *
6
+ * @param input - The command input to check (typically from stdin in Claude Code hooks)
7
+ * @returns CheckResult indicating whether the command should be blocked
8
+ */
9
+ export function checkCommand(input) {
10
+ const gitCommand = detectGitCommand(input);
11
+ if (!gitCommand) {
12
+ return { blocked: false };
13
+ }
14
+ if (hasNoVerifyFlag(input, gitCommand)) {
15
+ return {
16
+ blocked: true,
17
+ reason: `BLOCKED: --no-verify flag is not allowed with git ${gitCommand}. Git hooks must not be bypassed.`,
18
+ gitCommand,
19
+ };
20
+ }
21
+ return { blocked: false, gitCommand };
22
+ }
23
+ //# sourceMappingURL=check-command.js.map
@@ -0,0 +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;AAEzD;;;;;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,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAA;AACvC,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { GitCommand } from './git-command.js';
2
+ /**
3
+ * Result of checking a command for --no-verify flag
4
+ */
5
+ export interface CheckResult {
6
+ /** Whether the command is blocked */
7
+ blocked: boolean;
8
+ /** The reason the command was blocked, if any */
9
+ reason?: string;
10
+ /** The detected git command, if any */
11
+ gitCommand?: GitCommand;
12
+ }
13
+ //# sourceMappingURL=check-result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-result.d.ts","sourceRoot":"","sources":["../src/check-result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAElD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,qCAAqC;IACrC,OAAO,EAAE,OAAO,CAAA;IAChB,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,uCAAuC;IACvC,UAAU,CAAC,EAAE,UAAU,CAAA;CACxB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=check-result.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-result.js","sourceRoot":"","sources":["../src/check-result.ts"],"names":[],"mappings":""}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * block-no-verify CLI
4
+ *
5
+ * Usage in Claude Code hooks:
6
+ *
7
+ * In your .claude/settings.json:
8
+ * ```json
9
+ * {
10
+ * "hooks": {
11
+ * "PreToolUse": [
12
+ * {
13
+ * "matcher": "Bash",
14
+ * "hooks": [
15
+ * {
16
+ * "type": "command",
17
+ * "command": "block-no-verify"
18
+ * }
19
+ * ]
20
+ * }
21
+ * ]
22
+ * }
23
+ * }
24
+ * ```
25
+ *
26
+ * The CLI reads the command from stdin and exits with:
27
+ * - 0 if the command is allowed
28
+ * - 2 if the command is blocked (contains --no-verify)
29
+ * - 1 if an error occurred
30
+ */
31
+ export {};
32
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG"}
package/dist/cli.js ADDED
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * block-no-verify CLI
4
+ *
5
+ * Usage in Claude Code hooks:
6
+ *
7
+ * In your .claude/settings.json:
8
+ * ```json
9
+ * {
10
+ * "hooks": {
11
+ * "PreToolUse": [
12
+ * {
13
+ * "matcher": "Bash",
14
+ * "hooks": [
15
+ * {
16
+ * "type": "command",
17
+ * "command": "block-no-verify"
18
+ * }
19
+ * ]
20
+ * }
21
+ * ]
22
+ * }
23
+ * }
24
+ * ```
25
+ *
26
+ * The CLI reads the command from stdin and exits with:
27
+ * - 0 if the command is allowed
28
+ * - 2 if the command is blocked (contains --no-verify)
29
+ * - 1 if an error occurred
30
+ */
31
+ import { checkCommand, EXIT_CODES } from './index.js';
32
+ async function readStdin() {
33
+ return new Promise((resolve, reject) => {
34
+ let data = '';
35
+ // Set encoding to utf8
36
+ process.stdin.setEncoding('utf8');
37
+ // Handle data chunks
38
+ process.stdin.on('data', chunk => {
39
+ data += chunk;
40
+ });
41
+ // Resolve when stdin ends
42
+ process.stdin.on('end', () => {
43
+ resolve(data);
44
+ });
45
+ // Handle errors
46
+ process.stdin.on('error', err => {
47
+ reject(err);
48
+ });
49
+ // If stdin is empty/not piped, resolve with empty string after a short timeout
50
+ if (process.stdin.isTTY) {
51
+ resolve('');
52
+ }
53
+ });
54
+ }
55
+ async function main() {
56
+ try {
57
+ const input = await readStdin();
58
+ if (!input.trim()) {
59
+ // No input provided, allow by default
60
+ process.exit(EXIT_CODES.ALLOWED);
61
+ }
62
+ const result = checkCommand(input);
63
+ if (result.blocked) {
64
+ console.error(result.reason);
65
+ process.exit(EXIT_CODES.BLOCKED);
66
+ }
67
+ process.exit(EXIT_CODES.ALLOWED);
68
+ }
69
+ catch (error) {
70
+ console.error('Error:', error instanceof Error ? error.message : String(error));
71
+ process.exit(EXIT_CODES.ERROR);
72
+ }
73
+ }
74
+ main();
75
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAErD,KAAK,UAAU,SAAS;IACtB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,IAAI,GAAG,EAAE,CAAA;QAEb,uBAAuB;QACvB,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;QAEjC,qBAAqB;QACrB,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE;YAC/B,IAAI,IAAI,KAAK,CAAA;QACf,CAAC,CAAC,CAAA;QAEF,0BAA0B;QAC1B,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YAC3B,OAAO,CAAC,IAAI,CAAC,CAAA;QACf,CAAC,CAAC,CAAA;QAEF,gBAAgB;QAChB,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE;YAC9B,MAAM,CAAC,GAAG,CAAC,CAAA;QACb,CAAC,CAAC,CAAA;QAEF,+EAA+E;QAC/E,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACxB,OAAO,CAAC,EAAE,CAAC,CAAA;QACb,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAA;QAE/B,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;YAClB,sCAAsC;YACtC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;QAClC,CAAC;QAED,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,CAAA;QAElC,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,OAAO,CAAC,KAAK,CACX,QAAQ,EACR,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CACvD,CAAA;QACD,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;IAChC,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAA"}
@@ -0,0 +1,6 @@
1
+ import type { GitCommand } from './git-command.js';
2
+ /**
3
+ * Checks if the input contains a git command
4
+ */
5
+ export declare function detectGitCommand(input: string): GitCommand | null;
6
+ //# sourceMappingURL=detect-git-command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-git-command.d.ts","sourceRoot":"","sources":["../src/detect-git-command.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAElD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAmCjE"}
@@ -0,0 +1,39 @@
1
+ import { GIT_COMMANDS_WITH_NO_VERIFY } from './types.js';
2
+ /**
3
+ * Checks if the input contains a git command
4
+ */
5
+ export function detectGitCommand(input) {
6
+ for (const cmd of GIT_COMMANDS_WITH_NO_VERIFY) {
7
+ // Match patterns like: git commit, git -C /path commit
8
+ // Using string concatenation and simple includes/match to avoid non-literal RegExp
9
+ const gitIndex = input.indexOf('git');
10
+ if (gitIndex === -1)
11
+ continue;
12
+ const cmdIndex = input.indexOf(cmd, gitIndex);
13
+ if (cmdIndex === -1)
14
+ continue;
15
+ // Verify 'git' is a word boundary (not part of another word)
16
+ const beforeGit = gitIndex > 0 ? input[gitIndex - 1] : ' ';
17
+ const afterGit = input[gitIndex + 3] || ' ';
18
+ if (!/\s|^$/.test(beforeGit) && beforeGit !== ';' && beforeGit !== '&') {
19
+ continue;
20
+ }
21
+ if (!/\s/.test(afterGit))
22
+ continue;
23
+ // Verify the command is a word boundary
24
+ const beforeCmd = cmdIndex > 0 ? input[cmdIndex - 1] : ' ';
25
+ const afterCmd = input[cmdIndex + cmd.length] || ' ';
26
+ if (!/\s/.test(beforeCmd))
27
+ continue;
28
+ if (!/\s|$/.test(afterCmd) && afterCmd !== ';' && afterCmd !== '&') {
29
+ continue;
30
+ }
31
+ // Make sure there's no pipe or semicolon between git and cmd that would indicate separate commands
32
+ const between = input.slice(gitIndex + 3, cmdIndex);
33
+ if (/[;|]/.test(between))
34
+ continue;
35
+ return cmd;
36
+ }
37
+ return null;
38
+ }
39
+ //# sourceMappingURL=detect-git-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-git-command.js","sourceRoot":"","sources":["../src/detect-git-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAA;AAGxD;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,KAAK,MAAM,GAAG,IAAI,2BAA2B,EAAE,CAAC;QAC9C,uDAAuD;QACvD,mFAAmF;QACnF,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QACrC,IAAI,QAAQ,KAAK,CAAC,CAAC;YAAE,SAAQ;QAE7B,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAA;QAC7C,IAAI,QAAQ,KAAK,CAAC,CAAC;YAAE,SAAQ;QAE7B,6DAA6D;QAC7D,MAAM,SAAS,GAAG,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;QAC1D,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,IAAI,GAAG,CAAA;QAE3C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,SAAS,KAAK,GAAG,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;YACvE,SAAQ;QACV,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;YAAE,SAAQ;QAElC,wCAAwC;QACxC,MAAM,SAAS,GAAG,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;QAC1D,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,CAAA;QAEpD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;YAAE,SAAQ;QACnC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,GAAG,IAAI,QAAQ,KAAK,GAAG,EAAE,CAAC;YACnE,SAAQ;QACV,CAAC;QAED,mGAAmG;QACnG,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAA;QACnD,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,SAAQ;QAElC,OAAO,GAAG,CAAA;IACZ,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Exit codes for the CLI
3
+ */
4
+ export declare const EXIT_CODES: {
5
+ /** Command is allowed to proceed */
6
+ readonly ALLOWED: 0;
7
+ /** Command is blocked */
8
+ readonly BLOCKED: 2;
9
+ /** An error occurred */
10
+ readonly ERROR: 1;
11
+ };
12
+ //# sourceMappingURL=exit-codes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit-codes.d.ts","sourceRoot":"","sources":["../src/exit-codes.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,UAAU;IACrB,oCAAoC;;IAEpC,yBAAyB;;IAEzB,wBAAwB;;CAEhB,CAAA"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Exit codes for the CLI
3
+ */
4
+ export const EXIT_CODES = {
5
+ /** Command is allowed to proceed */
6
+ ALLOWED: 0,
7
+ /** Command is blocked */
8
+ BLOCKED: 2,
9
+ /** An error occurred */
10
+ ERROR: 1,
11
+ };
12
+ //# sourceMappingURL=exit-codes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit-codes.js","sourceRoot":"","sources":["../src/exit-codes.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,oCAAoC;IACpC,OAAO,EAAE,CAAC;IACV,yBAAyB;IACzB,OAAO,EAAE,CAAC;IACV,wBAAwB;IACxB,KAAK,EAAE,CAAC;CACA,CAAA"}
@@ -0,0 +1,6 @@
1
+ import { GIT_COMMANDS_WITH_NO_VERIFY } from './types.js';
2
+ /**
3
+ * Type representing git commands that support --no-verify
4
+ */
5
+ export type GitCommand = (typeof GIT_COMMANDS_WITH_NO_VERIFY)[number];
6
+ //# sourceMappingURL=git-command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-command.d.ts","sourceRoot":"","sources":["../src/git-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAA;AAExD;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=git-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-command.js","sourceRoot":"","sources":["../src/git-command.ts"],"names":[],"mappings":""}
@@ -0,0 +1,6 @@
1
+ import type { GitCommand } from './git-command.js';
2
+ /**
3
+ * Checks if the input contains a --no-verify flag for a specific git command
4
+ */
5
+ export declare function hasNoVerifyFlag(input: string, command: GitCommand): boolean;
6
+ //# sourceMappingURL=has-no-verify-flag.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"has-no-verify-flag.d.ts","sourceRoot":"","sources":["../src/has-no-verify-flag.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAElD;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAoB3E"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Checks if the input contains a --no-verify flag for a specific git command
3
+ */
4
+ export function hasNoVerifyFlag(input, command) {
5
+ // Check for --no-verify
6
+ if (/--no-verify\b/.test(input)) {
7
+ return true;
8
+ }
9
+ // For commit, -n is a shorthand for --no-verify
10
+ // For other commands, -n might mean something else, so we need to be careful
11
+ if (command === 'commit') {
12
+ // Match -n as a standalone flag or at the start of combined flags
13
+ if (/\s-n(?:\s|$)/.test(input) || /\s-n[a-zA-Z]/.test(input)) {
14
+ return true;
15
+ }
16
+ }
17
+ // For push, -n is --dry-run, not --no-verify
18
+ // For merge, -n is --no-commit, not --no-verify
19
+ // So we only block --no-verify (long form) for these
20
+ return false;
21
+ }
22
+ //# sourceMappingURL=has-no-verify-flag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"has-no-verify-flag.js","sourceRoot":"","sources":["../src/has-no-verify-flag.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,KAAa,EAAE,OAAmB;IAChE,wBAAwB;IACxB,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,IAAI,CAAA;IACb,CAAC;IAED,gDAAgD;IAChD,6EAA6E;IAC7E,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QACzB,kEAAkE;QAClE,IAAI,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7D,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;IAED,6CAA6C;IAC7C,gDAAgD;IAChD,qDAAqD;IAErD,OAAO,KAAK,CAAA;AACd,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * block-no-verify
3
+ *
4
+ * A security tool that blocks the --no-verify flag in git commands.
5
+ * Designed to prevent AI agents from bypassing git hooks.
6
+ */
7
+ export { GIT_COMMANDS_WITH_NO_VERIFY } from './types.js';
8
+ export type { GitCommand } from './git-command.js';
9
+ export type { CheckResult } from './check-result.js';
10
+ export { EXIT_CODES } from './exit-codes.js';
11
+ export { detectGitCommand } from './detect-git-command.js';
12
+ export { hasNoVerifyFlag } from './has-no-verify-flag.js';
13
+ export { checkCommand } from './check-command.js';
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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,YAAY,EAAE,MAAM,oBAAoB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * block-no-verify
3
+ *
4
+ * A security tool that blocks the --no-verify flag in git commands.
5
+ * Designed to prevent AI agents from bypassing git hooks.
6
+ */
7
+ export { GIT_COMMANDS_WITH_NO_VERIFY } from './types.js';
8
+ export { EXIT_CODES } from './exit-codes.js';
9
+ export { detectGitCommand } from './detect-git-command.js';
10
+ export { hasNoVerifyFlag } from './has-no-verify-flag.js';
11
+ export { checkCommand } from './check-command.js';
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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,YAAY,EAAE,MAAM,oBAAoB,CAAA"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Git commands that support the --no-verify flag
3
+ */
4
+ export declare const GIT_COMMANDS_WITH_NO_VERIFY: readonly ["commit", "push", "merge", "cherry-pick", "rebase", "am"];
5
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,2BAA2B,qEAO9B,CAAA"}
package/dist/types.js ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Git commands that support the --no-verify flag
3
+ */
4
+ export const GIT_COMMANDS_WITH_NO_VERIFY = [
5
+ 'commit',
6
+ 'push',
7
+ 'merge',
8
+ 'cherry-pick',
9
+ 'rebase',
10
+ 'am',
11
+ ];
12
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,QAAQ;IACR,MAAM;IACN,OAAO;IACP,aAAa;IACb,QAAQ;IACR,IAAI;CACI,CAAA"}
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "block-no-verify",
3
+ "version": "1.0.0",
4
+ "description": "CLI tool to block --no-verify flag in git commands. Prevents AI agents from bypassing git hooks.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "block-no-verify": "./dist/cli.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "keywords": [
21
+ "git",
22
+ "no-verify",
23
+ "hooks",
24
+ "cli",
25
+ "security",
26
+ "ai-safety",
27
+ "claude-code",
28
+ "agent-governance"
29
+ ],
30
+ "author": "",
31
+ "license": "MIT",
32
+ "engines": {
33
+ "node": ">=20.0.0"
34
+ },
35
+ "publishConfig": {
36
+ "access": "public"
37
+ },
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/tupe12334/block-no-verify.git"
41
+ },
42
+ "bugs": {
43
+ "url": "https://github.com/tupe12334/block-no-verify/issues"
44
+ },
45
+ "homepage": "https://github.com/tupe12334/block-no-verify#readme",
46
+ "devDependencies": {
47
+ "@commitlint/cli": "^20.3.1",
48
+ "@commitlint/config-conventional": "^20.3.1",
49
+ "@cspell/dict-he": "^4.0.5",
50
+ "@types/node": "^25.0.3",
51
+ "@vitest/coverage-v8": "^4.0.16",
52
+ "cspell": "^9.4.0",
53
+ "eslint": "^9.39.2",
54
+ "eslint-config-agent": "^1.9.0",
55
+ "eslint-config-publishable-package-json": "^1.0.0",
56
+ "eslint-import-resolver-typescript": "^4.4.4",
57
+ "husky": "^9.1.7",
58
+ "knip": "^5.80.2",
59
+ "lint-staged": "^16.2.7",
60
+ "prettier": "^3.7.4",
61
+ "release-it": "^19.2.3",
62
+ "typescript": "^5.9.3",
63
+ "vitest": "^4.0.16"
64
+ },
65
+ "scripts": {
66
+ "build": "tsc",
67
+ "dev": "tsc --watch",
68
+ "test": "vitest",
69
+ "test:watch": "vitest --watch",
70
+ "test:coverage": "vitest --coverage",
71
+ "lint": "eslint .",
72
+ "lint:fix": "eslint . --fix",
73
+ "format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json,md}\"",
74
+ "format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,json,md}\"",
75
+ "spell": "cspell lint '**/*.{ts,js,md,json}' --gitignore",
76
+ "spell:check": "cspell lint '**/*.{ts,js,md,json}' --gitignore",
77
+ "knip": "knip",
78
+ "release": "release-it"
79
+ }
80
+ }