@pushary/agent-hooks 1.9.7 → 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 (110) hide show
  1. package/CHANGELOG.md +11 -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 +101 -79
  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 -39
  15. package/dist/bin/pushary-disconnect.js +189 -54
  16. package/dist/bin/pushary-doctor.js +67 -58
  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 -32
  33. package/dist/bin/pushary-setup.js +91 -101
  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 +55 -25
  42. package/dist/bin/pushary-wait.js +23 -19
  43. package/dist/bin/pushary.js +15 -14
  44. package/dist/{chunk-R3YW55MY.js → chunk-2A53H4S6.js} +17 -15
  45. package/dist/{chunk-4YO4T5FV.js → chunk-2QGYMY7A.js} +83 -3
  46. package/dist/{chunk-MBK7N46B.js → chunk-2QTO5YIT.js} +6 -6
  47. package/dist/{chunk-D6S5EKXA.js → chunk-2VZAALEJ.js} +5 -9
  48. package/dist/chunk-2WXF3QJR.js +49 -0
  49. package/dist/{chunk-JCWZ23MJ.js → chunk-3I6IVOZV.js} +3 -3
  50. package/dist/chunk-3Z3A37WD.js +77 -0
  51. package/dist/{chunk-Z6HPS67T.js → chunk-5QUPKDI5.js} +1 -1
  52. package/dist/{chunk-JWKBDSPF.js → chunk-6TE27XZR.js} +2 -2
  53. package/dist/{chunk-STQRUH3S.js → chunk-7DVNSQWF.js} +59 -15
  54. package/dist/{chunk-QTO6HEZD.js → chunk-7PT35RY2.js} +2 -2
  55. package/dist/{chunk-7OIWWZAD.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-6DJTDHBI.js → chunk-CD47ZFFZ.js} +1 -1
  59. package/dist/{chunk-UFVGSEWH.js → chunk-CKV3UPMU.js} +2 -2
  60. package/dist/{chunk-4FK6RZVJ.js → chunk-CLOSJ4ES.js} +1 -1
  61. package/dist/{chunk-AVNKVF7N.js → chunk-DKMD6AWR.js} +4 -4
  62. package/dist/{chunk-SBLPHUEB.js → chunk-DL7XWKYV.js} +7 -5
  63. package/dist/{chunk-BTQGAXZ3.js → chunk-DPGSLWOS.js} +8 -8
  64. package/dist/{chunk-KYO45G5L.js → chunk-DUZVXBBU.js} +1 -1
  65. package/dist/{chunk-EB4XGVBG.js → chunk-EUW7JL2K.js} +0 -32
  66. package/dist/{chunk-4D2AYNSE.js → chunk-FQ2GORVG.js} +2 -2
  67. package/dist/{chunk-W2KI5KPD.js → chunk-HRULIYDU.js} +2 -2
  68. package/dist/{chunk-QR6VE5ME.js → chunk-I5IJRMNV.js} +58 -8
  69. package/dist/{chunk-T7Y5EADL.js → chunk-I6MJXLMY.js} +2 -2
  70. package/dist/{chunk-N4EUSDKX.js → chunk-IAD2RT4L.js} +14 -14
  71. package/dist/{chunk-H37L7TT3.js → chunk-IHFDPV7C.js} +2 -2
  72. package/dist/{chunk-3GNUXXDZ.js → chunk-IHO3YQAN.js} +2 -2
  73. package/dist/{chunk-JWQZSYCK.js → chunk-KF3UZLYI.js} +1 -1
  74. package/dist/chunk-KFF7G225.js +599 -0
  75. package/dist/{chunk-MZPXVH4A.js → chunk-KHNFLYJO.js} +204 -28
  76. package/dist/{chunk-QFEM7R6T.js → chunk-KRCR2CRQ.js} +9 -9
  77. package/dist/{chunk-VXRXFU6Q.js → chunk-LKLVTG3V.js} +14 -7
  78. package/dist/{chunk-KFKL3FHS.js → chunk-LWOO567I.js} +4 -3
  79. package/dist/{chunk-HPRZJKRO.js → chunk-M6BZZFVQ.js} +1 -1
  80. package/dist/{chunk-X5NXPCIC.js → chunk-MFF3ONG5.js} +16 -2
  81. package/dist/{chunk-H7MMU64M.js → chunk-MGRFDGWU.js} +2 -2
  82. package/dist/{chunk-L76HTPU6.js → chunk-MKTJEXZ3.js} +3 -3
  83. package/dist/{chunk-NIBFSARF.js → chunk-MXHTGVFZ.js} +33 -9
  84. package/dist/{chunk-ADSQDYYG.js → chunk-N4QSPI3B.js} +54 -5
  85. package/dist/{chunk-AQ55ZSSS.js → chunk-NWDG3MSW.js} +1 -1
  86. package/dist/chunk-OP7IHC2I.js +24 -0
  87. package/dist/{chunk-KT5E2RLS.js → chunk-QOLITCIP.js} +1 -1
  88. package/dist/{chunk-JXISQ7DT.js → chunk-TCQ43LSG.js} +3 -3
  89. package/dist/chunk-TCWKTUAE.js +50 -0
  90. package/dist/{chunk-RQGODFQN.js → chunk-V5HPPF3E.js} +1 -1
  91. package/dist/{chunk-7264S5HZ.js → chunk-WG3K4TCH.js} +1 -1
  92. package/dist/{chunk-GKI6LFAV.js → chunk-WS4H76EP.js} +2 -2
  93. package/dist/{chunk-XWAYAO3V.js → chunk-WWOHTTVP.js} +2 -2
  94. package/dist/{chunk-SD3272LS.js → chunk-YIG2R3BJ.js} +9 -7
  95. package/dist/{chunk-ZUTU43FT.js → chunk-ZBHUHJG6.js} +4 -4
  96. package/dist/{chunk-AUUXS44H.js → chunk-ZBK6E2OR.js} +1 -1
  97. package/dist/{chunk-QQ4HBXZC.js → chunk-ZN3C6GBG.js} +84 -673
  98. package/dist/{chunk-CBQACHKY.js → chunk-ZSTSEBG7.js} +1 -1
  99. package/dist/{chunk-3PVDOCFI.js → chunk-ZW3XZLJC.js} +5 -5
  100. package/dist/{global-upgrade-E2HUEB4B.js → global-upgrade-I56HNM23.js} +6 -6
  101. package/dist/{paths-QVTEGNZV.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-JCIDZMHF.js → upgrade-lock-B34TAUKV.js} +3 -3
  106. package/package.json +1 -1
  107. package/dist/chunk-ANEAA37E.js +0 -197
  108. package/dist/chunk-MNWRUGMH.js +0 -86
  109. package/dist/chunk-RQSOEB4S.js +0 -44
  110. package/dist/reapply-5QVKM6LA.js +0 -38
