@pushary/agent-hooks 0.99.0 → 1.0.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.
Files changed (79) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/bin/pushary-bell-hook.js +18 -18
  3. package/dist/bin/pushary-bell.js +6 -6
  4. package/dist/bin/pushary-claude.js +22 -24
  5. package/dist/bin/pushary-clean.js +60 -18
  6. package/dist/bin/pushary-codex-bridge.js +10 -10
  7. package/dist/bin/pushary-codex-hook.js +33 -35
  8. package/dist/bin/pushary-codex.js +6 -7
  9. package/dist/bin/pushary-connect.js +6 -6
  10. package/dist/bin/pushary-cowork.js +3 -3
  11. package/dist/bin/pushary-daemon.js +22 -22
  12. package/dist/bin/pushary-disconnect.js +48 -7
  13. package/dist/bin/pushary-doctor.js +58 -19
  14. package/dist/bin/pushary-elicitation-hook.js +17 -17
  15. package/dist/bin/pushary-gemini-bridge.js +9 -9
  16. package/dist/bin/pushary-gemini-hook.js +25 -27
  17. package/dist/bin/pushary-hook.js +61 -33
  18. package/dist/bin/pushary-login.js +7 -7
  19. package/dist/bin/pushary-logout.js +4 -4
  20. package/dist/bin/pushary-mode.js +3 -3
  21. package/dist/bin/pushary-notification-hook.js +26 -21
  22. package/dist/bin/pushary-opencode-hook.js +27 -29
  23. package/dist/bin/pushary-permission-denied-hook.js +24 -23
  24. package/dist/bin/pushary-permission-hook.js +32 -24
  25. package/dist/bin/pushary-post-hook.js +30 -22
  26. package/dist/bin/pushary-prompt-hook.js +26 -21
  27. package/dist/bin/pushary-session-end-hook.js +26 -21
  28. package/dist/bin/pushary-session-start-hook.js +30 -25
  29. package/dist/bin/pushary-setup.js +145 -37
  30. package/dist/bin/pushary-stats.js +2 -2
  31. package/dist/bin/pushary-status.js +10 -10
  32. package/dist/bin/pushary-stop-hook.js +27 -22
  33. package/dist/bin/pushary-stopfailure-hook.js +26 -21
  34. package/dist/bin/pushary-transcript-register.js +16 -16
  35. package/dist/bin/pushary-transcripts.js +4 -4
  36. package/dist/bin/pushary-upgrade.js +14 -14
  37. package/dist/bin/pushary-wait.js +3 -3
  38. package/dist/{chunk-PD6JY33P.js → chunk-2PS3DTHQ.js} +4 -3
  39. package/dist/{chunk-RALVI7OF.js → chunk-2SL5X7UB.js} +9 -6
  40. package/dist/{chunk-6KLCP7VF.js → chunk-3C4ERARU.js} +3 -3
  41. package/dist/{chunk-LBNAGGLV.js → chunk-3UUAK2AK.js} +3 -2
  42. package/dist/{chunk-V262ATS5.js → chunk-447SBIC7.js} +15 -2
  43. package/dist/{chunk-562UJ2DA.js → chunk-7WMFPYR5.js} +1 -1
  44. package/dist/{chunk-XPPXOKIG.js → chunk-7ZDFVWRR.js} +1 -1
  45. package/dist/{chunk-GCD3SQSV.js → chunk-A3D43VXO.js} +1 -1
  46. package/dist/{chunk-3RVCQDC4.js → chunk-BOZETFXB.js} +1 -1
  47. package/dist/{chunk-4C4XFAGJ.js → chunk-BPD4P3NN.js} +2 -2
  48. package/dist/{chunk-IRLTW6KF.js → chunk-CDTGL7TT.js} +1 -1
  49. package/dist/{chunk-CP34FI4B.js → chunk-D2N2EJH2.js} +2 -2
  50. package/dist/{chunk-6IFUXNFX.js → chunk-DMJTWULU.js} +1 -1
  51. package/dist/{chunk-4PBCNVI3.js → chunk-DOYARIYB.js} +1 -1
  52. package/dist/{chunk-XOOWC62T.js → chunk-DUOG74E7.js} +1 -1
  53. package/dist/{chunk-OPR2BPD4.js → chunk-EMCNSBF3.js} +1 -1
  54. package/dist/{chunk-5KLAETSU.js → chunk-GTR72MIU.js} +1 -1
  55. package/dist/{chunk-NSFNEDCT.js → chunk-HGEI7SVM.js} +6 -6
  56. package/dist/chunk-HS2KEAFD.js +224 -0
  57. package/dist/{chunk-T3JZZUAR.js → chunk-I3TWY7GH.js} +30 -29
  58. package/dist/{chunk-ID5FDKDZ.js → chunk-IBU7UU3R.js} +1 -1
  59. package/dist/{chunk-O3LZQEQP.js → chunk-IWZG2Y4Z.js} +1 -1
  60. package/dist/{chunk-WGV3VY7O.js → chunk-IYA3NCZG.js} +2 -2
  61. package/dist/{chunk-JBJBVERL.js → chunk-LTPQKBJH.js} +1 -1
  62. package/dist/{chunk-64WARXGV.js → chunk-MDV7ZRAT.js} +698 -43
  63. package/dist/{chunk-QS55LDX4.js → chunk-MGI6MLFU.js} +16 -16
  64. package/dist/{chunk-CRFLU455.js → chunk-MSOFZYI3.js} +3 -3
  65. package/dist/{chunk-LWKPMSBB.js → chunk-R744XA2M.js} +5 -5
  66. package/dist/{chunk-3ZAEUPM4.js → chunk-RFNMSC6N.js} +1 -1
  67. package/dist/{chunk-K6BASBQJ.js → chunk-S2W4ZSHE.js} +1 -1
  68. package/dist/{chunk-OUAE3GKO.js → chunk-TTBRBWAK.js} +278 -1
  69. package/dist/{chunk-6C6MS57P.js → chunk-TVY7AT6O.js} +1 -1
  70. package/dist/{chunk-EXHXR2X5.js → chunk-UWQVODHT.js} +1 -1
  71. package/dist/{chunk-JXELRCU5.js → chunk-XK34HTMW.js} +3 -3
  72. package/dist/{chunk-SI7GYBQP.js → chunk-XKDKUFMP.js} +1 -1
  73. package/dist/{chunk-HB2KB7QL.js → chunk-XNXIMIFY.js} +1 -1
  74. package/dist/{chunk-K4XFCEVI.js → chunk-Y55JNI2I.js} +1 -1
  75. package/dist/{chunk-JL33EDN7.js → chunk-ZZIUQVAN.js} +4 -4
  76. package/dist/{reapply-HQ264ZTR.js → reapply-I4NB5SSM.js} +8 -8
  77. package/dist/src/index.js +12 -10
  78. package/package.json +1 -1
  79. package/dist/chunk-A76GNRIK.js +0 -608
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  CLAUDE_HOOK_EVENTS,
3
3
  supportedClaudeEvents
