@pushary/agent-hooks 0.89.3 → 0.89.5

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 (58) hide show
  1. package/README.md +40 -0
  2. package/dist/bin/pushary-bell-hook.js +3 -3
  3. package/dist/bin/pushary-bell.js +9 -10
  4. package/dist/bin/pushary-claude.js +62 -26
  5. package/dist/bin/pushary-clean.js +25 -7
  6. package/dist/bin/pushary-codex-bridge.js +4 -5
  7. package/dist/bin/pushary-codex-hook.js +8 -7
  8. package/dist/bin/pushary-codex.js +6 -4
  9. package/dist/bin/pushary-connect.js +4 -4
  10. package/dist/bin/pushary-daemon.js +155 -40
  11. package/dist/bin/pushary-disconnect.js +3 -4
  12. package/dist/bin/pushary-doctor.js +77 -39
  13. package/dist/bin/pushary-elicitation-hook.js +4 -2
  14. package/dist/bin/pushary-gemini-bridge.js +3 -4
  15. package/dist/bin/pushary-gemini-hook.js +6 -4
  16. package/dist/bin/pushary-hook.js +9 -7
  17. package/dist/bin/pushary-login.js +4 -4
  18. package/dist/bin/pushary-logout.js +5 -6
  19. package/dist/bin/pushary-mode.js +2 -2
  20. package/dist/bin/pushary-notification-hook.js +6 -4
  21. package/dist/bin/pushary-opencode-hook.js +14 -6
  22. package/dist/bin/pushary-permission-denied-hook.js +7 -5
  23. package/dist/bin/pushary-permission-hook.js +7 -5
  24. package/dist/bin/pushary-post-hook.js +6 -4
  25. package/dist/bin/pushary-prompt-hook.js +6 -4
  26. package/dist/bin/pushary-session-end-hook.js +6 -4
  27. package/dist/bin/pushary-session-start-hook.js +6 -4
  28. package/dist/bin/pushary-setup.js +125 -39
  29. package/dist/bin/pushary-stats.js +2 -2
  30. package/dist/bin/pushary-status.js +7 -6
  31. package/dist/bin/pushary-stop-hook.js +6 -4
  32. package/dist/bin/pushary-stopfailure-hook.js +6 -4
  33. package/dist/bin/pushary-suggestions.js +2 -2
  34. package/dist/bin/pushary-upgrade.js +110 -46
  35. package/dist/bin/pushary-wait.js +2 -2
  36. package/dist/bin/pushary.js +1 -1
  37. package/dist/chunk-2HYPZLYY.js +45 -0
  38. package/dist/{chunk-GOEXZ5QJ.js → chunk-3XTFX4CL.js} +10 -2
  39. package/dist/{chunk-ZYPS2XMT.js → chunk-4ZHQNBDP.js} +1 -1
  40. package/dist/{chunk-HUJAAWNL.js → chunk-GKAKAOKC.js} +10 -3
  41. package/dist/{chunk-LGXTBUT4.js → chunk-KOPUTJQC.js} +1 -0
  42. package/dist/{chunk-LALHWDWL.js → chunk-L3YUHEB6.js} +16 -4
  43. package/dist/{chunk-SQOFGPNX.js → chunk-LURY4WNF.js} +1 -1
  44. package/dist/{chunk-JT6TIBYH.js → chunk-MZBT2LXW.js} +4 -4
  45. package/dist/{chunk-3UBYTSCY.js → chunk-NFI2K2ZQ.js} +15 -7
  46. package/dist/chunk-NKHEHEUM.js +56 -0
  47. package/dist/{chunk-3O2XPYLF.js → chunk-OBI4YMCT.js} +1 -1
  48. package/dist/{chunk-LUCFN47K.js → chunk-QH4AA7QV.js} +1 -1
  49. package/dist/chunk-TRQ46MXR.js +648 -0
  50. package/dist/{chunk-VKVHY5HD.js → chunk-V37ZXMH3.js} +11 -3
  51. package/dist/{chunk-MHBC2XUP.js → chunk-VP7SDXYG.js} +1 -1
  52. package/dist/{chunk-B7JE4XHD.js → chunk-WQGMUIDW.js} +1 -1
  53. package/dist/src/index.js +7 -5
  54. package/package.json +1 -1
  55. package/dist/chunk-GIRT7677.js +0 -11
  56. package/dist/chunk-K42SZKYF.js +0 -343
  57. package/dist/chunk-NRGRUOAR.js +0 -25
  58. package/dist/chunk-RN3NOEJF.js +0 -9
@@ -4,25 +4,23 @@ import {
4
4
  codexConfigToml,
5
5
  cursorUserMcp,
6
6
  geminiSettings
7
- } from "../chunk-VKVHY5HD.js";
8
- import "../chunk-GIRT7677.js";
7
+ } from "../chunk-V37ZXMH3.js";
9
8
  import {
10
9
  createIo
11
10
  } from "../chunk-5RUIFDTP.js";
