@pushary/agent-hooks 1.9.6 → 1.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +3 -3
  3. package/data/cursor-plugin/README.md +3 -7
  4. package/data/vscode-plugin/README.md +1 -1
  5. package/dist/bin/pushary-bell-hook.js +22 -23
  6. package/dist/bin/pushary-bell.js +9 -9
  7. package/dist/bin/pushary-claude.js +27 -28
  8. package/dist/bin/pushary-clean.js +98 -76
  9. package/dist/bin/pushary-codex-bridge.js +18 -18
  10. package/dist/bin/pushary-codex-hook.js +32 -33
  11. package/dist/bin/pushary-codex.js +13 -13
  12. package/dist/bin/pushary-connect.js +24 -21
  13. package/dist/bin/pushary-cowork.js +5 -5
  14. package/dist/bin/pushary-daemon.js +51 -38
  15. package/dist/bin/pushary-disconnect.js +187 -52
  16. package/dist/bin/pushary-doctor.js +68 -56
  17. package/dist/bin/pushary-elicitation-hook.js +24 -25
  18. package/dist/bin/pushary-gemini-bridge.js +13 -13
  19. package/dist/bin/pushary-gemini-hook.js +29 -30
  20. package/dist/bin/pushary-hook.js +30 -32
  21. package/dist/bin/pushary-login.js +12 -12
  22. package/dist/bin/pushary-logout.js +105 -42
  23. package/dist/bin/pushary-mcp.js +9 -9
  24. package/dist/bin/pushary-mode.js +28 -31
  25. package/dist/bin/pushary-notification-hook.js +26 -28
  26. package/dist/bin/pushary-opencode-hook.js +28 -29
  27. package/dist/bin/pushary-permission-denied-hook.js +30 -32
  28. package/dist/bin/pushary-permission-hook.js +29 -31
  29. package/dist/bin/pushary-post-hook.js +26 -28
  30. package/dist/bin/pushary-prompt-hook.js +26 -28
  31. package/dist/bin/pushary-session-end-hook.js +26 -28
  32. package/dist/bin/pushary-session-start-hook.js +31 -31
  33. package/dist/bin/pushary-setup.js +98 -106
  34. package/dist/bin/pushary-stats.js +5 -5
  35. package/dist/bin/pushary-status.js +34 -18
  36. package/dist/bin/pushary-stop-hook.js +26 -28
  37. package/dist/bin/pushary-stopfailure-hook.js +26 -28
  38. package/dist/bin/pushary-suggestions.js +19 -21
  39. package/dist/bin/pushary-transcript-register.js +18 -19
  40. package/dist/bin/pushary-transcripts.js +7 -7
  41. package/dist/bin/pushary-upgrade.js +67 -31
  42. package/dist/bin/pushary-wait.js +23 -19
  43. package/dist/bin/pushary.js +15 -14
  44. package/dist/{chunk-BSZ7VBVT.js → chunk-2A53H4S6.js} +17 -15
  45. package/dist/{chunk-D7SOOVHX.js → chunk-2QGYMY7A.js} +83 -3
  46. package/dist/{chunk-SVTHEMM3.js → chunk-2QTO5YIT.js} +6 -6
  47. package/dist/{chunk-WN6WYUCV.js → chunk-2VZAALEJ.js} +5 -9
  48. package/dist/chunk-2WXF3QJR.js +49 -0
  49. package/dist/{chunk-UKNKYTTY.js → chunk-3I6IVOZV.js} +3 -3
  50. package/dist/chunk-3Z3A37WD.js +77 -0
  51. package/dist/{chunk-2QRE6QH2.js → chunk-5QUPKDI5.js} +1 -1
  52. package/dist/chunk-6TE27XZR.js +69 -0
  53. package/dist/{chunk-L6USMDTW.js → chunk-7DVNSQWF.js} +59 -15
  54. package/dist/{chunk-SNJ3BOCP.js → chunk-7PT35RY2.js} +27 -8
  55. package/dist/{chunk-CBVDW2N6.js → chunk-B64KHETR.js} +3 -3
  56. package/dist/chunk-BEJRK4DF.js +94 -0
  57. package/dist/chunk-BXET3ALR.js +46 -0
  58. package/dist/{chunk-DJ4BB264.js → chunk-CD47ZFFZ.js} +1 -1
  59. package/dist/{chunk-FBD3QGVJ.js → chunk-CKV3UPMU.js} +2 -2
  60. package/dist/{chunk-7JTVYR5B.js → chunk-CLOSJ4ES.js} +1 -1
  61. package/dist/{chunk-DA4FTGTK.js → chunk-DKMD6AWR.js} +4 -4
  62. package/dist/{chunk-SPXBXN23.js → chunk-DL7XWKYV.js} +7 -5
  63. package/dist/{chunk-VRT3EEZN.js → chunk-DPGSLWOS.js} +8 -8
  64. package/dist/{chunk-3BUAEQCY.js → chunk-DUZVXBBU.js} +1 -1
  65. package/dist/{chunk-6GERGJHF.js → chunk-EUW7JL2K.js} +0 -32
  66. package/dist/{chunk-75CA37FZ.js → chunk-FQ2GORVG.js} +2 -2
  67. package/dist/{chunk-WUKUXICK.js → chunk-HRULIYDU.js} +2 -2
  68. package/dist/{chunk-Q4E56K4X.js → chunk-I5IJRMNV.js} +78 -8
  69. package/dist/{chunk-MKJ3RTUS.js → chunk-I6MJXLMY.js} +2 -2
  70. package/dist/{chunk-YPXUD6DW.js → chunk-IAD2RT4L.js} +14 -14
  71. package/dist/{chunk-LBLCFD5K.js → chunk-IHFDPV7C.js} +2 -2
  72. package/dist/{chunk-BVCHY4OY.js → chunk-IHO3YQAN.js} +2 -2
  73. package/dist/{chunk-RDK7FX5F.js → chunk-KF3UZLYI.js} +1 -1
  74. package/dist/chunk-KFF7G225.js +599 -0
  75. package/dist/{chunk-TE5M6GGK.js → chunk-KHNFLYJO.js} +204 -28
  76. package/dist/{chunk-CCDVL63C.js → chunk-KRCR2CRQ.js} +9 -9
  77. package/dist/{chunk-ZC3TF4LR.js → chunk-LKLVTG3V.js} +18 -9
  78. package/dist/{chunk-4QKM44N6.js → chunk-LWOO567I.js} +4 -3
  79. package/dist/{chunk-KK54WQ74.js → chunk-M6BZZFVQ.js} +1 -1
  80. package/dist/{chunk-RIC6OOJX.js → chunk-MFF3ONG5.js} +21 -1
  81. package/dist/{chunk-IMGJYFCX.js → chunk-MGRFDGWU.js} +3 -2
  82. package/dist/{chunk-ZPW4MJOV.js → chunk-MKTJEXZ3.js} +3 -3
  83. package/dist/{chunk-2I23NFVT.js → chunk-MXHTGVFZ.js} +52 -9
  84. package/dist/{chunk-5BHROGRB.js → chunk-N4QSPI3B.js} +54 -5
  85. package/dist/{chunk-DGQTJDSJ.js → chunk-NWDG3MSW.js} +1 -1
  86. package/dist/chunk-OP7IHC2I.js +24 -0
  87. package/dist/{chunk-EVFY3VE6.js → chunk-QOLITCIP.js} +1 -1
  88. package/dist/{chunk-W4Q7NFXU.js → chunk-TCQ43LSG.js} +3 -3
  89. package/dist/chunk-TCWKTUAE.js +50 -0
  90. package/dist/{chunk-EZAFBC2C.js → chunk-V5HPPF3E.js} +8 -4
  91. package/dist/{chunk-Q23MMVTD.js → chunk-WG3K4TCH.js} +1 -1
  92. package/dist/{chunk-F56SB65Y.js → chunk-WS4H76EP.js} +2 -2
  93. package/dist/{chunk-HWQNQVY6.js → chunk-WWOHTTVP.js} +2 -2
  94. package/dist/{chunk-NVGDMTX3.js → chunk-YIG2R3BJ.js} +9 -7
  95. package/dist/{chunk-HJXZJF6O.js → chunk-ZBHUHJG6.js} +4 -4
  96. package/dist/{chunk-5AXCOTIT.js → chunk-ZBK6E2OR.js} +1 -1
  97. package/dist/{chunk-5PMTC2CB.js → chunk-ZN3C6GBG.js} +84 -673
  98. package/dist/{chunk-GQHZIBAZ.js → chunk-ZSTSEBG7.js} +1 -1
  99. package/dist/{chunk-PYZC54KA.js → chunk-ZW3XZLJC.js} +61 -17
  100. package/dist/{global-upgrade-7F5RP45B.js → global-upgrade-I56HNM23.js} +6 -6
  101. package/dist/{paths-MELXIVBO.js → paths-AGY43CXS.js} +2 -2
  102. package/dist/reapply-IA5XUKWW.js +57 -0
  103. package/dist/src/index.d.ts +1 -0
  104. package/dist/src/index.js +19 -20
  105. package/dist/{upgrade-lock-AHRBA66K.js → upgrade-lock-B34TAUKV.js} +5 -3
  106. package/package.json +1 -1
  107. package/dist/chunk-HT3WMM6Q.js +0 -44
  108. package/dist/chunk-IR5FRUPQ.js +0 -197
  109. package/dist/chunk-JUFKJCZG.js +0 -38
  110. package/dist/chunk-SJN22ADZ.js +0 -86
  111. package/dist/reapply-NOB2Q6C4.js +0 -35