4
- } from "./chunk-PD6JY33P.js";
4
+ } from "./chunk-2PS3DTHQ.js";
5
5
  import {
6
6
  guardBinary,
7
7
  holdBudgetOf,
8
8
  isProtectedByScope,
9
9
  registerHookEntry
10
- } from "./chunk-JBJBVERL.js";
10
+ } from "./chunk-LTPQKBJH.js";
11
11
  import {
12
12
  HOOK_LOCATOR_BINARY,
13
13
  withHookHoldBudget
14
- } from "./chunk-OUAE3GKO.js";
14
+ } from "./chunk-TTBRBWAK.js";
15
15
 
16
16
  // src/claude-config.ts
17
17
  import { join } from "path";
@@ -113,6 +113,16 @@ var removeClaudeMcpServers = (config) => {
113
113
  }
114
114
  return changed;
115
115
  };
116
+ var removePusharyToolPermissions = (settings) => {
117
+ const permissions = asRecord(settings.permissions);
118
+ if (!permissions || !Array.isArray(permissions.allow)) return false;
119
+ const filtered = permissions.allow.filter((rule) => !isPusharyPermission(rule));
120
+ if (filtered.length === permissions.allow.length) return false;
121
+ if (filtered.length === 0) delete permissions.allow;
122
+ else permissions.allow = filtered;
123
+ if (Object.keys(permissions).length === 0) delete settings.permissions;
124
+ return true;
125
+ };
116
126
  var addPusharyToolPermissions = (settings) => {
117
127
  const permissions = ensureRecord(settings, "permissions");
118
128
  const allow = Array.isArray(permissions.allow) ? permissions.allow : [];
@@ -151,19 +161,7 @@ var entry = (definition, resolve) => ({
151
161
  });
152
162
  var removePusharySettings = (settings, scope) => {
153
163
  let changed = scope?.keepMcpServer === true ? false : removeClaudeMcpServers(settings);
154
- const permissions = scope?.keepMcpServer === true ? void 0 : asRecord(settings.permissions);
155
- if (permissions && Array.isArray(permissions.allow)) {
156
- const filtered = permissions.allow.filter((rule) => !isPusharyPermission(rule));
157
- if (filtered.length !== permissions.allow.length) {
158
- if (filtered.length === 0) {
159
- delete permissions.allow;
160
- } else {
161
- permissions.allow = filtered;
162
- }
163
- if (Object.keys(permissions).length === 0) delete settings.permissions;
164
- changed = true;
165
- }
166
- }
164
+ if (scope?.keepMcpServer !== true && removePusharyToolPermissions(settings)) changed = true;
167
165
  const hooks = asRecord(settings.hooks);
168
166
  if (hooks) {
169
167
  for (const { event: key } of CLAUDE_HOOK_EVENTS) {
@@ -185,12 +183,14 @@ var removePusharySettings = (settings, scope) => {
185
183
  };
186
184
 
187
185
  export {
186
+ isPusharyHook,
188
187
  addClaudeMcpServer,
189
188
  isClaudeMcpSnapshot,
190
189
  captureClaudeMcpServer,
191
190
  updateClaudeMcpSnapshot,
192
191
  restoreClaudeMcpServer,
193
192
  removeClaudeMcpServers,
193
+ removePusharyToolPermissions,
194
194
  addPusharyToolPermissions,
195
195
  addPusharyHooks,
196
196
  removePusharySettings
@@ -4,17 +4,17 @@ import {
4
4
  } from "./chunk-XHKBHWLX.js";
5
5
  import {
6
6
  getMachineId
7
- } from "./chunk-562UJ2DA.js";
7
+ } from "./chunk-7WMFPYR5.js";
8
8
  import {
9
9
  pusharyDir,
10
10
  resolveGlobalBinary
11
- } from "./chunk-JBJBVERL.js";
11
+ } from "./chunk-LTPQKBJH.js";
12
12
  import {
13
13
  getPackageVersion
14
14
  } from "./chunk-DINDL2CF.js";
15
15
  import {
16
16
  readControlMode
17
- } from "./chunk-4PBCNVI3.js";
17
+ } from "./chunk-DOYARIYB.js";
18
18
  import {
19
19
  readJsonSafe,
20
20
  writeFileAtomic,
@@ -1,18 +1,18 @@
1
1
  import {
2
2
  detectClaudeVersion
3
- } from "./chunk-K4XFCEVI.js";
3
+ } from "./chunk-Y55JNI2I.js";
4
4
  import {
5
5
  addClaudeMcpServer,
6
6
  addPusharyHooks,
7
7
  addPusharyToolPermissions
8
- } from "./chunk-QS55LDX4.js";
8
+ } from "./chunk-MGI6MLFU.js";
9
9
  import {
10
10
  claudeUnprovenHolds,
11
11
  claudeWired,
12
12
  codexUnprovenHolds,
13
13
  codexWired,
14
14
  geminiWired
15
- } from "./chunk-JXELRCU5.js";
15
+ } from "./chunk-XK34HTMW.js";
16
16
  import {
17
17
  CLAUDE_HOOK_BINARY,
18
18
  CLAUDE_HOOK_EVENTS,
@@ -24,7 +24,7 @@ import {
24
24
  needsReregistration,
25
25
  registrationSignatures,
26
26
  supportedClaudeEvents
27
- } from "./chunk-PD6JY33P.js";
27
+ } from "./chunk-2PS3DTHQ.js";
28
28
  import {
29
29
  CODEX_HOOK_BINARY,
30
30
  addCodexHookTrust,
@@ -44,7 +44,7 @@ import {
44
44
  registrationHolderOf,
45
45
  resolveGlobalBinary,
46
46
  vscodePluginMcp
47
- } from "./chunk-JBJBVERL.js";
47
+ } from "./chunk-LTPQKBJH.js";
48
48
  import {
49
49
  readJsonSafe,
50
50
  writeFileAtomic,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolvePathBinary
3
- } from "./chunk-JBJBVERL.js";
3
+ } from "./chunk-LTPQKBJH.js";
4
4
 