12
11
  import {
13
12
  clearKey,
14
13
  readKeySource
15
- } from "../chunk-LALHWDWL.js";
14
+ } from "../chunk-L3YUHEB6.js";
16
15
  import {
17
16
  parseFlags
18
17
  } from "../chunk-GMXKITVA.js";
19
18
  import {
20
19
  exitOnHelpFlag
21
- } from "../chunk-SQOFGPNX.js";
22
- import "../chunk-GOEXZ5QJ.js";
20
+ } from "../chunk-LURY4WNF.js";
21
+ import "../chunk-3XTFX4CL.js";
23
22
  import "../chunk-BC3VCZ3E.js";
24
23
  import "../chunk-DINDL2CF.js";
25
- import "../chunk-6MTNS63X.js";
26
24
  import "../chunk-OFRNZWC4.js";
27
25
  import {
28
26
  UsageError
@@ -30,6 +28,7 @@ import {
30
28
  import {
31
29
  EXIT
32
30
  } from "../chunk-KZERVKTD.js";
31
+ import "../chunk-6MTNS63X.js";
33
32
  import {
34
33
  getBaseUrl
35
34
  } from "../chunk-2UMNXADU.js";
@@ -11,8 +11,8 @@ import {
11
11
  } from "../chunk-GMXKITVA.js";
12
12
  import {
13
13
  exitOnHelpFlag
14
- } from "../chunk-SQOFGPNX.js";
15
- import "../chunk-GOEXZ5QJ.js";
14
+ } from "../chunk-LURY4WNF.js";
15
+ import "../chunk-3XTFX4CL.js";
16
16
  import "../chunk-DINDL2CF.js";
17
17
  import "../chunk-SAF6HGAA.js";
18
18
  import {
@@ -4,15 +4,17 @@ import {
4
4
  } from "../chunk-6CUUA7HO.js";
5
5
  import {
6
6
  handleNotification
7
- } from "../chunk-3UBYTSCY.js";
8
- import "../chunk-HUJAAWNL.js";
9
- import "../chunk-LGXTBUT4.js";
10
- import "../chunk-RN3NOEJF.js";
7
+ } from "../chunk-NFI2K2ZQ.js";
8
+ import "../chunk-GKAKAOKC.js";
9
+ import "../chunk-KOPUTJQC.js";
10
+ import "../chunk-2HYPZLYY.js";
11
+ import "../chunk-V37ZXMH3.js";
11
12
  import "../chunk-BSZYIAZL.js";
12
13
  import "../chunk-SAF6HGAA.js";
13
14
  import "../chunk-OFRNZWC4.js";
14
15
  import "../chunk-7QLSKOSU.js";
15
16
  import "../chunk-KZERVKTD.js";
17
+ import "../chunk-6MTNS63X.js";
16
18
  import "../chunk-2UMNXADU.js";
17
19
  import "../chunk-L4C2JXJS.js";
18
20
 
@@ -19,7 +19,7 @@ import {
19
19
  policyRequestFor,
20
20
  readLastPrompt,
21
21
  repoKeyFor
22
- } from "../chunk-3UBYTSCY.js";
22
+ } from "../chunk-NFI2K2ZQ.js";
23
23
  import {
24
24
  DEFAULT_SESSION,
25
25
  askUser,
@@ -27,23 +27,26 @@ import {
27
27
  savePendingQuestion,
28
28
  sendNotification,
29
29
  waitForAnswer
30
- } from "../chunk-HUJAAWNL.js";
30
+ } from "../chunk-GKAKAOKC.js";
31
31
  import {
32
+ HOOK_FALLBACK_MAX,
32
33
  OPENCODE_TOOL_NAMES,
33
34
  deriveActionBody,
34
35
  deriveBlocker,
35
36
  deriveToolTarget,
36
37
  describeToolCall,
37
38
  scopePathFor
38
- } from "../chunk-LGXTBUT4.js";
39
+ } from "../chunk-KOPUTJQC.js";
39
40
  import {
40
41
  getMachineId
41
- } from "../chunk-RN3NOEJF.js";
42
+ } from "../chunk-2HYPZLYY.js";
43
+ import "../chunk-V37ZXMH3.js";
42
44
  import "../chunk-BSZYIAZL.js";
43
45
  import "../chunk-SAF6HGAA.js";
44
46
  import "../chunk-OFRNZWC4.js";
45
47
  import "../chunk-7QLSKOSU.js";
46
48
  import "../chunk-KZERVKTD.js";
49
+ import "../chunk-6MTNS63X.js";
47
50
  import {
48
51
  getApiKey
49
52
  } from "../chunk-2UMNXADU.js";
@@ -55,6 +58,7 @@ import {
55
58
  gateOutputFor,
56
59
  hookWaitClamped,
57
60
  hookWaitDeadline,
61
+ redactSecrets,
58
62
  resolveGate
59
63
  } from "../chunk-L4C2JXJS.js";
60
64
 
@@ -108,9 +112,13 @@ var pollForAnswer = async (apiKey, correlationId, deadlineMs, pollInterval = 2e3
108
112
  return { answered: false };
109
113
  };