@@ -1,34 +1,200 @@
1
- import {
2
- addClaudeMcpServer,
3
- addPusharyToolPermissions,
4
- isPusharyHook,
5
- removeClaudeMcpServers
6
- } from "./chunk-IR5FRUPQ.js";
7
1
  import {
8
2
  CLAUDE_HOOK_EVENTS,
9
3
  addGeminiMcpServer,
10
- removeGeminiMcpServer
11
- } from "./chunk-UKNKYTTY.js";
4
+ removeGeminiMcpServer,
5
+ supportedClaudeEvents
6
+ } from "./chunk-3I6IVOZV.js";
12
7
  import {
13
8
  CLAUDE_CODE_AGENT,
14
9
  parseApplyPatchFiles
15
- } from "./chunk-CCDVL63C.js";
10
+ } from "./chunk-KRCR2CRQ.js";
16
11
  import {
17
12
  guardBinary,
18
13
  holdBudgetOf,
14
+ isProtectedByScope,
19
15
  registerHookEntry
20
- } from "./chunk-HJXZJF6O.js";
16
+ } from "./chunk-ZBHUHJG6.js";
21
17
  import {
18
+ HOOK_LOCATOR_BINARY,
22
19
  PHONE_ANSWERED_TOOLS,
23
20
  hookCompatibleProfile,
24
21
  hookCompatibleProfileBySource,
25
22
  toToolLookup,
26
23
  withHookHoldBudget
27
- } from "./chunk-Q4E56K4X.js";
24
+ } from "./chunk-I5IJRMNV.js";
25
+
26
+ // src/claude-config.ts
27
+ import { join } from "path";
28
+ import { isDeepStrictEqual } from "util";
29
+ var PUSHARY_MCP_URL = "https://pushary.com/api/mcp/mcp";
30
+ var PUSHARY_PERMISSION_RULE = "mcp__pushary__*";
31
+ var asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
32
+ var ensureRecord = (target, key) => {
33
+ const existing = asRecord(target[key]);
34
+ if (existing) return existing;
35
+ const created = {};
36
+ target[key] = created;
37
+ return created;
38
+ };
39
+ var isPusharyPermission = (rule) => typeof rule === "string" && (rule.includes("pushary") || rule.includes("MCP(pushary"));
40
+ var HOOK_BINARIES = /* @__PURE__ */ new Set([
41
+ ...CLAUDE_HOOK_EVENTS.map((hook) => hook.binary),
42
+ HOOK_LOCATOR_BINARY
43
+ ]);
44
+ var namesPusharyBinary = (command) => command.split(/[\s/\\"']+/).some((segment) => HOOK_BINARIES.has(segment.replace(/\.(cmd|exe)$/i, "")));
45
+ var isPusharyHook = (entry2, scope) => {
46
+ const hooks = asRecord(entry2)?.hooks;
47
+ if (!Array.isArray(hooks)) return false;
48
+ return hooks.some((hook) => {
49
+ const command = String(asRecord(hook)?.command ?? "");
50
+ if (isProtectedByScope(command, scope)) return false;
51
+ return namesPusharyBinary(command);
52
+ });
53
+ };
54
+ var pusharyMcpServer = (apiKey) => ({
55
+ type: "http",
56
+ url: PUSHARY_MCP_URL,
57
+ headers: { Authorization: `Bearer ${apiKey}` }
58
+ });
59
+ var addClaudeMcpServer = (config, apiKey) => {
60
+ const mcpServers = ensureRecord(config, "mcpServers");
61
+ mcpServers.pushary = pusharyMcpServer(apiKey);
62
+ };
63
+ var isClaudeMcpSnapshot = (value) => {
64
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
65
+ const snapshot = value;
66
+ return typeof snapshot.hadMcpServers === "boolean" && typeof snapshot.mcpServersWasRecord === "boolean" && (!snapshot.hadMcpServers || snapshot.mcpServersWasRecord || Object.hasOwn(snapshot, "mcpServers")) && typeof snapshot.hadPushary === "boolean" && (!snapshot.hadPushary || Object.hasOwn(snapshot, "pushary")) && (!Object.hasOwn(snapshot, "installedPushary") || asRecord(snapshot.installedPushary)?.type === "http" && asRecord(snapshot.installedPushary)?.url === PUSHARY_MCP_URL);
67
+ };
68
+ var captureClaudeMcpServer = (config, apiKey) => {
69
+ const mcpServers = asRecord(config.mcpServers);
70
+ const hadMcpServers = Object.hasOwn(config, "mcpServers");
71
+ return {
72
+ hadMcpServers,
73
+ mcpServersWasRecord: Boolean(mcpServers),
74
+ ...hadMcpServers && !mcpServers ? { mcpServers: structuredClone(config.mcpServers) } : {},
75
+ hadPushary: Boolean(mcpServers && Object.hasOwn(mcpServers, "pushary")),
76
+ ...mcpServers && Object.hasOwn(mcpServers, "pushary") ? { pushary: structuredClone(mcpServers.pushary) } : {},
77
+ ...apiKey ? { installedPushary: pusharyMcpServer(apiKey) } : {}
78
+ };
79
+ };
80
+ var updateClaudeMcpSnapshot = (snapshot, apiKey) => ({
81
+ ...snapshot,
82
+ installedPushary: pusharyMcpServer(apiKey)
83
+ });
84
+ var restoreClaudeMcpServer = (config, snapshot) => {
85
+ const mcpServers = asRecord(config.mcpServers);
86
+ const current = asRecord(mcpServers?.pushary);
87
+ if (Object.hasOwn(snapshot, "installedPushary")) {
88
+ if (!isDeepStrictEqual(mcpServers?.pushary, snapshot.installedPushary)) return false;
89
+ } else if (current?.type !== "http" || current.url !== PUSHARY_MCP_URL) {
90
+ return false;
91
+ }
92
+ if (!snapshot.mcpServersWasRecord) {
93
+ if (Object.keys(mcpServers).length === 1) {
94
+ if (snapshot.hadMcpServers) config.mcpServers = structuredClone(snapshot.mcpServers);
95
+ else delete config.mcpServers;
96
+ } else {
97
+ delete mcpServers.pushary;
98
+ }
99
+ } else if (snapshot.hadPushary) {
100
+ mcpServers.pushary = structuredClone(snapshot.pushary);
101
+ } else {
102
+ delete mcpServers.pushary;
103
+ if (!snapshot.hadMcpServers && Object.keys(mcpServers).length === 0) delete config.mcpServers;
104
+ }
105
+ return true;
106
+ };
107
+ var removeClaudeMcpServers = (config) => {
108
+ let changed = false;
109
+ const removeFrom = (target) => {
110
+ const mcpServers = asRecord(target.mcpServers);
111
+ if (!mcpServers?.pushary) return;
112
+ delete mcpServers.pushary;
113
+ if (Object.keys(mcpServers).length === 0) delete target.mcpServers;
114
+ changed = true;
115
+ };
116
+ removeFrom(config);
117
+ const projects = asRecord(config.projects);
118
+ if (projects) {
119
+ for (const project of Object.values(projects)) {
120
+ const projectConfig = asRecord(project);
121
+ if (projectConfig) removeFrom(projectConfig);
122
+ }
123
+ }
124
+ return changed;
125
+ };
126
+ var removePusharyToolPermissions = (settings) => {
127
+ const permissions = asRecord(settings.permissions);
128
+ if (!permissions || !Array.isArray(permissions.allow)) return false;
129
+ const filtered = permissions.allow.filter((rule) => !isPusharyPermission(rule));
130
+ if (filtered.length === permissions.allow.length) return false;
131
+ if (filtered.length === 0) delete permissions.allow;
132
+ else permissions.allow = filtered;
133
+ if (Object.keys(permissions).length === 0) delete settings.permissions;
134
+ return true;
135
+ };
136
+ var addPusharyToolPermissions = (settings) => {
137
+ const permissions = ensureRecord(settings, "permissions");
138
+ const allow = Array.isArray(permissions.allow) ? permissions.allow : [];
139
+ const filtered = allow.filter((rule) => !isPusharyPermission(rule));
140
+ if (!filtered.includes(PUSHARY_PERMISSION_RULE)) {
141
+ filtered.push(PUSHARY_PERMISSION_RULE);
142
+ }
143
+ permissions.allow = filtered;
144
+ };
145
+ var addPusharyHooks = (settings, binDir, version = null) => {
146
+ const resolve2 = (name) => guardBinary(binDir ? join(binDir, name) : name);
147
+ const hooks = ensureRecord(settings, "hooks");
148
+ const supported = new Map(supportedClaudeEvents(version).map((hook) => [hook.event, hook]));
149
+ for (const known of CLAUDE_HOOK_EVENTS) {
150
+ const current = Array.isArray(hooks[known.event]) ? hooks[known.event] : [];
151
+ const definition = supported.get(known.event);
152
+ if (definition) {
153
+ hooks[known.event] = registerHookEntry(current, isPusharyHook, entry(definition, resolve2));
154
+ continue;
155
+ }
156
+ const others = current.filter((item) => !isPusharyHook(item));
157
+ if (others.length > 0) {
158
+ hooks[known.event] = others;
159
+ } else {
160
+ delete hooks[known.event];
161
+ }
162
+ }
163
+ };
164
+ var entry = (definition, resolve2) => ({
165
+ ...definition.matcher ? { matcher: definition.matcher } : {},
166
+ hooks: [{
167
+ type: "command",
168
+ command: withHookHoldBudget(resolve2(definition.binary), holdBudgetOf(definition)),
169
+ timeout: definition.timeout
170
+ }]
171
+ });
172
+ var removePusharySettings = (settings, scope) => {
173
+ let changed = scope?.keepMcpServer === true ? false : removeClaudeMcpServers(settings);
174
+ if (scope?.keepMcpServer !== true && removePusharyToolPermissions(settings)) changed = true;
175
+ const hooks = asRecord(settings.hooks);
176
+ if (hooks) {
177
+ for (const { event: key } of CLAUDE_HOOK_EVENTS) {
178
+ const entries = hooks[key];
179
+ if (!Array.isArray(entries)) continue;
180
+ const filtered = entries.filter((entry2) => !isPusharyHook(entry2, scope));
181
+ if (filtered.length !== entries.length) {
182
+ if (filtered.length === 0) {
183
+ delete hooks[key];
184
+ } else {
185
+ hooks[key] = filtered;
186
+ }
187
+ changed = true;
188
+ }
189
+ }
190
+ if (Object.keys(hooks).length === 0) delete settings.hooks;
191
+ }
192
+ return changed;
193
+ };
28
194
 
29
195
  // src/compatible-config.ts
30
196
  import { homedir } from "os";
31
- import { isAbsolute, join, resolve } from "path";
197
+ import { isAbsolute, join as join2, resolve } from "path";
32
198
  var AGENT_FLAG = "--agent";
33
199
  var SOURCE_FLAG = "--source";
34
200
  var agentArgument = (profile) => `${AGENT_FLAG}=${profile.agentType}`;
@@ -74,25 +240,25 @@ var normalizeToolCall = (profile, input) => {
74
240
  const lookup = lookupFor(profile, input);
75
241
  return { ...input, tool_name: lookup.tool, tool_input: lookup.input };
76
242
  };
77
- var underHome = (segments, home = homedir()) => join(home, ...segments);
243
+ var underHome = (segments, home = homedir()) => join2(home, ...segments);
78
244
  var compatibleConfigFile = (profile, home) => underHome(profile.configFile, home);
79
245
  var compatibleMcpFile = (profile, home) => profile.mcp ? underHome(profile.mcp.file, home) : null;
80
246
  var compatibleInstructionsFile = (profile, home) => profile.instructions ? underHome(profile.instructions.file, home) : null;
81
- var asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
82
- var ensureRecord = (target, key) => {
83
- const existing = asRecord(target[key]);
247
+ var asRecord2 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
248
+ var ensureRecord2 = (target, key) => {
249
+ const existing = asRecord2(target[key]);
84
250
  if (existing) return existing;
85
251
  const created = {};
86
252
  target[key] = created;
87
253
  return created;
88
254
  };
89
- var descend = (config, keyPath) => keyPath.reduce(ensureRecord, config);
90
- var findMap = (config, keyPath) => keyPath.reduce((node, key) => node && asRecord(node[key]), config);
255
+ var descend = (config, keyPath) => keyPath.reduce(ensureRecord2, config);
256
+ var findMap = (config, keyPath) => keyPath.reduce((node, key) => node && asRecord2(node[key]), config);
91
257
  var pruneEmptyMap = (config, keyPath) => {
92
258
  if (keyPath.length === 0) return false;
93
259
  const parent = findMap(config, keyPath.slice(0, -1));
94
260
  const key = keyPath[keyPath.length - 1];
95
- const map = asRecord(parent?.[key]);
261
+ const map = asRecord2(parent?.[key]);
96
262
  if (!parent || !map || Object.keys(map).length > 0) return false;
97
263
  delete parent[key];
98
264
  return true;
@@ -114,12 +280,12 @@ var WRITTEN = { ok: true };
114
280
  var ROOT_KEY = "(root)";
115
281
  var dotted = (segments) => segments.join(".") || ROOT_KEY;
116
282
  var hooksShapeConflict = (config, profile) => {
117
- if (!asRecord(config)) return ROOT_KEY;
283
+ if (!asRecord2(config)) return ROOT_KEY;
118
284
  const walked = [];
119
285
  let node = config;
120
286
  for (const key of profile.hooksKeyPath) {
121
287
  if (node[key] === void 0) return void 0;
122
- const nested = asRecord(node[key]);
288
+ const nested = asRecord2(node[key]);
123
289
  if (!nested) return dotted([...walked, key]);
124
290
  walked.push(key);
125
291
  node = nested;
@@ -128,9 +294,9 @@ var hooksShapeConflict = (config, profile) => {
128
294
  return clash ? dotted([...walked, clash.event]) : void 0;
129
295
  };
130
296
  var permissionsShapeConflict = (config) => {
131
- if (!asRecord(config)) return ROOT_KEY;
297
+ if (!asRecord2(config)) return ROOT_KEY;
132
298
  if (config.permissions === void 0) return void 0;
133
- const permissions = asRecord(config.permissions);
299
+ const permissions = asRecord2(config.permissions);
134
300
  if (!permissions) return "permissions";
135
301
  return permissions.allow !== void 0 && !Array.isArray(permissions.allow) ? "permissions.allow" : void 0;
136
302
  };
@@ -154,7 +320,7 @@ var entryFor = (profile, definition, resolve2) => ({
154
320
  var addCompatibleHooks = (config, profile, binDir) => {
155
321
  const conflictAt = hooksShapeConflict(config, profile);
156
322
  if (conflictAt) return { ok: false, conflictAt };
157
- const resolve2 = (name) => guardBinary(binDir ? join(binDir, name) : name);
323
+ const resolve2 = (name) => guardBinary(binDir ? join2(binDir, name) : name);
158
324
  const hooks = descend(config, profile.hooksKeyPath);
159
325
  const supported = new Map(compatibleHookEvents(profile).map((hook) => [hook.event, hook]));
160
326
  for (const known of CLAUDE_HOOK_EVENTS) {
@@ -177,7 +343,7 @@ var removeCompatibleHooks = (config, profile, scope) => {
177
343
  for (const { event } of CLAUDE_HOOK_EVENTS) {
178
344
  const entries = hooks[event];
179
345
  if (!Array.isArray(entries)) continue;
180
- const kept = entries.filter((entry) => !isPusharyHook(entry, scope));
346
+ const kept = entries.filter((entry2) => !isPusharyHook(entry2, scope));
181
347
  if (kept.length === entries.length) continue;
182
348
  if (kept.length === 0) delete hooks[event];
183
349
  else hooks[event] = kept;
@@ -191,14 +357,14 @@ var hasCompatibleHooks = (config, profile) => {
191
357
  if (!hooks) return false;
192
358
  return compatibleHookEvents(profile).some(({ event }) => {
193
359
  const entries = hooks[event];
194
- return Array.isArray(entries) && entries.some((entry) => isPusharyHook(entry));
360
+ return Array.isArray(entries) && entries.some((entry2) => isPusharyHook(entry2));
195
361
  });
196
362
  };
197
363
  var missingCompatibleHookEvents = (config, profile) => {
198
364
  const hooks = findMap(config, profile.hooksKeyPath);
199
365
  return compatibleHookEvents(profile).filter(({ event }) => {
200
366
  const entries = hooks?.[event];
201
- return !Array.isArray(entries) || !entries.some((entry) => isPusharyHook(entry));
367
+ return !Array.isArray(entries) || !entries.some((entry2) => isPusharyHook(entry2));
202
368
  }).map(({ event }) => event);
203
369
  };
204
370
  var compatiblePermissionRuleFile = (profile, home) => profile.permissionRuleFile ? underHome(profile.permissionRuleFile, home) : null;
@@ -210,7 +376,7 @@ var addCompatibleMcpServer = (config, profile, apiKey) => {
210
376
  }
211
377
  addClaudeMcpServer(config, apiKey);
212
378
  if (!profile.mcp.trusted) return;
213
- const server = asRecord(asRecord(config.mcpServers)?.pushary);
379
+ const server = asRecord2(asRecord2(config.mcpServers)?.pushary);
214
380
  if (server) server.trust = true;
215
381
  };
216
382
  var removeCompatibleMcpServer = (config, profile) => {
@@ -219,6 +385,16 @@ var removeCompatibleMcpServer = (config, profile) => {
219
385
  };
220
386
 
221
387
  export {
388
+ addClaudeMcpServer,
389
+ isClaudeMcpSnapshot,
390
+ captureClaudeMcpServer,
391
+ updateClaudeMcpSnapshot,
392
+ restoreClaudeMcpServer,
393
+ removeClaudeMcpServers,
394
+ removePusharyToolPermissions,
395
+ addPusharyToolPermissions,
396
+ addPusharyHooks,
397
+ removePusharySettings,
222
398
  profileFromArgv,
223
399
  activeIdentity,
224
400
  activeHookSource,
@@ -14,36 +14,36 @@ import {
14
14
  IDLE_PROMPT_NOTIFICATION,
15
15
  NOTIFICATION_PUSH_TYPES,
16
16
  POSTTOOLUSE_MIRROR_ONLY_TOOLS
17
- } from "./chunk-DJ4BB264.js";
17
+ } from "./chunk-CD47ZFFZ.js";
18
18
  import {
19
19
  cancelQuestion,
20
20
  isPolicyConfig,
21
21
  sendNotification,
22
22
  waitForAnswer
23
- } from "./chunk-WN6WYUCV.js";
23
+ } from "./chunk-2VZAALEJ.js";
24
24
  import {
25
25
  clientErrorKindOf,
26
26
  reportClientError
27
- } from "./chunk-DA4FTGTK.js";
27
+ } from "./chunk-DKMD6AWR.js";
28
28
  import {
29
29
  withRetry
30
- } from "./chunk-ZPW4MJOV.js";
30
+ } from "./chunk-MKTJEXZ3.js";
31
31
  import {
32
32
  getMachineId
33
- } from "./chunk-3BUAEQCY.js";
33
+ } from "./chunk-DUZVXBBU.js";
34
34
  import {
35
35
  reportedInstallSource
36
- } from "./chunk-75CA37FZ.js";
36
+ } from "./chunk-FQ2GORVG.js";
37
37
  import {
38
38
  canonicalJson
39
- } from "./chunk-HJXZJF6O.js";
39
+ } from "./chunk-ZBHUHJG6.js";
40
40
  import {
41
41
  writeFileAtomic
42
42
  } from "./chunk-T7E75EKA.js";
43
43
  import {
44
44
  getApiKey,
45
45
  getBaseUrl
46
- } from "./chunk-2QRE6QH2.js";
46
+ } from "./chunk-5QUPKDI5.js";
47
47
  import {
48
48
  ACTION_BODY_MAX,
49
49
  AGENT_LABELS_BY_TYPE,
@@ -70,7 +70,7 @@ import {
70
70
  resolvePolicy,
71
71
  toToolLookup,
72
72
  truncateLine
73
- } from "./chunk-Q4E56K4X.js";
73
+ } from "./chunk-I5IJRMNV.js";
74
74
 
75
75
  // src/policy.ts
76
76
  import { createHash } from "crypto";
@@ -4,14 +4,14 @@ import {
4
4
  } from "./chunk-XHKBHWLX.js";
5
5
  import {
6
6
  readControlMode
7
- } from "./chunk-5BHROGRB.js";
7
+ } from "./chunk-N4QSPI3B.js";
8
8
  import {
9
9
  getMachineId
10
- } from "./chunk-3BUAEQCY.js";
10
+ } from "./chunk-DUZVXBBU.js";
11
11
  import {
12
12
  pusharyDir,
13
13
  resolveGlobalBinary
14
- } from "./chunk-HJXZJF6O.js";
14
+ } from "./chunk-ZBHUHJG6.js";
15
15
  import {
16
16
  readJsonSafe,
17
17
  writeFileAtomic,
@@ -20,14 +20,14 @@ import {
20
20
  } from "./chunk-T7E75EKA.js";
21
21
  import {
22
22
  getApiKey
23
- } from "./chunk-2QRE6QH2.js";
23
+ } from "./chunk-5QUPKDI5.js";
24
24
  import {
25
25
  CLI_PACKAGE_NAMES,
26
26
  cmdShimTarget,
27
27
  getPackageVersion,
28
28
  globalPackageFolder,
29
29
  globalRootFor
30
- } from "./chunk-Q4E56K4X.js";
30
+ } from "./chunk-I5IJRMNV.js";
31
31
 
32
32
  // src/daemon-lifecycle.ts
33
33
  import { dirname, join, win32 as win32Path } from "path";
@@ -38,7 +38,8 @@ import { execFileSync } from "child_process";
38
38
  var daemonNeedsHandoff = (status) => status.kind === "version-mismatch" || status.kind === "configuration-mismatch" || status.kind === "unresponsive" && status.processAlive === true;
39
39
  var DAEMON_REMOTE_PROOF_MAX_AGE_MS = 18e4;
40
40
  var DAEMON_REMOTE_PROOF_CLOCK_SKEW_MS = 3e4;
41
- var DAEMON_STARTUP_TIMEOUT_MS = 3e4;
41
+ var DAEMON_STARTUP_TIMEOUT_MS = 5e3;
42
+ var DAEMON_COLD_START_TIMEOUT_MS = 3e4;
42
43
  var remoteProofIsFresh = (timestamp, now) => {
43
44
  if (timestamp === null) return false;
44
45
  const age = now - Date.parse(timestamp);
@@ -719,8 +720,9 @@ var stopDaemonRunning = async (options = {}) => {
719
720
  safeUnlink(lockPath(dir));
720
721
  return { kind: "stopped" };
721
722
  };
723
+ var DAEMON_LOGIN_REASONS = ["key_rejected", "plan_inactive", "key_missing", "mac_signed_out"];
722
724
  var needsLoginPath = (dir) => join(dir, "daemon-needs-login.json");
723
- var isLoginReason = (value) => value === "key_rejected" || value === "plan_inactive";
725
+ var isLoginReason = (value) => DAEMON_LOGIN_REASONS.includes(value);
724
726
  var parseDaemonNeedsLogin = (value) => {
725
727
  if (typeof value !== "object" || value === null) return null;
726
728
  const record = value;
@@ -750,7 +752,13 @@ var clearDaemonNeedsLogin = (options = {}) => {
750
752
  safeUnlink(path);
751
753
  return true;
752
754
  };
753
- var describeDaemonLoginBlock = (record) => record.reason === "key_rejected" ? `this machine's key was rejected at ${record.at}; run \`pushary login\` to sign in again` : `this workspace had no active plan at ${record.at}; pick one at pushary.com/dashboard/settings?tab=billing, then run \`pushary login\``;
755
+ var DAEMON_LOGIN_BLOCK_DESCRIPTIONS = {
756
+ key_rejected: (at) => `this machine's key was rejected at ${at}; run \`pushary login\` to sign in again`,
757
+ plan_inactive: (at) => `this workspace had no active plan at ${at}; pick one at pushary.com/dashboard/settings?tab=billing, then run \`pushary login\``,
758
+ key_missing: (at) => `this machine had no key at ${at}; run \`pushary login\` to sign in again`,
759
+ mac_signed_out: (at) => `the key this machine shared with the Pushary Mac app was signed out on this Mac at ${at}; run \`pushary login\` to sign in again`
760
+ };
761
+ var describeDaemonLoginBlock = (record) => DAEMON_LOGIN_BLOCK_DESCRIPTIONS[record.reason](record.at);
754
762
  var recoverDaemonAfterLogin = (options = {}) => {
755
763
  const cleared = clearDaemonNeedsLogin(options);
756
764
  if (!cleared || readControlMode(join(options.dir ?? pusharyDir(), "config.json")) === "off" || !hasDaemonServiceDefinition(options)) {
@@ -1096,7 +1104,7 @@ var ensureDaemonRunning = async (options = {}) => {
1096
1104
  var waitForDaemonRemoteProof = async (options = {}) => {
1097
1105
  const sleep = options.sleep ?? wait;
1098
1106
  const pollIntervalMs = options.pollIntervalMs ?? 250;
1099
- const attempts = Math.max(1, Math.ceil((options.waitTimeoutMs ?? DAEMON_STARTUP_TIMEOUT_MS) / pollIntervalMs));
1107
+ const attempts = Math.max(1, Math.ceil((options.waitTimeoutMs ?? DAEMON_COLD_START_TIMEOUT_MS) / pollIntervalMs));
1100
1108
  let status = readDaemonStatus(options);
1101
1109
  for (let attempt = 0; attempt < attempts; attempt++) {
1102
1110
  status = readDaemonStatus(options);
@@ -1107,6 +1115,7 @@ var waitForDaemonRemoteProof = async (options = {}) => {
1107
1115
  };
1108
1116
 
1109
1117
  export {
1118
+ DAEMON_COLD_START_TIMEOUT_MS,
1110
1119
  daemonHasRemoteProof,
1111
1120
  daemonServiceManagerAvailable,
1112
1121
  DAEMON_LEASE_RENEW_INTERVAL_MS,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  pusharyFetch
3
- } from "./chunk-W4Q7NFXU.js";
3
+ } from "./chunk-TCQ43LSG.js";
4
4
  import {
5
5
  NetworkError
6
6
  } from "./chunk-7QLSKOSU.js";
@@ -9,11 +9,11 @@ import {
9
9
  } from "./chunk-KZERVKTD.js";
10
10
  import {
11
11
  getBaseUrl
12
- } from "./chunk-2QRE6QH2.js";
12
+ } from "./chunk-5QUPKDI5.js";
13
13
  import {
14
14
  isValidApiKey,
15
15
  normalizeKeyScope
16
- } from "./chunk-Q4E56K4X.js";
16
+ } from "./chunk-I5IJRMNV.js";
17
17
 
18
18
  // src/session.ts
19
19
  var samePusharyAccount = (left, right) => left.kind === "ok" && right.kind === "ok" && left.identity.workspaceId !== "" && left.identity.workspaceId === right.identity.workspaceId && left.identity.siteId === right.identity.siteId;
@@ -167,6 +167,7 @@ var describeKeyCheck = (check, baseUrl = getBaseUrl()) => {
167
167
 
168
168
  export {
169
169
  samePusharyAccount,
170
+ absoluteUrl,
170
171
  checkApiKey,
171
172
  keyCheckFromResponse,
172
173
  describeKeyCheck
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  readTranscriptPreference
3
- } from "./chunk-5BHROGRB.js";
3
+ } from "./chunk-N4QSPI3B.js";
4
4
 
5
5
  // src/transcript-setting.ts
6
6
  var transcriptEnvironmentPreference = () => {
@@ -1,7 +1,10 @@
1
+ import {
2
+ guardedArgv
3
+ } from "./chunk-ZBHUHJG6.js";
1
4
  import {
2
5
  HOOK_BUDGETS,
3
6
  OPENCODE_APPROVAL_EVENT
4
- } from "./chunk-Q4E56K4X.js";
7
+ } from "./chunk-I5IJRMNV.js";
5
8
 
6
9
  // src/opencode-plugin.ts
7
10
  var OPENCODE_PLUGIN_MARKER = "pushary-opencode-plugin w1";
@@ -298,6 +301,19 @@ var openCodePluginModule = () => ({
298
301
  }
299
302
  });
300
303
  var renderOpenCodePlugin = (module, argv) => module.source.replace(module.placeholder, JSON.stringify(argv));
304
+ var COMMAND_LINE = /^const COMMAND = (.*)$/m;
305
+ var isArgv = (value) => Array.isArray(value) && value.every((item) => typeof item === "string");
306
+ var openCodePluginArgv = (contents) => {
307
+ if (!isOpenCodePluginOurs(contents)) return null;
308
+ const line = contents.match(COMMAND_LINE)?.[1];
309
+ if (line === void 0) return null;
310
+ try {
311
+ const parsed = JSON.parse(line);
312
+ return isArgv(parsed) ? parsed : null;
313
+ } catch {
314
+ return null;
315
+ }
316
+ };
301
317
  var isOpenCodePluginOurs = (contents) => contents.includes(OPENCODE_PLUGIN_MARKER);
302
318
 
303
319
  // src/opencode-config.ts
@@ -305,6 +321,8 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync
305
321
  import { homedir } from "os";
306
322
  import { join } from "path";
307
323
  var OPENCODE_HOOK_BINARY = "pushary-opencode-hook";
324
+ var OPENCODE_HOOK_ARGS = ["--source", "opencode"];
325
+ var openCodeHookArgv = (resolvedBinary) => guardedArgv({ kind: "binary", path: resolvedBinary ?? OPENCODE_HOOK_BINARY, runtime: "node" }, OPENCODE_HOOK_ARGS);
308
326
  var openCodeConfigDirFrom = (home, env = process.env) => env.OPENCODE_CONFIG_DIR?.trim() || join(env.XDG_CONFIG_HOME?.trim() || join(home, ".config"), "opencode");
309
327
  var openCodeConfigDir = () => openCodeConfigDirFrom(homedir());
310
328
  var OPENCODE_PLUGIN_PATH = `${OPENCODE_PLUGIN_DIR}/${OPENCODE_PLUGIN_FILE}`;
@@ -361,8 +379,10 @@ export {
361
379
  OPENCODE_PLUGIN_PLACEHOLDER,
362
380
  OPENCODE_PLUGIN_SIBLING,
363
381
  OPENCODE_PLUGIN_SIBLING_CONTENTS,
382
+ openCodePluginArgv,
364
383
  isOpenCodePluginOurs,
365
384
  OPENCODE_HOOK_BINARY,
385
+ openCodeHookArgv,
366
386
  openCodeConfigDirFrom,
367
387
  openCodeConfigDir,
368
388
  openCodePluginDir,
@@ -8,10 +8,10 @@ import {
8
8
  codexHooksJsonIn,
9
9
  isPusharyCodexCommand,
10
10
  resolvePathBinary
11
- } from "./chunk-HJXZJF6O.js";
11
+ } from "./chunk-ZBHUHJG6.js";
12
12
  import {
13
13
  getPackageVersion
14
- } from "./chunk-Q4E56K4X.js";
14
+ } from "./chunk-I5IJRMNV.js";
15
15
 
16
16
  // src/codex-app-server.ts
17
17
  import { existsSync, realpathSync } from "fs";
@@ -327,6 +327,7 @@ var readCodexTrustForPusharyHooks = async (options = {}) => {
327
327
  };
328
328
 
329
329
  export {
330
+ CODEX_HOOK_STATUS,
330
331
  assessCodexHookTrust,
331
332
  ensureCodexTrustsPusharyHooks,
332
333
  readCodexTrustForPusharyHooks
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  keyCheckFromResponse
3
- } from "./chunk-4QKM44N6.js";
3
+ } from "./chunk-LWOO567I.js";
4
4
  import {
5
5
  installNetworkDefaults
6
- } from "./chunk-W4Q7NFXU.js";
6
+ } from "./chunk-TCQ43LSG.js";
7
7
  import {
8
8
  getBaseUrl
9
- } from "./chunk-2QRE6QH2.js";
9
+ } from "./chunk-5QUPKDI5.js";
10
10
 
11
11
  // src/retry.ts
12
12
  var isRetryable = (err) => {