@pushary/agent-hooks 0.89.4 → 0.89.6

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.
@@ -14,8 +14,8 @@ import {
14
14
  } from "../chunk-GMXKITVA.js";
15
15
  import {
16
16
  exitOnHelpFlag
17
- } from "../chunk-KJ57OPCC.js";
18
- import "../chunk-GPNOHKFO.js";
17
+ } from "../chunk-LURY4WNF.js";
18
+ import "../chunk-3XTFX4CL.js";
19
19
  import "../chunk-DINDL2CF.js";
20
20
  import "../chunk-SAF6HGAA.js";
21
21
  import {
@@ -3,7 +3,7 @@ import {
3
3
  COMMANDS,
4
4
  isCommandName,
5
5
  renderHelp
6
- } from "../chunk-GPNOHKFO.js";
6
+ } from "../chunk-3XTFX4CL.js";
7
7
  import {
8
8
  getPackageVersion
9
9
  } from "../chunk-DINDL2CF.js";
@@ -132,6 +132,7 @@ var SETUP_OPTIONS = [
132
132
  ["--connect browser", "Approve in a browser tab instead. For a machine with no app"],
133
133
  ["--connect web", "Legacy browser subscribe page"],
134
134
  ["--connect none", "Skip the phone connect step, same as --skip-phone"],
135
+ ["--control auto|on|off", "Manage phone-start automatically (default), require it, or disable its background service"],
135
136
  ["--skip-phone", "Skip the phone connect step"],
136
137
  ["--verify roundtrip", "Send a real question and wait for you to answer it (default when a human is present)"],
137
138
  ["--verify push", "Only prove a notification was delivered. Automatic when nobody is at the terminal"],
@@ -0,0 +1,210 @@
1
+ import {
2
+ detectClaudeVersion
3
+ } from "./chunk-475T3XIO.js";
4
+ import {
5
+ claudeWired,
6
+ codexWired,
7
+ geminiWired
8
+ } from "./chunk-OBI4YMCT.js";
9
+ import {
10
+ GEMINI_HOOK_BINARY,
11
+ addClaudeMcpServer,
12
+ addGeminiHooks,
13
+ addGeminiMcpServer,
14
+ addPusharyHooks,
15
+ addPusharyToolPermissions,
16
+ hasGeminiHooks
17
+ } from "./chunk-7TS2G4QG.js";
18
+ import {
19
+ guardBinary
20
+ } from "./chunk-AIGDBRIJ.js";
21
+ import {
22
+ resolveGlobalBinDir,
23
+ resolveGlobalBinary
24
+ } from "./chunk-PZA7G4CN.js";
25
+ import {
26
+ CODEX_HOOK_BINARY,
27
+ addCodexHookTrust,
28
+ addCodexHooks,
29
+ addCodexMcpServer,
30
+ codexConfigToml,
31
+ codexHookPositions,
32
+ codexHooksJson,
33
+ hasCodexHooks,
34
+ vscodePluginMcp
35
+ } from "./chunk-V37ZXMH3.js";
36
+ import {
37
+ readJsonSafe
38
+ } from "./chunk-6MTNS63X.js";
39
+
40
+ // src/reapply.ts
41
+ import { join, dirname } from "path";
42
+ import { homedir } from "os";
43
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
44
+ import { parse as parseTOML, stringify as stringifyTOML } from "smol-toml";
45
+ var CLAUDE_SETTINGS = join(homedir(), ".claude", "settings.json");
46
+ var CLAUDE_JSON = join(homedir(), ".claude.json");
47
+ var readJson = (filePath) => {
48
+ const result = readJsonSafe(filePath);
49
+ if (result.kind === "ok") return result.value;
50
+ if (result.kind === "missing") return {};
51
+ return null;
52
+ };
53
+ var writeJson = (filePath, data) => {
54
+ const dir = dirname(filePath);
55
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
56
+ writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
57
+ };
58
+ var hasPusharyClaudeHooks = (settings) => JSON.stringify(settings.hooks ?? {}).includes("pushary-hook");
59
+ var hasPusharyMcp = (claudeJson) => !!claudeJson.mcpServers?.pushary;
60
+ var reapplyClaudeSettings = (apiKey, paths = {}) => {
61
+ const settingsPath = paths.settingsPath ?? CLAUDE_SETTINGS;
62
+ const claudeJsonPath = paths.claudeJsonPath ?? CLAUDE_JSON;
63
+ const settings = readJson(settingsPath);
64
+ const claudeJson = readJson(claudeJsonPath);
65
+ const configured = settings != null && hasPusharyClaudeHooks(settings) || claudeJson != null && hasPusharyMcp(claudeJson);
66
+ if (!configured) return { configured: false, reapplied: false, hooks: false, mcp: false };
67
+ const settingsWritable = settings != null;
68
+ const claudeJsonWritable = claudeJson != null;
69
+ let hooks = false;
70
+ let mcp = false;
71
+ try {
72
+ if (!settingsWritable) throw new Error("settings.json could not be parsed");
73
+ const s = settings;
74
+ addPusharyToolPermissions(s);
75
+ addPusharyHooks(s, resolveGlobalBinDir("pushary-hook"), detectClaudeVersion());
76
+ writeJson(settingsPath, s);
77
+ hooks = true;
78
+ } catch {
79
+ }
80
+ if (apiKey) {
81
+ try {
82
+ if (!claudeJsonWritable) throw new Error(".claude.json could not be parsed");
83
+ const cj = claudeJson;
84
+ addClaudeMcpServer(cj, apiKey);
85
+ writeJson(claudeJsonPath, cj);
86
+ mcp = true;
87
+ } catch {
88
+ }
89
+ }
90
+ return { configured: true, reapplied: hooks || mcp, hooks, mcp };
91
+ };
92
+ var readToml = (filePath) => {
93
+ try {
94
+ const raw = readFileSync(filePath, "utf-8");
95
+ return raw.trim() === "" ? {} : parseTOML(raw);
96
+ } catch {
97
+ return null;
98
+ }
99
+ };
100
+ var inspectConfiguredManagedProviders = (paths = {}) => {
101
+ const providers = [];
102
+ const claudeSettings = readJson(paths.claudeSettingsPath ?? CLAUDE_SETTINGS);
103
+ const claudeJson = readJson(paths.claudeJsonPath ?? CLAUDE_JSON);
104
+ if (claudeWired({ claudeJson, settings: claudeSettings, skillExists: false })) {
105
+ providers.push("claude");
106
+ }
107
+ const codexConfig = readToml(paths.codexConfigPath ?? codexConfigToml());
108
+ const codexHooks = readJson(paths.codexHooksPath ?? codexHooksJson());
109
+ if (codexWired({ config: codexConfig, hooks: codexHooks, skillExists: false })) {
110
+ providers.push("codex");
111
+ }
112
+ const gemini = readJson(paths.geminiSettingsPath ?? join(homedir(), ".gemini", "settings.json"));
113
+ if (geminiWired({ settings: gemini })) {
114
+ providers.push("gemini");
115
+ }
116
+ return providers;
117
+ };
118
+ var reapplyCodexSettings = (apiKey, paths = {}) => {
119
+ const configPath = paths.configPath ?? codexConfigToml();
120
+ const hooksPath = paths.hooksPath ?? codexHooksJson();
121
+ const config = readToml(configPath);
122
+ const hooksConfig = readJson(hooksPath);
123
+ const configured = config != null && !!config.mcp_servers?.pushary || hooksConfig != null && hasCodexHooks(hooksConfig);
124
+ if (!configured) return { configured: false, reapplied: false, hooks: false, mcp: false };
125
+ const command = guardBinary(resolveGlobalBinary(CODEX_HOOK_BINARY) ?? CODEX_HOOK_BINARY);
126
+ let hooks = false;
127
+ let mcp = false;
128
+ if (hooksConfig != null) {
129
+ try {
130
+ addCodexHooks(hooksConfig, command);
131
+ writeJson(hooksPath, hooksConfig);
132
+ hooks = true;
133
+ } catch {
134
+ }
135
+ }
136
+ if (config != null) {
137
+ try {
138
+ if (hooks) addCodexHookTrust(config, hooksPath, command, codexHookPositions(hooksConfig ?? void 0));
139
+ if (apiKey) {
140
+ addCodexMcpServer(config, apiKey);
141
+ mcp = true;
142
+ }
143
+ if (hooks || apiKey) writeFileSync(configPath, stringifyTOML(config), "utf-8");
144
+ } catch {
145
+ }
146
+ }
147
+ return { configured: true, reapplied: hooks || mcp, hooks, mcp };
148
+ };
149
+ var reapplyGeminiSettings = (apiKey, paths = {}) => {
150
+ const settingsPath = paths.settingsPath ?? join(homedir(), ".gemini", "settings.json");
151
+ const settings = readJson(settingsPath);
152
+ if (settings == null) return { configured: false, reapplied: false, hooks: false, mcp: false };
153
+ const configured = hasGeminiHooks(settings) || !!settings.mcpServers?.pushary;
154
+ if (!configured) return { configured: false, reapplied: false, hooks: false, mcp: false };
155
+ let hooks = false;
156
+ let mcp = false;
157
+ try {
158
+ addGeminiHooks(settings, guardBinary(resolveGlobalBinary(GEMINI_HOOK_BINARY) ?? GEMINI_HOOK_BINARY));
159
+ hooks = true;
160
+ if (apiKey) {
161
+ addGeminiMcpServer(settings, apiKey);
162
+ mcp = true;
163
+ }
164
+ writeJson(settingsPath, settings);
165
+ } catch {
166
+ }
167
+ return { configured: true, reapplied: hooks || mcp, hooks, mcp };
168
+ };
169
+ var reapplyPluginMcp = (mcpPath, apiKey) => {
170
+ const mcpConfig = readJson(mcpPath);
171
+ if (mcpConfig == null) return { configured: false, reapplied: false, hooks: false, mcp: false };
172
+ const servers = mcpConfig.mcpServers;
173
+ if (!servers?.pushary) return { configured: false, reapplied: false, hooks: false, mcp: false };
174
+ if (!apiKey) return { configured: true, reapplied: false, hooks: false, mcp: false };
175
+ try {
176
+ addClaudeMcpServer(mcpConfig, apiKey);
177
+ writeJson(mcpPath, mcpConfig);
178
+ return { configured: true, reapplied: true, hooks: false, mcp: true };
179
+ } catch {
180
+ return { configured: true, reapplied: false, hooks: false, mcp: false };
181
+ }
182
+ };
183
+ var reapplyCursorPlugin = (apiKey, paths = {}) => reapplyPluginMcp(
184
+ paths.pluginMcpPath ?? join(homedir(), ".cursor", "plugins", "local", "pushary", "mcp.json"),
185
+ apiKey
186
+ );
187
+ var reapplyVsCodePlugin = (apiKey, paths = {}) => reapplyPluginMcp(paths.pluginMcpPath ?? vscodePluginMcp(), apiKey);
188
+ var reapplyAllAgents = (apiKey) => {
189
+ const runners = [
190
+ { id: "claude", label: "Claude Code", run: () => reapplyClaudeSettings(apiKey) },
191
+ { id: "codex", label: "Codex", run: () => reapplyCodexSettings(apiKey) },
192
+ { id: "gemini", label: "Gemini CLI", run: () => reapplyGeminiSettings(apiKey) },
193
+ { id: "cursor", label: "Cursor", run: () => reapplyCursorPlugin(apiKey) },
194
+ { id: "vscode", label: "VS Code", run: () => reapplyVsCodePlugin(apiKey) }
195
+ ];
196
+ const done = [];
197
+ for (const runner of runners) {
198
+ try {
199
+ const result = runner.run();
200
+ if (result.configured) done.push({ id: runner.id, label: runner.label, result });
201
+ } catch {
202
+ }
203
+ }
204
+ return done;
205
+ };
206
+
207
+ export {
208
+ inspectConfiguredManagedProviders,
209
+ reapplyAllAgents
210
+ };
@@ -121,7 +121,12 @@ var writeKey = (apiKey, options = {}) => {
121
121
  }
122
122
  writeJsonAtomic(
123
123
  configPath,
124
- { ...current, apiKey, installSource: resolveInstallSourceFor(current) },
124
+ {
125
+ ...current,
126
+ apiKey,
127
+ installSource: resolveInstallSourceFor(current),
128
+ ...options.controlMode ? { controlMode: options.controlMode } : {}
129
+ },
125
130
  KEY_FILE_MODE
126
131
  );
127
132
  restrictFile(configPath);
@@ -177,6 +182,12 @@ var readConfigKey = (configPath) => {
177
182
  return key || null;
178
183
  };
179
184
  var readConfigFileKey = () => readConfigKey(configFilePath());
185
+ var readControlMode = () => {
186
+ const result = readJsonSafe(configFilePath());
187
+ if (result.kind !== "ok") return null;
188
+ const value = result.value.controlMode;
189
+ return value === "auto" || value === "on" || value === "off" ? value : null;
190
+ };
180
191
  var readKeySource = () => {
181
192
  const configPath = configFilePath();
182
193
  const envKey = process.env.PUSHARY_API_KEY?.trim() || null;
@@ -194,5 +205,6 @@ export {
194
205
  writeKey,
195
206
  clearKey,
196
207
  readConfigFileKey,
208
+ readControlMode,
197
209
  readKeySource
198
210
  };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  renderCommandHelp
3
- } from "./chunk-GPNOHKFO.js";
3
+ } from "./chunk-3XTFX4CL.js";
4
4
  import {
5
5
  getPackageVersion
6
6
  } from "./chunk-DINDL2CF.js";