5
5
  // src/hermes-config.ts
6
6
  import { execFileSync } from "child_process";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  readConfigFileKey
3
- } from "./chunk-4PBCNVI3.js";
3
+ } from "./chunk-DOYARIYB.js";
4
4
 
5
5
  // src/bell/fleet.ts
6
6
  import { closeSync, constants, futimesSync, lstatSync, mkdirSync, openSync, readdirSync, unlinkSync } from "fs";
@@ -29,6 +29,7 @@ var defaults = {
29
29
  repoAware: false,
30
30
  disconnectable: false,
31
31
  managedProvider: false,
32
+ bridged: false,
32
33
  enforcement: "cooperative",
33
34
  connectVia: "Plain MCP",
34
35
  setupCommand: null,
@@ -45,6 +46,7 @@ var AGENTS = {
45
46
  label: "Claude Code",
46
47
  activationGuide: "/docs/agents/guides/claude-code#verify-a-real-approval",
47
48
  hookSource: "claude",
49
+ bridged: true,
48
50
  policyAgent: "claude_code",
49
51
  repoAware: true,
50
52
  disconnectable: true,
@@ -71,6 +73,7 @@ var AGENTS = {
71
73
  ...defaults,
72
74
  label: "Codex",
73
75
  hookSource: "codex",
76
+ bridged: true,
74
77
  policyAgent: "codex",
75
78
  repoAware: true,
76
79
  disconnectable: true,
@@ -90,6 +93,7 @@ var AGENTS = {
90
93
  ...defaults,
91
94
  label: "Gemini CLI",
92
95
  hookSource: "gemini",
96
+ bridged: true,
93
97
  policyAgent: "gemini_cli",
94
98
  repoAware: true,
95
99
  disconnectable: true,
@@ -113,6 +117,7 @@ var AGENTS = {
113
117
  ...defaults,
114
118
  label: "Cursor",
115
119
  hookSource: "cursor",
120
+ bridged: true,
116
121
  policyAgent: "cursor",
117
122
  disconnectable: true,
118
123
  enforcement: "enforced",
@@ -124,6 +129,7 @@ var AGENTS = {
124
129
  ...defaults,
125
130
  label: "VS Code",
126
131
  hookSource: "vscode",
132
+ bridged: true,
127
133
  policyAgent: "vscode",
128
134
  enforcement: "enforced",
129
135
  connectVia: "Agent plugin hooks + MCP",
@@ -135,6 +141,7 @@ var AGENTS = {
135
141
  ...defaults,
136
142
  label: "OpenCode",
137
143
  hookSource: "opencode",
144
+ bridged: true,
138
145
  policyAgent: "opencode",
139
146
  repoAware: true,
140
147
  disconnectable: true,
@@ -143,6 +150,69 @@ var AGENTS = {
143
150
  setupCommand: "npx @pushary/agent-hooks setup",
144
151
  enforcementDetail: "Shell, writes, edits and web fetches when OpenCode itself asks for permission."
145
152
  },
153
+ qwen_code: {
154
+ ...defaults,
155
+ label: "Qwen Code",
156
+ hookSource: "qwen",
157
+ policyAgent: "qwen_code",
158
+ repoAware: true,
159
+ disconnectable: true,
160
+ enforcement: "enforced",
161
+ connectVia: "Native hooks + MCP",
162
+ setupCommand: "npx @pushary/agent-hooks setup",
163
+ enforcementDetail: "Shell, writes and edits through native PreToolUse hooks, matched on Qwen's own tool names and their Claude-shaped aliases."
164
+ },
165
+ codebuddy: {
166
+ ...defaults,
167
+ label: "CodeBuddy",
168
+ hookSource: "codebuddy",
169
+ policyAgent: "codebuddy",
170
+ repoAware: true,
171
+ disconnectable: true,
172
+ enforcement: "enforced",
173
+ connectVia: "Native hooks + MCP",
174
+ setupCommand: "npx @pushary/agent-hooks setup",
175
+ enforcementDetail: "Shell, writes and edits through native PreToolUse hooks, plus PermissionRequest. CodeBuddy implements the Claude Code hook specification."
176
+ },
177
+ qoder: {
178
+ ...defaults,
179
+ label: "Qoder",
180
+ hookSource: "qoder",
181
+ policyAgent: "qoder",
182
+ repoAware: true,
183
+ disconnectable: true,
184
+ enforcement: "enforced",
185
+ connectVia: "Native hooks + MCP",
186
+ setupCommand: "npx @pushary/agent-hooks setup",
187
+ enforcementDetail: "Shell, writes and edits through native PreToolUse hooks, plus PermissionRequest, over Qoder's superset of the Claude Code event list.",
188
+ capabilityNote: "Qoder documents no user-level instructions file, so the proactive-ask block is not installed. Hooks and MCP are unaffected. Like every agent in this family, the CLI wires it; the macOS app does not yet."
189
+ },
190
+ droid: {
191
+ ...defaults,
192
+ label: "Droid",
193
+ hookSource: "droid",
194
+ policyAgent: "droid",
195
+ repoAware: true,
196
+ disconnectable: true,
197
+ enforcement: "enforced",
198
+ connectVia: "Native hooks",
199
+ setupCommand: "npx @pushary/agent-hooks setup",
200
+ enforcementDetail: "Execute, Create, Edit and ApplyPatch through native PreToolUse hooks in ~/.factory/hooks.json.",
201
+ capabilityNote: "Droid registers MCP servers through `droid mcp add` rather than a documented remote-server config shape, so setup writes hooks only. Add Pushary's MCP server yourself to let Droid send notifications and ask questions."
202
+ },
203
+ devin: {
204
+ ...defaults,
205
+ label: "Devin CLI",
206
+ hookSource: "devin",
207
+ policyAgent: "devin",
208
+ repoAware: true,
209
+ disconnectable: true,
210
+ enforcement: "enforced",
211
+ connectVia: "Native hooks",
212
+ setupCommand: "npx @pushary/agent-hooks setup",
213
+ enforcementDetail: "exec, write and edit through native PreToolUse hooks, answered in Devin's own approve/block schema.",
214
+ capabilityNote: "Devin CLI answers PreToolUse with `{decision}` rather than a permission decision. That schema has no third value, so where another agent would be asked, Pushary stays silent and Devin's own prompt decides; and it cannot carry an updated tool input, so Devin's own question and plan dialogs are left alone rather than answered from the phone without the answer reaching it. It also fires no Notification event."
215
+ },
146
216
  windsurf: {
147
217
  ...defaults,
148
218
  label: "Windsurf",
@@ -182,6 +252,184 @@ var AGENT_LABELS_BY_TYPE = Object.fromEntries(
182
252
  var DISCONNECTABLE_AGENTS = Object.freeze(Object.values(AGENTS).flatMap((agent) => agent.disconnectable ? [agent.hookSource] : []));
183
253
  var REPO_AWARE_AGENTS = Object.freeze(Object.values(AGENTS).flatMap((agent) => agent.repoAware ? [agent.policyAgent] : []));
184
254
  var MANAGED_PROVIDERS = Object.freeze(Object.values(AGENTS).flatMap((agent) => agent.managedProvider ? [agent.hookSource] : []));
255
+ var BRIDGE_HOOK_SOURCES = Object.freeze(Object.values(AGENTS).flatMap((agent) => agent.bridged ? [agent.hookSource] : []));
256
+
257
+ // ../contracts/src/agent-wiring.ts
258
+ var COMPATIBLE_AGENT_TYPES = ["qwen_code", "codebuddy", "qoder", "droid", "devin"];
259
+ var CANONICAL_PATH_KEYS = ["file_path", "path"];
260
+ var SHELL_TOOLS = /* @__PURE__ */ new Set(["Bash", "PowerShell"]);
261
+ var PATH_TOOLS = /* @__PURE__ */ new Set(["Write", "Edit", "MultiEdit", "NotebookEdit", "Read"]);
262
+ var PHONE_ANSWERED_TOOLS = /* @__PURE__ */ new Set(["AskUserQuestion", "ExitPlanMode"]);
263
+ var firstString = (record, keys) => {
264
+ for (const key of keys) {
265
+ const value = record[key];
266
+ if (typeof value === "string" && value.length > 0) return value;
267
+ }
268
+ return void 0;
269
+ };
270
+ var canonicalToolName = (profile, toolName) => profile.toolAliases[toolName] ?? toolName;
271
+ var toToolLookup = (profile, toolName, toolInput, resolvePath = (path) => path) => {
272
+ const tool = canonicalToolName(profile, toolName);
273
+ if (SHELL_TOOLS.has(tool)) {
274
+ const command = firstString(toolInput, ["command"]);
275
+ if (!command) return { tool, input: toolInput, pathless: false };
276
+ const context = Object.fromEntries(
277
+ profile.shellContextKeys.flatMap((key) => toolInput[key] === void 0 ? [] : [[key, toolInput[key]]])
278
+ );
279
+ return { tool, input: { command, ...context }, pathless: false };
280
+ }
281
+ if (!PATH_TOOLS.has(tool)) return { tool, input: toolInput, pathless: false };
282
+ const filePath = firstString(toolInput, [...profile.pathInputKeys, ...CANONICAL_PATH_KEYS]);
283
+ if (!filePath) return { tool, input: toolInput, pathless: true };
284
+ return { tool, input: { ...toolInput, file_path: resolvePath(filePath) }, pathless: false };
285
+ };
286
+ var renderPreToolUseVerdict = (profile, verdict) => {
287
+ if (profile.wire === "permission_decision") return verdict;
288
+ const { permissionDecision, permissionDecisionReason, updatedInput } = verdict.hookSpecificOutput;
289
+ if (permissionDecision === "ask" || updatedInput) return void 0;
290
+ const stop = verdict.continue === false ? { continue: false, ...verdict.stopReason ? { stopReason: verdict.stopReason } : {} } : {};
291
+ return {
292
+ decision: permissionDecision === "allow" ? "approve" : "block",
293
+ ...permissionDecisionReason ? { reason: permissionDecisionReason } : {},
294
+ ...stop
295
+ };
296
+ };
297
+ var CLAUDE_SHAPED_EVENTS = [
298
+ "PreToolUse",
299
+ "PostToolUse",
300
+ "Stop",
301
+ "UserPromptSubmit",
302
+ "Notification",
303
+ "SessionStart",
304
+ "SessionEnd",
305
+ "StopFailure",
306
+ "PermissionRequest",
307
+ "PermissionDenied",
308
+ "SubagentStart",
309
+ "SubagentStop",
310
+ "PreCompact",
311
+ "PostCompact",
312
+ "TeammateIdle",
313
+ "Elicitation"
314
+ ];
315
+ var without = (...absent) => CLAUDE_SHAPED_EVENTS.filter((event) => !absent.includes(event));
316
+ var QWEN_CODE = {
317
+ agentType: "qwen_code",
318
+ source: "qwen",
319
+ label: "Qwen Code",
320
+ binary: "qwen",
321
+ configFile: [".qwen", "settings.json"],
322
+ hooksKeyPath: ["hooks"],
323
+ toolAliases: {
324
+ run_shell_command: "Bash",
325
+ write_file: "Write",
326
+ edit: "Edit",
327
+ replace: "Edit",
328
+ read_file: "Read",
329
+ WriteFile: "Write",
330
+ ReadFile: "Read"
331
+ },
332
+ extraMatchers: ["mcp__.*"],
333
+ pathInputKeys: ["absolute_path"],
334
+ shellContextKeys: ["directory"],
335
+ events: without("TeammateIdle", "Elicitation", "PermissionDenied"),
336
+ wire: "permission_decision",
337
+ mcp: { shape: "gemini_http", file: [".qwen", "settings.json"], trusted: true },
338
+ instructions: { file: [".qwen", "QWEN.md"], label: "Qwen Code" },
339
+ permissionRuleFile: null
340
+ };
341
+ var CODEBUDDY = {
342
+ agentType: "codebuddy",
343
+ source: "codebuddy",
344
+ label: "CodeBuddy",
345
+ binary: "codebuddy",
346
+ configFile: [".codebuddy", "settings.json"],
347
+ hooksKeyPath: ["hooks"],
348
+ toolAliases: {},
349
+ extraMatchers: ["mcp__.*"],
350
+ pathInputKeys: [],
351
+ shellContextKeys: [],
352
+ events: without("Elicitation", "PermissionDenied"),
353
+ wire: "permission_decision",
354
+ mcp: { shape: "claude_http", file: [".codebuddy", ".mcp.json"], trusted: false },
355
+ instructions: { file: [".codebuddy", "CODEBUDDY.md"], label: "CodeBuddy" },
356
+ permissionRuleFile: [".codebuddy", "settings.json"]
357
+ };
358
+ var QODER = {
359
+ agentType: "qoder",
360
+ source: "qoder",
361
+ label: "Qoder",
362
+ binary: "qoder",
363
+ configFile: [".qoder", "settings.json"],
364
+ hooksKeyPath: ["hooks"],
365
+ toolAliases: {},
366
+ extraMatchers: ["mcp__.*"],
367
+ pathInputKeys: [],
368
+ shellContextKeys: [],
369
+ events: without("Elicitation", "PermissionDenied"),
370
+ wire: "permission_decision",
371
+ mcp: { shape: "claude_http", file: [".qoder", "settings.json"], trusted: true },
372
+ instructions: null,
373
+ permissionRuleFile: null
374
+ };
375
+ var DROID = {
376
+ agentType: "droid",
377
+ source: "droid",
378
+ label: "Droid",
379
+ binary: "droid",
380
+ configFile: [".factory", "hooks.json"],
381
+ hooksKeyPath: [],
382
+ toolAliases: {
383
+ Execute: "Bash",
384
+ Create: "Write",
385
+ ApplyPatch: "Edit",
386
+ FetchUrl: "WebFetch"
387
+ },
388
+ extraMatchers: ["mcp__.*"],
389
+ pathInputKeys: [],
390
+ shellContextKeys: [],
391
+ events: ["PreToolUse", "PostToolUse", "UserPromptSubmit", "Notification", "Stop", "SubagentStop", "PreCompact", "SessionStart", "SessionEnd"],
392
+ wire: "permission_decision",
393
+ mcp: null,
394
+ instructions: null,
395
+ permissionRuleFile: null
396
+ };
397
+ var DEVIN = {
398
+ agentType: "devin",
399
+ source: "devin",
400
+ label: "Devin CLI",
401
+ binary: "devin",
402
+ configFile: [".config", "devin", "config.json"],
403
+ hooksKeyPath: ["hooks"],
404
+ toolAliases: {
405
+ exec: "Bash",
406
+ write: "Write",
407
+ edit: "Edit",
408
+ read: "Read",
409
+ webfetch: "WebFetch",
410
+ web_search: "WebSearch",
411
+ run_subagent: "Task"
412
+ },
413
+ extraMatchers: ["mcp__.*"],
414
+ pathInputKeys: [],
415
+ shellContextKeys: [],
416
+ events: ["PreToolUse", "PostToolUse", "UserPromptSubmit", "Stop", "SessionStart", "SessionEnd"],
417
+ wire: "legacy_decision",
418
+ mcp: null,
419
+ instructions: null,
420
+ permissionRuleFile: null
421
+ };
422
+ var HOOK_COMPATIBLE_PROFILES = Object.freeze([QWEN_CODE, CODEBUDDY, QODER, DROID, DEVIN]);
423
+ var hookCompatibleProfile = (agentType) => HOOK_COMPATIBLE_PROFILES.find((profile) => profile.agentType === agentType);
424
+ var hookCompatibleProfileBySource = (source) => HOOK_COMPATIBLE_PROFILES.find((profile) => profile.source === source);
425
+ var compatibleConfigDir = (profile) => profile.configFile.slice(0, -1);
426
+ var compatibleTargetFiles = (profile) => {
427
+ const seen = /* @__PURE__ */ new Map();
428
+ for (const file of [profile.configFile, profile.mcp?.file, profile.permissionRuleFile, profile.instructions?.file]) {
429
+ if (file) seen.set(file.join("/"), file);
430
+ }
431
+ return [...seen.values()];
432
+ };
185
433
 
186
434
  // ../contracts/src/index.ts
187
435
  var KEY_SCOPES = ["full_access", "agent", "connector", "bound"];
@@ -290,7 +538,15 @@ var HOOK_BUDGETS = {
290
538
  // rather than one we are told. Chosen to match Claude Code, because what it
291
539
  // bounds is how long the person's tool call sits unanswered before Pushary
292
540
  // stops asking and hands it back to the terminal.
293
- opencode: { budgetSeconds: 120, guardSeconds: 10 }
541
+ opencode: { budgetSeconds: 120, guardSeconds: 10 },
542
+ // The hook-compatible agents take a per-hook `timeout` in seconds exactly as
543
+ // Claude Code does, and `compatibleHookEvents` writes Claude's own numbers into
544
+ // their config, so what we may wait for is what we registered for.
545
+ qwen: { budgetSeconds: 600, guardSeconds: 10 },
546
+ codebuddy: { budgetSeconds: 600, guardSeconds: 10 },
547
+ qoder: { budgetSeconds: 600, guardSeconds: 10 },
548
+ droid: { budgetSeconds: 600, guardSeconds: 10 },
549
+ devin: { budgetSeconds: 600, guardSeconds: 10 }
294
550
  };
295
551
  var hookMaxWaitSeconds = (agent) => Math.max(HOOK_BUDGETS[agent].budgetSeconds - HOOK_BUDGETS[agent].guardSeconds, 1);
296
552
  var HOOK_HOLD_BUDGET_FLAG = "--hold-budget";
@@ -1430,8 +1686,20 @@ var pendingCommandEvents = (source) => {
1430
1686
  // so there is nothing for this to print.
1431
1687
  case "opencode":
1432
1688
  return [];
1689
+ case "qwen":
1690
+ case "codebuddy":
1691
+ case "qoder":
1692
+ case "droid":
1693
+ case "devin":
1694
+ return compatiblePendingCommandEvents(source);
1433
1695
  }
1434
1696
  };
1697
+ var COMPATIBLE_PENDING_COMMAND_EVENTS = ["PostToolUse", "UserPromptSubmit"];
1698
+ var compatiblePendingCommandEvents = (source) => {
1699
+ const profile = hookCompatibleProfileBySource(source);
1700
+ if (!profile || profile.wire !== "permission_decision") return [];
1701
+ return COMPATIBLE_PENDING_COMMAND_EVENTS.filter((event) => profile.events.includes(event));
1702
+ };
1435
1703
  var claudePermissionRequestOutput = (decision, reason, updatedInput) => ({
1436
1704
  hookSpecificOutput: {
1437
1705
  hookEventName: "PermissionRequest",
@@ -1633,6 +1901,15 @@ export {
1633
1901
  DISCONNECTABLE_AGENTS,
1634
1902
  REPO_AWARE_AGENTS,
1635
1903
  MANAGED_PROVIDERS,
1904
+ COMPATIBLE_AGENT_TYPES,
1905
+ PHONE_ANSWERED_TOOLS,
1906
+ toToolLookup,
1907
+ renderPreToolUseVerdict,
1908
+ HOOK_COMPATIBLE_PROFILES,
1909
+ hookCompatibleProfile,
1910
+ hookCompatibleProfileBySource,
1911
+ compatibleConfigDir,
1912
+ compatibleTargetFiles,
1636
1913
  hookWritePath,
1637
1914
  isHookActivationReport,
1638
1915
  hookActivationResult,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  describeKeyCheck,
3
3
  keyCheckFromResponse
4
- } from "./chunk-3RVCQDC4.js";
4
+ } from "./chunk-BOZETFXB.js";
5
5
  import {
6
6
  createIo
7
7
  } from "./chunk-5RUIFDTP.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  guardBinary
3
- } from "./chunk-JBJBVERL.js";
3
+ } from "./chunk-LTPQKBJH.js";
4
4
 
5
5
  // src/bell/install.ts
6
6
  import { join } from "path";
@@ -2,17 +2,17 @@ import {
2
2
  CLAUDE_HOOK_EVENTS,
3
3
  GEMINI_HOOK_EVENTS,
4
4
  hasGeminiHooks
5
- } from "./chunk-PD6JY33P.js";
5
+ } from "./chunk-2PS3DTHQ.js";
6
6
  import {
7
7
  CODEX_HOOK_EVENTS,
8
8
  hasCodexHooks,
9
9
  holdBudgetOf
10
- } from "./chunk-JBJBVERL.js";
10
+ } from "./chunk-LTPQKBJH.js";
11
11
  import {
12
12
  CURSOR_GATE_EVENTS,
13
13
  HOOK_LOCATOR_BINARY,
14
14
  hookCommandHoldBudget
15
- } from "./chunk-OUAE3GKO.js";
15
+ } from "./chunk-TTBRBWAK.js";
16
16
 
17
17
  // src/diagnostics/wiring.ts
18
18
  var record = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  HOOK_HOLD_BUDGET_ENV,
3
3
  hookHoldBudgetProof
4
- } from "./chunk-OUAE3GKO.js";
4
+ } from "./chunk-TTBRBWAK.js";
5
5
 
6
6
  // src/hold-budget.ts
7
7
  var takeHookHoldBudget = (args = process.argv.slice(2), env = process.env) => {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  HOOK_BUDGETS,
3
3
  OPENCODE_APPROVAL_EVENT
4
- } from "./chunk-OUAE3GKO.js";
4
+ } from "./chunk-TTBRBWAK.js";
5
5
 
6
6
  // src/opencode-plugin.ts
7
7
  var OPENCODE_PLUGIN_MARKER = "pushary-opencode-plugin w1";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  parseVersion
3
- } from "./chunk-PD6JY33P.js";
3
+ } from "./chunk-2PS3DTHQ.js";
4
4
 
