@cybedefend/vibedefend 1.4.2 → 1.4.3
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/README.md +3 -1
- package/dist/clients/claude-code.js +4 -1
- package/dist/clients/claude-code.js.map +1 -1
- package/dist/clients/codex.js +4 -2
- package/dist/clients/codex.js.map +1 -1
- package/dist/hook-runner.js +938 -672
- package/dist/hooks/runtime/emit.js +25 -12
- package/dist/hooks/runtime/emit.js.map +1 -1
- package/dist/hooks/runtime/fetch-rules.js +38 -12
- package/dist/hooks/runtime/fetch-rules.js.map +1 -1
- package/dist/hooks/runtime/session-start.js +5 -1
- package/dist/hooks/runtime/session-start.js.map +1 -1
- package/dist/hooks/runtime/shell-writes.js +311 -0
- package/dist/hooks/runtime/shell-writes.js.map +1 -0
- package/dist/hooks/runtime/sniff.js +84 -5
- package/dist/hooks/runtime/sniff.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,3 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Universal stdin schema sniffer.
|
|
3
|
+
*
|
|
4
|
+
* Each of the 5 supported agents sends a different JSON shape on stdin
|
|
5
|
+
* when they invoke a hook. This module detects the calling agent and
|
|
6
|
+
* normalises the fields we care about into a single `NormalizedEvent`.
|
|
7
|
+
*
|
|
8
|
+
* Schema cheat sheet:
|
|
9
|
+
* - Windsurf: `.agent_action_name` + `.tool_info.{file_path, edits}`
|
|
10
|
+
* - VS Code: `.hookEventName` (camelCase field) + `.tool_input.…`
|
|
11
|
+
* - Cursor: `.hook_event_name` with **camelCase** value (`preToolUse`)
|
|
12
|
+
* - Codex: `.hook_event_name` with PascalCase value + `tool_name`
|
|
13
|
+
* `apply_patch` carrying a unified diff in `tool_input.patch`
|
|
14
|
+
* - Claude Code: `.hook_event_name` with PascalCase value (default fallback)
|
|
15
|
+
*/
|
|
16
|
+
import { homedir } from 'node:os';
|
|
17
|
+
import { isAbsolute, resolve as resolvePath } from 'node:path';
|
|
18
|
+
import { extractShellWriteTargets } from './shell-writes.js';
|
|
19
|
+
/**
|
|
20
|
+
* Make a shell write target absolute against the agent's cwd. `~` expands
|
|
21
|
+
* to the home directory; a token still carrying a `$VAR` is left untouched
|
|
22
|
+
* (guessing would produce a path that exists nowhere).
|
|
23
|
+
*/
|
|
24
|
+
export function resolveWriteTarget(cwd, target) {
|
|
25
|
+
if (target.includes('$'))
|
|
26
|
+
return target;
|
|
27
|
+
if (target === '~' || target.startsWith('~/')) {
|
|
28
|
+
return resolvePath(homedir(), target.slice(2));
|
|
29
|
+
}
|
|
30
|
+
return isAbsolute(target) ? resolvePath(target) : resolvePath(cwd, target);
|
|
31
|
+
}
|
|
1
32
|
/** Extract a file path from a unified-diff patch (Codex `apply_patch`). */
|
|
2
33
|
export function filePathFromPatch(patch) {
|
|
3
34
|
const lines = patch.split('\n');
|
|
@@ -44,7 +75,14 @@ export function sniff(input) {
|
|
|
44
75
|
else if (action === 'pre_read_code' || action === 'post_read_code') {
|
|
45
76
|
toolName = 'Read';
|
|
46
77
|
}
|
|
47
|
-
return {
|
|
78
|
+
return {
|
|
79
|
+
client: 'windsurf',
|
|
80
|
+
toolName,
|
|
81
|
+
filePath,
|
|
82
|
+
filePaths: filePath ? [filePath] : [],
|
|
83
|
+
newContent,
|
|
84
|
+
raw: input,
|
|
85
|
+
};
|
|
48
86
|
}
|
|
49
87
|
// ── VS Code Copilot ──────────────────────────────────────────────────
|
|
50
88
|
// VS Code uses camelCase field name `hookEventName` (distinct from
|
|
@@ -62,9 +100,15 @@ export function sniff(input) {
|
|
|
62
100
|
}
|
|
63
101
|
else {
|
|
64
102
|
// Codex emits `apply_patch` as a tool name (with patch payload);
|
|
65
|
-
// Claude Code uses Edit/Write/MultiEdit.
|
|
103
|
+
// Claude Code uses Edit/Write/MultiEdit. Both send `Bash` for shell
|
|
104
|
+
// commands, so tool_name alone cannot tell them apart there — Codex's
|
|
105
|
+
// envelope carries a `turn_id` (its documented extension), Claude
|
|
106
|
+
// Code's does not (observed on Codex 0.142 / Claude Code 2.1.267).
|
|
66
107
|
const toolName = typeof input.tool_name === 'string' ? input.tool_name : '';
|
|
67
|
-
client =
|
|
108
|
+
client =
|
|
109
|
+
toolName === 'apply_patch' || 'turn_id' in input
|
|
110
|
+
? 'codex'
|
|
111
|
+
: 'claude-code';
|
|
68
112
|
}
|
|
69
113
|
return extractToolInputShape(input, client);
|
|
70
114
|
}
|
|
@@ -73,6 +117,7 @@ export function sniff(input) {
|
|
|
73
117
|
client: 'unknown',
|
|
74
118
|
toolName: '',
|
|
75
119
|
filePath: '',
|
|
120
|
+
filePaths: [],
|
|
76
121
|
newContent: '',
|
|
77
122
|
raw: input,
|
|
78
123
|
};
|
|
@@ -86,8 +131,23 @@ function extractToolInputShape(input, client) {
|
|
|
86
131
|
const toolName = typeof input.tool_name === 'string' ? input.tool_name : '';
|
|
87
132
|
const toolInput = input.tool_input ?? {};
|
|
88
133
|
let filePath = typeof toolInput.file_path === 'string' ? toolInput.file_path : '';
|
|
134
|
+
let filePaths = [];
|
|
89
135
|
let newContent = '';
|
|
90
136
|
switch (toolName) {
|
|
137
|
+
case 'Bash': {
|
|
138
|
+
// Shell writes (BACK-173 follow-up): `cat > f <<EOF`, `sed -i`, `tee`,
|
|
139
|
+
// `cp`… An agent that edits through the shell must trigger the same
|
|
140
|
+
// rules fetch as one using the edit tool — in the field that is the
|
|
141
|
+
// common path, not the exception. The command text is the intent.
|
|
142
|
+
const command = typeof toolInput.command === 'string' ? toolInput.command : '';
|
|
143
|
+
newContent = command;
|
|
144
|
+
const cwd = typeof input.cwd === 'string' && input.cwd.length > 0
|
|
145
|
+
? input.cwd
|
|
146
|
+
: process.cwd();
|
|
147
|
+
filePaths = extractShellWriteTargets(command).map((t) => resolveWriteTarget(cwd, t));
|
|
148
|
+
filePath = filePaths[0] ?? '';
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
91
151
|
case 'Write':
|
|
92
152
|
newContent =
|
|
93
153
|
typeof toolInput.content === 'string' ? toolInput.content : '';
|
|
@@ -100,13 +160,32 @@ function extractToolInputShape(input, client) {
|
|
|
100
160
|
newContent = joinMultiEditNewStrings(toolInput.edits);
|
|
101
161
|
break;
|
|
102
162
|
case 'apply_patch': {
|
|
103
|
-
|
|
163
|
+
// Codex hands the patch text in `tool_input.command` (its docs: "for
|
|
164
|
+
// Bash and apply_patch: tool_input.command"; observed on 0.142 —
|
|
165
|
+
// BACK-173). Older builds used `tool_input.patch`. Accept both — with
|
|
166
|
+
// only `.patch` read, current Codex yielded an empty file path and
|
|
167
|
+
// fetch-rules exited before ever calling the gateway.
|
|
168
|
+
const patch = typeof toolInput.patch === 'string'
|
|
169
|
+
? toolInput.patch
|
|
170
|
+
: typeof toolInput.command === 'string'
|
|
171
|
+
? toolInput.command
|
|
172
|
+
: '';
|
|
104
173
|
newContent = patch;
|
|
105
174
|
if (!filePath)
|
|
106
175
|
filePath = filePathFromPatch(patch);
|
|
107
176
|
break;
|
|
108
177
|
}
|
|
109
178
|
}
|
|
110
|
-
|
|
179
|
+
// Relative paths (Codex `*** Update File: src/x.ts`, observed on 0.142)
|
|
180
|
+
// are resolved against the agent's cwd when the envelope carries one, so
|
|
181
|
+
// the rules fetch targets the same absolute file the agent is editing.
|
|
182
|
+
if (typeof input.cwd === 'string' && input.cwd.length > 0) {
|
|
183
|
+
if (filePath)
|
|
184
|
+
filePath = resolveWriteTarget(input.cwd, filePath);
|
|
185
|
+
filePaths = filePaths.map((f) => resolveWriteTarget(input.cwd, f));
|
|
186
|
+
}
|
|
187
|
+
if (filePaths.length === 0 && filePath)
|
|
188
|
+
filePaths = [filePath];
|
|
189
|
+
return { client, toolName, filePath, filePaths, newContent, raw: input };
|
|
111
190
|
}
|
|
112
191
|
//# sourceMappingURL=sniff.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sniff.js","sourceRoot":"","sources":["../../../src/hooks/runtime/sniff.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sniff.js","sourceRoot":"","sources":["../../../src/hooks/runtime/sniff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAC;AAE/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAG7D;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW,EAAE,MAAc;IAC5D,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC;IACxC,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9C,OAAO,WAAW,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAC7E,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAChC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,WAAW,GAAG,2CAA2C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3E,IAAI,WAAW;YAAE,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC;QACvC,MAAM,OAAO,GAAG,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAI,OAAO;YAAE,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,+DAA+D;AAC/D,SAAS,uBAAuB,CAC9B,KAAiD;IAEjD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACrC,OAAO,KAAK;SACT,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SAClE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;SAC3B,IAAI,CAAC,SAAS,CAAC,CAAC;AACrB,CAAC;AAED,yCAAyC;AACzC,SAAS,iBAAiB,CACxB,KAAiD;IAEjD,OAAO,uBAAuB,CAAC,KAAK,CAAC,CAAC;AACxC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,KAAK,CAAC,KAA8B;IAClD,wEAAwE;IACxE,IAAI,OAAO,KAAK,CAAC,iBAAiB,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,MAAM,GAAG,KAAK,CAAC,iBAAiB,CAAC;QACvC,MAAM,QAAQ,GAAI,KAAK,CAAC,SAAqC,IAAI,EAAE,CAAC;QACpE,MAAM,QAAQ,GACZ,OAAO,QAAQ,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,MAAM,UAAU,GAAG,iBAAiB,CAClC,QAAQ,CAAC,KAAmD,CAC7D,CAAC;QACF,IAAI,QAAQ,GAAG,MAAM,CAAC;QACtB,IAAI,MAAM,KAAK,gBAAgB,IAAI,MAAM,KAAK,iBAAiB,EAAE,CAAC;YAChE,QAAQ,GAAG,OAAO,CAAC;QACrB,CAAC;aAAM,IAAI,MAAM,KAAK,eAAe,IAAI,MAAM,KAAK,gBAAgB,EAAE,CAAC;YACrE,QAAQ,GAAG,MAAM,CAAC;QACpB,CAAC;QACD,OAAO;YACL,MAAM,EAAE,UAAU;YAClB,QAAQ;YACR,QAAQ;YACR,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;YACrC,UAAU;YACV,GAAG,EAAE,KAAK;SACX,CAAC;IACJ,CAAC;IAED,wEAAwE;IACxE,mEAAmE;IACnE,4DAA4D;IAC5D,IAAI,eAAe,IAAI,KAAK,EAAE,CAAC;QAC7B,OAAO,qBAAqB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAChD,CAAC;IAED,wEAAwE;IACxE,IAAI,iBAAiB,IAAI,KAAK,EAAE,CAAC;QAC/B,MAAM,GAAG,GACP,OAAO,KAAK,CAAC,eAAe,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC;QACzE,IAAI,MAAgB,CAAC;QACrB,IAAI,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,qDAAqD;YACrD,MAAM,GAAG,QAAQ,CAAC;QACpB,CAAC;aAAM,CAAC;YACN,iEAAiE;YACjE,oEAAoE;YACpE,sEAAsE;YACtE,kEAAkE;YAClE,mEAAmE;YACnE,MAAM,QAAQ,GACZ,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7D,MAAM;gBACJ,QAAQ,KAAK,aAAa,IAAI,SAAS,IAAI,KAAK;oBAC9C,CAAC,CAAC,OAAO;oBACT,CAAC,CAAC,aAAa,CAAC;QACtB,CAAC;QACD,OAAO,qBAAqB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC9C,CAAC;IAED,wEAAwE;IACxE,OAAO;QACL,MAAM,EAAE,SAAS;QACjB,QAAQ,EAAE,EAAE;QACZ,QAAQ,EAAE,EAAE;QACZ,SAAS,EAAE,EAAE;QACb,UAAU,EAAE,EAAE;QACd,GAAG,EAAE,KAAK;KACX,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,qBAAqB,CAC5B,KAA8B,EAC9B,MAAgB;IAEhB,MAAM,QAAQ,GACZ,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7D,MAAM,SAAS,GAAI,KAAK,CAAC,UAAsC,IAAI,EAAE,CAAC;IACtE,IAAI,QAAQ,GACV,OAAO,SAAS,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IACrE,IAAI,SAAS,GAAa,EAAE,CAAC;IAC7B,IAAI,UAAU,GAAG,EAAE,CAAC;IAEpB,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,uEAAuE;YACvE,oEAAoE;YACpE,oEAAoE;YACpE,kEAAkE;YAClE,MAAM,OAAO,GACX,OAAO,SAAS,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YACjE,UAAU,GAAG,OAAO,CAAC;YACrB,MAAM,GAAG,GACP,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC;gBACnD,CAAC,CAAC,KAAK,CAAC,GAAG;gBACX,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;YACpB,SAAS,GAAG,wBAAwB,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACtD,kBAAkB,CAAC,GAAG,EAAE,CAAC,CAAC,CAC3B,CAAC;YACF,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC9B,MAAM;QACR,CAAC;QACD,KAAK,OAAO;YACV,UAAU;gBACR,OAAO,SAAS,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YACjE,MAAM;QACR,KAAK,MAAM;YACT,UAAU;gBACR,OAAO,SAAS,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YACvE,MAAM;QACR,KAAK,WAAW;YACd,UAAU,GAAG,uBAAuB,CAClC,SAAS,CAAC,KAAmD,CAC9D,CAAC;YACF,MAAM;QACR,KAAK,aAAa,CAAC,CAAC,CAAC;YACnB,qEAAqE;YACrE,iEAAiE;YACjE,sEAAsE;YACtE,mEAAmE;YACnE,sDAAsD;YACtD,MAAM,KAAK,GACT,OAAO,SAAS,CAAC,KAAK,KAAK,QAAQ;gBACjC,CAAC,CAAC,SAAS,CAAC,KAAK;gBACjB,CAAC,CAAC,OAAO,SAAS,CAAC,OAAO,KAAK,QAAQ;oBACrC,CAAC,CAAC,SAAS,CAAC,OAAO;oBACnB,CAAC,CAAC,EAAE,CAAC;YACX,UAAU,GAAG,KAAK,CAAC;YACnB,IAAI,CAAC,QAAQ;gBAAE,QAAQ,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;YACnD,MAAM;QACR,CAAC;IACH,CAAC;IAED,wEAAwE;IACxE,yEAAyE;IACzE,uEAAuE;IACvE,IAAI,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1D,IAAI,QAAQ;YAAE,QAAQ,GAAG,kBAAkB,CAAC,KAAK,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QACjE,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,KAAK,CAAC,GAAa,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/E,CAAC;IACD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ;QAAE,SAAS,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC/D,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;AAC3E,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cybedefend/vibedefend",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.3",
|
|
4
4
|
"description": "VibeDefend — one-shot installer for CybeDefend's MCP server and Claude Code / Cursor / Codex / Windsurf hooks (for AI coding agents).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"esbuild": "^0.28.2",
|
|
42
42
|
"tsx": "^4.23.13",
|
|
43
43
|
"typescript": "^5.9.3",
|
|
44
|
-
"vitest": "^
|
|
44
|
+
"vitest": "^4.1.11"
|
|
45
45
|
},
|
|
46
46
|
"pnpm": {
|
|
47
47
|
"overrides": {
|