@@ -0,0 +1,56 @@
1
+ import {
2
+ resolveBinary,
3
+ resolveGlobalPackageVersion,
4
+ resolvePackageVersionFromBinary
5
+ } from "./chunk-PZA7G4CN.js";
6
+
7
+ // src/live-capabilities.ts
8
+ var CLAUDE_BRIDGE_CAPABILITY = "claude-bridge";
9
+ var CLAUDE_RESUME_CAPABILITY = "claude-resume";
10
+ var CODEX_BRIDGE_CAPABILITY = "codex-bridge";
11
+ var CODEX_RESUME_CAPABILITY = "codex-resume";
12
+ var GEMINI_BRIDGE_CAPABILITY = "gemini-bridge";
13
+ var GEMINI_RESUME_CAPABILITY = "gemini-resume";
14
+ var GEMINI_BRIDGE_MIN_VERSION = [0, 40, 0];
15
+ var version = (raw) => {
16
+ const match = raw?.match(/^(\d+)\.(\d+)\.(\d+)/);
17
+ return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;
18
+ };
19
+ var geminiLiveCapabilities = (rawVersion) => {
20
+ const installed = version(rawVersion);
21
+ if (!installed) return [];
22
+ for (let index = 0; index < GEMINI_BRIDGE_MIN_VERSION.length; index++) {
23
+ if (installed[index] > GEMINI_BRIDGE_MIN_VERSION[index]) break;
24
+ if (installed[index] < GEMINI_BRIDGE_MIN_VERSION[index]) return [];
25
+ }
26
+ return [GEMINI_BRIDGE_CAPABILITY, GEMINI_RESUME_CAPABILITY];
27
+ };
28
+ var providerLiveCapabilities = (probe) => [
29
+ ...probe.claude ? [CLAUDE_BRIDGE_CAPABILITY, CLAUDE_RESUME_CAPABILITY] : [],
30
+ ...probe.codex ? [CODEX_BRIDGE_CAPABILITY, CODEX_RESUME_CAPABILITY] : [],
31
+ ...geminiLiveCapabilities(probe.geminiVersion)
32
+ ];
33
+ var hasSpawnProvider = (capabilities) => capabilities.some(
34
+ (capability) => capability === CLAUDE_BRIDGE_CAPABILITY || capability === CODEX_BRIDGE_CAPABILITY || capability === GEMINI_BRIDGE_CAPABILITY
35
+ );
36
+ var resolveControlPolicy = (input) => {
37
+ if (input.mode === "off") return "disabled";
38
+ if (input.mode === null && !input.servicePresent) return "preserve-absent";
39
+ if (input.providerAvailable && input.managerAvailable) return "enabled";
40
+ return input.servicePresent ? "legacy" : "unsupported";
41
+ };
42
+ var detectProviderLiveCapabilities = (providers = ["claude", "codex", "gemini"]) => {
43
+ const enabled = new Set(providers);
44
+ const geminiBin = enabled.has("gemini") ? resolveBinary("gemini") : void 0;
45
+ return providerLiveCapabilities({
46
+ claude: enabled.has("claude") && resolveBinary("claude") !== void 0,
47
+ codex: enabled.has("codex") && resolveBinary("codex") !== void 0,
48
+ geminiVersion: geminiBin ? resolvePackageVersionFromBinary(geminiBin, "@google/gemini-cli") ?? resolveGlobalPackageVersion("@google/gemini-cli") : void 0
49
+ });
50
+ };
51
+
52
+ export {
53
+ hasSpawnProvider,
54
+ resolveControlPolicy,
55
+ detectProviderLiveCapabilities
56
+ };
@@ -30,6 +30,31 @@ import { createHash, randomUUID } from "crypto";
30
30
  import { homedir } from "os";