5
5
  // src/setup/agent-probe.ts
6
6
  import { execSync } from "child_process";
@@ -2,24 +2,24 @@ import {
2
2
  detectProviderLiveCapabilities,
3
3
  hasSpawnProvider,
4
4
  resolveControlPolicy
5
- } from "./chunk-WGV3VY7O.js";
5
+ } from "./chunk-IYA3NCZG.js";
6
6
  import {
7
7
  daemonHasRemoteProof,
8
8
  daemonServiceManagerAvailable,
9
9
  hasDaemonServiceDefinition,
10
10
  readDaemonNeedsLogin,
11
11
  readDaemonStatus
12
- } from "./chunk-CRFLU455.js";
12
+ } from "./chunk-MSOFZYI3.js";
13
13
  import {
14
14
  getMachineId
15
- } from "./chunk-562UJ2DA.js";
15
+ } from "./chunk-7WMFPYR5.js";
16
16
  import {
17
17
  getPackageVersion
18
18
  } from "./chunk-DINDL2CF.js";
19
19
  import {
20
20
  readControlMode,
21
21
  readKeySource
22
- } from "./chunk-4PBCNVI3.js";
22
+ } from "./chunk-DOYARIYB.js";
23
23
  import {
24
24
  getBaseUrl
25
25
  } from "./chunk-2UMNXADU.js";
@@ -8,15 +8,15 @@ import {
8
8
  reapplyGeminiSettings,
9
9
  reapplyVsCodePlugin,
10
10
  repairCodexHolds
11
- } from "./chunk-LWKPMSBB.js";
12
- import "./chunk-K4XFCEVI.js";
13
- import "./chunk-QS55LDX4.js";
14
- import "./chunk-JXELRCU5.js";
15
- import "./chunk-PD6JY33P.js";
16
- import "./chunk-OPR2BPD4.js";
17
- import "./chunk-JBJBVERL.js";
11
+ } from "./chunk-R744XA2M.js";
12
+ import "./chunk-Y55JNI2I.js";
13
+ import "./chunk-MGI6MLFU.js";
14
+ import "./chunk-XK34HTMW.js";
15
+ import "./chunk-2PS3DTHQ.js";
16
+ import "./chunk-EMCNSBF3.js";
17
+ import "./chunk-LTPQKBJH.js";
18
18
  import "./chunk-4LL6LG5X.js";
19
- import "./chunk-OUAE3GKO.js";
19
+ import "./chunk-TTBRBWAK.js";
20
20
  export {
21
21
  inspectConfiguredManagedProviders,
22
22
  reapplyAllAgents,