@pushary/agent-hooks 0.97.0 → 0.99.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 +20 -0
- package/dist/bin/pushary-bell-hook.js +20 -19
- package/dist/bin/pushary-bell.js +7 -6
- package/dist/bin/pushary-claude.js +21 -20
- package/dist/bin/pushary-clean.js +19 -18
- package/dist/bin/pushary-codex-bridge.js +11 -10
- package/dist/bin/pushary-codex-hook.js +33 -23
- package/dist/bin/pushary-codex.js +8 -7
- package/dist/bin/pushary-connect.js +7 -6
- package/dist/bin/pushary-cowork.js +3 -3
- package/dist/bin/pushary-daemon.js +24 -23
- package/dist/bin/pushary-disconnect.js +6 -6
- package/dist/bin/pushary-doctor.js +22 -21
- package/dist/bin/pushary-elicitation-hook.js +19 -18
- package/dist/bin/pushary-gemini-bridge.js +10 -9
- package/dist/bin/pushary-gemini-hook.js +22 -21
- package/dist/bin/pushary-hook.js +24 -23
- package/dist/bin/pushary-login.js +8 -7
- package/dist/bin/pushary-logout.js +5 -4
- package/dist/bin/pushary-mode.js +3 -3
- package/dist/bin/pushary-notification-hook.js +21 -20
- package/dist/bin/pushary-opencode-hook.js +22 -21
- package/dist/bin/pushary-permission-denied-hook.js +25 -24
- package/dist/bin/pushary-permission-hook.js +24 -23
- package/dist/bin/pushary-post-hook.js +21 -20
- package/dist/bin/pushary-prompt-hook.js +21 -20
- package/dist/bin/pushary-session-end-hook.js +21 -20
- package/dist/bin/pushary-session-start-hook.js +24 -23
- package/dist/bin/pushary-setup.js +38 -28
- package/dist/bin/pushary-stats.js +2 -2
- package/dist/bin/pushary-status.js +11 -10
- package/dist/bin/pushary-stop-hook.js +21 -20
- package/dist/bin/pushary-stopfailure-hook.js +21 -20
- package/dist/bin/pushary-transcript-register.js +18 -17
- package/dist/bin/pushary-transcripts.js +6 -5
- package/dist/bin/pushary-upgrade.js +15 -14
- package/dist/bin/pushary-wait.js +3 -3
- package/dist/{chunk-SW37HB27.js → chunk-3RVCQDC4.js} +1 -1
- package/dist/{chunk-AXSDMDJI.js → chunk-3ZAEUPM4.js} +1 -1
- package/dist/{chunk-B3557BDL.js → chunk-4C4XFAGJ.js} +2 -2
- package/dist/{chunk-VTUN7WSG.js → chunk-4LL6LG5X.js} +1 -43
- package/dist/{chunk-VF7YOT2W.js → chunk-4PBCNVI3.js} +4 -2
- package/dist/{chunk-IZKCA35M.js → chunk-562UJ2DA.js} +2 -2
- package/dist/{chunk-ROTIPRM4.js → chunk-5KLAETSU.js} +1 -1
- package/dist/{chunk-DGUMR5LZ.js → chunk-64WARXGV.js} +5 -5
- package/dist/{chunk-VDTC5DEM.js → chunk-6C6MS57P.js} +1 -1
- package/dist/{chunk-KDPYXMUI.js → chunk-6IFUXNFX.js} +2 -2
- package/dist/{chunk-XDMHLQMH.js → chunk-6KLCP7VF.js} +4 -4
- package/dist/{chunk-VCKQ45QA.js → chunk-A76GNRIK.js} +1 -1
- package/dist/{chunk-ICUBJNFL.js → chunk-CP34FI4B.js} +2 -2
- package/dist/{chunk-LYWTLNMG.js → chunk-CRFLU455.js} +4 -4
- package/dist/{chunk-WIKEADOS.js → chunk-EXHXR2X5.js} +1 -1
- package/dist/chunk-GCD3SQSV.js +44 -0
- package/dist/{chunk-EHQC3GWL.js → chunk-HB2KB7QL.js} +1 -1
- package/dist/{chunk-C2FYSFTQ.js → chunk-ID5FDKDZ.js} +1 -1
- package/dist/{chunk-BYH75I7Y.js → chunk-IRLTW6KF.js} +1 -1
- package/dist/{chunk-67RNDRKL.js → chunk-JBJBVERL.js} +111 -31
- package/dist/{chunk-3SNTEHOH.js → chunk-JL33EDN7.js} +4 -4
- package/dist/{chunk-FU5SQKAY.js → chunk-JXELRCU5.js} +16 -23
- package/dist/{chunk-YRXVC4HL.js → chunk-K4XFCEVI.js} +1 -1
- package/dist/{chunk-GGYH6LIE.js → chunk-K6BASBQJ.js} +1 -1
- package/dist/{chunk-H4VNAOCG.js → chunk-LBNAGGLV.js} +1 -1
- package/dist/{chunk-DOKFLZWL.js → chunk-LWKPMSBB.js} +69 -46
- package/dist/{chunk-6VXZKOBB.js → chunk-NSFNEDCT.js} +8 -8
- package/dist/{chunk-5ODZEFP3.js → chunk-O3LZQEQP.js} +1 -1
- package/dist/{chunk-QFAZ6QCT.js → chunk-OPR2BPD4.js} +1 -1
- package/dist/{chunk-HUZW6SEO.js → chunk-OUAE3GKO.js} +2 -2
- package/dist/{chunk-IBRX7LRE.js → chunk-PD6JY33P.js} +9 -8
- package/dist/{chunk-6WJKYD3Q.js → chunk-QS55LDX4.js} +11 -8
- package/dist/{chunk-4AXWBCCO.js → chunk-RALVI7OF.js} +4 -4
- package/dist/{chunk-OYTOLQ3N.js → chunk-SI7GYBQP.js} +1 -1
- package/dist/{chunk-YX3U2CLP.js → chunk-T3JZZUAR.js} +6 -6
- package/dist/{chunk-K7MLXXPY.js → chunk-V262ATS5.js} +3 -3
- package/dist/{chunk-DNLFSRCF.js → chunk-WGV3VY7O.js} +2 -2
- package/dist/{chunk-VOC55PQV.js → chunk-XOOWC62T.js} +1 -1
- package/dist/{chunk-CDSA3NTB.js → chunk-XPPXOKIG.js} +1 -1
- package/dist/{chunk-A4AIISZZ.js → chunk-YKLCWWEI.js} +1 -1
- package/dist/reapply-HQ264ZTR.js +30 -0
- package/dist/src/index.js +11 -10
- package/package.json +1 -1
|
@@ -2,16 +2,17 @@ import {
|
|
|
2
2
|
CLAUDE_HOOK_EVENTS,
|
|
3
3
|
GEMINI_HOOK_EVENTS,
|
|
4
4
|
hasGeminiHooks
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-PD6JY33P.js";
|
|
6
6
|
import {
|
|
7
7
|
CODEX_HOOK_EVENTS,
|
|
8
|
-
hasCodexHooks
|
|
9
|
-
|
|
8
|
+
hasCodexHooks,
|
|
9
|
+
holdBudgetOf
|
|
10
|
+
} from "./chunk-JBJBVERL.js";
|
|
10
11
|
import {
|
|
11
12
|
CURSOR_GATE_EVENTS,
|
|
12
13
|
HOOK_LOCATOR_BINARY,
|
|
13
14
|
hookCommandHoldBudget
|
|
14
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-OUAE3GKO.js";
|
|
15
16
|
|
|
16
17
|
// src/diagnostics/wiring.ts
|
|
17
18
|
var record = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -73,31 +74,20 @@ var toSeconds = (timeout, unit) => {
|
|
|
73
74
|
};
|
|
74
75
|
var registeredHooks = (entries, shape, unit) => {
|
|
75
76
|
if (!Array.isArray(entries)) return [];
|
|
76
|
-
return entries.flatMap((entry
|
|
77
|
+
return entries.flatMap((entry) => {
|
|
77
78
|
const container = record(entry);
|
|
78
79
|
if (!container) return [];
|
|
79
80
|
const hooks = shape === "nested" ? Array.isArray(container.hooks) ? container.hooks : [] : [container];
|
|
80
|
-
return hooks.flatMap((hook
|
|
81
|
+
return hooks.flatMap((hook) => {
|
|
81
82
|
const command = record(hook)?.command;
|
|
82
83
|
if (typeof command !== "string" || command.trim() === "") return [];
|
|
83
|
-
return [{
|
|
84
|
-
command,
|
|
85
|
-
timeoutSeconds: toSeconds(record(hook)?.timeout, unit),
|
|
86
|
-
order: [entryIndex, hookIndex]
|
|
87
|
-
}];
|
|
84
|
+
return [{ command, timeoutSeconds: toSeconds(record(hook)?.timeout, unit) }];
|
|
88
85
|
});
|
|
89
86
|
});
|
|
90
87
|
};
|
|
91
|
-
var runsBefore = (a, b) => a[0] < b[0] || a[0] === b[0] && a[1] < b[1];
|
|
92
88
|
var holdersOnEvent = (event, hooks) => {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return hooks.filter((hook) => pusharyHookExecutable(hook.command) === null).map((hook) => ({
|
|
96
|
-
event,
|
|
97
|
-
command: hook.command,
|
|
98
|
-
timeoutSeconds: hook.timeoutSeconds,
|
|
99
|
-
position: runsBefore(hook.order, ours.order) ? "before" : "after"
|
|
100
|
-
}));
|
|
89
|
+
if (!hooks.some((hook) => pusharyHookExecutable(hook.command) !== null)) return [];
|
|
90
|
+
return hooks.filter((hook) => pusharyHookExecutable(hook.command) === null).map((hook) => ({ event, command: hook.command, timeoutSeconds: hook.timeoutSeconds }));
|
|
101
91
|
};
|
|
102
92
|
var otherHolders = (hooks, events, shape, unit) => {
|
|
103
93
|
const table = record(hooks);
|
|
@@ -112,11 +102,14 @@ var claudeOtherHolders = (settings) => otherHolders(record(settings)?.hooks, CLA
|
|
|
112
102
|
var codexOtherHolders = (hooks) => otherHolders(record(hooks)?.hooks, CODEX_GATE_EVENTS, "nested", "seconds");
|
|
113
103
|
var geminiOtherHolders = (settings) => otherHolders(record(settings)?.hooks, GEMINI_GATE_EVENTS, "nested", "milliseconds");
|
|
114
104
|
var cursorOtherHolders = (userHooks) => otherHolders(record(userHooks)?.hooks, CURSOR_GATE_EVENTS, "flat", "seconds");
|
|
115
|
-
var holdEvents = (table) => table.
|
|
105
|
+
var holdEvents = (table) => table.flatMap((hook) => {
|
|
106
|
+
const seconds = holdBudgetOf(hook);
|
|
107
|
+
return seconds === void 0 ? [] : [{ event: hook.event, seconds }];
|
|
108
|
+
});
|
|
116
109
|
var unprovenHolds = (hooks, events) => {
|
|
117
110
|
const table = record(hooks);
|
|
118
111
|
if (!table) return [];
|
|
119
|
-
return events.filter((event) => registeredHooks(table[event], "nested", "seconds").some((hook) => pusharyHookExecutable(hook.command) !== null && hookCommandHoldBudget(hook.command)
|
|
112
|
+
return events.filter(({ event, seconds }) => registeredHooks(table[event], "nested", "seconds").some((hook) => pusharyHookExecutable(hook.command) !== null && hookCommandHoldBudget(hook.command) !== seconds)).map(({ event }) => event);
|
|
120
113
|
};
|
|
121
114
|
var claudeUnprovenHolds = (settings) => unprovenHolds(record(settings)?.hooks, holdEvents(CLAUDE_HOOK_EVENTS));
|
|
122
115
|
var codexUnprovenHolds = (hooks) => unprovenHolds(record(hooks)?.hooks, holdEvents(CODEX_HOOK_EVENTS));
|
|
@@ -134,7 +127,7 @@ var describeHoldTimeout = (holder) => {
|
|
|
134
127
|
if (seconds >= 60 && seconds % 60 === 0) return `${seconds / 60}m timeout`;
|
|
135
128
|
return `${seconds}s timeout`;
|
|
136
129
|
};
|
|
137
|
-
var describeOtherHolder = (holder) => `another hook on ${holder.event}: ${holderExecutable(holder.command)} (${describeHoldTimeout(holder)}
|
|
130
|
+
var describeOtherHolder = (holder) => `another hook also registered on ${holder.event}: ${holderExecutable(holder.command)} (${describeHoldTimeout(holder)})`;
|
|
138
131
|
var describeHoldSentence = (agentLabel) => `${agentLabel} waits for every hook on an event, so the terminal cannot move until that one returns, however fast your phone answered.`;
|
|
139
132
|
|
|
140
133
|
export {
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from "./chunk-7QLSKOSU.js";
|
|
7
7
|
import {
|
|
8
8
|
isValidApiKey
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-OUAE3GKO.js";
|
|
10
10
|
|
|
11
11
|
// src/setup/options.ts
|
|
12
12
|
var AGENT_CHOICES = ["claude_code", "codex", "gemini_cli", "hermes", "cursor", "vscode", "opencode", "custom"];
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
2
|
detectClaudeVersion
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-K4XFCEVI.js";
|
|
4
4
|
import {
|
|
5
5
|
addClaudeMcpServer,
|
|
6
6
|
addPusharyHooks,
|
|
7
7
|
addPusharyToolPermissions
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-QS55LDX4.js";
|
|
9
9
|
import {
|
|
10
|
+
claudeUnprovenHolds,
|
|
10
11
|
claudeWired,
|
|
12
|
+
codexUnprovenHolds,
|
|
11
13
|
codexWired,
|
|
12
14
|
geminiWired
|
|
13
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-JXELRCU5.js";
|
|
14
16
|
import {
|
|
17
|
+
CLAUDE_HOOK_BINARY,
|
|
15
18
|
CLAUDE_HOOK_EVENTS,
|
|
16
19
|
GEMINI_HOOK_BINARY,
|
|
17
20
|
addGeminiHooks,
|
|
@@ -21,7 +24,7 @@ import {
|
|
|
21
24
|
needsReregistration,
|
|
22
25
|
registrationSignatures,
|
|
23
26
|
supportedClaudeEvents
|
|
24
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-PD6JY33P.js";
|
|
25
28
|
import {
|
|
26
29
|
CODEX_HOOK_BINARY,
|
|
27
30
|
addCodexHookTrust,
|
|
@@ -31,67 +34,48 @@ import {
|
|
|
31
34
|
codexConfigToml,
|
|
32
35
|
codexHookPositions,
|
|
33
36
|
codexHooksJson,
|
|
37
|
+
codexRegistrationHolder,
|
|
38
|
+
codexVacatedIndexes,
|
|
39
|
+
dropVacatedCodexHookTrust,
|
|
34
40
|
guardBinary,
|
|
35
41
|
hasCodexHooks,
|
|
36
|
-
|
|
42
|
+
namesOurBinary,
|
|
43
|
+
registeredCommands,
|
|
44
|
+
registrationHolderOf,
|
|
37
45
|
resolveGlobalBinary,
|
|
38
46
|
vscodePluginMcp
|
|
39
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-JBJBVERL.js";
|
|
40
48
|
import {
|
|
41
49
|
readJsonSafe,
|
|
50
|
+
writeFileAtomic,
|
|
42
51
|
writeJsonAtomic
|
|
43
|
-
} from "./chunk-
|
|
44
|
-
import {
|
|
45
|
-
HOOK_LOCATOR_BINARY
|
|
46
|
-
} from "./chunk-HUZW6SEO.js";
|
|
52
|
+
} from "./chunk-4LL6LG5X.js";
|
|
47
53
|
|
|
48
54
|
// src/reapply.ts
|
|
49
|
-
import { join } from "path";
|
|
55
|
+
import { dirname, join } from "path";
|
|
50
56
|
import { homedir } from "os";
|
|
51
|
-
import { readFileSync,
|
|
57
|
+
import { readFileSync, statSync } from "fs";
|
|
52
58
|
import { parse as parseTOML, stringify as stringifyTOML } from "smol-toml";
|
|
53
59
|
|
|
54
60
|
// src/reregister.ts
|
|
55
61
|
var asRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
56
|
-
var
|
|
57
|
-
|
|
58
|
-
if (!hooks) return [];
|
|
59
|
-
const found = [];
|
|
60
|
-
for (const [event, value] of Object.entries(hooks)) {
|
|
61
|
-
if (!Array.isArray(value)) continue;
|
|
62
|
-
for (const item of value) {
|
|
63
|
-
const inner = asRecord(item)?.hooks;
|
|
64
|
-
if (!Array.isArray(inner)) continue;
|
|
65
|
-
for (const hook of inner) {
|
|
66
|
-
const command = asRecord(hook)?.command;
|
|
67
|
-
if (typeof command === "string") found.push({ event, command });
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
return found;
|
|
72
|
-
};
|
|
73
|
-
var segments = (command) => command.split(/[\s/\\"']+/).map((segment) => segment.replace(/\.(cmd|exe)$/i, ""));
|
|
74
|
-
var CLI_BINARIES = new Set(CLAUDE_HOOK_EVENTS.map((hook) => hook.binary));
|
|
75
|
-
var namesLocator = (command) => segments(command).includes(HOOK_LOCATOR_BINARY);
|
|
76
|
-
var namesCliBinary = (command) => segments(command).some((segment) => CLI_BINARIES.has(segment));
|
|
77
|
-
var registrationHolder = (settings) => {
|
|
78
|
-
const commands = commandsUnder(settings);
|
|
79
|
-
if (commands.some(({ command }) => namesLocator(command))) return "app";
|
|
80
|
-
return commands.some(({ command }) => namesCliBinary(command)) ? "cli" : "none";
|
|
81
|
-
};
|
|
62
|
+
var CLAUDE_CLI_BINARIES = new Set(CLAUDE_HOOK_EVENTS.map((hook) => hook.binary));
|
|
63
|
+
var registrationHolder = (settings) => registrationHolderOf(settings, CLAUDE_CLI_BINARIES);
|
|
82
64
|
var registeredPusharyEvents = (settings) => new Set(
|
|
83
|
-
|
|
65
|
+
registeredCommands(settings).filter(({ command }) => namesOurBinary(command, CLAUDE_CLI_BINARIES)).map(({ event }) => event)
|
|
84
66
|
);
|
|
85
67
|
var reregisterVerdict = ({ settings, stored, version }) => {
|
|
86
68
|
const holder = registrationHolder(settings);
|
|
87
69
|
if (holder === "none") return { kind: "not_wired" };
|
|
88
70
|
if (holder === "app") return { kind: "app_owned" };
|
|
89
|
-
|
|
71
|
+
const unproven = claudeUnprovenHolds(settings);
|
|
72
|
+
if (unproven.length === 0 && !needsReregistration(stored, version)) return { kind: "current" };
|
|
90
73
|
const supported = new Set(supportedClaudeEvents(version).map((hook) => hook.event));
|
|
91
74
|
const present = registeredPusharyEvents(settings);
|
|
92
75
|
const missing = [...supported].filter((event) => !present.has(event));
|
|
93
76
|
const extra = [...present].filter((event) => !supported.has(event));
|
|
94
|
-
|
|
77
|
+
const repairable = unproven.filter((event) => supported.has(event));
|
|
78
|
+
return missing.length > 0 || extra.length > 0 || repairable.length > 0 ? { kind: "stale", version, missing, extra, unproven: repairable } : { kind: "record_only", version };
|
|
95
79
|
};
|
|
96
80
|
var receiptFor = (version, now = /* @__PURE__ */ new Date()) => ({
|
|
97
81
|
signatures: registrationSignatures(supportedClaudeEvents(version), version),
|
|
@@ -117,8 +101,17 @@ var readJson = (filePath) => {
|
|
|
117
101
|
return null;
|
|
118
102
|
};
|
|
119
103
|
var writeJson = (filePath, data) => writeJsonAtomic(filePath, data);
|
|
120
|
-
var hasPusharyClaudeHooks = (settings) => JSON.stringify(settings.hooks ?? {}).includes(
|
|
104
|
+
var hasPusharyClaudeHooks = (settings) => JSON.stringify(settings.hooks ?? {}).includes(CLAUDE_HOOK_BINARY);
|
|
121
105
|
var hasPusharyMcp = (claudeJson) => !!claudeJson.mcpServers?.pushary;
|
|
106
|
+
var PRIVATE_TO_OWNER = 384;
|
|
107
|
+
var modeToPreserve = (filePath) => {
|
|
108
|
+
try {
|
|
109
|
+
return statSync(filePath).mode & 511;
|
|
110
|
+
} catch {
|
|
111
|
+
return PRIVATE_TO_OWNER;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
var wouldWriteBareNames = (resolve, probe) => resolve(probe) === void 0;
|
|
122
115
|
var reapplyClaudeSettings = (apiKey, paths = {}) => {
|
|
123
116
|
const settingsPath = paths.settingsPath ?? CLAUDE_SETTINGS;
|
|
124
117
|
const claudeJsonPath = paths.claudeJsonPath ?? CLAUDE_JSON;
|
|
@@ -134,7 +127,8 @@ var reapplyClaudeSettings = (apiKey, paths = {}) => {
|
|
|
134
127
|
if (!settingsWritable) throw new Error("settings.json could not be parsed");
|
|
135
128
|
const s = settings;
|
|
136
129
|
addPusharyToolPermissions(s);
|
|
137
|
-
|
|
130
|
+
const binary = (paths.resolveBinary ?? resolveGlobalBinary)(CLAUDE_HOOK_BINARY);
|
|
131
|
+
addPusharyHooks(s, binary ? dirname(binary) : void 0, (paths.detectVersion ?? detectClaudeVersion)());
|
|
138
132
|
writeJson(settingsPath, s);
|
|
139
133
|
hooks = true;
|
|
140
134
|
} catch {
|
|
@@ -166,6 +160,10 @@ var reapplyClaudeForVersion = (apiKey, paths = {}) => {
|
|
|
166
160
|
if (verdict.kind === "not_wired" || verdict.kind === "app_owned" || verdict.kind === "current") {
|
|
167
161
|
return { verdict: verdict.kind, rewrote: false, missing: [] };
|
|
168
162
|
}
|
|
163
|
+
const resolveBinary = paths.resolveBinary ?? resolveGlobalBinary;
|
|
164
|
+
if (verdict.kind === "stale" && wouldWriteBareNames(resolveBinary, CLAUDE_HOOK_BINARY)) {
|
|
165
|
+
return { verdict: "stale", rewrote: false, missing: verdict.missing };
|
|
166
|
+
}
|
|
169
167
|
const rewrote = verdict.kind === "stale" ? reapplyClaudeSettings(apiKey, { ...paths, settingsPath }).hooks : false;
|
|
170
168
|
if (verdict.kind === "stale" && !rewrote) return { verdict: "stale", rewrote: false, missing: verdict.missing };
|
|
171
169
|
writeJsonAtomic(receiptPath, receiptFor(version));
|
|
@@ -211,9 +209,10 @@ var reapplyCodexSettings = (apiKey, paths = {}) => {
|
|
|
211
209
|
const hooksConfig = readJson(hooksPath);
|
|
212
210
|
const configured = config != null && !!config.mcp_servers?.pushary || hooksConfig != null && hasCodexHooks(hooksConfig);
|
|
213
211
|
if (!configured) return { configured: false, reapplied: false, hooks: false, mcp: false };
|
|
214
|
-
const command = guardBinary(resolveGlobalBinary(CODEX_HOOK_BINARY) ?? CODEX_HOOK_BINARY);
|
|
212
|
+
const command = guardBinary((paths.resolveBinary ?? resolveGlobalBinary)(CODEX_HOOK_BINARY) ?? CODEX_HOOK_BINARY);
|
|
215
213
|
let hooks = false;
|
|
216
214
|
let mcp = false;
|
|
215
|
+
const vacated = codexVacatedIndexes(hooksConfig ?? void 0);
|
|
217
216
|
if (hooksConfig != null) {
|
|
218
217
|
try {
|
|
219
218
|
addCodexHooks(hooksConfig, command);
|
|
@@ -224,17 +223,35 @@ var reapplyCodexSettings = (apiKey, paths = {}) => {
|
|
|
224
223
|
}
|
|
225
224
|
if (config != null) {
|
|
226
225
|
try {
|
|
227
|
-
if (hooks)
|
|
226
|
+
if (hooks) {
|
|
227
|
+
dropVacatedCodexHookTrust(config, hooksPath, vacated);
|
|
228
|
+
addCodexHookTrust(config, hooksPath, command, codexHookPositions(hooksConfig ?? void 0));
|
|
229
|
+
}
|
|
228
230
|
if (apiKey) {
|
|
229
231
|
addCodexMcpServer(config, apiKey);
|
|
230
232
|
mcp = true;
|
|
231
233
|
}
|
|
232
|
-
if (hooks || apiKey)
|
|
234
|
+
if (hooks || apiKey) {
|
|
235
|
+
writeFileAtomic(configPath, stringifyTOML(config), modeToPreserve(configPath), "utf-8");
|
|
236
|
+
}
|
|
233
237
|
} catch {
|
|
234
238
|
}
|
|
235
239
|
}
|
|
236
240
|
return { configured: true, reapplied: hooks || mcp, hooks, mcp };
|
|
237
241
|
};
|
|
242
|
+
var repairCodexHolds = (paths = {}) => {
|
|
243
|
+
const idle = { configured: false, reapplied: false, hooks: false, mcp: false };
|
|
244
|
+
try {
|
|
245
|
+
const hooksPath = paths.hooksPath ?? codexHooksJson();
|
|
246
|
+
const hooksConfig = readJson(hooksPath);
|
|
247
|
+
if (!hooksConfig || codexRegistrationHolder(hooksConfig) !== "cli") return idle;
|
|
248
|
+
if (codexUnprovenHolds(hooksConfig).length === 0) return idle;
|
|
249
|
+
if (wouldWriteBareNames(paths.resolveBinary ?? resolveGlobalBinary, CODEX_HOOK_BINARY)) return idle;
|
|
250
|
+
return reapplyCodexSettings(void 0, paths);
|
|
251
|
+
} catch {
|
|
252
|
+
return idle;
|
|
253
|
+
}
|
|
254
|
+
};
|
|
238
255
|
var reapplyGeminiSettings = (apiKey, paths = {}) => {
|
|
239
256
|
const settingsPath = paths.settingsPath ?? join(homedir(), ".gemini", "settings.json");
|
|
240
257
|
const settings = readJson(settingsPath);
|
|
@@ -294,7 +311,13 @@ var reapplyAllAgents = (apiKey) => {
|
|
|
294
311
|
};
|
|
295
312
|
|
|
296
313
|
export {
|
|
314
|
+
reapplyClaudeSettings,
|
|
297
315
|
reapplyClaudeForVersion,
|
|
298
316
|
inspectConfiguredManagedProviders,
|
|
317
|
+
reapplyCodexSettings,
|
|
318
|
+
repairCodexHolds,
|
|
319
|
+
reapplyGeminiSettings,
|
|
320
|
+
reapplyCursorPlugin,
|
|
321
|
+
reapplyVsCodePlugin,
|
|
299
322
|
reapplyAllAgents
|
|
300
323
|
};
|
|
@@ -3,19 +3,19 @@ import {
|
|
|
3
3
|
loadPin,
|
|
4
4
|
savePin,
|
|
5
5
|
verifyRecipients
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-YKLCWWEI.js";
|
|
7
7
|
import {
|
|
8
8
|
hookOwnerOf
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-RALVI7OF.js";
|
|
10
10
|
import {
|
|
11
11
|
ensureDaemonRunning
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-CRFLU455.js";
|
|
13
13
|
import {
|
|
14
14
|
buildTranscriptRecords,
|
|
15
15
|
decodePublicKey,
|
|
16
16
|
generateSessionKey,
|
|
17
17
|
wrapSessionKey
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-XPPXOKIG.js";
|
|
19
19
|
import {
|
|
20
20
|
fetchTranscriptRecipients,
|
|
21
21
|
uploadTranscriptRecords
|
|
@@ -23,17 +23,17 @@ import {
|
|
|
23
23
|
import {
|
|
24
24
|
transcriptEnvironmentPreference,
|
|
25
25
|
transcriptsEnabled
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-ID5FDKDZ.js";
|
|
27
27
|
import {
|
|
28
28
|
codexHome,
|
|
29
29
|
pusharyDir
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-JBJBVERL.js";
|
|
31
31
|
import {
|
|
32
32
|
readTranscriptPreference
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-4PBCNVI3.js";
|
|
34
34
|
import {
|
|
35
35
|
writeJsonAtomic
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-4LL6LG5X.js";
|
|
37
37
|
import {
|
|
38
38
|
getApiKey,
|
|
39
39
|
getBaseUrl
|
|
@@ -1397,8 +1397,8 @@ var claudePermissionDeniedOutput = (decision) => ({
|
|
|
1397
1397
|
}
|
|
1398
1398
|
});
|
|
1399
1399
|
var CODEX_RESCUE_COMMAND_MAX_LENGTH = 2e3;
|
|
1400
|
-
var CODEX_RESCUE_APPROVED = "
|
|
1401
|
-
var codexRescueRetryInstruction = (command) => command.length <= CODEX_RESCUE_COMMAND_MAX_LENGTH ? `Run it again exactly as before
|
|
1400
|
+
var CODEX_RESCUE_APPROVED = "I approved this command in Pushary after the auto-reviewer denied it. If it is denied again, stop and tell me.";
|
|
1401
|
+
var codexRescueRetryInstruction = (command) => command.length <= CODEX_RESCUE_COMMAND_MAX_LENGTH ? `Run it again now, exactly as before: ${command}` : `Run it again now, exactly as before. It is too long to repeat in full here and begins: ${command.slice(0, CODEX_RESCUE_COMMAND_MAX_LENGTH)}`;
|
|
1402
1402
|
var codexStopRescueOutput = (decision, command) => decision === "allow" ? { decision: "block", reason: `${CODEX_RESCUE_APPROVED} ${codexRescueRetryInstruction(command)}` } : { continue: true };
|
|
1403
1403
|
var stoppedOutput = (output, stopReason) => ({ ...output, continue: false, stopReason });
|
|
1404
1404
|
var claudePreToolUseOutput = (decision, reason, updatedInput) => ({
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
NOTIFICATION_MATCHED_TYPES,
|
|
3
3
|
POSTTOOLUSE_MIRRORED_TOOLS
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-OPR2BPD4.js";
|
|
5
5
|
import {
|
|
6
|
-
isProtectedByScope
|
|
7
|
-
|
|
6
|
+
isProtectedByScope,
|
|
7
|
+
registerHookEntry
|
|
8
|
+
} from "./chunk-JBJBVERL.js";
|
|
8
9
|
import {
|
|
9
10
|
CLAUDE_PRETOOLUSE_MATCHER,
|
|
10
11
|
HOOK_BUDGETS,
|
|
11
12
|
HOOK_LOCATOR_BINARY
|
|
12
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-OUAE3GKO.js";
|
|
13
14
|
|
|
14
15
|
// src/gemini-config.ts
|
|
15
16
|
var GEMINI_HOOK_BINARY = "pushary-gemini-hook";
|
|
@@ -51,8 +52,7 @@ var addGeminiHooks = (settings, command) => {
|
|
|
51
52
|
const hooks = ensureRecord(settings, "hooks");
|
|
52
53
|
for (const definition of GEMINI_HOOK_EVENTS) {
|
|
53
54
|
const existing = Array.isArray(hooks[definition.event]) ? hooks[definition.event] : [];
|
|
54
|
-
|
|
55
|
-
entries.push({
|
|
55
|
+
hooks[definition.event] = registerHookEntry(existing, isPusharyGeminiHook, {
|
|
56
56
|
...definition.matcher ? { matcher: definition.matcher } : {},
|
|
57
57
|
hooks: [{
|
|
58
58
|
name: "pushary",
|
|
@@ -61,7 +61,6 @@ var addGeminiHooks = (settings, command) => {
|
|
|
61
61
|
timeout: definition.timeoutMs
|
|
62
62
|
}]
|
|
63
63
|
});
|
|
64
|
-
hooks[definition.event] = entries;
|
|
65
64
|
}
|
|
66
65
|
};
|
|
67
66
|
var removeGeminiHooks = (settings, scope) => {
|
|
@@ -130,8 +129,9 @@ var formatVersion = (version) => version.join(".");
|
|
|
130
129
|
var MIRRORED_TOOLS = POSTTOOLUSE_MIRRORED_TOOLS.join("|");
|
|
131
130
|
var ESTABLISHED = [1, 0, 0];
|
|
132
131
|
var OBSERVED = [2, 0, 0];
|
|
132
|
+
var CLAUDE_HOOK_BINARY = "pushary-hook";
|
|
133
133
|
var CLAUDE_HOOK_EVENTS = [
|
|
134
|
-
{ event: "PreToolUse", binary:
|
|
134
|
+
{ event: "PreToolUse", binary: CLAUDE_HOOK_BINARY, matcher: CLAUDE_PRETOOLUSE_MATCHER, timeout: HOOK_BUDGETS.claude.budgetSeconds, delivery: "approval", since: ESTABLISHED },
|
|
135
135
|
{ event: "PostToolUse", binary: "pushary-post-hook", matcher: MIRRORED_TOOLS, timeout: 10, delivery: "telemetry", since: ESTABLISHED },
|
|
136
136
|
{ event: "Stop", binary: "pushary-stop-hook", timeout: 10, delivery: "telemetry", since: ESTABLISHED },
|
|
137
137
|
{ event: "UserPromptSubmit", binary: "pushary-prompt-hook", timeout: 10, delivery: "telemetry", since: ESTABLISHED },
|
|
@@ -176,6 +176,7 @@ export {
|
|
|
176
176
|
parseVersion,
|
|
177
177
|
compareVersion,
|
|
178
178
|
formatVersion,
|
|
179
|
+
CLAUDE_HOOK_BINARY,
|
|
179
180
|
CLAUDE_HOOK_EVENTS,
|
|
180
181
|
supportedClaudeEvents,
|
|
181
182
|
registrationSignatures,
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CLAUDE_HOOK_EVENTS,
|
|
3
3
|
supportedClaudeEvents
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-PD6JY33P.js";
|
|
5
5
|
import {
|
|
6
6
|
guardBinary,
|
|
7
7
|
holdBudgetOf,
|
|
8
|
-
isProtectedByScope
|
|
9
|
-
|
|
8
|
+
isProtectedByScope,
|
|
9
|
+
registerHookEntry
|
|
10
|
+
} from "./chunk-JBJBVERL.js";
|
|
10
11
|
import {
|
|
11
12
|
HOOK_LOCATOR_BINARY,
|
|
12
13
|
withHookHoldBudget
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-OUAE3GKO.js";
|
|
14
15
|
|
|
15
16
|
// src/claude-config.ts
|
|
16
17
|
import { join } from "path";
|
|
@@ -126,12 +127,14 @@ var addPusharyHooks = (settings, binDir, version = null) => {
|
|
|
126
127
|
const hooks = ensureRecord(settings, "hooks");
|
|
127
128
|
const supported = new Map(supportedClaudeEvents(version).map((hook) => [hook.event, hook]));
|
|
128
129
|
for (const known of CLAUDE_HOOK_EVENTS) {
|
|
129
|
-
const current = hooks[known.event];
|
|
130
|
-
const others = (Array.isArray(current) ? current : []).filter((item) => !isPusharyHook(item));
|
|
130
|
+
const current = Array.isArray(hooks[known.event]) ? hooks[known.event] : [];
|
|
131
131
|
const definition = supported.get(known.event);
|
|
132
132
|
if (definition) {
|
|
133
|
-
hooks[known.event] =
|
|
134
|
-
|
|
133
|
+
hooks[known.event] = registerHookEntry(current, isPusharyHook, entry(definition, resolve));
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const others = current.filter((item) => !isPusharyHook(item));
|
|
137
|
+
if (others.length > 0) {
|
|
135
138
|
hooks[known.event] = others;
|
|
136
139
|
} else {
|
|
137
140
|
delete hooks[known.event];
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AGENT_CHOICES
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-LBNAGGLV.js";
|
|
4
4
|
import {
|
|
5
5
|
isBridgeLocator
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-IRLTW6KF.js";
|
|
7
7
|
import {
|
|
8
8
|
pusharyHookExecutable
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-JXELRCU5.js";
|
|
10
10
|
import {
|
|
11
11
|
BELL_HOOK_BINARY
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-EXHXR2X5.js";
|
|
13
13
|
|
|
14
14
|
// src/setup/hook-ownership.ts
|
|
15
15
|
var commandsIn = (value) => {
|
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
forgetBlockedActionHint,
|
|
5
5
|
hasBlockedActionHint,
|
|
6
6
|
recordBlockedActionHint
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-6KLCP7VF.js";
|
|
8
8
|
import {
|
|
9
9
|
isGatingMoment,
|
|
10
10
|
recordKeylessMoment
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-XOOWC62T.js";
|
|
12
12
|
import {
|
|
13
13
|
denyReasonFrom,
|
|
14
14
|
isDeferAnswer
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
reportEvent,
|
|
25
25
|
settleQuestionsForToolUse,
|
|
26
26
|
throttlePass
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-64WARXGV.js";
|
|
28
28
|
import {
|
|
29
29
|
UNNAMED_ACTION,
|
|
30
30
|
deriveAction,
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
describeToolCall,
|
|
35
35
|
permissionDeniedAction,
|
|
36
36
|
scopePathFor
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-A76GNRIK.js";
|
|
38
38
|
import {
|
|
39
39
|
DECISION_STOP_REASON,
|
|
40
40
|
askUser,
|
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
} from "./chunk-LGXUGYUH.js";
|
|
50
50
|
import {
|
|
51
51
|
getMachineId
|
|
52
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-562UJ2DA.js";
|
|
53
53
|
import {
|
|
54
54
|
getApiKey,
|
|
55
55
|
getBaseUrl
|
|
@@ -73,7 +73,7 @@ import {
|
|
|
73
73
|
parseAgentQuestions,
|
|
74
74
|
resolveGate,
|
|
75
75
|
stoppedOutput
|
|
76
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-OUAE3GKO.js";
|
|
77
77
|
|
|
78
78
|
// src/decision-episode.ts
|
|
79
79
|
var EPISODE_PATH = "/api/agent/decision-episode";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
openCodeConfigDirFrom
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-HB2KB7QL.js";
|
|
4
4
|
import {
|
|
5
5
|
codexHomeFrom
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-JBJBVERL.js";
|
|
7
7
|
|
|
8
8
|
// src/vscode-config.ts
|
|
9
9
|
import { homedir } from "os";
|
|
@@ -264,7 +264,7 @@ You have Pushary MCP tools that reach the user on their phone. Use them proactiv
|
|
|
264
264
|
|
|
265
265
|
- When you need the user to make a decision or answer a clarifying question, call \`ask_user\` instead of guessing or stalling. Use type "confirm" for yes/no, "select" for a fixed set of options, and "input" for free text. Read \`answered\`, \`status\` and the returned handoff instead of assuming the tool blocked. Silence is not consent; choice/text answers do not authorize a separate action.
|
|
266
266
|
- Ask once, on one channel. If you also have a built-in way to prompt the user, use that or \`ask_user\` for a given question, never both. \`ask_user\` is the one that reaches the user when they are away from this machine, so prefer it. Raising both strands the user in whichever prompt you are not waiting on.
|
|
267
|
-
- Honor authorization already granted in this session. Ask before a risky or irreversible action outside that authorization, or when an enforced host policy requires it. Do not ask again for an already authorized step, and never bypass an enforced gate.
|
|
267
|
+
- Honor authorization already granted in this session. Ask before a risky or irreversible action outside that authorization, or when an enforced host policy requires it. Do not ask again for an already authorized step, and never bypass an enforced gate. When a Pushary hook result says the user approved a specific command after a denial, rerunning that exact command is the approved path and not a bypass of that gate.
|
|
268
268
|
- Call \`propose_scope\` only for an unresolved or requested file boundary. A ratified scope narrows what may proceed; it does not bypass other approval rules. Do not add a plan approval merely because work spans several files, and do not propose a new scope mid-run just to widen it. Let the installed gate request any scope expansion before the edit executes.
|
|
269
269
|
- When you are blocked, stuck, or hit an error you cannot resolve on your own, call \`send_notification\` so the user knows, and call \`ask_user\` if you need a decision to continue.
|
|
270
270
|
- When meaningful work finishes while the user is away, or they requested an alert, call \`send_notification\` so the user knows it is done. Skip trivial completions and duplicate reports to someone already reading. Always pass \`context\` with a \`type\` of "task_complete", "error" or "info": it is what tells Pushary this is a task update, so the user's own setting for where updates land can route it.
|
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
resolveBinary,
|
|
3
3
|
resolveGlobalPackageVersion,
|
|
4
4
|
resolvePackageVersionFromBinary
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-JBJBVERL.js";
|
|
6
6
|
import {
|
|
7
7
|
MANAGED_PROVIDERS
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-OUAE3GKO.js";
|
|
9
9
|
|
|
10
10
|
// src/live-capabilities.ts
|
|
11
11
|
var CLAUDE_BRIDGE_CAPABILITY = "claude-bridge";
|