@@ -1,34 +1,200 @@
1
- import {
2
- addClaudeMcpServer,
3
- addPusharyToolPermissions,
4
- isPusharyHook,
5
- removeClaudeMcpServers
6
- } from "./chunk-ANEAA37E.js";
7
1
  import {
8
2
  CLAUDE_HOOK_EVENTS,
9
3
  addGeminiMcpServer,
10
- removeGeminiMcpServer
11
- } from "./chunk-JCWZ23MJ.js";
4
+ removeGeminiMcpServer,
5
+ supportedClaudeEvents
6
+ } from "./chunk-3I6IVOZV.js";
12
7
  import {
13
8
  CLAUDE_CODE_AGENT,
14
9
  parseApplyPatchFiles
15
- } from "./chunk-QFEM7R6T.js";
10
+ } from "./chunk-KRCR2CRQ.js";
16
11
  import {
17
12
  guardBinary,
18
13
  holdBudgetOf,
14
+ isProtectedByScope,
19
15
  registerHookEntry
20
- } from "./chunk-ZUTU43FT.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-QR6VE5ME.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-6DJTDHBI.js";
17
+ } from "./chunk-CD47ZFFZ.js";
18
18
  import {
19
19
  cancelQuestion,
20
20
  isPolicyConfig,
21
21
  sendNotification,
22
22
  waitForAnswer
23
- } from "./chunk-D6S5EKXA.js";
23
+ } from "./chunk-2VZAALEJ.js";
24
24
  import {
25
25
  clientErrorKindOf,
26
26
  reportClientError
27
- } from "./chunk-AVNKVF7N.js";
27
+ } from "./chunk-DKMD6AWR.js";
28
28
  import {
29
29
  withRetry
30
- } from "./chunk-L76HTPU6.js";
30
+ } from "./chunk-MKTJEXZ3.js";
31
31
  import {
32
32
  getMachineId
33
- } from "./chunk-KYO45G5L.js";
33
+ } from "./chunk-DUZVXBBU.js";
34
34
  import {
35
35
  reportedInstallSource
36
- } from "./chunk-4D2AYNSE.js";
36
+ } from "./chunk-FQ2GORVG.js";
37
37
  import {
38
38
  canonicalJson
39
- } from "./chunk-ZUTU43FT.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-Z6HPS67T.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-QR6VE5ME.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-ADSQDYYG.js";
7
+ } from "./chunk-N4QSPI3B.js";
8
8
  import {
9
9
  getMachineId
10
- } from "./chunk-KYO45G5L.js";
10
+ } from "./chunk-DUZVXBBU.js";
11
11
  import {
12
12
  pusharyDir,
13
13
  resolveGlobalBinary
14
- } from "./chunk-ZUTU43FT.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-Z6HPS67T.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-QR6VE5ME.js";
30
+ } from "./chunk-I5IJRMNV.js";
31
31
 