31
31
  import { execFileSync } from "child_process";
32
32
  var daemonNeedsHandoff = (status) => status.kind === "version-mismatch" || status.kind === "configuration-mismatch" || status.kind === "unresponsive" && status.processAlive === true;
33
+ var daemonServiceManagerAvailable = (options = {}) => {
34
+ const platform = options.platform ?? process.platform;
35
+ const run = options.run ?? ((command, args) => {
36
+ execFileSync(command, [...args], { stdio: "ignore", windowsHide: true });
37
+ });
38
+ try {
39
+ if (platform === "darwin") {
40
+ const uid = options.uid ?? process.getuid?.();
41
+ if (uid === void 0) return false;
42
+ run("launchctl", ["print", `gui/${uid}`]);
43
+ return true;
44
+ }
45
+ if (platform === "linux") {
46
+ run("systemctl", ["--user", "show-environment"]);
47
+ return true;
48
+ }
49
+ if (platform === "win32") {
50
+ run("sc.exe", ["query", "Schedule"]);
51
+ return true;
52
+ }
53
+ return false;
54
+ } catch {
55
+ return false;
56
+ }
57
+ };
33
58
  var statePath = (dir) => join(dir, "daemon-state.json");
34
59
  var lockPath = (dir) => join(dir, "daemon.lock");
