pushary 1.9.136 → 1.9.138
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/CHANGELOG.md +16 -0
- package/dist/{api-5H25QRNM.js → api-J4XJ7XWW.js} +9 -9
- package/dist/bin/pushary-audit.js +3 -3
- package/dist/bin/pushary-bell-hook.js +19 -19
- package/dist/bin/pushary-bell.js +7 -7
- package/dist/bin/pushary-claude.js +23 -23
- package/dist/bin/pushary-clean.js +34 -34
- package/dist/bin/pushary-codex-bridge.js +15 -15
- package/dist/bin/pushary-codex-hook.js +30 -30
- package/dist/bin/pushary-codex-session.js +6 -6
- package/dist/bin/pushary-codex.js +11 -11
- package/dist/bin/pushary-connect.js +23 -23
- package/dist/bin/pushary-daemon-supervisor.js +91 -12
- package/dist/bin/pushary-daemon.js +35 -35
- package/dist/bin/pushary-disconnect.js +23 -23
- package/dist/bin/pushary-display-hook.js +45 -24
- package/dist/bin/pushary-doctor.js +49 -45
- package/dist/bin/pushary-elicitation-hook.js +20 -20
- package/dist/bin/pushary-gemini-bridge.js +6 -6
- package/dist/bin/pushary-gemini-hook.js +23 -23
- package/dist/bin/pushary-hook.js +25 -25
- package/dist/bin/pushary-login.js +17 -17
- package/dist/bin/pushary-logout.js +21 -21
- package/dist/bin/pushary-mcp.js +11 -11
- package/dist/bin/pushary-mode.js +12 -12
- package/dist/bin/pushary-notification-hook.js +19 -19
- package/dist/bin/pushary-opencode-hook.js +22 -22
- package/dist/bin/pushary-permission-denied-hook.js +25 -25
- package/dist/bin/pushary-permission-hook.js +25 -25
- package/dist/bin/pushary-post-hook.js +20 -20
- package/dist/bin/pushary-prompt-hook.js +19 -19
- package/dist/bin/pushary-session-end-hook.js +19 -19
- package/dist/bin/pushary-session-start-hook.js +28 -28
- package/dist/bin/pushary-setup.js +54 -52
- package/dist/bin/pushary-status.js +27 -27
- package/dist/bin/pushary-stop-hook.js +19 -19
- package/dist/bin/pushary-stopfailure-hook.js +19 -19
- package/dist/bin/pushary-suggestions.js +12 -12
- package/dist/bin/pushary-transcript-register.js +9 -9
- package/dist/bin/pushary-transcripts.js +19 -19
- package/dist/bin/pushary-upgrade.js +37 -37
- package/dist/bin/pushary-wait.js +12 -12
- package/dist/bin/pushary.js +6 -6
- package/dist/{chunk-ICCM3DLT.js → chunk-33E75LIY.js} +1 -1
- package/dist/{chunk-IHAKBLW2.js → chunk-42BVIKPZ.js} +3 -3
- package/dist/{chunk-3QBI5C6P.js → chunk-52B2TQJM.js} +1 -1
- package/dist/{chunk-NZD6ISCL.js → chunk-5ZK4RHYR.js} +1 -1
- package/dist/{chunk-FAF5RDWT.js → chunk-6TK3DWSF.js} +293 -48
- package/dist/{chunk-DBIPNY7J.js → chunk-7WR3FDDX.js} +2 -2
- package/dist/{chunk-6SWFS4GU.js → chunk-AGVE7MXF.js} +2 -2
- package/dist/{chunk-43DT3QWZ.js → chunk-APTNHX63.js} +3 -3
- package/dist/{chunk-L2GADKFL.js → chunk-B3AZPYRU.js} +6 -6
- package/dist/chunk-B4UIRMOE.js +31 -0
- package/dist/{chunk-JZJ5CM6X.js → chunk-CBTXOWB3.js} +3 -3
- package/dist/{chunk-A7R43KOX.js → chunk-CULDO4UA.js} +2 -2
- package/dist/{chunk-YHX5YF77.js → chunk-DES272QQ.js} +3 -3
- package/dist/{chunk-WXUEOHYY.js → chunk-DK6CMXYI.js} +5 -5
- package/dist/{chunk-VV7WRIQT.js → chunk-DMZMPYLB.js} +2 -2
- package/dist/{chunk-WNT4JHK3.js → chunk-EHQCMJHI.js} +1 -1
- package/dist/{chunk-V7ZY7P2X.js → chunk-EJSU5YWO.js} +3 -3
- package/dist/{chunk-HKJLPVPZ.js → chunk-FJ7OESWX.js} +3 -3
- package/dist/{chunk-2R4OVJHS.js → chunk-FO5MHOBI.js} +4 -4
- package/dist/{chunk-NN43KGTN.js → chunk-FQ3ASV5L.js} +3 -3
- package/dist/{chunk-GS5FH3C2.js → chunk-FYLYAVQG.js} +2 -2
- package/dist/{chunk-2MVKT7KH.js → chunk-H5XLVJI7.js} +1 -1
- package/dist/{chunk-UP5QXEUU.js → chunk-HVRXBHX2.js} +2 -2
- package/dist/{chunk-VBWJ756P.js → chunk-ICQU3SNR.js} +3 -3
- package/dist/{chunk-2XDVEBHI.js → chunk-IDGWQY3J.js} +4 -4
- package/dist/{chunk-L7Q57R4J.js → chunk-JFGM6VSU.js} +3 -3
- package/dist/{chunk-RPFSVNH6.js → chunk-KN4YJ4QS.js} +2 -2
- package/dist/{chunk-Q2VV77IY.js → chunk-KXKE3SW3.js} +4 -4
- package/dist/{chunk-MQ3I5OIC.js → chunk-L3UV4LLL.js} +7 -7
- package/dist/{chunk-D7AAAD6W.js → chunk-LF3ZRLUQ.js} +8 -8
- package/dist/{chunk-YURIU333.js → chunk-LIUWN23V.js} +4 -4
- package/dist/{chunk-54TZGPZP.js → chunk-LIZEMDE4.js} +1 -1
- package/dist/{chunk-G73ACPR2.js → chunk-LPXHKIJC.js} +1 -1
- package/dist/{chunk-2E46RALI.js → chunk-NIBF37NU.js} +2 -2
- package/dist/{chunk-EJHD44ZN.js → chunk-NLJ2ILA7.js} +1 -1
- package/dist/{chunk-3HXOR6E5.js → chunk-NNDUDXOJ.js} +9 -9
- package/dist/{chunk-H2RE3IPK.js → chunk-NUG2A73X.js} +1 -1
- package/dist/{chunk-62GD26OE.js → chunk-O26H5X5M.js} +2 -2
- package/dist/{chunk-POV2TBFA.js → chunk-OAGYR5LI.js} +9 -9
- package/dist/{chunk-4T72AHIA.js → chunk-OXPYENHL.js} +1 -1
- package/dist/{chunk-EQZB5P6I.js → chunk-P6HLLS5J.js} +2 -2
- package/dist/{chunk-ZWLSXECG.js → chunk-P7YVVWTW.js} +1 -1
- package/dist/{chunk-TLK5YLIE.js → chunk-PNDL3OMR.js} +2 -2
- package/dist/{chunk-A4YOXS24.js → chunk-PPCZSOCL.js} +2 -2
- package/dist/{chunk-KLV2NQVT.js → chunk-S47AAQFT.js} +2 -2
- package/dist/{chunk-PHA6AFOR.js → chunk-SNMTACCY.js} +4 -4
- package/dist/{chunk-VO77WHK4.js → chunk-TJCUGBCZ.js} +5 -5
- package/dist/{chunk-R7KC57PC.js → chunk-TN5PGMH5.js} +1 -1
- package/dist/{chunk-O5T53LZ5.js → chunk-TXPXK5Q6.js} +10 -10
- package/dist/{chunk-ZWIJJYN3.js → chunk-VF4N6NHG.js} +3 -3
- package/dist/{chunk-HY4ATVCT.js → chunk-VQMGR32B.js} +1 -1
- package/dist/{chunk-LAWI6NQK.js → chunk-WHOFZB5W.js} +1 -1
- package/dist/{chunk-J42EAEX3.js → chunk-XR27HPYC.js} +2 -1
- package/dist/{codex-app-cards-switch-Z7TMF2OR.js → codex-app-cards-switch-R3MIDYFA.js} +6 -6
- package/dist/{codex-desktop-launch-HKXGKL3T.js → codex-desktop-launch-2YRIBVDK.js} +1 -1
- package/dist/{codex-session-launch-DTGH7ZKM.js → codex-session-launch-CTMTMGHU.js} +15 -15
- package/dist/{global-upgrade-5UAH5DCG.js → global-upgrade-NMTIVAJ3.js} +8 -8
- package/dist/{identity-UFJEWGEU.js → identity-3XKATUN2.js} +3 -3
- package/dist/{live-capabilities-BL3SHFWX.js → live-capabilities-MR35FXPF.js} +3 -3
- package/dist/paths-YA5ROXGC.js +2 -2
- package/dist/{reapply-OPQF4DPQ.js → reapply-LIBOIVBT.js} +23 -23
- package/dist/src/index.js +25 -25
- package/dist/{upgrade-lock-AZLOOGKV.js → upgrade-lock-LK4XD3HR.js} +3 -3
- package/package.json +1 -1
- package/dist/bin/pushary-daemon-supervisor.d.ts +0 -1
- package/dist/chunk-GACQSKNG.js +0 -75
|
@@ -4,16 +4,16 @@ import {
|
|
|
4
4
|
} from "./chunk-H6CL3T2S.js";
|
|
5
5
|
import {
|
|
6
6
|
getMachineId
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-EHQCMJHI.js";
|
|
8
8
|
import {
|
|
9
9
|
readControlMode
|
|
10
10
|
} from "./chunk-PNVTPEO5.js";
|
|
11
11
|
import {
|
|
12
12
|
pusharyDir
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-TN5PGMH5.js";
|
|
14
14
|
import {
|
|
15
15
|
resolveGlobalBinary
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-FYLYAVQG.js";
|
|
17
17
|
import {
|
|
18
18
|
getApiKey
|
|
19
19
|
} from "./chunk-IKBTG3OT.js";
|
|
@@ -34,9 +34,158 @@ import {
|
|
|
34
34
|
isRecord
|
|
35
35
|
} from "./chunk-DL67HX3D.js";
|
|
36
36
|
|
|
37
|
+
// src/daemon-entry-guard.ts
|
|
38
|
+
import { mkdirSync, readFileSync } from "fs";
|
|
39
|
+
import { basename, dirname, join } from "path";
|
|
40
|
+
var DAEMON_ENTRY_GUARD_SOURCE = [
|
|
41
|
+
"const { existsSync } = require('node:fs')",
|
|
42
|
+
"if (process.argv[1] && !existsSync(process.argv[1])) process.exit(0)",
|
|
43
|
+
""
|
|
44
|
+
].join("\n");
|
|
45
|
+
var DAEMON_ENTRY_GUARD_FILE = "daemon-entry-guard.cjs";
|
|
46
|
+
var NODE_EXECUTABLE = /^node(?:\.exe)?$/i;
|
|
47
|
+
var ENTRY_GUARD_PRELOAD_FLAG = "--require";
|
|
48
|
+
var UNGUARDED = { kind: "unguarded" };
|
|
49
|
+
var daemonEntryGuardPath = (stateDir) => join(stateDir, DAEMON_ENTRY_GUARD_FILE);
|
|
50
|
+
var entryGuardApplies = (platform, execPath) => platform === "darwin" && NODE_EXECUTABLE.test(basename(execPath));
|
|
51
|
+
var holdsDaemonEntryGuard = (path) => {
|
|
52
|
+
try {
|
|
53
|
+
return readFileSync(path, "utf8") === DAEMON_ENTRY_GUARD_SOURCE;
|
|
54
|
+
} catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
var writeDaemonEntryGuardAt = (path) => {
|
|
59
|
+
if (holdsDaemonEntryGuard(path)) return { kind: "in-place" };
|
|
60
|
+
try {
|
|
61
|
+
mkdirSync(dirname(path), { recursive: true, mode: 448 });
|
|
62
|
+
writeFileAtomic(path, DAEMON_ENTRY_GUARD_SOURCE, 384);
|
|
63
|
+
return { kind: "in-place" };
|
|
64
|
+
} catch (error) {
|
|
65
|
+
return { kind: "failed", detail: error instanceof Error ? error.message : String(error) };
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
var writeDaemonEntryGuard = (input) => {
|
|
69
|
+
if (!entryGuardApplies(input.platform, input.execPath)) return UNGUARDED;
|
|
70
|
+
const path = daemonEntryGuardPath(input.stateDir);
|
|
71
|
+
const written = writeDaemonEntryGuardAt(path);
|
|
72
|
+
if (written.kind === "in-place") return { kind: "guarded", path };
|
|
73
|
+
input.warn(`[pushary] could not write ${path}, so the background service was installed without its uninstall guard: ${written.detail}
|
|
74
|
+
`);
|
|
75
|
+
return UNGUARDED;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// src/daemon-supervisor.ts
|
|
79
|
+
import { join as join2 } from "path";
|
|
80
|
+
var DAEMON_SUPERVISOR_SCRIPT = "pushary-daemon-supervisor.js";
|
|
81
|
+
var SUPERVISOR_LAUNCH_FLAG = "--launch";
|
|
82
|
+
var DAEMON_LOG_FILE = "daemon.log";
|
|
83
|
+
var DAEMON_ERROR_LOG_FILE = "daemon-error.log";
|
|
84
|
+
var supervisorTaskArguments = (daemonEntry, stateDir) => [daemonEntry, stateDir, SUPERVISOR_LAUNCH_FLAG];
|
|
85
|
+
var parseSupervisorInvocation = (args) => {
|
|
86
|
+
const launching = args.length > 1 && args[args.length - 1] === SUPERVISOR_LAUNCH_FLAG;
|
|
87
|
+
const [daemonEntry, stateDir] = launching ? args.slice(0, -1) : args;
|
|
88
|
+
if (!daemonEntry || daemonEntry === SUPERVISOR_LAUNCH_FLAG) return { kind: "missing-entry" };
|
|
89
|
+
return { kind: launching ? "launch" : "supervise", daemonEntry, stateDir: stateDir || null };
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// src/diagnostics/service-runtime.ts
|
|
93
|
+
var unescapeXml = (value) => value.replaceAll(""", '"').replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">").replaceAll("&", "&");
|
|
94
|
+
var unquoteSystemdExecutable = (value) => value.replace(/\\(["\\])|%(%)/g, (_match, escaped, percent) => escaped ?? percent ?? "");
|
|
95
|
+
var unquoteSystemdArgument = (value) => value.replace(/\\(["\\])|%(%)|\$(\$)/g, (_match, escaped, percent, dollar) => escaped ?? percent ?? dollar ?? "");
|
|
96
|
+
var readServiceExecPath = (contents, platform) => {
|
|
97
|
+
if (platform === "darwin") {
|
|
98
|
+
const program = contents.match(/<key>ProgramArguments<\/key>\s*<array>\s*<string>([^<]*)<\/string>/)?.[1];
|
|
99
|
+
return program ? unescapeXml(program) : null;
|
|
100
|
+
}
|
|
101
|
+
if (platform === "linux") {
|
|
102
|
+
const exec = contents.match(/^ExecStart="((?:[^"\\]|\\.)*)"/m)?.[1];
|
|
103
|
+
return exec ? unquoteSystemdExecutable(exec) : null;
|
|
104
|
+
}
|
|
105
|
+
if (platform === "win32") {
|
|
106
|
+
const command = contents.match(/<Command>([^<]*)<\/Command>/)?.[1];
|
|
107
|
+
return command ? unescapeXml(command) : null;
|
|
108
|
+
}
|
|
109
|
+
return null;
|
|
110
|
+
};
|
|
111
|
+
var readLaunchdProgramArguments = (contents) => {
|
|
112
|
+
const array = contents.match(/<key>ProgramArguments<\/key>\s*<array>([\s\S]*?)<\/array>/)?.[1] ?? "";
|
|
113
|
+
return [...array.matchAll(/<string>([^<]*)<\/string>/g)].map((match) => unescapeXml(match[1] ?? ""));
|
|
114
|
+
};
|
|
115
|
+
var systemdExecStartArguments = (contents) => {
|
|
116
|
+
const line = contents.match(/^ExecStart=(.*)$/m)?.[1] ?? "";
|
|
117
|
+
return [...line.matchAll(/"((?:[^"\\]|\\.)*)"/g)].map((match, index) => (index === 0 ? unquoteSystemdExecutable : unquoteSystemdArgument)(match[1] ?? ""));
|
|
118
|
+
};
|
|
119
|
+
var windowsTaskArguments = (contents) => {
|
|
120
|
+
const args = unescapeXml(contents.match(/<Arguments>([^<]*)<\/Arguments>/)?.[1] ?? "");
|
|
121
|
+
return [...args.matchAll(/"([^"]*)"/g)].map((match) => match[1] ?? "");
|
|
122
|
+
};
|
|
123
|
+
var serviceArguments = (contents, platform) => {
|
|
124
|
+
if (platform === "darwin") return readLaunchdProgramArguments(contents);
|
|
125
|
+
if (platform === "linux") return systemdExecStartArguments(contents);
|
|
126
|
+
if (platform === "win32") return windowsTaskArguments(contents);
|
|
127
|
+
return [];
|
|
128
|
+
};
|
|
129
|
+
var namesTheSupervisor = (path) => path.split(/[\\/]/).at(-1) === DAEMON_SUPERVISOR_SCRIPT;
|
|
130
|
+
var windowsTaskDaemonEntry = (contents) => {
|
|
131
|
+
const [program, ...supervisorArguments] = windowsTaskArguments(contents);
|
|
132
|
+
if (program === void 0) return null;
|
|
133
|
+
if (!namesTheSupervisor(program)) return program;
|
|
134
|
+
const invocation = parseSupervisorInvocation(supervisorArguments);
|
|
135
|
+
return invocation.kind === "missing-entry" ? null : invocation.daemonEntry;
|
|
136
|
+
};
|
|
137
|
+
var readServiceDaemonEntry = (contents, platform) => platform === "win32" ? windowsTaskDaemonEntry(contents) : serviceArguments(contents, platform).at(-1) ?? null;
|
|
138
|
+
var readServiceEntryGuard = (contents, platform) => {
|
|
139
|
+
if (platform !== "darwin") return null;
|
|
140
|
+
const [, flag, guard] = readLaunchdProgramArguments(contents);
|
|
141
|
+
return flag === ENTRY_GUARD_PRELOAD_FLAG && guard !== void 0 ? guard : null;
|
|
142
|
+
};
|
|
143
|
+
var serviceStartFileChecks = (contents, platform, exists) => {
|
|
144
|
+
const checks = [];
|
|
145
|
+
const entry = readServiceDaemonEntry(contents, platform);
|
|
146
|
+
if (entry !== null) {
|
|
147
|
+
const present = exists(entry);
|
|
148
|
+
checks.push({
|
|
149
|
+
label: "Remote-control service entry",
|
|
150
|
+
passed: present,
|
|
151
|
+
detail: present ? entry : `${entry} is gone, so the background service starts nothing at login; run \`pushary daemon install\` from the Pushary install you use`
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
const guard = readServiceEntryGuard(contents, platform);
|
|
155
|
+
if (guard !== null && !exists(guard)) {
|
|
156
|
+
checks.push({
|
|
157
|
+
label: "Remote-control service start guard",
|
|
158
|
+
passed: false,
|
|
159
|
+
detail: `${guard} is gone, so the background service cannot start; run \`pushary daemon install\` to restore it`
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
return checks;
|
|
163
|
+
};
|
|
164
|
+
var MANAGER_SEGMENTS = [
|
|
165
|
+
[".nvm", "nvm"],
|
|
166
|
+
["nvm", "nvm"],
|
|
167
|
+
["fnm", "fnm"],
|
|
168
|
+
[".fnm", "fnm"],
|
|
169
|
+
[".volta", "volta"],
|
|
170
|
+
["volta", "volta"],
|
|
171
|
+
[".asdf", "asdf"],
|
|
172
|
+
["asdf", "asdf"],
|
|
173
|
+
["Cellar", "homebrew"]
|
|
174
|
+
];
|
|
175
|
+
var versionManagerOf = (execPath) => {
|
|
176
|
+
const segments = execPath.split(/[/\\]/);
|
|
177
|
+
for (const segment of segments) {
|
|
178
|
+
const hit = MANAGER_SEGMENTS.find(([name]) => name === segment);
|
|
179
|
+
if (hit) return hit[1];
|
|
180
|
+
}
|
|
181
|
+
return null;
|
|
182
|
+
};
|
|
183
|
+
var describeVersionManagerPin = (execPath, manager) => `The background service is pinned to ${execPath}, which ${manager} manages. Switching or upgrading Node strands it; run pushary daemon install afterwards.`;
|
|
184
|
+
var describeServiceNodeRisk = (manager) => manager === "homebrew" ? "a Homebrew version folder; brew upgrade strands the service, and `pushary daemon install` repins it to the stable link" : `managed by ${manager}; a version switch strands the service`;
|
|
185
|
+
|
|
37
186
|
// src/daemon-lifecycle.ts
|
|
38
|
-
import { dirname, join, win32 as win32Path } from "path";
|
|
39
|
-
import { existsSync, mkdirSync, readFileSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
187
|
+
import { dirname as dirname2, join as join3, win32 as win32Path } from "path";
|
|
188
|
+
import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, realpathSync, renameSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
40
189
|
import { createHash, randomUUID } from "crypto";
|
|
41
190
|
import { homedir, uptime, userInfo } from "os";
|
|
42
191
|
import { execFileSync } from "child_process";
|
|
@@ -55,7 +204,7 @@ var remoteProofIsFresh = (timestamp, now) => {
|
|
|
55
204
|
};
|
|
56
205
|
var daemonHasRemoteProof = (status, now = Date.now()) => status.kind === "running" && remoteProofIsFresh(status.lastSuccessfulHeartbeatAt, now) && remoteProofIsFresh(status.lastSuccessfulControlAt, now);
|
|
57
206
|
var readServiceDefinitionFile = (path) => {
|
|
58
|
-
const bytes =
|
|
207
|
+
const bytes = readFileSync2(path);
|
|
59
208
|
const encoding = bytes.length >= 2 && bytes[0] === 255 && bytes[1] === 254 ? "utf16le" : "utf-8";
|
|
60
209
|
return { contents: bytes.toString(encoding), encoding };
|
|
61
210
|
};
|
|
@@ -105,9 +254,9 @@ var daemonServiceManagerAvailable = (options = {}) => {
|
|
|
105
254
|
}
|
|
106
255
|
};
|
|
107
256
|
var DAEMON_STATE_FILE = "daemon-state.json";
|
|
108
|
-
var statePath = (dir) =>
|
|
109
|
-
var lockPath = (dir) =>
|
|
110
|
-
var targetPath = (dir) =>
|
|
257
|
+
var statePath = (dir) => join3(dir, DAEMON_STATE_FILE);
|
|
258
|
+
var lockPath = (dir) => join3(dir, "daemon.lock");
|
|
259
|
+
var targetPath = (dir) => join3(dir, "daemon-target.json");
|
|
111
260
|
var DAEMON_LEASE_RENEW_INTERVAL_MS = 3e4;
|
|
112
261
|
var LOCAL_LEASE_TIMEOUT_MS = DAEMON_LEASE_RENEW_INTERVAL_MS * 3;
|
|
113
262
|
var DAEMON_YIELD_CHECK_INTERVAL_MS = 2e3;
|
|
@@ -117,28 +266,56 @@ var buildDaemonLaunch = (input) => input.siblingEntry ? { command: input.execPat
|
|
|
117
266
|
shell: needsShell(input.daemonBinary, input.platform ?? process.platform)
|
|
118
267
|
};
|
|
119
268
|
var xml = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
120
|
-
var
|
|
269
|
+
var WINDOWS_TASK_NAME = "Pushary Daemon";
|
|
270
|
+
var POWERSHELL_SINGLE_QUOTES = /['\u2018\u2019\u201A\u201B]/g;
|
|
271
|
+
var powershellLiteral = (value) => `'${value.replace(POWERSHELL_SINGLE_QUOTES, (quote) => quote + quote)}'`;
|
|
272
|
+
var WQL_LIKE_SPECIALS = /[[%_]/g;
|
|
273
|
+
var wqlLikeLiteral = (value) => value.replace(WQL_LIKE_SPECIALS, (special) => `[${special}]`);
|
|
274
|
+
var WINDOWS_TASK_LOOKUP = `$task = @(Get-ScheduledTask -ErrorAction Stop) | Where-Object { $_.TaskName -eq ${powershellLiteral(WINDOWS_TASK_NAME)} -and $_.TaskPath -eq '\\' } | Select-Object -First 1; if ($null -eq $task) { exit 3 }`;
|
|
275
|
+
var POWERSHELL_HOSTS = ["powershell.exe", "pwsh.exe"];
|
|
276
|
+
var withoutTrailingSeparators = (path) => path.replace(/[\\/]+$/, "");
|
|
277
|
+
var POWERSHELL_STOP_ON_ERROR = "$ErrorActionPreference = 'Stop'";
|
|
278
|
+
var powershellCommandLineContains = (text) => `$_.CommandLine.ToUpperInvariant().Contains(${powershellLiteral(text)}.ToUpperInvariant())`;
|
|
279
|
+
var powershellCommandLineEndsWithLaunchFlag = `$_.CommandLine.TrimEnd().TrimEnd([char]34).EndsWith(${powershellLiteral(SUPERVISOR_LAUNCH_FLAG)})`;
|
|
280
|
+
var windowsSupervisorProcesses = (stateDir) => [
|
|
281
|
+
`@(Get-CimInstance -ClassName Win32_Process -Filter ${powershellLiteral(`CommandLine LIKE '%${wqlLikeLiteral(DAEMON_SUPERVISOR_SCRIPT)}%'`)}`,
|
|
282
|
+
`| Where-Object { $_.ProcessId -ne $PID -and ${POWERSHELL_HOSTS.map((host) => `$_.Name -ne ${powershellLiteral(host)}`).join(" -and ")}`,
|
|
283
|
+
`-and $null -ne $_.CommandLine -and ${powershellCommandLineContains(withoutTrailingSeparators(stateDir))} })`
|
|
284
|
+
].join(" ");
|
|
285
|
+
var windowsRunningSupervisors = (stateDir) => `@(${windowsSupervisorProcesses(stateDir)} | Where-Object { -not (${powershellCommandLineEndsWithLaunchFlag}) })`;
|
|
286
|
+
var taskArgument = (value) => `"${xml(value)}"`;
|
|
287
|
+
var systemdQuotedEnvironment = (value) => `"${value.replaceAll("%", "%%").replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
|
|
288
|
+
var escapeSystemdSpecifiers = (value) => value.replaceAll("%", "%%");
|
|
289
|
+
var systemdQuotedWord = (escaped) => `"${escaped.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
|
|
290
|
+
var systemdExecutableWord = (value) => systemdQuotedWord(escapeSystemdSpecifiers(value));
|
|
291
|
+
var systemdArgumentWord = (value) => systemdQuotedWord(escapeSystemdSpecifiers(value).replaceAll("$", "$$$$"));
|
|
292
|
+
var systemdExecLine = (executable, args) => [systemdExecutableWord(executable), ...args.map(systemdArgumentWord)].join(" ");
|
|
293
|
+
var ENTRY_PRESENT_CHECK = "process.exit(require('node:fs').existsSync(process.argv[1]) ? 0 : 1)";
|
|
294
|
+
var guardedLaunchdProgram = (input) => {
|
|
295
|
+
const guard = input.entryGuard ?? UNGUARDED;
|
|
296
|
+
return guard.kind === "guarded" ? [input.execPath, ENTRY_GUARD_PRELOAD_FLAG, guard.path, input.daemonEntry] : [input.execPath, input.daemonEntry];
|
|
297
|
+
};
|
|
121
298
|
var buildDaemonService = (input) => {
|
|
122
299
|
if (input.platform === "darwin") {
|
|
123
300
|
if (!Number.isInteger(input.uid) || input.uid < 0) return null;
|
|
124
301
|
const label = "com.pushary.daemon";
|
|
125
302
|
const domain = `gui/${input.uid}`;
|
|
126
303
|
const target = `${domain}/${label}`;
|
|
127
|
-
const definitionPath =
|
|
304
|
+
const definitionPath = join3(input.homeDir, "Library", "LaunchAgents", `${label}.plist`);
|
|
128
305
|
const contents = `<?xml version="1.0" encoding="UTF-8"?>
|
|
129
306
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
130
307
|
<plist version="1.0">
|
|
131
308
|
<dict>
|
|
132
309
|
<key>Label</key><string>${label}</string>
|
|
133
310
|
<key>ProgramArguments</key>
|
|
134
|
-
<array
|
|
311
|
+
<array>${guardedLaunchdProgram(input).map((argument) => `<string>${xml(argument)}</string>`).join("")}</array>
|
|
135
312
|
<key>WorkingDirectory</key><string>${xml(input.homeDir)}</string>
|
|
136
313
|
<key>EnvironmentVariables</key><dict><key>PATH</key><string>${xml(input.pathEnv)}</string></dict>
|
|
137
314
|
<key>RunAtLoad</key><true/>
|
|
138
315
|
<key>KeepAlive</key><dict><key>SuccessfulExit</key><false/></dict>
|
|
139
316
|
<key>ThrottleInterval</key><integer>10</integer>
|
|
140
|
-
<key>StandardOutPath</key><string>${xml(
|
|
141
|
-
<key>StandardErrorPath</key><string>${xml(
|
|
317
|
+
<key>StandardOutPath</key><string>${xml(join3(input.stateDir, DAEMON_LOG_FILE))}</string>
|
|
318
|
+
<key>StandardErrorPath</key><string>${xml(join3(input.stateDir, DAEMON_ERROR_LOG_FILE))}</string>
|
|
142
319
|
</dict>
|
|
143
320
|
</plist>
|
|
144
321
|
`;
|
|
@@ -157,6 +334,8 @@ var buildDaemonService = (input) => {
|
|
|
157
334
|
disable: [{ command: "launchctl", args: ["disable", target] }],
|
|
158
335
|
canDisableWhenUnregistered: true,
|
|
159
336
|
uninstall: [{ command: "launchctl", args: ["bootout", domain, definitionPath], ignoreFailure: true }],
|
|
337
|
+
platform: input.platform,
|
|
338
|
+
startGuardPath: daemonEntryGuardPath(input.stateDir),
|
|
160
339
|
registrationProbe: {
|
|
161
340
|
command: "launchctl",
|
|
162
341
|
args: ["print", target],
|
|
@@ -177,15 +356,17 @@ var buildDaemonService = (input) => {
|
|
|
177
356
|
}
|
|
178
357
|
if (input.platform === "linux") {
|
|
179
358
|
const unit = "pushary-daemon.service";
|
|
180
|
-
const definitionPath =
|
|
359
|
+
const definitionPath = join3(input.homeDir, ".config", "systemd", "user", unit);
|
|
181
360
|
const contents = `[Unit]
|
|
182
361
|
Description=Pushary phone-to-agent daemon
|
|
183
362
|
After=network-online.target
|
|
363
|
+
ConditionPathExists=${escapeSystemdSpecifiers(input.daemonEntry)}
|
|
184
364
|
|
|
185
365
|
[Service]
|
|
186
366
|
Type=simple
|
|
187
|
-
|
|
188
|
-
|
|
367
|
+
ExecCondition=${systemdExecLine(input.execPath, ["-e", ENTRY_PRESENT_CHECK, input.daemonEntry])}
|
|
368
|
+
ExecStart=${systemdExecLine(input.execPath, [input.daemonEntry])}
|
|
369
|
+
Environment=${systemdQuotedEnvironment(`PATH=${input.pathEnv}`)}
|
|
189
370
|
Restart=on-failure
|
|
190
371
|
RestartSec=10
|
|
191
372
|
KillMode=process
|
|
@@ -216,18 +397,20 @@ WantedBy=default.target
|
|
|
216
397
|
args: ["--user", "is-active", unit],
|
|
217
398
|
negativeOutputPattern: /^(?:inactive|failed|unknown|activating|deactivating)\s*$/m
|
|
218
399
|
},
|
|
219
|
-
reloadAfterUninstall: { command: "systemctl", args: ["--user", "daemon-reload"] }
|
|
400
|
+
reloadAfterUninstall: { command: "systemctl", args: ["--user", "daemon-reload"] },
|
|
401
|
+
platform: input.platform,
|
|
402
|
+
startGuardPath: null
|
|
220
403
|
};
|
|
221
404
|
}
|
|
222
405
|
if (input.platform === "win32") {
|
|
223
|
-
const taskName =
|
|
406
|
+
const taskName = WINDOWS_TASK_NAME;
|
|
224
407
|
const username = process.env.USERNAME?.trim() || userInfo().username;
|
|
225
408
|
const domain = process.env.USERDOMAIN?.trim();
|
|
226
409
|
const userId = input.userId?.trim() || (domain ? `${domain}\\${username}` : username);
|
|
227
410
|
const definitionPath = win32Path.join(input.stateDir, "pushary-daemon-task.xml");
|
|
228
|
-
const supervisorPath = win32Path.join(win32Path.dirname(input.daemonEntry),
|
|
411
|
+
const supervisorPath = win32Path.join(win32Path.dirname(input.daemonEntry), DAEMON_SUPERVISOR_SCRIPT);
|
|
229
412
|
const supervised = (input.entryExists ?? existsSync)(supervisorPath);
|
|
230
|
-
const args = supervised ?
|
|
413
|
+
const args = supervised ? [supervisorPath, ...supervisorTaskArguments(input.daemonEntry, withoutTrailingSeparators(input.stateDir))].map(taskArgument).join(" ") : taskArgument(input.daemonEntry);
|
|
231
414
|
const contents = `\uFEFF<?xml version="1.0" encoding="UTF-16"?>
|
|
232
415
|
<Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
|
|
233
416
|
<RegistrationInfo><Description>Pushary phone-to-agent daemon</Description></RegistrationInfo>
|
|
@@ -250,25 +433,41 @@ WantedBy=default.target
|
|
|
250
433
|
</Actions>
|
|
251
434
|
</Task>
|
|
252
435
|
`;
|
|
436
|
+
const stopTaskAndSupervisors = [
|
|
437
|
+
{ command: "schtasks.exe", args: ["/End", "/TN", taskName], ignoreFailure: true },
|
|
438
|
+
{
|
|
439
|
+
command: "powershell.exe",
|
|
440
|
+
args: [
|
|
441
|
+
"-NoProfile",
|
|
442
|
+
"-NonInteractive",
|
|
443
|
+
"-Command",
|
|
444
|
+
`${POWERSHELL_STOP_ON_ERROR}; ${windowsSupervisorProcesses(input.stateDir)} | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }`
|
|
445
|
+
],
|
|
446
|
+
ignoreFailure: true
|
|
447
|
+
}
|
|
448
|
+
];
|
|
253
449
|
return {
|
|
254
450
|
definitionPath,
|
|
255
451
|
contents,
|
|
256
452
|
encoding: "utf16le",
|
|
257
453
|
install: [
|
|
454
|
+
...stopTaskAndSupervisors,
|
|
258
455
|
{ command: "schtasks.exe", args: ["/Create", "/TN", taskName, "/XML", definitionPath, "/F"] },
|
|
259
456
|
{ command: "schtasks.exe", args: ["/Run", "/TN", taskName] }
|
|
260
457
|
],
|
|
261
458
|
start: [{ command: "schtasks.exe", args: ["/Run", "/TN", taskName] }],
|
|
262
|
-
stop:
|
|
459
|
+
stop: stopTaskAndSupervisors,
|
|
263
460
|
disable: [{ command: "schtasks.exe", args: ["/Change", "/TN", taskName, "/Disable"] }],
|
|
264
461
|
uninstall: [{ command: "schtasks.exe", args: ["/Delete", "/TN", taskName, "/F"], ignoreFailure: true }],
|
|
462
|
+
platform: input.platform,
|
|
463
|
+
startGuardPath: null,
|
|
265
464
|
registrationProbe: {
|
|
266
465
|
command: "powershell.exe",
|
|
267
466
|
args: [
|
|
268
467
|
"-NoProfile",
|
|
269
468
|
"-NonInteractive",
|
|
270
469
|
"-Command",
|
|
271
|
-
|
|
470
|
+
WINDOWS_TASK_LOOKUP
|
|
272
471
|
],
|
|
273
472
|
negativeExitCodes: [3]
|
|
274
473
|
},
|
|
@@ -278,7 +477,7 @@ WantedBy=default.target
|
|
|
278
477
|
"-NoProfile",
|
|
279
478
|
"-NonInteractive",
|
|
280
479
|
"-Command",
|
|
281
|
-
|
|
480
|
+
`${WINDOWS_TASK_LOOKUP}; if ($null -eq $task.Settings -or $null -eq $task.Settings.Enabled) { exit 5 }; if (-not $task.Settings.Enabled) { exit 4 }`
|
|
282
481
|
],
|
|
283
482
|
negativeExitCodes: [3, 4]
|
|
284
483
|
},
|
|
@@ -288,7 +487,7 @@ WantedBy=default.target
|
|
|
288
487
|
"-NoProfile",
|
|
289
488
|
"-NonInteractive",
|
|
290
489
|
"-Command",
|
|
291
|
-
|
|
490
|
+
`${POWERSHELL_STOP_ON_ERROR}; if (${windowsRunningSupervisors(input.stateDir)}.Count -gt 0) { exit 0 }; ${WINDOWS_TASK_LOOKUP}; if ($task.State -ne 'Running') { exit 4 }`
|
|
292
491
|
],
|
|
293
492
|
negativeExitCodes: [3, 4]
|
|
294
493
|
}
|
|
@@ -297,7 +496,7 @@ WantedBy=default.target
|
|
|
297
496
|
return null;
|
|
298
497
|
};
|
|
299
498
|
var WINDOWS_DAEMON_ENTRY_SEGMENTS = ["dist", "bin", "pushary-daemon.js"];
|
|
300
|
-
var readTextFile = (path) =>
|
|
499
|
+
var readTextFile = (path) => readFileSync2(path, "utf8");
|
|
301
500
|
var windowsPackageDaemonEntries = (globalPrefix) => {
|
|
302
501
|
const root = globalRootFor(globalPrefix, "win32");
|
|
303
502
|
return CLI_PACKAGE_NAMES.map((name) => win32Path.join(globalPackageFolder(root, name, "win32"), ...WINDOWS_DAEMON_ENTRY_SEGMENTS));
|
|
@@ -316,7 +515,8 @@ var serviceNodeFor = (execPath, exists) => {
|
|
|
316
515
|
const linked = homebrewLinkedNodeFor(execPath);
|
|
317
516
|
return linked !== null && exists(linked) ? linked : execPath;
|
|
318
517
|
};
|
|
319
|
-
var
|
|
518
|
+
var serviceExecPathFor = (options) => serviceNodeFor(options.execPath ?? process.execPath, options.entryExists ?? existsSync);
|
|
519
|
+
var resolveDaemonServiceInput = (options) => {
|
|
320
520
|
const platform = options.platform ?? process.platform;
|
|
321
521
|
const exists = options.entryExists ?? existsSync;
|
|
322
522
|
const globalBinary = options.globalBinary ?? resolveGlobalBinary("pushary-daemon");
|
|
@@ -333,18 +533,22 @@ var resolveDaemonServiceDefinition = (options = {}) => {
|
|
|
333
533
|
}
|
|
334
534
|
}
|
|
335
535
|
if (!daemonEntry || !exists(daemonEntry)) return null;
|
|
336
|
-
|
|
337
|
-
return buildDaemonService({
|
|
536
|
+
return {
|
|
338
537
|
platform,
|
|
339
|
-
homeDir,
|
|
538
|
+
homeDir: options.homeDir ?? homedir(),
|
|
340
539
|
stateDir: options.stateDir ?? pusharyDir(),
|
|
341
|
-
execPath:
|
|
540
|
+
execPath: serviceExecPathFor(options),
|
|
342
541
|
daemonEntry,
|
|
343
542
|
pathEnv: options.pathEnv ?? process.env.PATH ?? "",
|
|
344
543
|
uid: options.uid ?? process.getuid?.(),
|
|
345
544
|
entryExists: exists
|
|
346
|
-
}
|
|
545
|
+
};
|
|
546
|
+
};
|
|
547
|
+
var resolveDaemonServiceDefinition = (options = {}) => {
|
|
548
|
+
const input = resolveDaemonServiceInput(options);
|
|
549
|
+
return input ? buildDaemonService(input) : null;
|
|
347
550
|
};
|
|
551
|
+
var daemonEntryGuardPathFor = (options = {}) => entryGuardApplies(options.platform ?? process.platform, serviceExecPathFor(options)) ? daemonEntryGuardPath(options.stateDir ?? pusharyDir()) : null;
|
|
348
552
|
var runDaemonServiceSteps = (steps, run) => {
|
|
349
553
|
for (const step of steps) {
|
|
350
554
|
try {
|
|
@@ -409,7 +613,17 @@ var manageDaemonService = (action, options = {}) => {
|
|
|
409
613
|
if (action === "uninstall" && !daemonServiceManagerAvailable(options)) {
|
|
410
614
|
return { kind: "failed", detail: "Native background-service manager is unavailable" };
|
|
411
615
|
}
|
|
412
|
-
|
|
616
|
+
const applied = applyDaemonService(action, definition, { run: options.run });
|
|
617
|
+
return action === "uninstall" && applied.kind === "ok" ? removeEntryGuardOf(definition) : applied;
|
|
618
|
+
};
|
|
619
|
+
var removeEntryGuardOf = (definition) => {
|
|
620
|
+
if (!definition.startGuardPath) return { kind: "ok" };
|
|
621
|
+
try {
|
|
622
|
+
safeUnlink(definition.startGuardPath);
|
|
623
|
+
return { kind: "ok" };
|
|
624
|
+
} catch (err) {
|
|
625
|
+
return { kind: "failed", detail: `the background service is removed, but its start guard ${definition.startGuardPath} could not be: ${err instanceof Error ? err.message : String(err)}` };
|
|
626
|
+
}
|
|
413
627
|
};
|
|
414
628
|
var nominalDaemonService = (options) => buildDaemonService({
|
|
415
629
|
platform: options.platform ?? process.platform,
|
|
@@ -431,7 +645,7 @@ var readInstalledDaemonService = (options = {}) => {
|
|
|
431
645
|
try {
|
|
432
646
|
return {
|
|
433
647
|
path: definition.definitionPath,
|
|
434
|
-
contents:
|
|
648
|
+
contents: readFileSync2(definition.definitionPath, definition.encoding ?? "utf-8")
|
|
435
649
|
};
|
|
436
650
|
} catch {
|
|
437
651
|
return null;
|
|
@@ -595,7 +809,7 @@ var acquireDaemonLease = (options = {}) => {
|
|
|
595
809
|
const instanceId = randomUUID();
|
|
596
810
|
const startedAt = new Date(now()).toISOString();
|
|
597
811
|
const writeLock = () => {
|
|
598
|
-
|
|
812
|
+
mkdirSync2(dir, { recursive: true });
|
|
599
813
|
writeFileSync(lockPath(dir), JSON.stringify({ instanceId, pid }), { flag: "wx", mode: 384 });
|
|
600
814
|
};
|
|
601
815
|
try {
|
|
@@ -619,7 +833,7 @@ var acquireDaemonLease = (options = {}) => {
|
|
|
619
833
|
if (owner && ownerIsFromThisBoot && (options.isProcessAlive ?? processIsAlive)(owner.pid)) {
|
|
620
834
|
return { kind: "unavailable", detail: "daemon owner is still running or starting" };
|
|
621
835
|
}
|
|
622
|
-
const stale =
|
|
836
|
+
const stale = join3(dir, `daemon.lock.${instanceId}.stale`);
|
|
623
837
|
let ownsReplacement = false;
|
|
624
838
|
try {
|
|
625
839
|
renameSync(lockPath(dir), stale);
|
|
@@ -763,8 +977,16 @@ var stopDaemonRunning = async (options = {}) => {
|
|
|
763
977
|
safeUnlink(lockPath(dir));
|
|
764
978
|
return { kind: "stopped" };
|
|
765
979
|
};
|
|
980
|
+
var writeEntryGuardForService = (input, options) => writeDaemonEntryGuard({
|
|
981
|
+
stateDir: input.stateDir,
|
|
982
|
+
platform: input.platform,
|
|
983
|
+
execPath: input.execPath,
|
|
984
|
+
warn: options.warn ?? ((message) => {
|
|
985
|
+
process.stderr.write(message);
|
|
986
|
+
})
|
|
987
|
+
});
|
|
766
988
|
var DAEMON_LOGIN_REASONS = ["key_rejected", "plan_inactive", "key_missing", "mac_signed_out"];
|
|
767
|
-
var needsLoginPath = (dir) =>
|
|
989
|
+
var needsLoginPath = (dir) => join3(dir, "daemon-needs-login.json");
|
|
768
990
|
var isLoginReason = (value) => DAEMON_LOGIN_REASONS.includes(value);
|
|
769
991
|
var parseDaemonNeedsLogin = (value) => {
|
|
770
992
|
if (typeof value !== "object" || value === null) return null;
|
|
@@ -804,7 +1026,7 @@ var DAEMON_LOGIN_BLOCK_DESCRIPTIONS = {
|
|
|
804
1026
|
var describeDaemonLoginBlock = (record) => DAEMON_LOGIN_BLOCK_DESCRIPTIONS[record.reason](record.at);
|
|
805
1027
|
var recoverDaemonAfterLogin = (options = {}) => {
|
|
806
1028
|
const cleared = clearDaemonNeedsLogin(options);
|
|
807
|
-
if (!cleared || readControlMode(
|
|
1029
|
+
if (!cleared || readControlMode(join3(options.dir ?? pusharyDir(), "config.json")) === "off" || !hasDaemonServiceDefinition(options)) {
|
|
808
1030
|
return { cleared, restarted: false, detail: null };
|
|
809
1031
|
}
|
|
810
1032
|
const started = manageDaemonService("start", options);
|
|
@@ -878,12 +1100,26 @@ var probeDaemonServiceState = (definition, run) => {
|
|
|
878
1100
|
}
|
|
879
1101
|
};
|
|
880
1102
|
var previousEncoding = (snapshot) => snapshot.previousEncoding ?? "utf-8";
|
|
1103
|
+
var launchdEntryGuardArguments = (guard) => `<string>${xml(ENTRY_GUARD_PRELOAD_FLAG)}</string><string>${xml(guard)}</string>`;
|
|
1104
|
+
var restorableContents = (definition, contents) => {
|
|
1105
|
+
const guard = definition.startGuardPath;
|
|
1106
|
+
if (!guard || contents === null || readServiceEntryGuard(contents, definition.platform) !== guard) {
|
|
1107
|
+
return { kind: "ready", contents };
|
|
1108
|
+
}
|
|
1109
|
+
const written = writeDaemonEntryGuardAt(guard);
|
|
1110
|
+
if (written.kind === "in-place") return { kind: "ready", contents };
|
|
1111
|
+
const unguarded = contents.replace(launchdEntryGuardArguments(guard), "");
|
|
1112
|
+
return readServiceEntryGuard(unguarded, definition.platform) === null ? { kind: "ready", contents: unguarded } : { kind: "failed", detail: `could not write the start guard ${guard} the previous service names (${written.detail}), or restore that service without it` };
|
|
1113
|
+
};
|
|
881
1114
|
var restoreDaemonServiceSnapshot = (definition, snapshot, run) => {
|
|
1115
|
+
const restorable = restorableContents(definition, snapshot.previousContents);
|
|
1116
|
+
if (restorable.kind !== "ready") return restorable;
|
|
1117
|
+
const previousContents = restorable.contents;
|
|
882
1118
|
const removed = applyDaemonService("uninstall", definition, { run });
|
|
883
1119
|
if (removed.kind !== "ok") return removed;
|
|
884
1120
|
try {
|
|
885
|
-
if (
|
|
886
|
-
else writeFileAtomic(definition.definitionPath,
|
|
1121
|
+
if (previousContents === null) safeUnlink(definition.definitionPath);
|
|
1122
|
+
else writeFileAtomic(definition.definitionPath, previousContents, 384, previousEncoding(snapshot));
|
|
887
1123
|
} catch (err) {
|
|
888
1124
|
return {
|
|
889
1125
|
kind: "failed",
|
|
@@ -892,7 +1128,7 @@ var restoreDaemonServiceSnapshot = (definition, snapshot, run) => {
|
|
|
892
1128
|
}
|
|
893
1129
|
if (!snapshot.previousRegistered) {
|
|
894
1130
|
const reload = definition.reloadAfterUninstall;
|
|
895
|
-
if (
|
|
1131
|
+
if (previousContents !== null && reload) {
|
|
896
1132
|
try {
|
|
897
1133
|
run(reload.command, reload.args);
|
|
898
1134
|
} catch (err) {
|
|
@@ -917,12 +1153,12 @@ var restoreDaemonServiceSnapshot = (definition, snapshot, run) => {
|
|
|
917
1153
|
}
|
|
918
1154
|
return { kind: "ok" };
|
|
919
1155
|
}
|
|
920
|
-
if (
|
|
1156
|
+
if (previousContents === null) {
|
|
921
1157
|
return { kind: "failed", detail: "the previous registered service had no recoverable definition" };
|
|
922
1158
|
}
|
|
923
1159
|
const restored = applyDaemonService("install", {
|
|
924
1160
|
...definition,
|
|
925
|
-
contents:
|
|
1161
|
+
contents: previousContents,
|
|
926
1162
|
encoding: previousEncoding(snapshot)
|
|
927
1163
|
}, { run });
|
|
928
1164
|
if (restored.kind !== "ok") return restored;
|
|
@@ -971,19 +1207,22 @@ var recoverDaemonServiceTransaction = (definition, path, run) => {
|
|
|
971
1207
|
return { kind: "ok" };
|
|
972
1208
|
};
|
|
973
1209
|
var replaceDaemonService = async (options = {}) => {
|
|
974
|
-
const
|
|
975
|
-
|
|
1210
|
+
const input = resolveDaemonServiceInput(options);
|
|
1211
|
+
const unguarded = input ? buildDaemonService(input) : null;
|
|
1212
|
+
if (!input || !unguarded) {
|
|
976
1213
|
return {
|
|
977
1214
|
kind: "unavailable",
|
|
978
1215
|
detail: "Could not find the globally installed daemon entry. Run Pushary setup again."
|
|
979
1216
|
};
|
|
980
1217
|
}
|
|
981
1218
|
const run = options.run ?? runDaemonServiceCommand;
|
|
982
|
-
const transactionPath =
|
|
983
|
-
const recovered = recoverDaemonServiceTransaction(
|
|
1219
|
+
const transactionPath = join3(options.stateDir ?? options.dir ?? pusharyDir(), "daemon-service-transaction.json");
|
|
1220
|
+
const recovered = recoverDaemonServiceTransaction(unguarded, transactionPath, run);
|
|
984
1221
|
if (recovered.kind !== "ok") {
|
|
985
1222
|
return { kind: "failed", detail: `Could not recover interrupted service replacement: ${recovered.detail}` };
|
|
986
1223
|
}
|
|
1224
|
+
const definition = buildDaemonService({ ...input, entryGuard: writeEntryGuardForService(input, options) });
|
|
1225
|
+
if (!definition) return { kind: "unavailable", detail: "Could not build the daemon service definition for this platform." };
|
|
987
1226
|
let previousContents = null;
|
|
988
1227
|
let previousDefinitionEncoding = "utf-8";
|
|
989
1228
|
try {
|
|
@@ -1088,7 +1327,7 @@ var replaceDaemonService = async (options = {}) => {
|
|
|
1088
1327
|
var launchInstalledDaemon = (options) => {
|
|
1089
1328
|
const entryExists = options.entryExists ?? existsSync;
|
|
1090
1329
|
const argvEntry = process.argv[1];
|
|
1091
|
-
const candidate = options.daemonEntry !== void 0 ? options.daemonEntry : argvEntry ?
|
|
1330
|
+
const candidate = options.daemonEntry !== void 0 ? options.daemonEntry : argvEntry ? join3(dirname2(argvEntry), "pushary-daemon.js") : null;
|
|
1092
1331
|
const siblingEntry = candidate && entryExists(candidate) ? candidate : null;
|
|
1093
1332
|
const platform = options.platform ?? process.platform;
|
|
1094
1333
|
const daemonBinary = options.daemonBinary ?? resolveGlobalBinary("pushary-daemon") ?? (platform === "win32" ? "pushary-daemon.cmd" : "pushary-daemon");
|
|
@@ -1163,6 +1402,11 @@ var waitForDaemonRemoteProof = async (options = {}) => {
|
|
|
1163
1402
|
};
|
|
1164
1403
|
|
|
1165
1404
|
export {
|
|
1405
|
+
readServiceExecPath,
|
|
1406
|
+
serviceStartFileChecks,
|
|
1407
|
+
versionManagerOf,
|
|
1408
|
+
describeVersionManagerPin,
|
|
1409
|
+
describeServiceNodeRisk,
|
|
1166
1410
|
daemonIsServing,
|
|
1167
1411
|
daemonProcessIsThere,
|
|
1168
1412
|
DAEMON_COLD_START_TIMEOUT_MS,
|
|
@@ -1172,6 +1416,7 @@ export {
|
|
|
1172
1416
|
DAEMON_YIELD_CHECK_INTERVAL_MS,
|
|
1173
1417
|
xml,
|
|
1174
1418
|
serviceNodeFor,
|
|
1419
|
+
daemonEntryGuardPathFor,
|
|
1175
1420
|
parseDaemonAction,
|
|
1176
1421
|
manageDaemonService,
|
|
1177
1422
|
hasDaemonServiceDefinition,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
realpath
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-NLJ2ILA7.js";
|
|
4
4
|
import {
|
|
5
5
|
findNativeClaudeInstall
|
|
6
6
|
} from "./chunk-CYTPQDQY.js";
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
resolvePackageVersionFromBinary,
|
|
14
14
|
resolvePathBinary,
|
|
15
15
|
resolvePathBinaryAsync
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-FYLYAVQG.js";
|
|
17
17
|
import {
|
|
18
18
|
MANAGED_PROVIDERS
|
|
19
19
|
} from "./chunk-DL67HX3D.js";
|
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
codexHome,
|
|
8
8
|
codexHooksJsonIn,
|
|
9
9
|
isPusharyCodexCommand
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-TN5PGMH5.js";
|
|
11
11
|
import {
|
|
12
12
|
resolvePathBinary
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-FYLYAVQG.js";
|
|
14
14
|
import {
|
|
15
15
|
getPackageVersion
|
|
16
16
|
} from "./chunk-WIIMW5YO.js";
|