32
32
  // src/daemon-lifecycle.ts
33
33
  import { dirname, join, win32 as win32Path } from "path";
@@ -720,8 +720,9 @@ var stopDaemonRunning = async (options = {}) => {
720
720
  safeUnlink(lockPath(dir));
721
721
  return { kind: "stopped" };
722
722
  };
723
+ var DAEMON_LOGIN_REASONS = ["key_rejected", "plan_inactive", "key_missing", "mac_signed_out"];
723
724
  var needsLoginPath = (dir) => join(dir, "daemon-needs-login.json");
724
- var isLoginReason = (value) => value === "key_rejected" || value === "plan_inactive";
725
+ var isLoginReason = (value) => DAEMON_LOGIN_REASONS.includes(value);
725
726
  var parseDaemonNeedsLogin = (value) => {
726
727
  if (typeof value !== "object" || value === null) return null;
727
728
  const record = value;
@@ -751,7 +752,13 @@ var clearDaemonNeedsLogin = (options = {}) => {
751
752
  safeUnlink(path);
752
753
  return true;
753
754
  };
754
- 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);
755
762
  var recoverDaemonAfterLogin = (options = {}) => {
756
763
  const cleared = clearDaemonNeedsLogin(options);
757
764
  if (!cleared || readControlMode(join(options.dir ?? pusharyDir(), "config.json")) === "off" || !hasDaemonServiceDefinition(options)) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  pusharyFetch
3
- } from "./chunk-JXISQ7DT.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-Z6HPS67T.js";
12
+ } from "./chunk-5QUPKDI5.js";
13
13
  import {
14
14
  isValidApiKey,
15
15
  normalizeKeyScope
16
- } from "./chunk-QR6VE5ME.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-ADSQDYYG.js";
3
+ } from "./chunk-N4QSPI3B.js";
4
4
 
5
5
  // src/transcript-setting.ts
