@pushary/agent-hooks 1.7.3 → 1.8.1

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 (108) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +39 -19
  3. package/data/SKILL.md +8 -8
  4. package/data/cowork/SKILL.md +2 -2
  5. package/data/cursor-plugin/README.md +2 -2
  6. package/data/cursor-plugin/scripts/pushary-gate.mjs +2 -21
  7. package/data/cursor-plugin/scripts/redaction.mjs +53 -0
  8. package/data/cursor-plugin/skills/pushary/SKILL.md +7 -7
  9. package/data/vscode-plugin/README.md +4 -4
  10. package/data/vscode-plugin/scripts/pushary-gate.mjs +3 -23
  11. package/data/vscode-plugin/scripts/redaction.mjs +53 -0
  12. package/data/vscode-plugin/skills/pushary/SKILL.md +7 -7
  13. package/dist/bin/pushary-bell-hook.js +23 -23
  14. package/dist/bin/pushary-bell.js +9 -9
  15. package/dist/bin/pushary-claude.js +26 -26
  16. package/dist/bin/pushary-clean.js +97 -111
  17. package/dist/bin/pushary-codex-bridge.js +18 -18
  18. package/dist/bin/pushary-codex-hook.js +42 -43
  19. package/dist/bin/pushary-codex.js +13 -13
  20. package/dist/bin/pushary-connect.js +13 -13
  21. package/dist/bin/pushary-cowork.js +5 -5
  22. package/dist/bin/pushary-daemon.js +27 -27
  23. package/dist/bin/pushary-disconnect.js +18 -18
  24. package/dist/bin/pushary-doctor.js +92 -86
  25. package/dist/bin/pushary-elicitation-hook.js +25 -25
  26. package/dist/bin/pushary-gemini-bridge.js +12 -12
  27. package/dist/bin/pushary-gemini-hook.js +29 -30
  28. package/dist/bin/pushary-hook.js +32 -32
  29. package/dist/bin/pushary-login.js +12 -12
  30. package/dist/bin/pushary-logout.js +7 -7
  31. package/dist/bin/pushary-mcp.js +85 -28
  32. package/dist/bin/pushary-mode.js +9 -9
  33. package/dist/bin/pushary-notification-hook.js +28 -28
  34. package/dist/bin/pushary-opencode-hook.js +28 -29
  35. package/dist/bin/pushary-permission-denied-hook.js +32 -32
  36. package/dist/bin/pushary-permission-hook.js +31 -31
  37. package/dist/bin/pushary-post-hook.js +28 -28
  38. package/dist/bin/pushary-prompt-hook.js +28 -28
  39. package/dist/bin/pushary-session-end-hook.js +28 -28
  40. package/dist/bin/pushary-session-start-hook.js +32 -32
  41. package/dist/bin/pushary-setup.js +62 -129
  42. package/dist/bin/pushary-stats.js +5 -5
  43. package/dist/bin/pushary-status.js +15 -15
  44. package/dist/bin/pushary-stop-hook.js +28 -28
  45. package/dist/bin/pushary-stopfailure-hook.js +28 -28
  46. package/dist/bin/pushary-suggestions.js +4 -4
  47. package/dist/bin/pushary-transcript-register.js +19 -19
  48. package/dist/bin/pushary-transcripts.js +7 -7
  49. package/dist/bin/pushary-upgrade.js +236 -110
  50. package/dist/bin/pushary-wait.js +9 -9
  51. package/dist/bin/pushary.js +6 -6
  52. package/dist/{chunk-DUQO4C4I.js → chunk-2SLCHCVN.js} +3 -3
  53. package/dist/{chunk-YYCTF4Q5.js → chunk-35X5UDML.js} +7 -7
  54. package/dist/{chunk-OVC5QXN5.js → chunk-4A3UQERT.js} +1 -1
  55. package/dist/chunk-5DGNEUXK.js +73 -0
  56. package/dist/{chunk-62CVUUNU.js → chunk-5Y2DY6X4.js} +2 -2
  57. package/dist/{chunk-G4GLCLKK.js → chunk-5YY3IJT4.js} +159 -36
  58. package/dist/{chunk-KJXUIPS4.js → chunk-64H5IZZD.js} +28 -16
  59. package/dist/{chunk-OTNOANMX.js → chunk-6TK4IY3A.js} +8 -8
  60. package/dist/{chunk-LPNJLKBQ.js → chunk-72WOCX22.js} +1 -1
  61. package/dist/{chunk-IRZG3HEU.js → chunk-7ITOAMCD.js} +1 -1
  62. package/dist/{chunk-G62JL2NT.js → chunk-7U7ZWUTR.js} +1 -1
  63. package/dist/{chunk-IPSRMLCJ.js → chunk-ASWRMBOM.js} +1 -1
  64. package/dist/{chunk-5S2VBSJI.js → chunk-CB23AO4D.js} +2 -2
  65. package/dist/{chunk-VKVSRCBO.js → chunk-CHMOVJ2M.js} +1 -1
  66. package/dist/{chunk-BGBLLHZ4.js → chunk-DLEKCAQL.js} +1 -1
  67. package/dist/{chunk-EEEJ2JIL.js → chunk-DVW2MYCM.js} +3 -3
  68. package/dist/{chunk-AWVNAYGD.js → chunk-DXBS2EL7.js} +1 -1
  69. package/dist/{chunk-ZKJ34T2F.js → chunk-EIGJYCOE.js} +31 -17
  70. package/dist/{chunk-U6RVDUJ5.js → chunk-F6NTWZZC.js} +283 -41
  71. package/dist/{chunk-7RUJKCR4.js → chunk-FLQPM2GQ.js} +2 -2
  72. package/dist/{chunk-TCVMK6GI.js → chunk-GBNQXYN4.js} +4 -4
  73. package/dist/{chunk-G6RRVJOG.js → chunk-GH6KGWMC.js} +6 -6
  74. package/dist/chunk-GU3EJCVV.js +43 -0
  75. package/dist/{chunk-6JQFIHZC.js → chunk-HBWC3JVZ.js} +3 -3
  76. package/dist/{chunk-IWJKSIB4.js → chunk-HMNR7B2F.js} +1 -1
  77. package/dist/{chunk-NOI3XTCY.js → chunk-HOEB6AKG.js} +1 -1
  78. package/dist/{chunk-62VT3BPH.js → chunk-HQRCVEI2.js} +32 -17
  79. package/dist/{chunk-MIXWMA73.js → chunk-HTEGMMT3.js} +3 -3
  80. package/dist/{chunk-BIH2Y2HP.js → chunk-HVDMGDYV.js} +2 -2
  81. package/dist/{chunk-VE7TXLR4.js → chunk-I4HKMUZQ.js} +3 -3
  82. package/dist/{chunk-YPUBA2FL.js → chunk-INSMZNS7.js} +5 -5
  83. package/dist/{chunk-G3OMOTJ4.js → chunk-JRQRNNGA.js} +3 -3
  84. package/dist/{chunk-N5MZH5A6.js → chunk-KB2FTO4O.js} +4 -4
  85. package/dist/{chunk-O3JDWNLU.js → chunk-LK2S5XIV.js} +183 -28
  86. package/dist/{chunk-YC27PROF.js → chunk-MMVCI6DT.js} +20 -5
  87. package/dist/{chunk-3EUBQARL.js → chunk-MYHG7PX2.js} +1 -1
  88. package/dist/{chunk-EADXTSHE.js → chunk-N6JJJTPH.js} +6 -3
  89. package/dist/{chunk-PRNFSORD.js → chunk-NHCUXTEM.js} +1 -1
  90. package/dist/{chunk-KEL5MXRL.js → chunk-NOLPURUI.js} +1 -1
  91. package/dist/{chunk-WTJM7PSL.js → chunk-OCVVSRDA.js} +3 -3
  92. package/dist/{chunk-R6OYCUNK.js → chunk-ON5JW2HP.js} +1 -1
  93. package/dist/{chunk-UOQRM7JQ.js → chunk-QB6QYZ6B.js} +5 -5
  94. package/dist/{chunk-7OA34PNW.js → chunk-T55H6YEP.js} +40 -10
  95. package/dist/{chunk-D6OODZCM.js → chunk-TJMAXQ5Q.js} +2 -2
  96. package/dist/{chunk-WGMW7OXW.js → chunk-TKQ6LZQZ.js} +6 -6
  97. package/dist/{chunk-WPX67AKT.js → chunk-UMMCHS6P.js} +1 -1
  98. package/dist/{chunk-MZBRL5H5.js → chunk-UPLV5AJF.js} +108 -25
  99. package/dist/{chunk-P2VIBGXA.js → chunk-URNXU3FO.js} +1 -1
  100. package/dist/{chunk-EUGNVLMG.js → chunk-VFFHQC7W.js} +3 -1
  101. package/dist/{chunk-Y4ZH64UK.js → chunk-VZMIHERK.js} +2 -2
  102. package/dist/{chunk-RLW3JWDY.js → chunk-W2LJ4O3A.js} +2 -2
  103. package/dist/{chunk-LHC45YUC.js → chunk-ZJYJAD52.js} +1 -1
  104. package/dist/{reapply-PH5T4BGR.js → reapply-ICGTBHVE.js} +9 -9
  105. package/dist/src/index.js +20 -20
  106. package/package.json +1 -1
  107. package/dist/chunk-5GB22QYL.js +0 -255
  108. package/dist/chunk-VYPJHGG6.js +0 -92
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  readExistingMachineId
3
- } from "./chunk-OVC5QXN5.js";
3
+ } from "./chunk-4A3UQERT.js";
4
4
  import {
5
5
  NetworkError
6
6
  } from "./chunk-7QLSKOSU.js";