110
114
  var agentNameFor = (input) => `${OPENCODE_AGENT.label} - ${basename(input.cwd ?? process.cwd())}`;
115
+ var describeFor = (input, lookup) => {
116
+ if (lookup.tool) return describeToolCall(lookup.tool, lookup.input, "hook");
117
+ return redactSecrets(input.title ?? "").trim().slice(0, HOOK_FALLBACK_MAX) || "this request";
118
+ };
111
119
  var pushQuestion = async (apiKey, input, lookup, waitSeconds, mode, pollInterval = 2e3) => {
112
120
  const projectName = basename(input.cwd ?? process.cwd());
113
- const description = describeToolCall(lookup.tool, lookup.input, "hook");
121
+ const description = describeFor(input, lookup);
114
122
  const result = await askUser(apiKey, {
115
123
  question: `Allow ${description}?`,
116
124
  type: "confirm",
@@ -147,7 +155,7 @@ var notifyApprovalNeeded = async (apiKey, input, lookup) => {
147
155
  try {
148
156
  await sendNotification(apiKey, {
149
157
  title: "Agent needs approval",
150
- body: describeToolCall(lookup.tool, lookup.input, "hook"),
158
+ body: describeFor(input, lookup),
151
159
  agentName: agentNameFor(input),
152
160
  sessionId: input.session_id,
153
161
  machineId: getMachineId()
@@ -1,22 +1,24 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handlePermissionDenied
4
- } from "../chunk-JT6TIBYH.js";
4
+ } from "../chunk-MZBT2LXW.js";
5
5
  import "../chunk-ATBKJNWS.js";
6
6
  import "../chunk-VZKXBFUA.js";
7
7
  import {
8
8
  readHookInput
9
9
  } from "../chunk-6CUUA7HO.js";
10
10
  import "../chunk-YHG74UFF.js";
11
- import "../chunk-3UBYTSCY.js";
12
- import "../chunk-HUJAAWNL.js";
13
- import "../chunk-LGXTBUT4.js";
14
- import "../chunk-RN3NOEJF.js";
11
+ import "../chunk-NFI2K2ZQ.js";
12
+ import "../chunk-GKAKAOKC.js";
13
+ import "../chunk-KOPUTJQC.js";
14
+ import "../chunk-2HYPZLYY.js";
15
+ import "../chunk-V37ZXMH3.js";
15
16
  import "../chunk-BSZYIAZL.js";
16
17
  import "../chunk-SAF6HGAA.js";
17
18
  import "../chunk-OFRNZWC4.js";
18
19
  import "../chunk-7QLSKOSU.js";
19
20
  import "../chunk-KZERVKTD.js";
21
+ import "../chunk-6MTNS63X.js";
20
22
  import "../chunk-2UMNXADU.js";
21
23
  import "../chunk-L4C2JXJS.js";
22
24
 
@@ -1,22 +1,24 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handlePermissionRequest
4
- } from "../chunk-JT6TIBYH.js";
4
+ } from "../chunk-MZBT2LXW.js";
5
5
  import "../chunk-ATBKJNWS.js";
6
6
  import "../chunk-VZKXBFUA.js";
7
7
  import {
8
8
  readHookInput
9
9
  } from "../chunk-6CUUA7HO.js";
10
10
  import "../chunk-YHG74UFF.js";
11
- import "../chunk-3UBYTSCY.js";
12
- import "../chunk-HUJAAWNL.js";
13
- import "../chunk-LGXTBUT4.js";
14
- import "../chunk-RN3NOEJF.js";
11
+ import "../chunk-NFI2K2ZQ.js";
12
+ import "../chunk-GKAKAOKC.js";
13
+ import "../chunk-KOPUTJQC.js";
14
+ import "../chunk-2HYPZLYY.js";
15
+ import "../chunk-V37ZXMH3.js";
15
16
  import "../chunk-BSZYIAZL.js";
16
17
  import "../chunk-SAF6HGAA.js";
17
18
  import "../chunk-OFRNZWC4.js";
18
19
  import "../chunk-7QLSKOSU.js";
19
20
  import "../chunk-KZERVKTD.js";
21
+ import "../chunk-6MTNS63X.js";
20
22
  import "../chunk-2UMNXADU.js";
21
23
  import "../chunk-L4C2JXJS.js";
22
24
 
@@ -4,15 +4,17 @@ import {
4
4
  } from "../chunk-6CUUA7HO.js";
5
5
  import {
6
6
  handlePostToolUse
7
- } from "../chunk-3UBYTSCY.js";
8
- import "../chunk-HUJAAWNL.js";
9
- import "../chunk-LGXTBUT4.js";
10
- import "../chunk-RN3NOEJF.js";
7
+ } from "../chunk-NFI2K2ZQ.js";
8
+ import "../chunk-GKAKAOKC.js";
9
+ import "../chunk-KOPUTJQC.js";
10
+ import "../chunk-2HYPZLYY.js";
11
+ import "../chunk-V37ZXMH3.js";
11
12
  import "../chunk-BSZYIAZL.js";
12
13
  import "../chunk-SAF6HGAA.js";
13
14
  import "../chunk-OFRNZWC4.js";
14
15
  import "../chunk-7QLSKOSU.js";
15
16
  import "../chunk-KZERVKTD.js";
17
+ import "../chunk-6MTNS63X.js";
16
18
  import "../chunk-2UMNXADU.js";
17
19
  import "../chunk-L4C2JXJS.js";
18
20
 
@@ -4,15 +4,17 @@ import {
4
4
  } from "../chunk-6CUUA7HO.js";
5
5
  import {
6
6
  handleUserPrompt
7
- } from "../chunk-3UBYTSCY.js";
8
- import "../chunk-HUJAAWNL.js";
9
- import "../chunk-LGXTBUT4.js";
10
- import "../chunk-RN3NOEJF.js";
7
+ } from "../chunk-NFI2K2ZQ.js";
8
+ import "../chunk-GKAKAOKC.js";
9
+ import "../chunk-KOPUTJQC.js";
10
+ import "../chunk-2HYPZLYY.js";
11
+ import "../chunk-V37ZXMH3.js";
11
12
  import "../chunk-BSZYIAZL.js";
12
13
  import "../chunk-SAF6HGAA.js";
13
14
  import "../chunk-OFRNZWC4.js";
14
15
  import "../chunk-7QLSKOSU.js";
15
16
  import "../chunk-KZERVKTD.js";
17
+ import "../chunk-6MTNS63X.js";
16
18
  import "../chunk-2UMNXADU.js";
17
19
  import "../chunk-L4C2JXJS.js";
18
20
 
@@ -4,15 +4,17 @@ import {
4
4
  } from "../chunk-6CUUA7HO.js";
5
5
  import {
6
6
  handleSessionEnd
7
- } from "../chunk-3UBYTSCY.js";
8
- import "../chunk-HUJAAWNL.js";
9
- import "../chunk-LGXTBUT4.js";
10
- import "../chunk-RN3NOEJF.js";
7
+ } from "../chunk-NFI2K2ZQ.js";
8
+ import "../chunk-GKAKAOKC.js";
9
+ import "../chunk-KOPUTJQC.js";
10
+ import "../chunk-2HYPZLYY.js";
11
+ import "../chunk-V37ZXMH3.js";
11
12
  import "../chunk-BSZYIAZL.js";