6
6
  var transcriptEnvironmentPreference = () => {
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  guardedArgv
3
- } from "./chunk-ZUTU43FT.js";
3
+ } from "./chunk-ZBHUHJG6.js";
4
4
  import {
5
5
  HOOK_BUDGETS,
6
6
  OPENCODE_APPROVAL_EVENT
7
- } from "./chunk-QR6VE5ME.js";
7
+ } from "./chunk-I5IJRMNV.js";
8
8
 
9
9
  // src/opencode-plugin.ts
10
10
  var OPENCODE_PLUGIN_MARKER = "pushary-opencode-plugin w1";
@@ -301,6 +301,19 @@ var openCodePluginModule = () => ({
301
301
  }
302
302
  });
303
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
+ };
304
317
  var isOpenCodePluginOurs = (contents) => contents.includes(OPENCODE_PLUGIN_MARKER);
305
318
 
306
319
  // src/opencode-config.ts
@@ -366,6 +379,7 @@ export {
366
379
  OPENCODE_PLUGIN_PLACEHOLDER,
367
380
  OPENCODE_PLUGIN_SIBLING,
368
381
  OPENCODE_PLUGIN_SIBLING_CONTENTS,
382
+ openCodePluginArgv,
369
383
  isOpenCodePluginOurs,
370
384
  OPENCODE_HOOK_BINARY,
371
385
  openCodeHookArgv,
@@ -8,10 +8,10 @@ import {
8
8
  codexHooksJsonIn,
9
9
  isPusharyCodexCommand,
10
10
  resolvePathBinary
11
- } from "./chunk-ZUTU43FT.js";
11
+ } from "./chunk-ZBHUHJG6.js";
12
12
  import {
13
13
  getPackageVersion
14
- } from "./chunk-QR6VE5ME.js";
14
+ } from "./chunk-I5IJRMNV.js";
15
15
 
16
16
  // src/codex-app-server.ts
17
17
  import { existsSync, realpathSync } from "fs";
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  keyCheckFromResponse
3
- } from "./chunk-KFKL3FHS.js";
3
+ } from "./chunk-LWOO567I.js";
4
4
  import {
5
5
  installNetworkDefaults
6
- } from "./chunk-JXISQ7DT.js";
6
+ } from "./chunk-TCQ43LSG.js";
7
7
  import {
8
8
  getBaseUrl
9
- } from "./chunk-Z6HPS67T.js";
9
+ } from "./chunk-5QUPKDI5.js";
10
10
 
11
11
  // src/retry.ts
12
12
  var isRetryable = (err) => {
@@ -1,28 +1,36 @@
1
+ import {
2
+ agentHookOwner,
3
+ macAppBridgeAvailable,
4
+ openCodePluginOwner
5
+ } from "./chunk-3Z3A37WD.js";
1
6
  import {
2
7
  ensureCodexTrustsPusharyHooks
3
- } from "./chunk-H7MMU64M.js";
8
+ } from "./chunk-MGRFDGWU.js";
4
9
  import {
5
10
  OPENCODE_HOOK_BINARY,
6
11
  installOpenCodePlugin,
7
12
  openCodeHookArgv,
8
13
  openCodePluginDir,
9
14
  openCodeWired
10
- } from "./chunk-X5NXPCIC.js";
15
+ } from "./chunk-MFF3ONG5.js";
11
16
  import {
12
17
  addClaudeMcpServer,
13
18
  addPusharyHooks,
14
19
  addPusharyToolPermissions
15
- } from "./chunk-ANEAA37E.js";
20
+ } from "./chunk-KHNFLYJO.js";
16
21
  import {
17
22
  detectClaudeVersion
18
23
  } from "./chunk-RIVNNBEK.js";
