@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.
- package/dist/bin/pushary-bell-hook.js +2 -2
- package/dist/bin/pushary-bell.js +4 -4
- package/dist/bin/pushary-claude.js +1 -1
- package/dist/bin/pushary-clean.js +5 -8
- package/dist/bin/pushary-codex-bridge.js +1 -1
- package/dist/bin/pushary-connect.js +3 -3
- package/dist/bin/pushary-daemon.js +64 -31
- package/dist/bin/pushary-disconnect.js +2 -2
- package/dist/bin/pushary-doctor.js +51 -24
- package/dist/bin/pushary-hook.js +2 -2
- package/dist/bin/pushary-login.js +3 -3
- package/dist/bin/pushary-logout.js +3 -3
- package/dist/bin/pushary-mode.js +2 -2
- package/dist/bin/pushary-setup.js +116 -21
- package/dist/bin/pushary-stats.js +2 -2
- package/dist/bin/pushary-status.js +3 -3
- package/dist/bin/pushary-suggestions.js +2 -2
- package/dist/bin/pushary-upgrade.js +68 -199
- package/dist/bin/pushary-wait.js +2 -2
- package/dist/bin/pushary.js +1 -1
- package/dist/{chunk-GPNOHKFO.js → chunk-3XTFX4CL.js} +1 -0
- package/dist/chunk-5TASNKRX.js +210 -0
- package/dist/{chunk-W6NPWHBJ.js → chunk-L3YUHEB6.js} +13 -1
- package/dist/{chunk-KJ57OPCC.js → chunk-LURY4WNF.js} +1 -1
- package/dist/chunk-NKHEHEUM.js +56 -0
- package/dist/{chunk-NLMSSKES.js → chunk-NQNCSPEH.js} +72 -9
- package/dist/{chunk-7IJYOBHL.js → chunk-WQGMUIDW.js} +1 -1
- package/package.json +1 -1
- package/dist/chunk-FWUEYXSD.js +0 -29
package/dist/bin/pushary-wait.js
CHANGED
|
@@ -14,8 +14,8 @@ import {
|
|
|
14
14
|
} from "../chunk-GMXKITVA.js";
|
|
15
15
|
import {
|
|
16
16
|
exitOnHelpFlag
|
|
17
|
-
} from "../chunk-
|
|
18
|
-
import "../chunk-
|
|
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 {
|
package/dist/bin/pushary.js
CHANGED
|
@@ -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
|
-
{
|
|
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
|
};
|
|
@@ -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
|
};
|
package/package.json
CHANGED
package/dist/chunk-FWUEYXSD.js
DELETED
|
@@ -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
|
-
};
|