7
7
  import {
8
8
  getBaseUrl
9
- } from "./chunk-R6OYCUNK.js";
9
+ } from "./chunk-ON5JW2HP.js";
10
10
  import {
11
11
  clientContextHeaders,
12
12
  getPackageVersion
13
- } from "./chunk-G4GLCLKK.js";
13
+ } from "./chunk-5YY3IJT4.js";
14
14
 
15
15
  // src/cli/net.ts
16
16
  import { createRequire } from "module";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  SETUP_AGENT_CHOICES
3
- } from "./chunk-G4GLCLKK.js";
3
+ } from "./chunk-5YY3IJT4.js";
4
4
 
5
5
  // src/cli/commands.ts
6
- var NPX_LATEST_COMMAND = "npx @pushary/agent-hooks@latest";
6
+ var NPX_LATEST_COMMAND = "npx pushary@latest";
7
7
  var COMMAND_LIST = [
8
8
  {
9
9
  name: "cowork",
@@ -181,11 +181,11 @@ var SETUP_OPTIONS = [
181
181
  ];
182
182
  var AGENT_IDS = SETUP_AGENT_CHOICES.join(", ");
183
183
  var USAGE_EXAMPLES = [
184
- "npx @pushary/agent-hooks@latest setup",
185
- "npx @pushary/agent-hooks@latest setup --agents auto --yes --skip-phone",
186
- "npx @pushary/agent-hooks@latest setup --key-stdin --agents claude_code --yes < key.txt",
187
- "npx @pushary/agent-hooks@latest doctor",
188
- "npx @pushary/agent-hooks@latest mode push_only --for 30m",
184
+ `${NPX_LATEST_COMMAND} setup`,
185
+ `${NPX_LATEST_COMMAND} setup --agents auto --yes --skip-phone`,
186
+ `${NPX_LATEST_COMMAND} setup --key-stdin --agents claude_code --yes < key.txt`,
187
+ `${NPX_LATEST_COMMAND} doctor`,
188
+ `${NPX_LATEST_COMMAND} mode push_only --for 30m`,
189
189
  "pushary claude # native terminal, reachable from your phone",
190
190
  'pushary claude --remote -p "start the refactor" # start headless, drive from your phone',
191
191
  "pushary daemon # keep this machine ready to spawn a session"
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  pusharyDir
3
- } from "./chunk-MZBRL5H5.js";
3
+ } from "./chunk-UPLV5AJF.js";
4
4
  import {
5
5
  writeFileAtomic
6
6
  } from "./chunk-T7E75EKA.js";
@@ -0,0 +1,73 @@
1
+ import {
2
+ AUTO_DECISION_WINDOW_MS,
3
+ claimThrottle,
4
+ deriveToolTarget,
5
+ permissionDeniedAction,
6
+ releaseThrottle,
7
+ reportEvent
8
+ } from "./chunk-F6NTWZZC.js";
9
+ import {
10
+ DEFAULT_SESSION
11
+ } from "./chunk-N6IOSZOE.js";
12
+ import {
13
+ machineDecisionFor,
14
+ shouldDeferToNativeMode,
15
+ wireVerdictFor
16
+ } from "./chunk-5YY3IJT4.js";
17
+
18
+ // src/machine-decision-audit.ts
19
+ import { basename } from "path";
20
+ var reportMachineDenial = async (input, verdict, agent) => {
21
+ const decision = machineDecisionFor(wireVerdictFor(verdict, 0));
22
+ if (!decision) return;
23
+ const sessionKey = input.session_id || DEFAULT_SESSION;
24
+ const toolTarget = deriveToolTarget(input.tool_name, input.tool_input);
25
+ const throttleKey = `machinedecision:${agent.type}:${sessionKey}:${input.tool_name}:${decision.origin}:${toolTarget ?? ""}`;
26
+ const throttle = claimThrottle(throttleKey, AUTO_DECISION_WINDOW_MS);
27
+ if (throttle === "throttled") return;
28
+ if (throttle === "unavailable") {
29
+ console.error("[Pushary] Could not access the audit throttle; reporting this denial without deduplication.");
30
+ }
31
+ try {
32
+ const response = await reportEvent({
33
+ event: "permission_denied",
34
+ occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
35
+ toolUseId: input.tool_use_id,
36
+ agentType: agent.type,
37
+ agentName: `${agent.label} - ${basename(input.cwd ?? process.cwd())}`,
38
+ action: permissionDeniedAction(input.tool_name),
39
+ sessionId: input.session_id,
40
+ decisionSource: "policy_auto",
41
+ decisionOrigin: decision.origin,
42
+ decisionOutcome: decision.outcome,
43
+ toolName: input.tool_name,
44
+ toolTarget
45
+ }, { maxAttempts: 1, timeoutMs: 800, requireOk: true, skipDrain: true });
46
+ if (response?.ok !== true) throw new Error("Audit delivery was not acknowledged");
47
+ } catch {
48
+ console.error("[Pushary] Could not record the machine denial. The action remains blocked; its audit delivery will be retried on the next matching denial.");
49
+ if (throttle === "passed") {
50
+ try {
51
+ releaseThrottle(throttleKey);
52
+ } catch {
53
+ console.error("[Pushary] Could not reset the failed audit throttle.");
54
+ }
55
+ }
56
+ }
57
+ };
58
+
59
+ // src/native-defer.ts
60
+ var nativeDeferOptions = () => {
61
+ const respect = process.env.PUSHARY_RESPECT_PERMISSION_MODE;
62
+ const bypass = process.env.PUSHARY_DEFER_BYPASS;
63
+ return {
64
+ respectPermissionMode: !(respect === "0" || respect === "false"),
65
+ deferBypass: bypass === "1" || bypass === "true"
66
+ };
67
+ };
68
+ var defersToNativeMode = (permissionMode, toolName) => shouldDeferToNativeMode(permissionMode, toolName, nativeDeferOptions());
69
+
70
+ export {
71
+ reportMachineDenial,
72
+ defersToNativeMode
73
+ };
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  configFilePath
3
- } from "./chunk-R6OYCUNK.js";
3
+ } from "./chunk-ON5JW2HP.js";
4
4
  import {
5
5
  normalizeInstallSource
6
- } from "./chunk-G4GLCLKK.js";
6
+ } from "./chunk-5YY3IJT4.js";
7
7
 