24
+ import {
25
+ planHooks
26
+ } from "./chunk-YIG2R3BJ.js";
19
27
  import {
20
28
  claudeUnprovenHolds,
21
29
  claudeWired,
22
30
  codexUnprovenHolds,
23
31
  codexWired,
24
32
  geminiWired
25
- } from "./chunk-4YO4T5FV.js";
33
+ } from "./chunk-2QGYMY7A.js";
26
34
  import {
27
35
  CLAUDE_HOOK_BINARY,
28
36
  CLAUDE_HOOK_EVENTS,
@@ -33,7 +41,7 @@ import {
33
41
  needsReregistration,
34
42
  registrationSignatures,
35
43
  supportedClaudeEvents
36
- } from "./chunk-JCWZ23MJ.js";
44
+ } from "./chunk-3I6IVOZV.js";
37
45
  import {
38
46
  formatVersion
39
47
  } from "./chunk-6ICPEJY5.js";
@@ -56,7 +64,7 @@ import {
56
64
  registrationHolderOf,
57
65
  resolveGlobalBinary,
58
66
  vscodePluginMcp
59
- } from "./chunk-ZUTU43FT.js";
67
+ } from "./chunk-ZBHUHJG6.js";
60
68
  import {
61
69
  readJsonSafe,
62
70
  writeFileAtomic,
@@ -322,7 +330,18 @@ var reapplyOpenCodePlugin = (paths = {}) => {
322
330
  return { configured: true, reapplied: false, hooks: false, mcp: false, failed: true };
323
331
  }
324
332
  };
325
- var reapplyAllAgents = (apiKey) => {
333
+ var SETUP_CHOICE_BY_REAPPLY_ID = {
334
+ claude: "claude_code",
335
+ codex: "codex",
336
+ gemini: "gemini_cli",
337
+ cursor: "cursor",
338
+ vscode: "vscode"
339
+ };
340
+ var reapplyHookOwner = (id, appAvailable) => id === "opencode" ? openCodePluginOwner(appAvailable) : agentHookOwner(SETUP_CHOICE_BY_REAPPLY_ID[id], appAvailable);
341
+ var reapplyHolder = (id, appAvailable) => planHooks({ owner: reapplyHookOwner(id, appAvailable), takeOverHooks: false, nonInteractive: true }) === "keep" ? "app" : "cli";
342
+ var KEPT_FOR_APP = { configured: true, reapplied: false, hooks: false, mcp: false };
343
+ var FAILED_REAPPLY = { configured: false, reapplied: false, hooks: false, mcp: false, failed: true };
344
+ var reapplyAllAgents = (apiKey, options = {}) => {
326
345
  const runners = [
327
346
  { id: "claude", label: "Claude Code", run: () => reapplyClaudeSettings(apiKey) },
328
347
  { id: "codex", label: "Codex", run: () => reapplyCodexSettings(apiKey) },
@@ -331,13 +350,18 @@ var reapplyAllAgents = (apiKey) => {
331
350
  { id: "vscode", label: "VS Code", run: () => reapplyVsCodePlugin(apiKey) },
332
351
  { id: "opencode", label: "OpenCode", run: () => reapplyOpenCodePlugin() }
333
352
  ];
353
+ const appAvailable = (options.appAvailable ?? macAppBridgeAvailable)();
334
354
  const done = [];
335
355
  for (const runner of runners) {
336
356
  try {
357
+ if (reapplyHolder(runner.id, appAvailable) === "app") {
358
+ done.push({ id: runner.id, label: runner.label, heldBy: "app", result: KEPT_FOR_APP });
359
+ continue;
360
+ }
337
361
  const result = runner.run();
338
- if (result.configured) done.push({ id: runner.id, label: runner.label, result });
362
+ if (result.configured) done.push({ id: runner.id, label: runner.label, heldBy: "cli", result });
339
363
  } catch {
340
- done.push({ id: runner.id, label: runner.label, result: { configured: false, reapplied: false, hooks: false, mcp: false, failed: true } });
364
+ done.push({ id: runner.id, label: runner.label, heldBy: "cli", result: FAILED_REAPPLY });
341
365
  }
342
366
  }
343
367
  return done;