12
13
  import "../chunk-SAF6HGAA.js";
13
14
  import "../chunk-OFRNZWC4.js";
14
15
  import "../chunk-7QLSKOSU.js";
15
16
  import "../chunk-KZERVKTD.js";
17
+ import "../chunk-6MTNS63X.js";
16
18
  import "../chunk-2UMNXADU.js";
17
19
  import "../chunk-L4C2JXJS.js";
18
20
 
@@ -4,15 +4,17 @@ import {
4
4
  } from "../chunk-6CUUA7HO.js";
5
5
  import {
6
6
  handleSessionStart
7
- } from "../chunk-3UBYTSCY.js";
8
- import "../chunk-HUJAAWNL.js";
9
- import "../chunk-LGXTBUT4.js";
10
- import "../chunk-RN3NOEJF.js";
7
+ } from "../chunk-NFI2K2ZQ.js";
8
+ import "../chunk-GKAKAOKC.js";
9
+ import "../chunk-KOPUTJQC.js";
10
+ import "../chunk-2HYPZLYY.js";
11
+ import "../chunk-V37ZXMH3.js";
11
12
  import "../chunk-BSZYIAZL.js";
12
13
  import "../chunk-SAF6HGAA.js";
13
14
  import "../chunk-OFRNZWC4.js";
14
15
  import "../chunk-7QLSKOSU.js";
15
16
  import "../chunk-KZERVKTD.js";
17
+ import "../chunk-6MTNS63X.js";
16
18
  import "../chunk-2UMNXADU.js";
17
19
  import "../chunk-L4C2JXJS.js";
18
20
 
@@ -6,13 +6,10 @@ import {
6
6
  claudeWired,
7
7
  codexWired,
8
8
  geminiWired
9
- } from "../chunk-3O2XPYLF.js";
9
+ } from "../chunk-OBI4YMCT.js";
10
10
  import {
11
11
  runBrowserLogin
12
12
  } from "../chunk-Z3Z4VK5F.js";
