@pushary/agent-hooks 0.95.8 → 0.98.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/CHANGELOG.md +27 -0
- package/dist/bin/pushary-bell-hook.js +19 -21
- package/dist/bin/pushary-bell.js +6 -8
- package/dist/bin/pushary-claude.js +21 -23
- package/dist/bin/pushary-clean.js +19 -22
- package/dist/bin/pushary-codex-bridge.js +13 -14
- package/dist/bin/pushary-codex-hook.js +452 -104
- package/dist/bin/pushary-codex.js +8 -8
- package/dist/bin/pushary-connect.js +6 -6
- package/dist/bin/pushary-cowork.js +3 -3
- package/dist/bin/pushary-daemon.js +25 -27
- package/dist/bin/pushary-disconnect.js +6 -8
- package/dist/bin/pushary-doctor.js +28 -23
- package/dist/bin/pushary-elicitation-hook.js +19 -21
- package/dist/bin/pushary-gemini-bridge.js +11 -12
- package/dist/bin/pushary-gemini-hook.js +22 -24
- package/dist/bin/pushary-hook.js +24 -26
- package/dist/bin/pushary-login.js +7 -8
- package/dist/bin/pushary-logout.js +4 -4
- package/dist/bin/pushary-mode.js +3 -3
- package/dist/bin/pushary-notification-hook.js +21 -23
- package/dist/bin/pushary-opencode-hook.js +22 -24
- package/dist/bin/pushary-permission-denied-hook.js +28 -27
- package/dist/bin/pushary-permission-hook.js +24 -26
- package/dist/bin/pushary-post-hook.js +21 -23
- package/dist/bin/pushary-prompt-hook.js +21 -23
- package/dist/bin/pushary-session-end-hook.js +21 -23
- package/dist/bin/pushary-session-start-hook.js +24 -26
- package/dist/bin/pushary-setup.js +45 -40
- package/dist/bin/pushary-stats.js +2 -2
- package/dist/bin/pushary-status.js +10 -11
- package/dist/bin/pushary-stop-hook.js +21 -23
- package/dist/bin/pushary-stopfailure-hook.js +21 -23
- package/dist/bin/pushary-transcript-register.js +17 -19
- package/dist/bin/pushary-transcripts.js +5 -5
- package/dist/bin/pushary-upgrade.js +17 -20
- package/dist/bin/pushary-wait.js +3 -3
- package/dist/{chunk-GOPIMNVC.js → chunk-2GLOHBYB.js} +1 -1
- package/dist/{chunk-BQL7UDIB.js → chunk-3RVCQDC4.js} +1 -1
- package/dist/chunk-53QCTSWY.js +202 -0
- package/dist/{chunk-3YFJGKJQ.js → chunk-5B5QV3KC.js} +8 -8
- package/dist/{chunk-FRXZMCVA.js → chunk-5KLAETSU.js} +1 -1
- package/dist/{chunk-SDNTRS76.js → chunk-6C6MS57P.js} +1 -1
- package/dist/{chunk-A22VQ5ZL.js → chunk-6CYB77VD.js} +111 -55
- package/dist/{chunk-QD73WATQ.js → chunk-6LRGZJFB.js} +21 -21
- package/dist/{chunk-Z4JVEL7R.js → chunk-A76GNRIK.js} +191 -2
- package/dist/{chunk-RE25RJ5A.js → chunk-B35OCFXH.js} +4 -4
- package/dist/{chunk-UKMLSQXA.js → chunk-CP34FI4B.js} +2 -2
- package/dist/{chunk-I7LKI4WO.js → chunk-DOD3A6EU.js} +6 -8
- package/dist/{chunk-N6FAXQDD.js → chunk-FAJ4R7IB.js} +1 -1
- package/dist/{chunk-U5RIXR7I.js → chunk-HB2KB7QL.js} +1 -1
- package/dist/{chunk-QV266EGS.js → chunk-HFQ7WSHZ.js} +11 -14
- package/dist/{chunk-QJPYJVL3.js → chunk-IRLTW6KF.js} +1 -1
- package/dist/{chunk-Y6SCMXR6.js → chunk-J44RPHUZ.js} +2 -2
- package/dist/{chunk-R6LBGKWQ.js → chunk-JQU6PMH4.js} +17 -15
- package/dist/{chunk-4DUEIUUO.js → chunk-K6CH5NVW.js} +1 -1
- package/dist/{chunk-XZWUOCJZ.js → chunk-LBNAGGLV.js} +1 -1
- package/dist/{chunk-XS33QBJA.js → chunk-LGXUGYUH.js} +50 -1
- package/dist/{chunk-XO3JR3OP.js → chunk-LX4NNYII.js} +2 -2
- package/dist/{chunk-XEVOPOKT.js → chunk-M4TVEMLH.js} +1 -1
- package/dist/{chunk-TY6IJY6I.js → chunk-NIXVMMJM.js} +1 -1
- package/dist/{chunk-VERXHIQF.js → chunk-NQGYPTJQ.js} +1 -1
- package/dist/{chunk-EMGGUO2Q.js → chunk-OBYC6SN4.js} +1 -1
- package/dist/{chunk-XUTSZYYJ.js → chunk-OPR2BPD4.js} +1 -4
- package/dist/{chunk-MC5WUOJJ.js → chunk-OUAE3GKO.js} +75 -1
- package/dist/{chunk-ATKGKAP6.js → chunk-QXIF6R4P.js} +16 -13
- package/dist/chunk-SI7GYBQP.js +15 -0
- package/dist/{chunk-VMQU7YEJ.js → chunk-SJLGOVC6.js} +1 -1
- package/dist/{chunk-54W7ELDQ.js → chunk-TZHDKRMG.js} +2 -2
- package/dist/{chunk-F4TMY6XI.js → chunk-V47GITZV.js} +3 -3
- package/dist/{chunk-L7NOG547.js → chunk-VZD2GEKB.js} +1 -1
- package/dist/{chunk-R3OZ5ISU.js → chunk-W2MG2P46.js} +4 -4
- package/dist/{chunk-E47WV7BJ.js → chunk-WU6LSXJ6.js} +2 -2
- package/dist/{chunk-NOVA7KZ2.js → chunk-XL3RKJYQ.js} +308 -35
- package/dist/{chunk-5GKNAQTG.js → chunk-XOOWC62T.js} +1 -1
- package/dist/{chunk-SKPXQRKN.js → chunk-XPPXOKIG.js} +1 -1
- package/dist/{chunk-HUGIKB5O.js → chunk-YJDRHQLG.js} +6 -6
- package/dist/src/index.js +11 -11
- package/package.json +1 -1
- package/dist/chunk-3AJIK5AO.js +0 -57
- package/dist/chunk-L4ZCFMWW.js +0 -177
- package/dist/chunk-VDI645ZX.js +0 -18
|
@@ -1,7 +1,222 @@
|
|
|
1
1
|
import {
|
|
2
2
|
HOOK_BUDGETS,
|
|
3
|
-
HOOK_LOCATOR_BINARY
|
|
4
|
-
|
|
3
|
+
HOOK_LOCATOR_BINARY,
|
|
4
|
+
withHookHoldBudget
|
|
5
|
+
} from "./chunk-OUAE3GKO.js";
|
|
6
|
+
|
|
7
|
+
// src/npm.ts
|
|
8
|
+
import { execFileSync, execSync } from "child_process";
|
|
9
|
+
import { existsSync, readFileSync, realpathSync } from "fs";
|
|
10
|
+
import { dirname, isAbsolute, join, relative, resolve } from "path";
|
|
11
|
+
var cleanNpmEnv = () => {
|
|
12
|
+
const env = {};
|
|
13
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
14
|
+
if (key.toLowerCase().startsWith("npm_config_workspace")) continue;
|
|
15
|
+
env[key] = value;
|
|
16
|
+
}
|
|
17
|
+
return env;
|
|
18
|
+
};
|
|
19
|
+
var npmErrorMessage = (err) => {
|
|
20
|
+
const e = err;
|
|
21
|
+
const text = [e?.stderr, e?.stdout].map((part) => part ? part.toString() : "").join("\n");
|
|
22
|
+
const line = text.split("\n").map((l) => l.replace(/^npm error\s*/i, "").trim()).find((l) => l && !l.startsWith("A complete log") && !/^code\s/i.test(l));
|
|
23
|
+
return line || e?.message || String(err);
|
|
24
|
+
};
|
|
25
|
+
var execNpm = (args, options = {}) => {
|
|
26
|
+
return execSync(`npm ${args}`, {
|
|
27
|
+
timeout: 12e4,
|
|
28
|
+
stdio: "pipe",
|
|
29
|
+
...options,
|
|
30
|
+
env: { ...cleanNpmEnv(), ...options.env ?? {} }
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
var resolveGlobalBinary = (name) => {
|
|
34
|
+
try {
|
|
35
|
+
const prefix = execNpm("prefix -g --no-workspaces", { timeout: 5e3 }).toString().trim();
|
|
36
|
+
const candidates = process.platform === "win32" ? [join(prefix, `${name}.cmd`), join(prefix, name)] : [join(prefix, "bin", name)];
|
|
37
|
+
return candidates.find(existsSync);
|
|
38
|
+
} catch {
|
|
39
|
+
return void 0;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
var resolvePathBinary = (name, platform = process.platform) => {
|
|
43
|
+
try {
|
|
44
|
+
return execFileSync(platform === "win32" ? "where" : "which", [name], {
|
|
45
|
+
encoding: "utf8",
|
|
46
|
+
stdio: "pipe",
|
|
47
|
+
timeout: 5e3
|
|
48
|
+
}).split(/\r?\n/, 1)[0]?.trim() || void 0;
|
|
49
|
+
} catch {
|
|
50
|
+
return void 0;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
var resolveBinary = (name) => resolveGlobalBinary(name) ?? resolvePathBinary(name);
|
|
54
|
+
var resolvePackageVersionFromBinary = (binary, packageName) => {
|
|
55
|
+
try {
|
|
56
|
+
let dir = dirname(realpathSync(binary));
|
|
57
|
+
const packagePath = packageName.split("/");
|
|
58
|
+
for (let depth = 0; depth < 8; depth++) {
|
|
59
|
+
for (const manifest of [
|
|
60
|
+
join(dir, "package.json"),
|
|
61
|
+
join(dir, "node_modules", ...packagePath, "package.json")
|
|
62
|
+
]) {
|
|
63
|
+
try {
|
|
64
|
+
const value = JSON.parse(readFileSync(manifest, "utf8"));
|
|
65
|
+
if (value.name === packageName && typeof value.version === "string") return value.version;
|
|
66
|
+
} catch {
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const parent = dirname(dir);
|
|
70
|
+
if (parent === dir) break;
|
|
71
|
+
dir = parent;
|
|
72
|
+
}
|
|
73
|
+
} catch {
|
|
74
|
+
}
|
|
75
|
+
return void 0;
|
|
76
|
+
};
|
|
77
|
+
var resolveGlobalPackageVersion = (name) => {
|
|
78
|
+
try {
|
|
79
|
+
const result = JSON.parse(execNpm("list -g --depth=0 --json --no-workspaces", { timeout: 5e3 }).toString());
|
|
80
|
+
const value = result.dependencies?.[name]?.version;
|
|
81
|
+
return typeof value === "string" ? value : void 0;
|
|
82
|
+
} catch {
|
|
83
|
+
return void 0;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
var localImportsPresent = (entry, packageDir, seen = /* @__PURE__ */ new Set()) => {
|
|
87
|
+
if (seen.has(entry)) return true;
|
|
88
|
+
seen.add(entry);
|
|
89
|
+
try {
|
|
90
|
+
const source = readFileSync(entry, "utf8");
|
|
91
|
+
for (const match of source.matchAll(/\b(?:import|export)\s+(?:[^"'()]*?\s+from\s+)?["'](\.{1,2}\/[^"']+)["']|\bimport\s*\(\s*["'](\.{1,2}\/[^"']+)["']/g)) {
|
|
92
|
+
const dependency = resolve(dirname(entry), match[1] ?? match[2]);
|
|
93
|
+
const localPath = relative(packageDir, dependency);
|
|
94
|
+
if (localPath.startsWith("..") || isAbsolute(localPath) || !existsSync(dependency)) return false;
|
|
95
|
+
if (/\.[cm]?js$/.test(dependency) && !localImportsPresent(dependency, packageDir, seen)) return false;
|
|
96
|
+
}
|
|
97
|
+
return true;
|
|
98
|
+
} catch {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
var packageBinsPresent = (packageDir, prefix, platform = process.platform, requiredFiles = []) => {
|
|
103
|
+
try {
|
|
104
|
+
const manifest = JSON.parse(readFileSync(join(packageDir, "package.json"), "utf8"));
|
|
105
|
+
if (!manifest.bin || typeof manifest.bin !== "object" || Array.isArray(manifest.bin)) return false;
|
|
106
|
+
const bins = Object.entries(manifest.bin);
|
|
107
|
+
if (bins.length === 0) return false;
|
|
108
|
+
if (!requiredFiles.every((path) => existsSync(join(packageDir, path)))) return false;
|
|
109
|
+
const seen = /* @__PURE__ */ new Set();
|
|
110
|
+
return bins.every(([name, target]) => {
|
|
111
|
+
if (typeof target !== "string") return false;
|
|
112
|
+
const shims = platform === "win32" ? [join(prefix, `${name}.cmd`), join(prefix, name)] : [join(prefix, "bin", name)];
|
|
113
|
+
const entry = join(packageDir, target);
|
|
114
|
+
return existsSync(entry) && shims.some(existsSync) && localImportsPresent(entry, packageDir, seen);
|
|
115
|
+
});
|
|
116
|
+
} catch {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
var AGENT_HOOKS_RUNTIME_FILES = [
|
|
121
|
+
"data/SKILL.md",
|
|
122
|
+
"data/cursor-plugin/.cursor-plugin/plugin.json",
|
|
123
|
+
"data/cursor-plugin/hooks/hooks.json",
|
|
124
|
+
"data/cursor-plugin/mcp.json",
|
|
125
|
+
"data/cursor-plugin/scripts/pushary-gate.mjs",
|
|
126
|
+
"data/vscode-plugin/.claude-plugin/plugin.json",
|
|
127
|
+
"data/vscode-plugin/hooks/hooks.json",
|
|
128
|
+
"data/vscode-plugin/.mcp.json",
|
|
129
|
+
"data/vscode-plugin/scripts/pushary-gate.mjs"
|
|
130
|
+
];
|
|
131
|
+
var globalPackageBinsPresent = (name) => {
|
|
132
|
+
try {
|
|
133
|
+
const root = execNpm("root -g --no-workspaces", { timeout: 5e3 }).toString().trim();
|
|
134
|
+
const prefix = execNpm("prefix -g --no-workspaces", { timeout: 5e3 }).toString().trim();
|
|
135
|
+
return packageBinsPresent(join(root, ...name.split("/")), prefix, process.platform, AGENT_HOOKS_RUNTIME_FILES);
|
|
136
|
+
} catch {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
var resolveGlobalBinDir = (probe) => {
|
|
141
|
+
if (process.platform === "win32") return void 0;
|
|
142
|
+
const resolved = resolveGlobalBinary(probe);
|
|
143
|
+
return resolved ? resolved.slice(0, resolved.length - probe.length - 1) : void 0;
|
|
144
|
+
};
|
|
145
|
+
var quoteIfNeeded = (path) => /\s/.test(path) ? `"${path}"` : path;
|
|
146
|
+
var needsGlobalInstall = (requested, installed, binaryPresent) => requested !== installed || !binaryPresent;
|
|
147
|
+
var installState;
|
|
148
|
+
var installGlobally = (options) => {
|
|
149
|
+
if (installState) {
|
|
150
|
+
return installState.then((result) => result === "installed" ? "cached" : result);
|
|
151
|
+
}
|
|
152
|
+
const started = (async () => {
|
|
153
|
+
const pinned = process.env.PUSHARY_PIN_GLOBAL_VERSION !== "0";
|
|
154
|
+
if (pinned && !needsGlobalInstall(
|
|
155
|
+
options.version,
|
|
156
|
+
resolveGlobalPackageVersion("@pushary/agent-hooks"),
|
|
157
|
+
globalPackageBinsPresent("@pushary/agent-hooks")
|
|
158
|
+
)) {
|
|
159
|
+
return "skipped";
|
|
160
|
+
}
|
|
161
|
+
const spec = pinned && options.version && options.version !== "0.0.0" ? `@pushary/agent-hooks@${options.version}` : "@pushary/agent-hooks@latest";
|
|
162
|
+
execNpm(`install -g --no-workspaces ${spec}`, { timeout: options.timeoutMs ?? 12e4 });
|
|
163
|
+
return "installed";
|
|
164
|
+
})();
|
|
165
|
+
installState = started;
|
|
166
|
+
started.catch(() => {
|
|
167
|
+
if (installState === started) installState = void 0;
|
|
168
|
+
});
|
|
169
|
+
return started;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// src/hook-command.ts
|
|
173
|
+
var HOOK_SHELL = "/bin/sh -c";
|
|
174
|
+
var holdBudgetOf = (hook) => hook.holds ? hook.timeout : void 0;
|
|
175
|
+
var LOCATE = 'B=$(command -v "$0") || exit 0; [ -f "$B" ] || exit 0; [ -x "$B" ] || exit 0';
|
|
176
|
+
var NODE_PRESENT = "command -v node >/dev/null 2>&1 || exit 0";
|
|
177
|
+
var CURSOR_NO_OPINION = { permission: "deny", user_message: "Command denied via Pushary.", agent_message: "Pushary hook is unavailable. Repair the integration before retrying." };
|
|
178
|
+
var shellDoubleQuoted = (text) => `"${text.replace(/(["\\$`])/g, "\\$1")}"`;
|
|
179
|
+
var CURSOR_NATIVE_PROMPT = { permission: "ask" };
|
|
180
|
+
var CURSOR_NATIVE_PROMPT_EVENTS = ["beforeShellExecution", "beforeMCPExecution"];
|
|
181
|
+
var hookEventIsOneOf = (events) => events.flatMap((event) => [`*\\"hook_event_name\\":\\"${event}\\"*`, `*\\"hook_event_name\\":\\ \\"${event}\\"*`]).join("|");
|
|
182
|
+
var CURSOR_MISS = `{ E=$(cat); case "$E" in ${hookEventIsOneOf(CURSOR_NATIVE_PROMPT_EVENTS)}) printf %s ${shellDoubleQuoted(JSON.stringify(CURSOR_NATIVE_PROMPT))} ;; *) printf %s ${shellDoubleQuoted(JSON.stringify(CURSOR_NO_OPINION))} ;; esac; exit 0; }`;
|
|
183
|
+
var HOOK_GUARD_SCRIPTS = {
|
|
184
|
+
native_binary: `${LOCATE}; exec "$B" "$@"`,
|
|
185
|
+
node_binary: `${LOCATE}; ${NODE_PRESENT}; exec "$B" "$@"`,
|
|
186
|
+
node_script: `[ -f "$0" ] || exit 0; ${NODE_PRESENT}; exec node "$0" "$@"`,
|
|
187
|
+
cursor_gate_script: `[ -f "$0" ] || ${CURSOR_MISS}; command -v node >/dev/null 2>&1 || ${CURSOR_MISS}; exec node "$0" "$@"`
|
|
188
|
+
};
|
|
189
|
+
var BINARY_GUARDS = {
|
|
190
|
+
native: "native_binary",
|
|
191
|
+
node: "node_binary"
|
|
192
|
+
};
|
|
193
|
+
var guardKindOf = (target) => {
|
|
194
|
+
switch (target.kind) {
|
|
195
|
+
case "node":
|
|
196
|
+
return "node_script";
|
|
197
|
+
case "cursor_gate":
|
|
198
|
+
return "cursor_gate_script";
|
|
199
|
+
case "binary":
|
|
200
|
+
return BINARY_GUARDS[target.runtime];
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
var targetPath = (target) => target.kind === "binary" ? target.path : target.script;
|
|
204
|
+
var runsThroughNode = (target) => target.kind !== "binary";
|
|
205
|
+
var guardHookCommand = (target, platform = process.platform) => {
|
|
206
|
+
const path = quoteIfNeeded(targetPath(target));
|
|
207
|
+
if (platform === "win32") return runsThroughNode(target) ? `node ${path}` : path;
|
|
208
|
+
return `${HOOK_SHELL} '${HOOK_GUARD_SCRIPTS[guardKindOf(target)]}' ${path}`;
|
|
209
|
+
};
|
|
210
|
+
var guardBinary = (path, platform) => guardHookCommand({ kind: "binary", path, runtime: "node" }, platform);
|
|
211
|
+
var guardCursorGate = (script, platform) => guardHookCommand({ kind: "cursor_gate", script }, platform);
|
|
212
|
+
var guardedArgv = (target, args = [], platform = process.platform) => {
|
|
213
|
+
const path = targetPath(target);
|
|
214
|
+
if (platform === "win32") {
|
|
215
|
+
return runsThroughNode(target) ? ["node", path, ...args] : [path, ...args];
|
|
216
|
+
}
|
|
217
|
+
const [shell, ...shellArgs] = HOOK_SHELL.split(/\s+/);
|
|
218
|
+
return [shell, ...shellArgs, HOOK_GUARD_SCRIPTS[guardKindOf(target)], path, ...args];
|
|
219
|
+
};
|
|
5
220
|
|
|
6
221
|
// src/removal-scope.ts
|
|
7
222
|
var namesAppLocator = (command) => command.includes(HOOK_LOCATOR_BINARY);
|
|
@@ -10,7 +225,24 @@ var isProtectedByScope = (command, scope) => scope?.keepAppWiring === true && na
|
|
|
10
225
|
// src/codex-config.ts
|
|
11
226
|
import { createHash } from "crypto";
|
|
12
227
|
import { homedir } from "os";
|
|
13
|
-
import { join } from "path";
|
|
228
|
+
import { join as join2 } from "path";
|
|
229
|
+
|
|
230
|
+
// src/hook-entries.ts
|
|
231
|
+
var registerHookEntry = (existing, isOurs, entry) => {
|
|
232
|
+
const rewritten = [];
|
|
233
|
+
let placed = false;
|
|
234
|
+
for (const item of existing) {
|
|
235
|
+
if (!isOurs(item)) {
|
|
236
|
+
rewritten.push(item);
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
if (placed) continue;
|
|
240
|
+
rewritten.push(entry);
|
|
241
|
+
placed = true;
|
|
242
|
+
}
|
|
243
|
+
if (!placed) rewritten.push(entry);
|
|
244
|
+
return rewritten;
|
|
245
|
+
};
|
|
14
246
|
|
|
15
247
|
// src/canonical-json.ts
|
|
16
248
|
var canonicalJson = (value) => {
|
|
@@ -23,17 +255,17 @@ var canonicalJson = (value) => {
|
|
|
23
255
|
// src/codex-config.ts
|
|
24
256
|
var CODEX_HOOK_BINARY = "pushary-codex-hook";
|
|
25
257
|
var codexHome = () => codexHomeFrom(homedir());
|
|
26
|
-
var codexHomeFrom = (home) => process.env.CODEX_HOME?.trim() ||
|
|
27
|
-
var codexConfigToml = () =>
|
|
28
|
-
var codexHooksJson = () =>
|
|
29
|
-
var codexAgentsMd = () =>
|
|
30
|
-
var codexSkillDir = () =>
|
|
258
|
+
var codexHomeFrom = (home) => process.env.CODEX_HOME?.trim() || join2(home, ".codex");
|
|
259
|
+
var codexConfigToml = () => join2(codexHome(), "config.toml");
|
|
260
|
+
var codexHooksJson = () => join2(codexHome(), "hooks.json");
|
|
261
|
+
var codexAgentsMd = () => join2(codexHome(), "AGENTS.md");
|
|
262
|
+
var codexSkillDir = () => join2(codexHome(), "skills", "pushary");
|
|
31
263
|
var CODEX_HOOK_EVENTS = [
|
|
32
264
|
{ event: "PermissionRequest", delivery: "approval", timeout: HOOK_BUDGETS.codex.budgetSeconds, statusMessage: "Waiting for your phone" },
|
|
33
265
|
{ event: "PreToolUse", matcher: "Bash|apply_patch|mcp__.*", delivery: "approval", timeout: HOOK_BUDGETS.codex.budgetSeconds, statusMessage: "Checking Pushary policy" },
|
|
34
266
|
{ event: "PostToolUse", matcher: "Bash|apply_patch|mcp__.*", delivery: "telemetry", timeout: 10 },
|
|
35
267
|
{ event: "UserPromptSubmit", delivery: "telemetry", timeout: 10 },
|
|
36
|
-
{ event: "Stop", delivery: "
|
|
268
|
+
{ event: "Stop", delivery: "rescue", timeout: HOOK_BUDGETS.codex.budgetSeconds, holds: true },
|
|
37
269
|
// `clear` alongside startup and resume, matching what we already do on Claude
|
|
38
270
|
// Code. Codex names all three in its own SessionStart sources, and without it a
|
|
39
271
|
// session the person started by clearing is one we never see begin.
|
|
@@ -110,17 +342,15 @@ var addCodexHooks = (config, command) => {
|
|
|
110
342
|
const hooks = ensureRecord(config, "hooks");
|
|
111
343
|
for (const definition of CODEX_HOOK_EVENTS) {
|
|
112
344
|
const existing = Array.isArray(hooks[definition.event]) ? hooks[definition.event] : [];
|
|
113
|
-
|
|
114
|
-
entries.push({
|
|
345
|
+
hooks[definition.event] = registerHookEntry(existing, isPusharyCodexHook, {
|
|
115
346
|
...definition.matcher ? { matcher: definition.matcher } : {},
|
|
116
347
|
hooks: [{
|
|
117
348
|
type: "command",
|
|
118
|
-
command,
|
|
349
|
+
command: withHookHoldBudget(command, holdBudgetOf(definition)),
|
|
119
350
|
timeout: definition.timeout,
|
|
120
351
|
...definition.statusMessage ? { statusMessage: definition.statusMessage } : {}
|
|
121
352
|
}]
|
|
122
353
|
});
|
|
123
|
-
hooks[definition.event] = entries;
|
|
124
354
|
}
|
|
125
355
|
};
|
|
126
356
|
var removeCodexHooks = (config, scope) => {
|
|
@@ -159,7 +389,7 @@ var missingCodexHookEvents = (config) => {
|
|
|
159
389
|
}).map((definition) => definition.event);
|
|
160
390
|
};
|
|
161
391
|
var codexHookTrustHash = (definition, command) => {
|
|
162
|
-
const hook = { command, timeout: definition.timeout, type: "command" };
|
|
392
|
+
const hook = { command: withHookHoldBudget(command, holdBudgetOf(definition)), timeout: definition.timeout, type: "command" };
|
|
163
393
|
if (definition.statusMessage) hook.statusMessage = definition.statusMessage;
|
|
164
394
|
const entry = { hooks: [hook] };
|
|
165
395
|
if (definition.matcher) entry.matcher = definition.matcher;
|
|
@@ -206,6 +436,33 @@ var codexHookPositions = (hooksConfig) => {
|
|
|
206
436
|
return positions;
|
|
207
437
|
};
|
|
208
438
|
var codexHookStateKey = (hooksJsonPath, event, position) => `${hooksJsonPath}:${CODEX_EVENT_KEY[event]}:${position[0]}:${position[1]}`;
|
|
439
|
+
var codexVacatedIndexes = (hooksConfig) => {
|
|
440
|
+
const hooks = asRecord(hooksConfig?.hooks);
|
|
441
|
+
const vacated = {};
|
|
442
|
+
for (const definition of CODEX_HOOK_EVENTS) {
|
|
443
|
+
const entries = hooks?.[definition.event];
|
|
444
|
+
if (!Array.isArray(entries)) continue;
|
|
445
|
+
const ours = entries.flatMap((entry, index) => isPusharyCodexHook(entry) ? [index] : []);
|
|
446
|
+
if (ours.length > 1) vacated[definition.event] = ours[1];
|
|
447
|
+
}
|
|
448
|
+
return vacated;
|
|
449
|
+
};
|
|
450
|
+
var dropVacatedCodexHookTrust = (config, hooksJsonPath, vacated) => {
|
|
451
|
+
const state = asRecord(asRecord(config.hooks)?.state);
|
|
452
|
+
if (!state) return false;
|
|
453
|
+
let changed = false;
|
|
454
|
+
for (const [event, from] of Object.entries(vacated)) {
|
|
455
|
+
const prefix = `${hooksJsonPath}:${CODEX_EVENT_KEY[event] ?? codexEventKeyOf(event)}:`;
|
|
456
|
+
for (const key of Object.keys(state)) {
|
|
457
|
+
if (!key.startsWith(prefix)) continue;
|
|
458
|
+
const entryIndex = Number(key.slice(prefix.length).split(":")[0]);
|
|
459
|
+
if (!Number.isInteger(entryIndex) || entryIndex < from) continue;
|
|
460
|
+
delete state[key];
|
|
461
|
+
changed = true;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
return changed;
|
|
465
|
+
};
|
|
209
466
|
var captureCodexHookTrust = (config, hooksJsonPath, positions) => {
|
|
210
467
|
const state = asRecord(asRecord(config.hooks)?.state);
|
|
211
468
|
if (!state) return {};
|
|
@@ -308,29 +565,43 @@ var staleTrustKeys = (state, hooksJsonPath, event, currentKey, ourHash) => {
|
|
|
308
565
|
|
|
309
566
|
// src/setup/paths.ts
|
|
310
567
|
import { homedir as homedir2 } from "os";
|
|
311
|
-
import { join as
|
|
312
|
-
var claudeSettings = () =>
|
|
313
|
-
var claudeJson = () =>
|
|
314
|
-
var claudeSkillDir = () =>
|
|
315
|
-
var cursorPluginDir = () =>
|
|
316
|
-
var cursorUserHooks = () =>
|
|
317
|
-
var cursorUserMcp = () =>
|
|
318
|
-
var vscodePluginDir = () =>
|
|
319
|
-
var vscodePluginMcp = () =>
|
|
320
|
-
var claudeSettingsLocal = () =>
|
|
321
|
-
var pusharyDir = () =>
|
|
322
|
-
var claudeMcpReceipt = () =>
|
|
323
|
-
var bridgeAgentKey = () =>
|
|
324
|
-
var claudeRegistrationReceipt = () =>
|
|
325
|
-
var hermesConfigReceipt = () =>
|
|
326
|
-
var hookTakeoverReceipt = (agent) =>
|
|
327
|
-
var codexSkillDir2 = () =>
|
|
328
|
-
var codexAgentsMd2 = () =>
|
|
329
|
-
var geminiSettings = () =>
|
|
330
|
-
var geminiMd = () =>
|
|
331
|
-
var pusharyConfigFile = () =>
|
|
568
|
+
import { join as join3 } from "path";
|
|
569
|
+
var claudeSettings = () => join3(homedir2(), ".claude", "settings.json");
|
|
570
|
+
var claudeJson = () => join3(homedir2(), ".claude.json");
|
|
571
|
+
var claudeSkillDir = () => join3(homedir2(), ".claude", "skills", "pushary");
|
|
572
|
+
var cursorPluginDir = () => join3(homedir2(), ".cursor", "plugins", "local", "pushary");
|
|
573
|
+
var cursorUserHooks = () => join3(homedir2(), ".cursor", "hooks.json");
|
|
574
|
+
var cursorUserMcp = () => join3(homedir2(), ".cursor", "mcp.json");
|
|
575
|
+
var vscodePluginDir = () => join3(homedir2(), ".pushary", "plugins", "vscode");
|
|
576
|
+
var vscodePluginMcp = () => join3(vscodePluginDir(), ".mcp.json");
|
|
577
|
+
var claudeSettingsLocal = () => join3(homedir2(), ".claude", "settings.local.json");
|
|
578
|
+
var pusharyDir = () => join3(homedir2(), ".pushary");
|
|
579
|
+
var claudeMcpReceipt = () => join3(pusharyDir(), "setup", "claude-mcp.json");
|
|
580
|
+
var bridgeAgentKey = () => join3(pusharyDir(), "bridge-auth", "agent-key.json");
|
|
581
|
+
var claudeRegistrationReceipt = () => join3(pusharyDir(), "setup", "claude-registration.json");
|
|
582
|
+
var hermesConfigReceipt = () => join3(pusharyDir(), "setup", "hermes-config.json");
|
|
583
|
+
var hookTakeoverReceipt = (agent) => join3(pusharyDir(), "setup", `hook-takeover-${agent}.json`);
|
|
584
|
+
var codexSkillDir2 = () => join3(codexHome(), "skills", "pushary");
|
|
585
|
+
var codexAgentsMd2 = () => join3(codexHome(), "AGENTS.md");
|
|
586
|
+
var geminiSettings = () => join3(homedir2(), ".gemini", "settings.json");
|
|
587
|
+
var geminiMd = () => join3(homedir2(), ".gemini", "GEMINI.md");
|
|
588
|
+
var pusharyConfigFile = () => join3(homedir2(), ".pushary", "config.json");
|
|
332
589
|
|
|
333
590
|
export {
|
|
591
|
+
npmErrorMessage,
|
|
592
|
+
execNpm,
|
|
593
|
+
resolveGlobalBinary,
|
|
594
|
+
resolvePathBinary,
|
|
595
|
+
resolveBinary,
|
|
596
|
+
resolvePackageVersionFromBinary,
|
|
597
|
+
resolveGlobalPackageVersion,
|
|
598
|
+
resolveGlobalBinDir,
|
|
599
|
+
installGlobally,
|
|
600
|
+
holdBudgetOf,
|
|
601
|
+
guardBinary,
|
|
602
|
+
guardCursorGate,
|
|
603
|
+
guardedArgv,
|
|
604
|
+
registerHookEntry,
|
|
334
605
|
isProtectedByScope,
|
|
335
606
|
canonicalJson,
|
|
336
607
|
CODEX_HOOK_BINARY,
|
|
@@ -349,6 +620,8 @@ export {
|
|
|
349
620
|
missingCodexHookEvents,
|
|
350
621
|
codexTrustSchemeAgrees,
|
|
351
622
|
codexHookPositions,
|
|
623
|
+
codexVacatedIndexes,
|
|
624
|
+
dropVacatedCodexHookTrust,
|
|
352
625
|
captureCodexHookTrust,
|
|
353
626
|
restoreCodexHookTrust,
|
|
354
627
|
codexTrustGaps,
|
|
@@ -18,26 +18,26 @@ import {
|
|
|
18
18
|
summarizeStop,
|
|
19
19
|
taskTitleFrom,
|
|
20
20
|
toolResultErrorText
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-A76GNRIK.js";
|
|
22
22
|
import {
|
|
23
23
|
NOTIFICATION_PUSH_TYPES,
|
|
24
24
|
POSTTOOLUSE_MIRROR_ONLY_TOOLS
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-OPR2BPD4.js";
|
|
26
26
|
import {
|
|
27
27
|
cancelQuestion,
|
|
28
28
|
isPolicyConfig,
|
|
29
29
|
sendNotification,
|
|
30
30
|
waitForAnswer
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-LGXUGYUH.js";
|
|
32
32
|
import {
|
|
33
33
|
getMachineId
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-WU6LSXJ6.js";
|
|
35
35
|
import {
|
|
36
36
|
withRetry
|
|
37
37
|
} from "./chunk-EYRGBYZG.js";
|
|
38
38
|
import {
|
|
39
39
|
reportedInstallSource
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-VZD2GEKB.js";
|
|
41
41
|
import {
|
|
42
42
|
getApiKey,
|
|
43
43
|
getBaseUrl
|
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
pendingCommandEvents,
|
|
55
55
|
resolveAutoResolveOrigin,
|
|
56
56
|
resolvePolicy
|
|
57
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-OUAE3GKO.js";
|
|
58
58
|
|
|
59
59
|
// src/policy.ts
|
|
60
60
|
import { createHash } from "crypto";
|
package/dist/src/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
handlePreToolUse
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
5
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-6CYB77VD.js";
|
|
4
|
+
import "../chunk-53QCTSWY.js";
|
|
5
|
+
import "../chunk-XOOWC62T.js";
|
|
6
6
|
import "../chunk-YHG74UFF.js";
|
|
7
7
|
import {
|
|
8
8
|
fetchAccountPublicKey
|
|
@@ -15,28 +15,28 @@ import {
|
|
|
15
15
|
handlePostToolUse,
|
|
16
16
|
handleStop,
|
|
17
17
|
reportEvent
|
|
18
|
-
} from "../chunk-
|
|
19
|
-
import "../chunk-
|
|
20
|
-
import "../chunk-
|
|
18
|
+
} from "../chunk-YJDRHQLG.js";
|
|
19
|
+
import "../chunk-A76GNRIK.js";
|
|
20
|
+
import "../chunk-OPR2BPD4.js";
|
|
21
21
|
import {
|
|
22
22
|
askUser,
|
|
23
23
|
cancelQuestion,
|
|
24
24
|
waitForAnswer
|
|
25
|
-
} from "../chunk-
|
|
26
|
-
import "../chunk-
|
|
27
|
-
import "../chunk-
|
|
25
|
+
} from "../chunk-LGXUGYUH.js";
|
|
26
|
+
import "../chunk-WU6LSXJ6.js";
|
|
27
|
+
import "../chunk-XL3RKJYQ.js";
|
|
28
28
|
import "../chunk-EYRGBYZG.js";
|
|
29
29
|
import "../chunk-SAF6HGAA.js";
|
|
30
30
|
import "../chunk-7QLSKOSU.js";
|
|
31
31
|
import "../chunk-KZERVKTD.js";
|
|
32
|
-
import "../chunk-
|
|
32
|
+
import "../chunk-VZD2GEKB.js";
|
|
33
33
|
import {
|
|
34
34
|
getApiKey,
|
|
35
35
|
getBaseUrl
|
|
36
36
|
} from "../chunk-2UMNXADU.js";
|
|
37
37
|
import {
|
|
38
38
|
resolvePolicy
|
|
39
|
-
} from "../chunk-
|
|
39
|
+
} from "../chunk-OUAE3GKO.js";
|
|
40
40
|
export {
|
|
41
41
|
askUser,
|
|
42
42
|
cancelQuestion,
|
package/package.json
CHANGED
package/dist/chunk-3AJIK5AO.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
quoteIfNeeded
|
|
3
|
-
} from "./chunk-L4ZCFMWW.js";
|
|
4
|
-
|
|
5
|
-
// src/hook-command.ts
|
|
6
|
-
var HOOK_SHELL = "/bin/sh -c";
|
|
7
|
-
var LOCATE = 'B=$(command -v "$0") || exit 0; [ -f "$B" ] || exit 0; [ -x "$B" ] || exit 0';
|
|
8
|
-
var NODE_PRESENT = "command -v node >/dev/null 2>&1 || exit 0";
|
|
9
|
-
var CURSOR_NO_OPINION = { permission: "deny", user_message: "Command denied via Pushary.", agent_message: "Pushary hook is unavailable. Repair the integration before retrying." };
|
|
10
|
-
var shellDoubleQuoted = (text) => `"${text.replace(/(["\\$`])/g, "\\$1")}"`;
|
|
11
|
-
var CURSOR_NATIVE_PROMPT = { permission: "ask" };
|
|
12
|
-
var CURSOR_NATIVE_PROMPT_EVENTS = ["beforeShellExecution", "beforeMCPExecution"];
|
|
13
|
-
var hookEventIsOneOf = (events) => events.flatMap((event) => [`*\\"hook_event_name\\":\\"${event}\\"*`, `*\\"hook_event_name\\":\\ \\"${event}\\"*`]).join("|");
|
|
14
|
-
var CURSOR_MISS = `{ E=$(cat); case "$E" in ${hookEventIsOneOf(CURSOR_NATIVE_PROMPT_EVENTS)}) printf %s ${shellDoubleQuoted(JSON.stringify(CURSOR_NATIVE_PROMPT))} ;; *) printf %s ${shellDoubleQuoted(JSON.stringify(CURSOR_NO_OPINION))} ;; esac; exit 0; }`;
|
|
15
|
-
var HOOK_GUARD_SCRIPTS = {
|
|
16
|
-
native_binary: `${LOCATE}; exec "$B" "$@"`,
|
|
17
|
-
node_binary: `${LOCATE}; ${NODE_PRESENT}; exec "$B" "$@"`,
|
|
18
|
-
node_script: `[ -f "$0" ] || exit 0; ${NODE_PRESENT}; exec node "$0" "$@"`,
|
|
19
|
-
cursor_gate_script: `[ -f "$0" ] || ${CURSOR_MISS}; command -v node >/dev/null 2>&1 || ${CURSOR_MISS}; exec node "$0" "$@"`
|
|
20
|
-
};
|
|
21
|
-
var BINARY_GUARDS = {
|
|
22
|
-
native: "native_binary",
|
|
23
|
-
node: "node_binary"
|
|
24
|
-
};
|
|
25
|
-
var guardKindOf = (target) => {
|
|
26
|
-
switch (target.kind) {
|
|
27
|
-
case "node":
|
|
28
|
-
return "node_script";
|
|
29
|
-
case "cursor_gate":
|
|
30
|
-
return "cursor_gate_script";
|
|
31
|
-
case "binary":
|
|
32
|
-
return BINARY_GUARDS[target.runtime];
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
var targetPath = (target) => target.kind === "binary" ? target.path : target.script;
|
|
36
|
-
var runsThroughNode = (target) => target.kind !== "binary";
|
|
37
|
-
var guardHookCommand = (target, platform = process.platform) => {
|
|
38
|
-
const path = quoteIfNeeded(targetPath(target));
|
|
39
|
-
if (platform === "win32") return runsThroughNode(target) ? `node ${path}` : path;
|
|
40
|
-
return `${HOOK_SHELL} '${HOOK_GUARD_SCRIPTS[guardKindOf(target)]}' ${path}`;
|
|
41
|
-
};
|
|
42
|
-
var guardBinary = (path, platform) => guardHookCommand({ kind: "binary", path, runtime: "node" }, platform);
|
|
43
|
-
var guardCursorGate = (script, platform) => guardHookCommand({ kind: "cursor_gate", script }, platform);
|
|
44
|
-
var guardedArgv = (target, args = [], platform = process.platform) => {
|
|
45
|
-
const path = targetPath(target);
|
|
46
|
-
if (platform === "win32") {
|
|
47
|
-
return runsThroughNode(target) ? ["node", path, ...args] : [path, ...args];
|
|
48
|
-
}
|
|
49
|
-
const [shell, ...shellArgs] = HOOK_SHELL.split(/\s+/);
|
|
50
|
-
return [shell, ...shellArgs, HOOK_GUARD_SCRIPTS[guardKindOf(target)], path, ...args];
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
export {
|
|
54
|
-
guardBinary,
|
|
55
|
-
guardCursorGate,
|
|
56
|
-
guardedArgv
|
|
57
|
-
};
|