35
60
  var targetPath = (dir) => join(dir, "daemon-target.json");
@@ -78,7 +103,8 @@ var buildDaemonService = (input) => {
78
103
  ],
79
104
  start: [{ command: "launchctl", args: ["kickstart", "-k", target] }],
80
105
  stop: [{ command: "launchctl", args: ["kill", "SIGTERM", target], ignoreFailure: true }],
81
- uninstall: [{ command: "launchctl", args: ["bootout", domain, definitionPath], ignoreFailure: true }]
106
+ uninstall: [{ command: "launchctl", args: ["bootout", domain, definitionPath], ignoreFailure: true }],
107
+ registrationProbe: { command: "launchctl", args: ["print", target] }
82
108
  };
83
109
  }
84
110
  if (input.platform === "linux") {
@@ -111,6 +137,7 @@ WantedBy=default.target
111
137
  uninstall: [
112
138
  { command: "systemctl", args: ["--user", "disable", "--now", unit], ignoreFailure: true }
113
139
  ],
140
+ registrationProbe: { command: "systemctl", args: ["--user", "is-enabled", unit] },
114
141
  reloadAfterUninstall: { command: "systemctl", args: ["--user", "daemon-reload"] }
115
142
  };
116
143
  }
@@ -148,7 +175,8 @@ WantedBy=default.target
148
175
  ],