8
8
  // src/install-source.ts
9
9
  import { readFileSync } from "fs";
@@ -22,7 +22,7 @@ var COWORK_STANDING_INSTRUCTIONS = `Pushary is connected as a custom connector.
22
22
  - If Pushary tools are missing or disabled, report that once and continue within my authorization. Do not claim a notification or approval was delivered.`;
23
23
 
24
24
  // ../contracts/src/agent-manifest.ts
25
- var AGENT_HOOKS_SETUP_COMMAND = "npx @pushary/agent-hooks@latest setup";
25
+ var PUSHARY_SETUP_COMMAND = "npx pushary@latest setup";
26
26
  var defaults = {
27
27
  hasStoredIdentity: true,
28
28
  hookSource: null,
@@ -54,7 +54,7 @@ var AGENTS = {
54
54
  managedProvider: true,
55
55
  enforcement: "enforced",
56
56
  connectVia: "Native hooks + MCP",
57
- setupCommand: AGENT_HOOKS_SETUP_COMMAND,
57
+ setupCommand: PUSHARY_SETUP_COMMAND,
58
58
  enforcementDetail: "Shell, writes and edits, subject to Claude Code permission mode and explicit policy."
59
59
  },
60
60
  claude_chat: {
@@ -81,7 +81,7 @@ var AGENTS = {
81
81
  managedProvider: true,
82
82
  enforcement: "enforced",
83
83
  connectVia: "Native hooks + MCP",
84
- setupCommand: AGENT_HOOKS_SETUP_COMMAND,
84
+ setupCommand: PUSHARY_SETUP_COMMAND,
85
85
  enforcementDetail: "Shell and apply_patch edits through native permission hooks; requires a compatible Codex runtime."
86
86
  },
87
87
  chatgpt: {
@@ -101,7 +101,7 @@ var AGENTS = {
101
101
  managedProvider: true,
102
102
  enforcement: "enforced",
103
103
  connectVia: "Native hooks + MCP",
104
- setupCommand: AGENT_HOOKS_SETUP_COMMAND,
104
+ setupCommand: PUSHARY_SETUP_COMMAND,
105
105
  enforcementDetail: "Shell, writes and edits through native BeforeTool hooks."
106
106
  },
107
107
  hermes: {
@@ -110,7 +110,7 @@ var AGENTS = {
110
110
  policyAgent: "hermes",
111
111
  enforcement: "enforced",
112
112
  connectVia: "Native Python plugin + approval transport",
113
- setupCommand: AGENT_HOOKS_SETUP_COMMAND,
113
+ setupCommand: PUSHARY_SETUP_COMMAND,
114
114
  enforcementDetail: "Hermes dangerous-command approvals when the Pushary transport is selected; optional PUSHARY_GATE_TOOLS gates named tools.",
115
115
  capabilityNote: "Uses the Python plugin, not a macOS bridge HookSource. CLI disconnect and managed-provider controls are not implemented for Hermes."
116
116
  },
@@ -123,7 +123,7 @@ var AGENTS = {
123
123
  disconnectable: true,
124
124
  enforcement: "enforced",
125
125
  connectVia: "Editor plugin hooks + MCP",
126
- setupCommand: AGENT_HOOKS_SETUP_COMMAND,
126
+ setupCommand: PUSHARY_SETUP_COMMAND,
127
127
  enforcementDetail: "With installed hooks: shell, MCP execution and Write/Delete/Edit tool calls. Plain MCP remains cooperative."
128
128
  },
129
129
  vscode: {
@@ -134,7 +134,7 @@ var AGENTS = {
134
134
  policyAgent: "vscode",
135
135
  enforcement: "enforced",
136
136
  connectVia: "Agent plugin hooks + MCP",
137
- setupCommand: AGENT_HOOKS_SETUP_COMMAND,
137
+ setupCommand: PUSHARY_SETUP_COMMAND,
138
138
  enforcementDetail: "PreToolUse approval hooks from the installed agent plugin; the host decides which events it exposes.",
139
139
  capabilityNote: "Has both a bridge HookSource and a per-agent policy profile. CLI disconnect and managed-provider controls are not implemented for VS Code."
140
140
  },
@@ -148,14 +148,14 @@ var AGENTS = {
148
148
  disconnectable: true,
149
149
  enforcement: "enforced",
150
150
  connectVia: "Generated plugin + MCP",
151
- setupCommand: AGENT_HOOKS_SETUP_COMMAND,
151
+ setupCommand: PUSHARY_SETUP_COMMAND,
152
152
  enforcementDetail: "Shell, writes, edits and web fetches when OpenCode itself asks for permission."
153
153
  },
154
154
  fx: {
155
155
  ...defaults,
156
156
  label: "fx",
157
157
  connectVia: "Local MCP bridge",
158
- setupCommand: AGENT_HOOKS_SETUP_COMMAND,
158
+ setupCommand: PUSHARY_SETUP_COMMAND,
159
159
  capabilityNote: "fx has no hooks that other tools can register, so Pushary cannot answer fx's own approval prompts. Setup turns off fx's terminal question tool so fx's agent asks through Pushary. fx's full-access mode ignores that setting; there the agent is only instructed to ask through Pushary."
160
160
  },
161
161
  qwen_code: {
@@ -168,7 +168,7 @@ var AGENTS = {
168
168
  disconnectable: true,
169
169
  enforcement: "enforced",
170
170
  connectVia: "Native hooks + MCP",
171
- setupCommand: AGENT_HOOKS_SETUP_COMMAND,
171
+ setupCommand: PUSHARY_SETUP_COMMAND,
172
172
  enforcementDetail: "Shell, writes and edits through native PreToolUse hooks, matched on Qwen's own tool names and their Claude-shaped aliases."
173
173
  },
174
174
  codebuddy: {
@@ -181,7 +181,7 @@ var AGENTS = {
181
181
  disconnectable: true,
182
182
  enforcement: "enforced",
183
183
  connectVia: "Native hooks + MCP",
184
- setupCommand: AGENT_HOOKS_SETUP_COMMAND,
184
+ setupCommand: PUSHARY_SETUP_COMMAND,
185
185
  enforcementDetail: "Shell, writes and edits through native PreToolUse hooks, plus PermissionRequest. CodeBuddy implements the Claude Code hook specification."
186
186
  },
187
187
  qoder: {
@@ -194,7 +194,7 @@ var AGENTS = {
194
194
  disconnectable: true,
195
195
  enforcement: "enforced",
196
196
  connectVia: "Native hooks + MCP",
197
- setupCommand: AGENT_HOOKS_SETUP_COMMAND,
197
+ setupCommand: PUSHARY_SETUP_COMMAND,
198
198
  enforcementDetail: "Shell, writes and edits through native PreToolUse hooks, plus PermissionRequest, over Qoder's superset of the Claude Code event list.",
199
199
  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."
200
200
  },
@@ -208,7 +208,7 @@ var AGENTS = {
208
208
  disconnectable: true,
209
209
  enforcement: "enforced",
210
210
  connectVia: "Native hooks",
211
- setupCommand: AGENT_HOOKS_SETUP_COMMAND,
211
+ setupCommand: PUSHARY_SETUP_COMMAND,
212
212
  enforcementDetail: "Execute, Create, Edit and ApplyPatch through native PreToolUse hooks in ~/.factory/hooks.json.",
213
213
  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."
214
214
  },
@@ -222,14 +222,14 @@ var AGENTS = {
222
222
  disconnectable: true,
223
223
  enforcement: "enforced",
224
224
  connectVia: "Native hooks",
225
- setupCommand: AGENT_HOOKS_SETUP_COMMAND,
225
+ setupCommand: PUSHARY_SETUP_COMMAND,
226
226
  enforcementDetail: "exec, write and edit through native PreToolUse hooks, answered in Devin's own approve/block schema.",
227
227
  capabilityNote: "Devin CLI answers PreToolUse with `{decision}` rather than a permission decision. Pushary blocks an unanswered approval because this adapter cannot request a native prompt reliably. Question and plan dialogs remain with Devin; this adapter does not render their answers. It also fires no Notification event."
228
228
  },
229
229
  windsurf: {
230
230
  ...defaults,
231
231
  label: "Windsurf",
232
- setupCommand: AGENT_HOOKS_SETUP_COMMAND,
232
+ setupCommand: PUSHARY_SETUP_COMMAND,
233
233
  setupChoice: "Other"
234
234
  },
235
235
  unknown: {
@@ -246,7 +246,7 @@ var AGENTS = {
246
246
  ...defaults,
247
247
  hasStoredIdentity: false,
248
248
  label: "Any MCP client",
249
- setupCommand: AGENT_HOOKS_SETUP_COMMAND,
249
+ setupCommand: PUSHARY_SETUP_COMMAND,
250
250
  setupChoice: "Other"
251
251
  },
252
252
  http: {
@@ -455,7 +455,7 @@ var compatibleTargetFiles = (profile) => {
455
455
  };
456
456
 
457
457
  // ../contracts/src/redaction.ts
458
- var CREDENTIAL_NAME = String.raw`(?:secret|token|password|passwd|api[_-]?key|access[_-]?key|client[_-]?secret|private[_-]?key)["']?`;
458
+ var CREDENTIAL_NAME = String.raw`(?:authorization|secret|token|password|passwd|api[_-]?key|access[_-]?key|client[_-]?secret|private[_-]?key)["']?`;
459
459
  var CREDENTIAL_KEY = String.raw`${CREDENTIAL_NAME}\s*[=:]\s*`;
460
460
  var DISPLAYED_CREDENTIAL_KEY = String.raw`${CREDENTIAL_NAME}(?:[ \t]*:[ \t]*|[ \t]+=[ \t]*|=)`;
461
461
  var SHELL_INERT_UNIT = String.raw`(?:[A-Za-z0-9_\-./+=:@%^!#]|\\[^\s'"])`;
@@ -467,6 +467,7 @@ var credentialAssignmentRule = (key, doubleQuoted, singleQuoted, bare) => ({
467
467
  replacement: "$1$2$3$4[redacted]$2$3"
468
468
  });
469
469
  var DISPLAYED_SECRET_SHAPES = {
470
+ separator: String.raw`[ \t]`,
470
471
  privateKeyBody: String.raw`${PEM_LINE_BREAK}?(?:(?:Proc-Type|DEK-Info): [A-Za-z0-9,-]+${PEM_LINE_BREAK})*(?:[A-Za-z0-9+/=\r\n]|\\[rn])*?`,
471
472
  urlPassword: `${SHELL_INERT_URL_PASSWORD_UNIT}+`,
472
473
  authorizationValue: `${SHELL_INERT_UNIT}+`,
@@ -478,6 +479,7 @@ var DISPLAYED_SECRET_SHAPES = {
478
479
  )
479
480
  };
480
481
  var CUT_OFF_SECRET_SHAPES = {
482
+ separator: String.raw`\s`,
481
483
  privateKeyBody: String.raw`[\s\S]*?`,
482
484
  urlPassword: String.raw`[^\s@/]+`,
483
485
  authorizationValue: String.raw`\S+`,
@@ -504,8 +506,8 @@ var secretRedactionRules = (shapes) => [
504
506
  { pattern: /\bxai-[A-Za-z0-9]{16,}\b/g, replacement: "[redacted]" },
505
507
  { pattern: /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g, replacement: "[redacted]" },
506
508
  { pattern: new RegExp(String.raw`\b([a-z][a-z0-9+.-]*:\/\/[^\s:/@]+:)${shapes.urlPassword}@`, "gi"), replacement: "$1[redacted]@" },
507
- { pattern: /\bbearer\s+[A-Za-z0-9._~+/=-]+/gi, replacement: "bearer [redacted]" },
508
- { pattern: new RegExp(String.raw`\bauthorization:\s*${shapes.authorizationValue}`, "gi"), replacement: "authorization: [redacted]" },
509
+ { pattern: new RegExp(String.raw`\bbearer${shapes.separator}+[A-Za-z0-9._~+/=-]+`, "gi"), replacement: "bearer [redacted]" },
510
+ { pattern: new RegExp(String.raw`\bauthorization:${shapes.separator}*${shapes.authorizationValue}`, "gi"), replacement: "authorization: [redacted]" },
509
511
  shapes.credentialAssignment
510
512
  ];
511
513
  var SECRET_REDACTION_RULES = secretRedactionRules(DISPLAYED_SECRET_SHAPES);
@@ -643,7 +645,7 @@ var parseAgentQuestionAnswers = (questions, value) => {
643
645
  return answers;
644
646
  };
645
647
  var INSTALL_SOURCES = [
646
- /** `npx @pushary/agent-hooks@latest ...`, the documented one-liner. */
648
+ /** `npx pushary@latest ...`, the documented one-liner. */
647
649
  "npx",
648
650
  /** A global or project npm install, invoked as `pushary`. */
649
651
  "npm",
@@ -659,9 +661,13 @@ var INSTALL_SOURCES = [
659
661
  "framework_adapter",
660
662
  /** The browser onboarding wizard. */
661
663
  "dashboard",
662
- /** Reported nothing, or reported something we do not recognise. */
663
664
  /** The macOS app pairing a phone from its own onboarding. */
664
665
  "mac_app",
666
+ /** The phone app's own sign-up, which provisions the agent site before any web step. */
667
+ "mobile_app",
668
+ /** The CLI's device-code sign-in page (`/cli/authorize`), which provisions a site before any web step. */
669
+ "cli_login",
670
+ /** Reported nothing, or reported something we do not recognise. */
665
671
  "unknown"
666
672
  ];
667
673
  var isInstallSource = (value) => typeof value === "string" && INSTALL_SOURCES.includes(value);
@@ -1535,6 +1541,16 @@ var API_KEY_PATTERN = /^pk_[a-f0-9]+\.[a-f0-9]+$/;
1535
1541
  var isValidApiKey = (value) => API_KEY_PATTERN.test(value);
1536
1542
  var ACTION_BODY_MAX = 4e3;
1537
1543
  var DECISION_LINE_MAX = 500;
1544
+ var ASK_QUESTION_MAX = 500;
1545
+ var ASK_AGENT_NAME_MAX = 100;
1546
+ var TRUNCATION_MARK = "\u2026";
1547
+ var isHighSurrogate = (code) => code >= 55296 && code <= 56319;
1548
+ var truncateLine = (text, max, mark = TRUNCATION_MARK) => {
1549
+ if (text.length <= max) return text;
1550
+ const end = max - mark.length;
1551
+ const keep = isHighSurrogate(text.charCodeAt(end - 1)) ? end - 1 : end;
1552
+ return `${text.slice(0, keep)}${mark}`;
1553
+ };
1538
1554
  var APPROVAL_FATIGUE_FLAG_PATTERNS = [
1539
1555
  /\brm\s+-[a-z]*r/i,
1540
1556
  /\brmdir\b/i,
@@ -2539,40 +2555,126 @@ var hookActivationResult = (report) => {
2539
2555
  return report && !report.truncated && report.evidence.length === 1 ? report.evidence[0].result : "unverified";
2540
2556
  };
2541
2557
 
2558
+ // src/cli-package-name.ts
2559
+ var CANONICAL_PACKAGE = "pushary";
2560
+ var LEGACY_PACKAGE = "@pushary/agent-hooks";
2561
+ var CLI_PACKAGE_NAMES = [CANONICAL_PACKAGE, LEGACY_PACKAGE];
2562
+ var isCliPackageName = (value) => typeof value === "string" && CLI_PACKAGE_NAMES.some((name) => name === value);
2563
+ var cliPackagePathSegments = (name) => name.split("/");
2564
+
2565
+ // src/global-package.ts
2566
+ import { posix, win32 } from "path";
2567
+ var OWNERSHIP_PROBE_COMMAND = "pushary-hook";
2568
+ var pathApiFor = (platform) => platform === "win32" ? win32 : posix;
2569
+ var POSIX_GLOBAL_ROOT_SEGMENTS = ["lib", "node_modules"];
2570
+ var UPGRADE_ENTRY_SEGMENTS = ["dist", "bin", "pushary-upgrade.js"];
2571
+ var globalRootFor = (prefix, platform) => platform === "win32" ? win32.join(prefix, "node_modules") : posix.join(prefix, ...POSIX_GLOBAL_ROOT_SEGMENTS);
2572
+ var globalPackageFolder = (root, name, platform) => pathApiFor(platform).join(root, ...cliPackagePathSegments(name));
2573
+ var globalUpgradeEntry = (prefix, name, platform) => pathApiFor(platform).join(globalPackageFolder(globalRootFor(prefix, platform), name, platform), ...UPGRADE_ENTRY_SEGMENTS);
2574
+ var isInsideFolder = (target, folder, platform) => {
2575
+ const pathApi = pathApiFor(platform);
2576
+ const relativePath = pathApi.relative(folder, target);
2577
+ return relativePath !== "" && !relativePath.startsWith("..") && !pathApi.isAbsolute(relativePath);
2578
+ };
2579
+ var linkPointsInto = (evidence, targets, name) => evidence.globalRoots.some((root) => {
2580
+ const folder = globalPackageFolder(root, name, evidence.platform);
2581
+ return targets.some((target) => isInsideFolder(target, folder, evidence.platform));
2582
+ });
2583
+ var ownerFromInstalled = (installed, whenNone) => {
2584
+ const [only, ...others] = installed;
2585
+ if (only === void 0) return whenNone;
2586
+ if (others.length > 0) return { kind: "unknown", reason: "both_installed" };
2587
+ return { kind: "owned", name: only };
2588
+ };
2589
+ var decideCommandOwner = (evidence) => {
2590
+ const { link } = evidence;
2591
+ if (link.kind === "resolved") {
2592
+ const name = CLI_PACKAGE_NAMES.find((candidate) => linkPointsInto(evidence, link.targets, candidate));
2593
+ return name === void 0 ? { kind: "unknown", reason: "foreign_command" } : { kind: "owned", name };
2594
+ }
2595
+ const whenNone = link.kind === "absent" ? { kind: "none" } : { kind: "unknown", reason: "unreadable_command" };
2596
+ return ownerFromInstalled(evidence.installed, whenNone);
2597
+ };
2598
+ var CMD_SHIM_TARGET = /"%(?:~dp0|dp0%)\\([^"]+?)"\s+%[*]/;
2599
+ var cmdShimTarget = (shimDir, contents) => {
2600
+ const relativeTarget = CMD_SHIM_TARGET.exec(contents)?.[1];
2601
+ return relativeTarget === void 0 ? void 0 : win32.resolve(shimDir, relativeTarget);
2602
+ };
2603
+ var launchedPackage = (ownName) => ownName ?? LEGACY_PACKAGE;
2604
+ var globalInstallTarget = (owner, ownName) => {
2605
+ switch (owner.kind) {
2606
+ case "owned":
2607
+ return owner.name;
2608
+ case "none":
2609
+ return launchedPackage(ownName);
2610
+ case "unknown":
2611
+ return LEGACY_PACKAGE;
2612
+ }
2613
+ };
2614
+ var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2615
+ var declaresOwnershipProbe = (bin) => isRecord2(bin) && typeof bin[OWNERSHIP_PROBE_COMMAND] === "string";
2616
+ var cliManifestName = (manifest) => {
2617
+ if (!isRecord2(manifest) || !isCliPackageName(manifest.name) || !declaresOwnershipProbe(manifest.bin)) return void 0;
2618
+ return manifest.name;
2619
+ };
2620
+ var classifyGlobalFolder = (name, read) => {
2621
+ if (read.kind === "unreadable") return { kind: "unseen" };
2622
+ const { manifest } = read;
2623
+ if (!isRecord2(manifest) || cliManifestName(manifest) !== name) return { kind: "foreign" };
2624
+ return { kind: "ours", installed: { name, version: typeof manifest.version === "string" ? manifest.version : void 0 } };
2625
+ };
2626
+ var classifyGlobalInstall = (installed, owner) => {
2627
+ const [only, ...others] = installed;
2628
+ if (only === void 0) return { kind: "absent" };
2629
+ if (others.length === 0) return { kind: "single", installed: only };
2630
+ return { kind: "both", installed, owner };
2631
+ };
2632
+ var isUninstallable = (evidence) => evidence.listing !== "absent" && evidence.folder !== "foreign";
2633
+ var globalPackagesToUninstall = (evidence) => evidence.filter(isUninstallable).map((entry) => entry.name);
2634
+ var commandsPackage = (install) => {
2635
+ if (install.kind === "single") return install.installed;
2636
+ if (install.kind !== "both" || install.owner.kind !== "owned") return void 0;
2637
+ const ownerName = install.owner.name;
2638
+ return install.installed.find((installed) => installed.name === ownerName);
2639
+ };
2640
+
2542
2641
  // src/cli/version.ts
2543
2642
  import { readFileSync } from "fs";
2544
2643
  import { dirname, join, parse } from "path";
2545
2644
  import { fileURLToPath } from "url";
2546
- var PACKAGE_NAME = "@pushary/agent-hooks";
2547
2645
  var UNKNOWN_VERSION = "0.0.0";
2548
- var findOwnPackageJson = (start) => {
2646
+ var cliManifestNameAt = (manifestPath) => {
2647
+ try {
2648
+ return cliManifestName(JSON.parse(readFileSync(manifestPath, "utf-8")));
2649
+ } catch {
2650
+ return void 0;
2651
+ }
2652
+ };
2653
+ var findOwnPackage = (start) => {
2549
2654
  const { root } = parse(start);
2550
2655
  let dir = start;
2551
2656
  while (true) {
2552
- const candidate = join(dir, "package.json");
2553
- try {
2554
- const pkg = JSON.parse(readFileSync(candidate, "utf-8"));
2555
- if (pkg.name === PACKAGE_NAME) return candidate;
2556
- } catch {
2557
- }
2657
+ const name = cliManifestNameAt(join(dir, "package.json"));
2658
+ if (name !== void 0) return { root: dir, name };
2558
2659
  if (dir === root) return void 0;
2559
2660
  const parent = dirname(dir);
2560
2661
  if (parent === dir) return void 0;
2561
2662
  dir = parent;
2562
2663
  }
2563
2664
  };
2564
- var getPackageVersion = () => {
2565
- const root = ownPackageRoot();
2566
- return (root === void 0 ? void 0 : packageVersionAt(root)) ?? UNKNOWN_VERSION;
2567
- };
2568
- var ownPackageRoot = () => {
2665
+ var runningPackage = () => {
2569
2666
  try {
2570
- const found = findOwnPackageJson(dirname(fileURLToPath(import.meta.url)));
2571
- return found ? dirname(found) : void 0;
2667
+ return findOwnPackage(dirname(fileURLToPath(import.meta.url)));
2572
2668
  } catch {
2573
2669
  return void 0;
2574
2670
  }
2575
2671
  };
2672
+ var getPackageVersion = () => {
2673
+ const root = ownPackageRoot();
2674
+ return (root === void 0 ? void 0 : packageVersionAt(root)) ?? UNKNOWN_VERSION;
2675
+ };
2676
+ var ownPackageRoot = () => runningPackage()?.root;
2677
+ var ownPackageName = () => runningPackage()?.name;
2576
2678
  var packageVersionAt = (packageRoot) => {
2577
2679
  try {
2578
2680
  const manifest = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf-8"));
@@ -2657,6 +2759,9 @@ export {
2657
2759
  isValidApiKey,
2658
2760
  ACTION_BODY_MAX,
2659
2761
  DECISION_LINE_MAX,
2762
+ ASK_QUESTION_MAX,
2763
+ ASK_AGENT_NAME_MAX,
2764
+ truncateLine,
2660
2765
  isAnswerSource,
2661
2766
  buildDecisionEpisodeFeatures,
2662
2767
  resolveAutoResolveOrigin,
@@ -2700,8 +2805,26 @@ export {
2700
2805
  planElicitationAsk,
2701
2806
  elicitationContent,
2702
2807
  elicitationContentFromAnswers,
2808
+ CANONICAL_PACKAGE,
2809
+ LEGACY_PACKAGE,
2810
+ CLI_PACKAGE_NAMES,
2811
+ cliPackagePathSegments,
2812
+ OWNERSHIP_PROBE_COMMAND,
2813
+ POSIX_GLOBAL_ROOT_SEGMENTS,
2814
+ globalRootFor,
2815
+ globalPackageFolder,
2816
+ globalUpgradeEntry,
2817
+ decideCommandOwner,
2818
+ cmdShimTarget,
2819
+ launchedPackage,
2820
+ globalInstallTarget,
2821
+ classifyGlobalFolder,
2822
+ classifyGlobalInstall,
2823
+ globalPackagesToUninstall,
2824
+ commandsPackage,
2703
2825
  getPackageVersion,
2704
2826
  ownPackageRoot,
2827
+ ownPackageName,
2705
2828
  packageVersionAt,
2706
2829
  isNewerVersion,
2707
2830
  isReleaseVersion,
@@ -3,23 +3,25 @@ import {
3
3
  } from "./chunk-POFBE6ZY.js";
4
4
  import {
5
5
  autoUpdateState
6
- } from "./chunk-MZBRL5H5.js";
6
+ } from "./chunk-UPLV5AJF.js";
7
7
  import {
8
8
  readJsonSafe,
9
9
  writeJsonAtomic
10
10
  } from "./chunk-T7E75EKA.js";
11
11
  import {
12
+ CLI_PACKAGE_NAMES,
13
+ POSIX_GLOBAL_ROOT_SEGMENTS,
14
+ cliPackagePathSegments,
15
+ globalUpgradeEntry,
12
16
  ownPackageRoot
13
- } from "./chunk-G4GLCLKK.js";
17
+ } from "./chunk-5YY3IJT4.js";
14
18
 
15
19
  // src/auto-update.ts
16
20
  import { spawn } from "child_process";
17
- import { dirname, join } from "path";
21
+ import { dirname } from "path";
18
22
  var AUTO_UPDATE_DISABLE_ENV = "PUSHARY_DISABLE_AUTOUPDATE";
19
23
  var AUTO_UPDATE_INTERVAL_MS = 24 * 60 * 60 * 1e3;
20
24
  var AUTO_UPDATE_FLAG = "--auto";
21
- var GLOBAL_PACKAGE_SUBPATH = "/lib/node_modules/@pushary/agent-hooks";
22
- var UPGRADE_ENTRY_SUBPATH = ["dist", "bin", "pushary-upgrade.js"];
23
25
  var NON_GLOBAL_INSTALL_SEGMENTS = ["/_npx/", "/.volta/"];
24
26
  var AUTO_UPDATE_RESULTS = ["updated", "current", "needs_manual", "failed", "finish_pending"];
25
27
  var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
@@ -55,14 +57,24 @@ var autoUpdateOffReason = (input) => {
55
57
  if (input.platform === "linux") return "linux";
56
58
  return null;
57
59
  };
58
- var globalInstallPrefix = (packageRoot) => {
59
- const root = packageRoot.replace(/\/+$/, "");
60
- if (!root.endsWith(GLOBAL_PACKAGE_SUBPATH)) return null;
61
- if (NON_GLOBAL_INSTALL_SEGMENTS.some((segment) => root.includes(segment))) return null;
62
- const prefix = root.slice(0, -GLOBAL_PACKAGE_SUBPATH.length);
60
+ var globalPackageSubpath = (name) => `/${[...POSIX_GLOBAL_ROOT_SEGMENTS, ...cliPackagePathSegments(name)].join("/")}`;
61
+ var prefixOfGlobalPackage = (root, name) => {
62
+ const subpath = globalPackageSubpath(name);
63
+ if (!root.endsWith(subpath)) return null;
64
+ const prefix = root.slice(0, -subpath.length);
63
65
  return prefix.startsWith("/") ? prefix : null;
64
66
  };
65
- var upgradeEntryFor = (prefix) => join(prefix, GLOBAL_PACKAGE_SUBPATH, ...UPGRADE_ENTRY_SUBPATH);
67
+ var isNonGlobalInstall = (root) => NON_GLOBAL_INSTALL_SEGMENTS.some((segment) => root.includes(segment));
68
+ var globalInstallLocation = (packageRoot) => {
69
+ const root = packageRoot.replace(/\/+$/, "");
70
+ if (isNonGlobalInstall(root)) return null;
71
+ for (const packageName of CLI_PACKAGE_NAMES) {
72
+ const prefix = prefixOfGlobalPackage(root, packageName);
73
+ if (prefix !== null) return { prefix, packageName };
74
+ }
75
+ return null;
76
+ };
77
+ var upgradeEntryFor = (location, platform = process.platform) => globalUpgradeEntry(location.prefix, location.packageName, platform);
66
78
  var checkedWithinInterval = (lastCheckAt, now) => {
67
79
  const last = lastCheckAt === void 0 ? Number.NaN : Date.parse(lastCheckAt);
68
80
  if (Number.isNaN(last)) return false;
@@ -73,10 +85,10 @@ var autoUpdateDecision = (input) => {
73
85
  if (input.isSubagentStart) return { kind: "skip", reason: "subagent_start" };
74
86
  const offReason = autoUpdateOffReason(input);
75
87
  if (offReason !== null) return { kind: "skip", reason: offReason };
76
- const prefix = input.packageRoot === void 0 ? null : globalInstallPrefix(input.packageRoot);
77
- if (prefix === null) return { kind: "skip", reason: "not_global_install" };
88
+ const location = input.packageRoot === void 0 ? null : globalInstallLocation(input.packageRoot);
89
+ if (location === null) return { kind: "skip", reason: "not_global_install" };
78
90
  if (checkedWithinInterval(input.state.lastCheckAt, input.now)) return { kind: "skip", reason: "checked_recently" };
79
- return { kind: "check", prefix };
91
+ return { kind: "check", ...location };
80
92
  };
81
93
  var parseAutoUpdateFlag = (args) => {
82
94
  const token = args.find((arg) => arg === AUTO_UPDATE_FLAG || arg.startsWith(`${AUTO_UPDATE_FLAG}=`));
@@ -141,7 +153,7 @@ var triggerAutoUpdate = (trigger) => {
141
153
  if (decision.kind === "skip") return decision;
142
154
  updateAutoUpdateState(statePath, { lastCheckAt: new Date(now).toISOString() });
143
155
  const spawnUpgrade = trigger.spawn ?? spawnDetached;
144
- spawnUpgrade(trigger.execPath ?? process.execPath, [upgradeEntryFor(decision.prefix), AUTO_UPDATE_FLAG], dirname(statePath));
156
+ spawnUpgrade(trigger.execPath ?? process.execPath, [upgradeEntryFor(decision), AUTO_UPDATE_FLAG], dirname(statePath));
145
157
  return decision;
146
158
  } catch {
147
159
  return null;
@@ -152,7 +164,7 @@ export {
152
164
  AUTO_UPDATE_DISABLE_ENV,
153
165
  isAutoUpdateDisabledByEnv,
154
166
  autoUpdateOffReason,
155
- globalInstallPrefix,
167
+ globalInstallLocation,
156
168
  upgradeEntryFor,
157
169
  parseAutoUpdateFlag,
158
170
  describeAutoUpdateCheck,