13
- import {
14
- ensureDaemonRunning
15
- } from "../chunk-K42SZKYF.js";
16
13
  import {
17
14
  describeDetection,
18
15
  detectAllAgents,
@@ -24,7 +21,7 @@ import {
24
21
  shortenHome,
25
22
  vscodeSettingsTargets,
26
23
  writeInstructionBlock
27
- } from "../chunk-LUCFN47K.js";
24
+ } from "../chunk-QH4AA7QV.js";
28
25
  import {
29
26
  OPENCODE_HOOK_BINARY,
30
27
  addOpenCodeMcpServer,
@@ -52,6 +49,19 @@ import {
52
49
  guardNodeScript,
53
50
  guardedArgv
54
51
  } from "../chunk-AIGDBRIJ.js";
52
+ import {
53
+ daemonServiceManagerAvailable,
54
+ disableDaemonService,
55
+ ensureDaemonRunning,
56
+ hasDaemonServiceDefinition,
57
+ readDaemonStatus,
58
+ replaceDaemonService
59
+ } from "../chunk-TRQ46MXR.js";
60
+ import {
61
+ detectProviderLiveCapabilities,
62
+ hasSpawnProvider,
63
+ resolveControlPolicy
64
+ } from "../chunk-NKHEHEUM.js";
55
65
  import "../chunk-XHKBHWLX.js";
56
66
  import {
57
67
  installGlobally,
@@ -59,6 +69,12 @@ import {
59
69
  resolveGlobalBinDir,
60
70
  resolveGlobalBinary
61
71
  } from "../chunk-PZA7G4CN.js";
72
+ import {
73
+ reportEvent
74
+ } from "../chunk-NFI2K2ZQ.js";
75
+ import "../chunk-GKAKAOKC.js";
76
+ import "../chunk-KOPUTJQC.js";
77
+ import "../chunk-2HYPZLYY.js";
62
78
  import {
63
79
  addCodexHookTrust,
64
80
  addCodexHooks,
@@ -78,14 +94,7 @@ import {
78
94
  geminiSettings,
79
95
  pusharyConfigFile,
80
96
  vscodePluginDir
81
- } from "../chunk-VKVHY5HD.js";
82
- import "../chunk-GIRT7677.js";
83
- import {
84
- reportEvent
85
- } from "../chunk-3UBYTSCY.js";
86
- import "../chunk-HUJAAWNL.js";
87
- import "../chunk-LGXTBUT4.js";
88
- import "../chunk-RN3NOEJF.js";
97
+ } from "../chunk-V37ZXMH3.js";
89
98
  import {
90
99
  confirmAppConnection,
91
100
  connectDevice,
@@ -108,15 +117,16 @@ import {
108
117
  exportLine,
109
118
  keyPrefix,
110
119
  readConfigFileKey,
120
+ readControlMode,
111
121
  readKeySource,
112
122
  writeKey
113
- } from "../chunk-LALHWDWL.js";
123
+ } from "../chunk-L3YUHEB6.js";
114
124
  import {
115
125
  parseFlags
116
126
  } from "../chunk-GMXKITVA.js";
117
127
  import {
118
128
  renderCommandHelp
119
- } from "../chunk-GOEXZ5QJ.js";
129
+ } from "../chunk-3XTFX4CL.js";
120
130
  import {
121
131
  installClaudeAlias,
122
132
  resolveShellRc
@@ -125,12 +135,6 @@ import {
125
135
  getPackageVersion,
126
136
  isNewerVersion
127
137
  } from "../chunk-DINDL2CF.js";
128
- import {
129
- backupFile,
130
- readJsonSafe,
131
- writeFileAtomic,
132
- writeJsonAtomic
133
- } from "../chunk-6MTNS63X.js";
134
138
  import "../chunk-BSZYIAZL.js";
135
139
  import "../chunk-SAF6HGAA.js";
136
140
  import "../chunk-OFRNZWC4.js";
@@ -140,6 +144,12 @@ import {
140
144
  import {
141
145
  EXIT
142
146
  } from "../chunk-KZERVKTD.js";
147
+ import {
148
+ backupFile,
149
+ readJsonSafe,
150
+ writeFileAtomic,
151
+ writeJsonAtomic
152
+ } from "../chunk-6MTNS63X.js";
143
153
  import "../chunk-2UMNXADU.js";
144
154
  import {
145
155
  CURSOR_GATE_EVENTS,
@@ -204,6 +214,18 @@ var describeClosing = (facts) => {
204
214
  exitCode: EXIT.PROBLEMS_FOUND
205
215
  };
206
216
  }
217
+ if (facts.daemonReady === false) {
218
+ return {
219
+ ok: false,
220
+ headline: "Setup finished with 1 problem.",
221
+ next: [
222
+ "Approvals are configured, but this machine cannot start an agent from your phone.",
223
+ "pushary daemon install install or repair the background service",
224
+ "pushary doctor verify it became reachable"
225
+ ],
226
+ exitCode: EXIT.PROBLEMS_FOUND
227
+ };
228
+ }
207
229
  if (facts.roundTripAnswered === true) {
208
230
  return {
209
231
  ok: true,
@@ -475,6 +497,12 @@ var parseVerifyMode = (raw) => {
475
497
  if (VERIFY_MODES.includes(value)) return value;
476
498
  throw new UsageError(`--verify must be one of: ${VERIFY_MODES.join(", ")} (got ${raw})`);
477
499
  };
500
+ var CONTROL_MODES = ["auto", "on", "off"];
501
+ var parseControlMode = (raw) => {
502
+ const value = raw.trim().toLowerCase();
503
+ if (CONTROL_MODES.includes(value)) return value;
504
+ throw new UsageError(`--control must be one of: ${CONTROL_MODES.join(", ")} (got ${raw})`);
505
+ };
478
506
  var effectiveVerify = (options, context) => {
479
507
  if (options.verifyExplicit) return options.verify;
480
508
  if (options.verify === "roundtrip") return "roundtrip";
@@ -482,8 +510,9 @@ var effectiveVerify = (options, context) => {
482
510
  };
483
511
  var SETUP_FLAGS = {
484
512
  bools: ["key-stdin", "skip-phone", "yes", "y", "json", "dry-run", "help", "h"],
485
- values: ["key", "connect", "agents", "verify"]
513
+ values: ["key", "connect", "agents", "verify", "control"]
486
514
  };
515
+ var effectiveControlMode = (options, stored, configPresent) => options.controlExplicit ? options.control : stored ?? (configPresent ? null : options.control);
487
516
  var isAgentChoice = (value) => AGENT_CHOICES.includes(value);
488
517
  var parseAgentSelection = (raw, yes) => {
489
518
  if (raw === void 0) {
@@ -520,6 +549,7 @@ var parseSetupOptions = (input2) => {
520
549
  const connectRaw = flags.values.get("connect");
521
550
  const connectMode = connectRaw === void 0 ? "app" : parseConnectMode(connectRaw);
522
551
  const verifyRaw = flags.values.get("verify");
552
+ const controlRaw = flags.values.get("control");
523
553
  const nonInteractive = yes || agentsFlag !== void 0 || flags.bools.has("json") || !input2.stdinIsTty;
524
554
  const verify = verifyRaw !== void 0 ? parseVerifyMode(verifyRaw) : nonInteractive ? "push" : "roundtrip";
525
555
  const key = flags.values.get("key")?.trim() || null;
@@ -555,7 +585,9 @@ var parseSetupOptions = (input2) => {
555
585
  key,
556
586
  keyStdin,
557
587
  verify,
558
- verifyExplicit: verifyRaw !== void 0
588
+ verifyExplicit: verifyRaw !== void 0,
589
+ control: controlRaw === void 0 ? "auto" : parseControlMode(controlRaw),
590
+ controlExplicit: controlRaw !== void 0
559
591
  };
560
592
  };
561
593
 
@@ -707,7 +739,9 @@ var checkForUpdates = async (current) => {
707
739
  } catch {
708
740
  }
709
741
  };
742
+ var globalInstallReady = false;
710
743
  var installGlobally2 = async () => {
744
+ if (globalInstallReady) return;
711
745
  const version = getPackageVersion();
712
746
  await spinner(`Installing pushary-hook globally (${version})`, async () => {
713
747
  try {
@@ -716,6 +750,7 @@ var installGlobally2 = async () => {
716
750
  throw new Error(npmErrorMessage(err));
717
751
  }
718
752
  });
753
+ globalInstallReady = true;
719
754
  };
720
755
  var _cachedSkillContent = null;
721
756
  var fetchSkillContent = async () => {
@@ -1133,14 +1168,17 @@ var installCursorUserHooks = (gateScript) => {
1133
1168
  const bundled = readJson(join3(CURSOR_PLUGIN_DIR, "hooks", "hooks.json")).hooks ?? {};
1134
1169
  let userHooks = {};
1135
1170
  if (existsSync(CURSOR_USER_HOOKS)) {
1136
- try {
1137
- userHooks = JSON.parse(readFileSync(CURSOR_USER_HOOKS, "utf-8"));
1138
- } catch {
1171
+ const result = readJsonSafe(CURSOR_USER_HOOKS);
1172
+ if (result.kind === "ok") userHooks = result.value;
1173
+ else {
1174
+ let backup = "";
1139
1175
  try {
1140
- cpSync(CURSOR_USER_HOOKS, `${CURSOR_USER_HOOKS}.bak`);
1176
+ backup = backupFile(CURSOR_USER_HOOKS);
1141
1177
  } catch {
1142
1178
  }
1143
- userHooks = {};
1179
+ throw new Error(
1180
+ `Could not parse or read Cursor hooks.json; left it untouched${backup ? ` and backed it up at ${backup}` : ""}. Fix the file, then re-run setup.`
1181
+ );
1144
1182
  }
1145
1183
  }
1146
1184
  const hooks = userHooks.hooks ?? {};
@@ -1331,10 +1369,10 @@ ${pluginLocationSnippet(VSCODE_PLUGIN_DIR)}`
1331
1369
  console.log(` ${dim("\u2022")} Fully quit and reopen VS Code to load the plugin`);
1332
1370
  noteManual("Fully quit and reopen VS Code. A Reload Window may not pick up a new plugin location.");
1333
1371
  };
1334
- var saveApiKey = async (apiKey) => {
1372
+ var saveApiKey = async (apiKey, controlMode) => {
1335
1373
  let result;
1336
1374
  await spinner("Saving your API key", async () => {
1337
- result = writeKey(apiKey);
1375
+ result = writeKey(apiKey, controlMode === null ? {} : { controlMode });
1338
1376
  });
1339
1377
  if (!result) throw new Error("Could not save the API key");
1340
1378
  if (result.configBackupPath) {
@@ -1687,7 +1725,7 @@ var AGENT_TARGETS = {
1687
1725
  ],
1688
1726
  custom: ["nothing (prints connection details only)"]
1689
1727
  };
1690
- var reportDryRun = (apiKey, agents, keyCheck) => {
1728
+ var reportDryRun = (apiKey, agents, keyCheck, controlMode) => {
1691
1729
  console.log();
1692
1730
  console.log(` ${bold("Dry run")} ${dim("\u2014 nothing below has been written")}`);
1693
1731
  console.log();
@@ -1695,6 +1733,7 @@ var reportDryRun = (apiKey, agents, keyCheck) => {
1695
1733
  apiKey ? ` ${dim("Key:")} ${dim(`${apiKey.slice(0, 8)}...${apiKey.slice(-4)}`)} ${dim(`(${keyCheck?.kind ?? "not verified"})`)}` : ` ${dim("Key:")} ${dim("none on this machine \u2014 a real run would acquire one")}`
1696
1734
  );
1697
1735
  console.log(` ${dim("Key store:")} ${PUSHARY_CONFIG_FILE}`);
1736
+ console.log(` ${dim("Control:")} ${controlMode ?? "unchanged (legacy install)"}`);
1698
1737
  const rc = resolveShellRc();
1699
1738
  console.log(` ${dim("Shell rc:")} ${rc ? rc.path : dim("none for this shell; the export line would be printed instead")}`);
1700
1739
  console.log();
@@ -1733,6 +1772,7 @@ var main = async () => {
1733
1772
  `);
1734
1773
  process.exit(EXIT.OK);
1735
1774
  }
1775
+ const controlMode = effectiveControlMode(options, readControlMode(), existsSync(PUSHARY_CONFIG_FILE));
1736
1776
  recordSetupOptions(options);
1737
1777
  if (options.json) {
1738
1778
  jsonMode = true;
@@ -1791,11 +1831,12 @@ var main = async () => {
1791
1831
  console.log();
1792
1832
  markStep("resolve-agents");
1793
1833
  const plannedAgents = await resolveAgents(options);
1794
- reportDryRun(null, plannedAgents, null);
1795
- emitJson(options, { ok: true, dryRun: true, agents: plannedAgents, keyCheck: "skipped", key: "none" });
1834
+ reportDryRun(null, plannedAgents, null, controlMode);
1835
+ emitJson(options, { ok: true, dryRun: true, agents: plannedAgents, control: controlMode, keyCheck: "skipped", key: "none" });
1796
1836
  process.exit(EXIT.OK);
1797
1837
  } else if (connectMode === "app" && canShowPairingQr() && !options.skipPhone) {
1798
1838
  console.log(` ${dim("Pairing with your Pushary app.")}`);
1839
+ console.log(` ${dim("Agent control requires a paid plan after the trial. Current pricing:")} ${cyan("https://pushary.com/pricing")}`);
1799
1840
  console.log(` ${dim("No app yet? Get it at")} ${cyan("https://pushary.com/download")}${dim(", this keeps waiting.")}`);
1800
1841
  console.log(` ${dim("No phone? Ctrl-C, then:")} ${cyan("npx @pushary/agent-hooks setup --connect browser")}`);
1801
1842
  markStep("pair");
@@ -1878,12 +1919,12 @@ var main = async () => {
1878
1919
  markStep("resolve-agents");
1879
1920
  const agents = await resolveAgents(options);
1880
1921
  if (options.dryRun) {
1881
- reportDryRun(trimmedKey, agents, keyCheck);
1882
- emitJson(options, { ok: true, dryRun: true, agents, keyCheck: keyCheck?.kind ?? "skipped" });
1922
+ reportDryRun(trimmedKey, agents, keyCheck, controlMode);
1923
+ emitJson(options, { ok: true, dryRun: true, agents, control: controlMode, keyCheck: keyCheck?.kind ?? "skipped" });
1883
1924
  process.exit(EXIT.OK);
1884
1925
  }
1885
1926
  markStep("save-key");
1886
- const rc = await saveApiKey(trimmedKey);
1927
+ const rc = await saveApiKey(trimmedKey, controlMode);
1887
1928
  const context = { rc };
1888
1929
  if (envKey && envKey !== trimmedKey) {
1889
1930
  noteManual(
@@ -1893,6 +1934,7 @@ var main = async () => {
1893
1934
  const failed = [];
1894
1935
  const completed = [];
1895
1936
  const skipped = [];
1937
+ let controlDisableFailure = null;
1896
1938
  if (agents.length === 0) {
1897
1939
  console.log(`
1898
1940
  ${check} API key saved. No agents configured.`);
@@ -1931,6 +1973,16 @@ var main = async () => {
1931
1973
  await offerClaudeAlias(options);
1932
1974
  }
1933
1975
  }
1976
+ if (controlMode === "off") {
1977
+ markStep("control:disable");
1978
+ const disabled = await disableDaemonService();
1979
+ if (disabled.kind !== "ok") {
1980
+ controlDisableFailure = disabled.detail;
1981
+ console.log(` ${yellow("!")} Could not fully disable phone-start: ${controlDisableFailure}`);
1982
+ } else {
1983
+ console.log(` ${check} Phone-start background service disabled.`);
1984
+ }
1985
+ }
1934
1986
  markStep("connect-phone");
1935
1987
  const skipPhone = options.skipPhone;
1936
1988
  let phone = null;
@@ -1992,6 +2044,8 @@ var main = async () => {
1992
2044
  failed,
1993
2045
  keyCheck: "locked",
1994
2046
  rc: rc.kind,
2047
+ control: controlMode,
2048
+ daemon: controlMode === "off" ? controlDisableFailure ? "unavailable" : "disabled" : "skipped",
1995
2049
  exitCode: report.exitCode
1996
2050
  });
1997
2051
  await reportSetupOutcome({
@@ -2011,6 +2065,36 @@ var main = async () => {
2011
2065
  const reachChecked = phone !== null;
2012
2066
  const reachesYou = phone?.reachesYou ?? true;
2013
2067
  markStep("closing");
2068
+ const keyIsTrusted = keyFromPairing || keyCheck?.kind === "ok";
2069
+ const managedControlAgents = ["claude_code", "codex", "gemini_cli"];
2070
+ const configuredControlAgents = managedControlAgents.filter((agent) => agentIsWired(agent));
2071
+ const controlCapabilities = detectProviderLiveCapabilities(configuredControlAgents.map(
2072
+ (agent) => agent === "claude_code" ? "claude" : agent === "gemini_cli" ? "gemini" : agent
2073
+ ));
2074
+ const providerAvailable = hasSpawnProvider(controlCapabilities);
2075
+ const managerAvailable = daemonServiceManagerAvailable();
2076
+ const servicePresent = readDaemonStatus().kind !== "absent" || hasDaemonServiceDefinition();
2077
+ const controlPolicy = resolveControlPolicy({
2078
+ mode: controlMode,
2079
+ providerAvailable,
2080
+ managerAvailable,
2081
+ servicePresent
2082
+ });
2083
+ if (controlMode === "on" && controlPolicy !== "enabled") {
2084
+ console.log(` ${yellow("!")} Phone-start was required, but this machine has no supported provider or native background-service manager.`);
2085
+ } else if (controlPolicy === "legacy") {
2086
+ console.log(` ${yellow("!")} A legacy phone-start service cannot be safely adopted in this session. Disable it with --control off or restore its provider and native service manager.`);
2087
+ }
2088
+ const daemon = keyIsTrusted && controlPolicy === "enabled" ? await (async () => {
2089
+ try {
2090
+ await installGlobally2();
2091
+ const service = await replaceDaemonService();
2092
+ return service.kind === "ok" ? ensureDaemonRunning({ spawnDaemon: () => {
2093
+ } }) : { kind: "unavailable", detail: service.detail };
2094
+ } catch (err) {
2095
+ return { kind: "unavailable", detail: formatError(err) };
2096
+ }
2097
+ })() : controlMode === "on" || controlPolicy === "legacy" ? { kind: "unavailable", detail: "Managed control is required but no usable provider/service-manager pair is available" } : null;
2014
2098
  const closing = describeClosing({
2015
2099
  agentsOk,
2016
2100
  configuredNothing,
@@ -2018,12 +2102,11 @@ var main = async () => {
2018
2102
  failed,
2019
2103
  reachChecked,
2020
2104
  reachesYou,
2105
+ daemonReady: controlDisableFailure ? false : daemon === null ? null : daemon.kind === "running" || daemon.kind === "started",
2021
2106
  // null when the check did not run, so it changes nothing. Only an outright
2022
2107
  // `false` is allowed to hold back "Setup complete.".
2023
2108
  roundTripAnswered: roundTrip === null ? null : roundTrip.kind === "answered" ? true : roundTrip.kind === "unanswered" ? false : null
2024
2109
  });
2025
- const keyIsTrusted = keyFromPairing || keyCheck?.kind === "ok";
2026
- const daemon = keyIsTrusted && completed.length > 0 ? await ensureDaemonRunning() : null;
2027
2110
  console.log(` ${closing.ok ? green(bold(closing.headline)) : yellow(bold(closing.headline))}`);
2028
2111
  if (failed.length > 0) {
2029
2112
  console.log();
@@ -2064,7 +2147,10 @@ var main = async () => {
2064
2147
  roundTrip: roundTrip === null ? "skipped" : roundTrip.kind,
2065
2148
  rc: rc.kind,
2066
2149
  rcPath: rc.path,
2067
- daemon: daemon?.kind ?? "skipped",
2150
+ daemon: controlMode === "off" ? controlDisableFailure ? "unavailable" : "disabled" : controlPolicy === "unsupported" || controlPolicy === "preserve-absent" ? "unsupported" : daemon?.kind ?? "skipped",
2151
+ control: controlMode,
2152
+ controlPolicy,
2153
+ controlCapabilities,
2068
2154
  exitCode
2069
2155
  });
2070
2156
  if (exitCode !== EXIT.OK) {