149
176
  start: [{ command: "schtasks.exe", args: ["/Run", "/TN", taskName] }],
150
177
  stop: [{ command: "schtasks.exe", args: ["/End", "/TN", taskName], ignoreFailure: true }],
151
- uninstall: [{ command: "schtasks.exe", args: ["/Delete", "/TN", taskName, "/F"], ignoreFailure: true }]
178
+ uninstall: [{ command: "schtasks.exe", args: ["/Delete", "/TN", taskName, "/F"], ignoreFailure: true }],
179
+ registrationProbe: { command: "schtasks.exe", args: ["/Query", "/TN", taskName] }
152
180
  };
153
181
  }
154
182
  return null;
@@ -179,12 +207,6 @@ var resolveDaemonServiceDefinition = (options = {}) => {
179
207
  }
180
208
  }
181
209
  }
182
- const argvEntry = options.argvEntry ?? process.argv[1];
183
- if (!daemonEntry && argvEntry) {
184
- const path = platform === "win32" ? win32Path : { dirname, join };
185
- const candidate = path.join(path.dirname(argvEntry), "pushary-daemon.js");
186
- if (exists(candidate)) daemonEntry = candidate;
187
- }
188
210
  if (!daemonEntry || !exists(daemonEntry)) return null;
189
211
  const homeDir = options.homeDir ?? homedir();
190
212
  return buildDaemonService({
@@ -212,6 +234,13 @@ var applyDaemonService = (action, definition, options = {}) => {
212
234
  }
213
235
  }
214
236
  if (action === "uninstall") {
237
+ let registered = false;
238
+ try {
239
+ run(definition.registrationProbe.command, definition.registrationProbe.args);
240
+ registered = true;
241
+ } catch {
242
+ }
243
+ if (registered) throw new Error("Native background service remains registered");
215
244
  safeUnlink(definition.definitionPath);
216
245
  const reload = definition.reloadAfterUninstall;
217
246
  if (reload) run(reload.command, reload.args);
@@ -236,7 +265,7 @@ var parseDaemonAction = (argv) => {
236
265
  return DAEMON_ACTIONS.has(action) ? action : null;
237
266
  };
238
267
  var manageDaemonService = (action, options = {}) => {
239
- const definition = action === "uninstall" ? buildDaemonService({
268
+ const definition = action === "uninstall" || action === "stop" ? buildDaemonService({
240
269
  platform: options.platform ?? process.platform,
241
270
  homeDir: options.homeDir ?? homedir(),
242
271
  stateDir: options.stateDir ?? pusharyDir(),
@@ -251,8 +280,23 @@ var manageDaemonService = (action, options = {}) => {
251
280
  detail: "Could not find the globally installed daemon entry. Run Pushary setup again."
252
281
  };
253
282
  }
283
+ if (action === "uninstall" && !daemonServiceManagerAvailable(options)) {
284
+ return { kind: "failed", detail: "Native background-service manager is unavailable" };
285
+ }
254
286
  return applyDaemonService(action, definition, { run: options.run });
255
287
  };
288
+ var hasDaemonServiceDefinition = (options = {}) => {
289
+ const definition = buildDaemonService({
290
+ platform: options.platform ?? process.platform,
291
+ homeDir: options.homeDir ?? homedir(),
292
+ stateDir: options.stateDir ?? pusharyDir(),
293
+ execPath: options.execPath ?? process.execPath,
294
+ daemonEntry: options.daemonEntry ?? process.execPath,
295
+ pathEnv: options.pathEnv ?? process.env.PATH ?? "",
296
+ uid: options.uid ?? process.getuid?.()
297
+ });
298
+ return definition !== null && existsSync(definition.definitionPath);
299
+ };
256
300
  var spawnDetachedDaemon = (plan, options = {}) => {
257
301
  const spawnImpl = options.spawnImpl ?? spawnClaude;
258
302
  const child = spawnImpl(plan.command, plan.args, {
@@ -515,6 +559,21 @@ var stopDaemonRunning = async (options = {}) => {
515
559
  safeUnlink(lockPath(dir));
516
560
  return { kind: "stopped" };
517
561
  };
562
+ var deactivateDaemonService = async (action, options) => {
563
+ const platform = options.platform ?? process.platform;
564
+ const supported = ["darwin", "linux", "win32"].includes(platform);
565
+ const managerAvailable = supported && daemonServiceManagerAvailable(options);
566
+ const definitionPresent = supported && hasDaemonServiceDefinition(options);
567
+ const service = definitionPresent && !managerAvailable ? { kind: "failed", detail: "Native background-service manager is unavailable" } : managerAvailable ? manageDaemonService(action, options) : { kind: "ok" };
568
+ const stopped = await stopDaemonRunning(options);
569
+ const failures = [
570
+ service.kind === "ok" ? null : service.detail,
571
+ stopped.kind === "unavailable" ? stopped.detail : null
572
+ ].filter((detail) => detail !== null);
573
+ return failures.length > 0 ? { kind: "failed", detail: failures.join("; ") } : { kind: "ok" };
574
+ };
575
+ var stopDaemonService = async (options = {}) => deactivateDaemonService("stop", options);
576
+ var disableDaemonService = async (options = {}) => deactivateDaemonService("uninstall", options);
518
577
  var replaceDaemonService = async (options = {}) => {
519
578
  const stopped = await stopDaemonRunning(options);
520
579
  return stopped.kind === "unavailable" ? stopped : manageDaemonService("install", options);
@@ -576,13 +635,17 @@ var ensureDaemonRunning = async (options = {}) => {
576
635
  };
577
636
 
578
637
  export {
638
+ daemonServiceManagerAvailable,
579
639
  DAEMON_LEASE_RENEW_INTERVAL_MS,
580
640
  parseDaemonAction,
581
641
  manageDaemonService,
642
+ hasDaemonServiceDefinition,
582
643
  readDaemonStatus,
583
644
  acquireDaemonLease,
584
645
  requestDaemonHandoff,
585
646
  stopDaemonRunning,
647
+ stopDaemonService,
648
+ disableDaemonService,
586
649
  replaceDaemonService,
587
650
  ensureDaemonRunning
588
651
  };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  readConfigFileKey
3
- } from "./chunk-W6NPWHBJ.js";
3
+ } from "./chunk-L3YUHEB6.js";
4
4
 
5
5
  // src/bell/fleet.ts
6
6
  import { closeSync, constants, futimesSync, lstatSync, mkdirSync, openSync, readdirSync, unlinkSync } from "fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pushary/agent-hooks",
3
- "version": "0.89.4",
3
+ "version": "0.89.6",
4
4
  "description": "Permission hooks for AI coding agents: route tool approvals through Pushary push notifications",
5
5
  "keywords": [
6
6
  "pushary",
@@ -1,29 +0,0 @@
1
- // src/live-capabilities.ts
2
- var CLAUDE_BRIDGE_CAPABILITY = "claude-bridge";
3
- var CLAUDE_RESUME_CAPABILITY = "claude-resume";
4
- var CODEX_BRIDGE_CAPABILITY = "codex-bridge";
5
- var CODEX_RESUME_CAPABILITY = "codex-resume";
6
- var GEMINI_BRIDGE_CAPABILITY = "gemini-bridge";
7
- var GEMINI_RESUME_CAPABILITY = "gemini-resume";
8
- var GEMINI_BRIDGE_MIN_VERSION = [0, 40, 0];
9
- var version = (raw) => {
10
- const match = raw?.match(/^(\d+)\.(\d+)\.(\d+)/);
11
- return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;
12
- };
13
- var geminiLiveCapabilities = (rawVersion) => {
14
- const installed = version(rawVersion);
15
- if (!installed) return [];
16
- for (let index = 0; index < GEMINI_BRIDGE_MIN_VERSION.length; index++) {
17
- if (installed[index] > GEMINI_BRIDGE_MIN_VERSION[index]) break;
18
- if (installed[index] < GEMINI_BRIDGE_MIN_VERSION[index]) return [];
19
- }
20
- return [GEMINI_BRIDGE_CAPABILITY, GEMINI_RESUME_CAPABILITY];
21
- };
22
-
23
- export {
24
- CLAUDE_BRIDGE_CAPABILITY,
25
- CLAUDE_RESUME_CAPABILITY,
26
- CODEX_BRIDGE_CAPABILITY,
27
- CODEX_RESUME_CAPABILITY,
28
- geminiLiveCapabilities
29
- };