@pushary/agent-hooks 1.8.3 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/bin/pushary-bell-hook.js +23 -23
- package/dist/bin/pushary-bell.js +9 -9
- package/dist/bin/pushary-claude.js +26 -26
- package/dist/bin/pushary-clean.js +28 -28
- package/dist/bin/pushary-codex-bridge.js +18 -18
- package/dist/bin/pushary-codex-hook.js +31 -31
- package/dist/bin/pushary-codex.js +13 -13
- package/dist/bin/pushary-connect.js +13 -13
- package/dist/bin/pushary-cowork.js +5 -5
- package/dist/bin/pushary-daemon.js +26 -26
- package/dist/bin/pushary-disconnect.js +18 -18
- package/dist/bin/pushary-doctor.js +30 -30
- package/dist/bin/pushary-elicitation-hook.js +25 -25
- package/dist/bin/pushary-gemini-bridge.js +13 -13
- package/dist/bin/pushary-gemini-hook.js +28 -28
- package/dist/bin/pushary-hook.js +32 -32
- package/dist/bin/pushary-login.js +12 -12
- package/dist/bin/pushary-logout.js +7 -7
- package/dist/bin/pushary-mcp.js +9 -9
- package/dist/bin/pushary-mode.js +9 -9
- package/dist/bin/pushary-notification-hook.js +28 -28
- package/dist/bin/pushary-opencode-hook.js +27 -27
- package/dist/bin/pushary-permission-denied-hook.js +32 -32
- package/dist/bin/pushary-permission-hook.js +31 -31
- package/dist/bin/pushary-post-hook.js +28 -28
- package/dist/bin/pushary-prompt-hook.js +28 -28
- package/dist/bin/pushary-session-end-hook.js +28 -28
- package/dist/bin/pushary-session-start-hook.js +31 -31
- package/dist/bin/pushary-setup.js +53 -38
- package/dist/bin/pushary-stats.js +5 -5
- package/dist/bin/pushary-status.js +15 -15
- package/dist/bin/pushary-stop-hook.js +28 -28
- package/dist/bin/pushary-stopfailure-hook.js +28 -28
- package/dist/bin/pushary-suggestions.js +4 -4
- package/dist/bin/pushary-transcript-register.js +19 -19
- package/dist/bin/pushary-transcripts.js +7 -7
- package/dist/bin/pushary-upgrade.js +42 -394
- package/dist/bin/pushary-wait.js +9 -9
- package/dist/bin/pushary.js +6 -6
- package/dist/{chunk-ON5JW2HP.js → chunk-4SB46XLF.js} +1 -1
- package/dist/{chunk-HMNR7B2F.js → chunk-4XT4JXMG.js} +1 -1
- package/dist/{chunk-YOYSXLUB.js → chunk-5K43TBK4.js} +3 -3
- package/dist/{chunk-ZOKXZ3AS.js → chunk-65TOHCXT.js} +4 -4
- package/dist/{chunk-4CW5EAOI.js → chunk-6JTTJIKJ.js} +3 -3
- package/dist/{chunk-6SS74UHS.js → chunk-6L7TNZ43.js} +1 -1
- package/dist/{chunk-EJXEHNB5.js → chunk-6Q4NM2LW.js} +3 -3
- package/dist/{chunk-5Y2DY6X4.js → chunk-6QSDNXGM.js} +2 -2
- package/dist/{chunk-72WOCX22.js → chunk-7ER66HZH.js} +1 -1
- package/dist/{chunk-OLYTGVCC.js → chunk-AKCJ5SNO.js} +6 -6
- package/dist/{chunk-N6JJJTPH.js → chunk-C6PPDKVI.js} +3 -3
- package/dist/{chunk-VI55VXDH.js → chunk-CE4UH4AP.js} +2 -2
- package/dist/{chunk-NOLPURUI.js → chunk-CGRPHFOV.js} +1 -1
- package/dist/{chunk-XH7UNEHO.js → chunk-COSADFEH.js} +1 -1
- package/dist/{chunk-YLJ26RR2.js → chunk-D3RS57MN.js} +3 -3
- package/dist/{chunk-6UDK5TY6.js → chunk-DMA3QUOB.js} +3 -3
- package/dist/{chunk-URNXU3FO.js → chunk-FJPC35OW.js} +1 -1
- package/dist/{chunk-35X5UDML.js → chunk-FVOCQSBG.js} +1 -1
- package/dist/{chunk-FBTUF2PH.js → chunk-GHKNUQYU.js} +2 -2
- package/dist/{chunk-DLEKCAQL.js → chunk-HU2LWGEE.js} +1 -1
- package/dist/{chunk-SOUJG6UY.js → chunk-IITCMJ4G.js} +2 -2
- package/dist/{chunk-MSMKCO4Y.js → chunk-IJXJW2VH.js} +10 -10
- package/dist/{chunk-DMU5E6HJ.js → chunk-J7JXA2LX.js} +1 -1
- package/dist/{chunk-4DYHBXX4.js → chunk-JCER3Q6P.js} +9 -9
- package/dist/{chunk-CB23AO4D.js → chunk-JGQ2ANHQ.js} +2 -2
- package/dist/{chunk-AKCE6ZRF.js → chunk-JHZAZAI3.js} +5 -5
- package/dist/{chunk-27A7L4DA.js → chunk-KR5JASA4.js} +2 -2
- package/dist/{chunk-VF3X4MDB.js → chunk-LJI7U6PM.js} +2 -2
- package/dist/{chunk-7U7ZWUTR.js → chunk-LKKYRNJT.js} +1 -1
- package/dist/{chunk-MYHG7PX2.js → chunk-LXWUYG7D.js} +1 -1
- package/dist/{chunk-VUP5BMOD.js → chunk-LZMH4EGE.js} +1 -1
- package/dist/{chunk-CTNLP4A5.js → chunk-NVLXK2I6.js} +5 -5
- package/dist/{chunk-7ITOAMCD.js → chunk-P7YDVWLL.js} +1 -1
- package/dist/{chunk-IEXWWAJY.js → chunk-PEGKBNGN.js} +5 -5
- package/dist/{chunk-UMMCHS6P.js → chunk-PMS3EBD2.js} +1 -1
- package/dist/chunk-QQJCDRD3.js +242 -0
- package/dist/chunk-QXL27RY6.js +175 -0
- package/dist/{chunk-TJMAXQ5Q.js → chunk-RJ7ECJSZ.js} +2 -2
- package/dist/{chunk-VFFHQC7W.js → chunk-RNDFGHSQ.js} +1 -1
- package/dist/{chunk-4SJIPHR3.js → chunk-RS4ZOFSF.js} +10 -7
- package/dist/{chunk-HVDMGDYV.js → chunk-SKEP3M6M.js} +2 -2
- package/dist/{chunk-UXKXGRKG.js → chunk-SPB3QRE7.js} +4 -4
- package/dist/{chunk-CXYKQAL2.js → chunk-SWGY5WNX.js} +5 -5
- package/dist/{chunk-E5JGQGLD.js → chunk-UPTEPARD.js} +2 -2
- package/dist/{chunk-CHMOVJ2M.js → chunk-UYHLMBPQ.js} +1 -1
- package/dist/{chunk-XNJ4MQF3.js → chunk-V4H33GBM.js} +6 -6
- package/dist/{chunk-34EQOFMH.js → chunk-VH6763OR.js} +3 -3
- package/dist/{chunk-DXBS2EL7.js → chunk-VQLWYKX7.js} +1 -1
- package/dist/{chunk-SD6OLZJX.js → chunk-WWDPULS3.js} +8 -8
- package/dist/{chunk-5YY3IJT4.js → chunk-XEIV5QOT.js} +92 -23
- package/dist/{chunk-APURTMSW.js → chunk-XW2B4QV2.js} +2 -2
- package/dist/{chunk-ZR7LIQKO.js → chunk-ZMKEKWNR.js} +70 -49
- package/dist/global-upgrade-ML2RHV4W.js +24 -0
- package/dist/paths-LG3IEDDM.js +71 -0
- package/dist/{reapply-DYOQAVUP.js → reapply-7PFOITE4.js} +8 -8
- package/dist/src/index.js +20 -20
- package/dist/upgrade-lock-2A2YUUEU.js +17 -0
- package/package.json +1 -1
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import {
|
|
2
|
+
claimUpgradeLock,
|
|
3
|
+
finishWithUpgradeLock,
|
|
4
|
+
installWithUpgradeLock,
|
|
5
|
+
releaseAutoUpdateLock
|
|
6
|
+
} from "./chunk-QXL27RY6.js";
|
|
7
|
+
import {
|
|
8
|
+
describeAutoUpdateCheck,
|
|
9
|
+
globalInstallLocation,
|
|
10
|
+
hasPendingUpgradeFinish,
|
|
11
|
+
readAutoUpdateState,
|
|
12
|
+
updateAutoUpdateState,
|
|
13
|
+
upgradeEntryFor
|
|
14
|
+
} from "./chunk-CE4UH4AP.js";
|
|
15
|
+
import {
|
|
16
|
+
EXIT
|
|
17
|
+
} from "./chunk-KZERVKTD.js";
|
|
18
|
+
import {
|
|
19
|
+
autoUpdateLock,
|
|
20
|
+
autoUpdateLog,
|
|
21
|
+
autoUpdateState,
|
|
22
|
+
execNpm,
|
|
23
|
+
fetchLatestPublishedVersion,
|
|
24
|
+
npmErrorMessage,
|
|
25
|
+
readGlobalCliInstallAt,
|
|
26
|
+
readGlobalPrefix
|
|
27
|
+
} from "./chunk-ZMKEKWNR.js";
|
|
28
|
+
import {
|
|
29
|
+
NPX_LATEST_COMMAND
|
|
30
|
+
} from "./chunk-FVOCQSBG.js";
|
|
31
|
+
import {
|
|
32
|
+
commandsPackage,
|
|
33
|
+
globalUpgradeEntry,
|
|
34
|
+
isNewerVersion,
|
|
35
|
+
isReleaseVersion,
|
|
36
|
+
isSameMajorVersion,
|
|
37
|
+
ownPackageRoot,
|
|
38
|
+
packageVersionAt
|
|
39
|
+
} from "./chunk-XEIV5QOT.js";
|
|
40
|
+
|
|
41
|
+
// src/global-upgrade.ts
|
|
42
|
+
import { existsSync } from "fs";
|
|
43
|
+
|
|
44
|
+
// src/auto-update-run.ts
|
|
45
|
+
import { closeSync, mkdirSync, openSync, statSync, writeSync } from "fs";
|
|
46
|
+
import { dirname } from "path";
|
|
47
|
+
var FINISH_UPGRADE_FLAG = "--finish-upgrade";
|
|
48
|
+
var INSTALL_TIMEOUT_MS = 12e4;
|
|
49
|
+
var LOG_LIMIT_BYTES = 256 * 1024;
|
|
50
|
+
var UNREADABLE_INSTALLED_VERSION = "could not read the installed version";
|
|
51
|
+
var UNREACHABLE_REGISTRY = "could not read the latest version from the npm registry";
|
|
52
|
+
var MANUAL_UPGRADE_COMMAND = `${NPX_LATEST_COMMAND} upgrade`;
|
|
53
|
+
var openAutoUpdateLog = (logPath) => {
|
|
54
|
+
mkdirSync(dirname(logPath), { recursive: true });
|
|
55
|
+
const size = statSync(logPath, { throwIfNoEntry: false })?.size ?? 0;
|
|
56
|
+
return openSync(logPath, size > LOG_LIMIT_BYTES ? "w" : "a");
|
|
57
|
+
};
|
|
58
|
+
var appendAutoUpdateLog = (logPath, line) => {
|
|
59
|
+
try {
|
|
60
|
+
const handle = openAutoUpdateLog(logPath);
|
|
61
|
+
try {
|
|
62
|
+
writeSync(handle, `${line}
|
|
63
|
+
`);
|
|
64
|
+
} finally {
|
|
65
|
+
closeSync(handle);
|
|
66
|
+
}
|
|
67
|
+
} catch {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
var finishInNewInstall = async (request) => {
|
|
72
|
+
const handle = openAutoUpdateLog(request.logPath);
|
|
73
|
+
try {
|
|
74
|
+
await finishWithUpgradeLock({
|
|
75
|
+
entry: request.entry,
|
|
76
|
+
args: [FINISH_UPGRADE_FLAG],
|
|
77
|
+
lockPath: request.lockPath,
|
|
78
|
+
stdio: ["ignore", handle, handle, "ipc"],
|
|
79
|
+
env: { npm_config_prefix: request.prefix }
|
|
80
|
+
});
|
|
81
|
+
} finally {
|
|
82
|
+
closeSync(handle);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
var incompleteFinishDetail = (logPath) => `installed, but refreshing the agent configs did not finish cleanly; see ${logPath}`;
|
|
86
|
+
var newMajorDetail = (latest) => `${latest} is a new major version; run ${MANUAL_UPGRADE_COMMAND}`;
|
|
87
|
+
var finishInstalledUpgrade = async (context, from, to) => {
|
|
88
|
+
const pending = { result: "finish_pending", from, to, detail: incompleteFinishDetail(context.logPath) };
|
|
89
|
+
recordAutoUpdateCheck(context.statePath, pending, new Date(context.now()).toISOString());
|
|
90
|
+
try {
|
|
91
|
+
await context.finish({ lockPath: context.lockPath, entry: upgradeEntryFor(context.location), prefix: context.location.prefix, logPath: context.logPath });
|
|
92
|
+
return { result: "updated", from, to };
|
|
93
|
+
} catch {
|
|
94
|
+
return pending;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
var isInstallableRelease = (latest, installed) => latest !== void 0 && isNewerVersion(latest, installed) && isSameMajorVersion(latest, installed);
|
|
98
|
+
var checkAndInstall = async (context) => {
|
|
99
|
+
const installed = packageVersionAt(context.packageRoot);
|
|
100
|
+
if (installed === void 0 || !isReleaseVersion(installed)) {
|
|
101
|
+
return { result: "failed", from: installed, detail: UNREADABLE_INSTALLED_VERSION };
|
|
102
|
+
}
|
|
103
|
+
const previous = readAutoUpdateState(context.statePath);
|
|
104
|
+
const pendingFinish = hasPendingUpgradeFinish(previous, installed);
|
|
105
|
+
const latest = await fetchLatestPublishedVersion({ packageName: context.location.packageName, fetchImpl: context.fetchImpl });
|
|
106
|
+
if (pendingFinish && !isInstallableRelease(latest, installed)) return finishInstalledUpgrade(context, previous.from, installed);
|
|
107
|
+
if (latest === void 0) return { result: "failed", from: installed, detail: UNREACHABLE_REGISTRY };
|
|
108
|
+
if (!isNewerVersion(latest, installed)) return { result: "current", from: installed };
|
|
109
|
+
if (!isSameMajorVersion(latest, installed)) {
|
|
110
|
+
return { result: "needs_manual", from: installed, to: latest, detail: newMajorDetail(latest) };
|
|
111
|
+
}
|
|
112
|
+
appendAutoUpdateLog(context.logPath, `${new Date(context.now()).toISOString()} installing ${context.location.packageName}@${latest} into ${context.location.prefix}`);
|
|
113
|
+
try {
|
|
114
|
+
installWithUpgradeLock({
|
|
115
|
+
packageName: context.location.packageName,
|
|
116
|
+
version: latest,
|
|
117
|
+
prefix: context.location.prefix,
|
|
118
|
+
timeoutMs: INSTALL_TIMEOUT_MS
|
|
119
|
+
}, context.lockPath, context.runNpm);
|
|
120
|
+
} catch (error) {
|
|
121
|
+
return { result: "failed", from: installed, to: latest, detail: npmErrorMessage(error) };
|
|
122
|
+
}
|
|
123
|
+
return finishInstalledUpgrade(context, installed, latest);
|
|
124
|
+
};
|
|
125
|
+
var recordAutoUpdateCheck = (statePath, check, at) => updateAutoUpdateState(statePath, {
|
|
126
|
+
lastCheckAt: at,
|
|
127
|
+
lastResult: check.result,
|
|
128
|
+
from: check.from,
|
|
129
|
+
to: check.to,
|
|
130
|
+
at,
|
|
131
|
+
detail: check.detail,
|
|
132
|
+
announced: check.result === "updated" ? false : void 0
|
|
133
|
+
});
|
|
134
|
+
var runAutoUpdate = async (run = {}) => {
|
|
135
|
+
if ((run.platform ?? process.platform) === "linux") return { kind: "linux" };
|
|
136
|
+
const packageRoot = run.packageRoot ?? ownPackageRoot();
|
|
137
|
+
const location = packageRoot === void 0 ? null : globalInstallLocation(packageRoot);
|
|
138
|
+
if (packageRoot === void 0 || location === null) return { kind: "not_global_install" };
|
|
139
|
+
const now = run.now ?? Date.now;
|
|
140
|
+
const lockPath = run.lockPath ?? autoUpdateLock();
|
|
141
|
+
const logPath = run.logPath ?? autoUpdateLog();
|
|
142
|
+
const claim = await claimUpgradeLock({ lockPath });
|
|
143
|
+
if (claim.kind === "unavailable") {
|
|
144
|
+
const at = new Date(now()).toISOString();
|
|
145
|
+
const state = recordAutoUpdateCheck(run.statePath ?? autoUpdateState(), { result: "failed", detail: claim.reason }, at);
|
|
146
|
+
appendAutoUpdateLog(logPath, `${at} ${describeAutoUpdateCheck(state)}`);
|
|
147
|
+
return { kind: "recorded", state };
|
|
148
|
+
}
|
|
149
|
+
if (claim.kind !== "acquired") return { kind: "locked" };
|
|
150
|
+
try {
|
|
151
|
+
const check = await checkAndInstall({
|
|
152
|
+
lockPath,
|
|
153
|
+
packageRoot,
|
|
154
|
+
statePath: run.statePath ?? autoUpdateState(),
|
|
155
|
+
location,
|
|
156
|
+
logPath,
|
|
157
|
+
now,
|
|
158
|
+
fetchImpl: run.fetchImpl ?? fetch,
|
|
159
|
+
runNpm: run.runNpm ?? execNpm,
|
|
160
|
+
finish: run.finish ?? finishInNewInstall
|
|
161
|
+
});
|
|
162
|
+
const at = new Date(now()).toISOString();
|
|
163
|
+
const state = recordAutoUpdateCheck(run.statePath ?? autoUpdateState(), check, at);
|
|
164
|
+
appendAutoUpdateLog(logPath, `${at} ${describeAutoUpdateCheck(state)}`);
|
|
165
|
+
return { kind: "recorded", state };
|
|
166
|
+
} finally {
|
|
167
|
+
releaseAutoUpdateLock(lockPath);
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// src/global-upgrade.ts
|
|
172
|
+
var NOT_INSTALLED = { kind: "not_installed" };
|
|
173
|
+
var globalUpgradeSubject = (prefix, install) => {
|
|
174
|
+
if (prefix === void 0) return NOT_INSTALLED;
|
|
175
|
+
const commands = commandsPackage(install);
|
|
176
|
+
if (commands?.version !== void 0) return { kind: "installed", prefix, name: commands.name, version: commands.version };
|
|
177
|
+
return install.kind === "both" ? { kind: "both_installed" } : NOT_INSTALLED;
|
|
178
|
+
};
|
|
179
|
+
var readGlobalUpgradeSubject = (platform = process.platform) => {
|
|
180
|
+
const prefix = readGlobalPrefix();
|
|
181
|
+
return globalUpgradeSubject(prefix, prefix === void 0 ? { kind: "unavailable" } : readGlobalCliInstallAt(prefix, platform));
|
|
182
|
+
};
|
|
183
|
+
var finishWithThisNode = (entry) => finishWithUpgradeLock({ entry, args: [FINISH_UPGRADE_FLAG] });
|
|
184
|
+
var finishGlobalUpgrade = async (subject, platform = process.platform, runFinish = finishWithThisNode) => {
|
|
185
|
+
const entry = globalUpgradeEntry(subject.prefix, subject.name, platform);
|
|
186
|
+
if (!existsSync(entry)) return { kind: "entry_missing", entry };
|
|
187
|
+
try {
|
|
188
|
+
await runFinish(entry);
|
|
189
|
+
return { kind: "finished" };
|
|
190
|
+
} catch {
|
|
191
|
+
return { kind: "failed" };
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
var describeHeldUpgradeLock = (holderPid) => `Another Pushary upgrade is already running${holderPid === void 0 ? "" : ` (pid ${holderPid})`}. Try again when it has finished.`;
|
|
195
|
+
var withUpgradeLock = async (run, request = {}) => {
|
|
196
|
+
const claim = await claimUpgradeLock(request);
|
|
197
|
+
if (claim.kind === "unavailable") return { kind: "refused", exitCode: EXIT.FAILED, message: `Could not lock the Pushary upgrade: ${claim.reason}` };
|
|
198
|
+
if (claim.kind === "held") return { kind: "refused", exitCode: EXIT.FAILED, message: describeHeldUpgradeLock(claim.holderPid) };
|
|
199
|
+
try {
|
|
200
|
+
await run();
|
|
201
|
+
} finally {
|
|
202
|
+
releaseAutoUpdateLock(request.lockPath ?? autoUpdateLock());
|
|
203
|
+
}
|
|
204
|
+
return { kind: "ran" };
|
|
205
|
+
};
|
|
206
|
+
var finishUpgradeWithLock = async (run, request) => {
|
|
207
|
+
const outcome = await withUpgradeLock(run, request);
|
|
208
|
+
if (outcome.kind === "refused") {
|
|
209
|
+
updateAutoUpdateState(request.statePath, { lastResult: "finish_pending", to: request.installedVersion, detail: outcome.message });
|
|
210
|
+
}
|
|
211
|
+
return outcome;
|
|
212
|
+
};
|
|
213
|
+
var describeUpgradeStart = (subject, latest) => `Upgrading ${subject.name} ${subject.version} -> ${latest ?? "latest"}`;
|
|
214
|
+
var upgradeInstalledPackage = async (subject, effects) => {
|
|
215
|
+
const pendingFinish = effects.hasPendingFinish(subject.version);
|
|
216
|
+
const latest = await effects.fetchLatest(subject.name);
|
|
217
|
+
const newerPublished = latest !== void 0 && isNewerVersion(latest, subject.version);
|
|
218
|
+
if (pendingFinish && !newerPublished) {
|
|
219
|
+
const finish = await effects.finish(subject);
|
|
220
|
+
if (finish.kind !== "finished") return { kind: "pending_finish_failed", finish };
|
|
221
|
+
effects.recordFinished();
|
|
222
|
+
}
|
|
223
|
+
if (latest !== void 0 && !newerPublished) return { kind: "current", version: subject.version };
|
|
224
|
+
effects.announce(describeUpgradeStart(subject, latest));
|
|
225
|
+
try {
|
|
226
|
+
effects.install(subject.name);
|
|
227
|
+
} catch (error) {
|
|
228
|
+
return { kind: "install_failed", detail: npmErrorMessage(error) };
|
|
229
|
+
}
|
|
230
|
+
return { kind: "installed", finish: await effects.finish(subject) };
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
export {
|
|
234
|
+
FINISH_UPGRADE_FLAG,
|
|
235
|
+
runAutoUpdate,
|
|
236
|
+
globalUpgradeSubject,
|
|
237
|
+
readGlobalUpgradeSubject,
|
|
238
|
+
finishGlobalUpgrade,
|
|
239
|
+
withUpgradeLock,
|
|
240
|
+
finishUpgradeWithLock,
|
|
241
|
+
upgradeInstalledPackage
|
|
242
|
+
};
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import {
|
|
2
|
+
autoUpdateLock,
|
|
3
|
+
installPackageGlobally,
|
|
4
|
+
npmErrorMessage
|
|
5
|
+
} from "./chunk-ZMKEKWNR.js";
|
|
6
|
+
import {
|
|
7
|
+
writeJsonAtomic
|
|
8
|
+
} from "./chunk-T7E75EKA.js";
|
|
9
|
+
|
|
10
|
+
// src/upgrade-lock.ts
|
|
11
|
+
import { fork } from "child_process";
|
|
12
|
+
import { createHash } from "crypto";
|
|
13
|
+
import { existsSync, mkdirSync, readFileSync, realpathSync, unlinkSync } from "fs";
|
|
14
|
+
import { createServer, Server } from "net";
|
|
15
|
+
import { basename, dirname, join } from "path";
|
|
16
|
+
var LOCK_HOST = "127.0.0.1";
|
|
17
|
+
var LOCK_PORT_START = 49152;
|
|
18
|
+
var LOCK_PORT_COUNT = 16384;
|
|
19
|
+
var INHERITED_LOCK_ENV = "PUSHARY_UPGRADE_LOCK";
|
|
20
|
+
var LOCK_READY = "pushary-upgrade-lock-ready";
|
|
21
|
+
var LOCK_HANDLE = "pushary-upgrade-lock-handle";
|
|
22
|
+
var HANDOFF_TIMEOUT_MS = 1e4;
|
|
23
|
+
var FINISH_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
24
|
+
var KERNEL_LOCK_FORMAT = "kernel-v1";
|
|
25
|
+
var heldLocks = /* @__PURE__ */ new Map();
|
|
26
|
+
var canonicalLockPath = (path) => {
|
|
27
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
28
|
+
return join(realpathSync(dirname(path)), basename(path));
|
|
29
|
+
};
|
|
30
|
+
var lockPort = (path) => LOCK_PORT_START + createHash("sha256").update(path).digest().readUInt32BE(0) % LOCK_PORT_COUNT;
|
|
31
|
+
var readLockRecord = (path) => {
|
|
32
|
+
try {
|
|
33
|
+
const value = JSON.parse(readFileSync(path, "utf8"));
|
|
34
|
+
const pid = value && typeof value === "object" && "pid" in value ? value.pid : void 0;
|
|
35
|
+
return {
|
|
36
|
+
pid: typeof pid === "number" && Number.isInteger(pid) && pid > 0 ? pid : void 0,
|
|
37
|
+
installationPending: value !== null && typeof value === "object" && "installationPending" in value && value.installationPending === true,
|
|
38
|
+
usesKernelLock: value !== null && typeof value === "object" && "format" in value && value.format === KERNEL_LOCK_FORMAT
|
|
39
|
+
};
|
|
40
|
+
} catch {
|
|
41
|
+
return { pid: void 0, usesKernelLock: false, installationPending: false };
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
var isProcessAlive = (pid) => {
|
|
45
|
+
try {
|
|
46
|
+
process.kill(pid, 0);
|
|
47
|
+
return true;
|
|
48
|
+
} catch (error) {
|
|
49
|
+
return !(error instanceof Error && "code" in error && error.code === "ESRCH");
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
var rejectConnection = (socket) => {
|
|
53
|
+
socket.destroy();
|
|
54
|
+
};
|
|
55
|
+
var inheritLock = (path) => new Promise((resolve) => {
|
|
56
|
+
const done = (claim) => {
|
|
57
|
+
clearTimeout(timer);
|
|
58
|
+
process.off("message", receive);
|
|
59
|
+
process.off("disconnect", disconnected);
|
|
60
|
+
resolve(claim);
|
|
61
|
+
};
|
|
62
|
+
const disconnected = () => done({ kind: "unavailable", reason: "Upgrade parent disconnected before transferring its lock" });
|
|
63
|
+
const receive = (message, handle) => {
|
|
64
|
+
if (message !== LOCK_HANDLE || !(handle instanceof Server)) return;
|
|
65
|
+
const address = handle.address();
|
|
66
|
+
if (address === null || typeof address === "string" || address.port !== lockPort(path) || address.address !== LOCK_HOST) {
|
|
67
|
+
handle.close();
|
|
68
|
+
done({ kind: "unavailable", reason: "Invalid inherited upgrade lock" });
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
handle.on("connection", rejectConnection);
|
|
72
|
+
heldLocks.set(path, handle);
|
|
73
|
+
done({ kind: "inherited" });
|
|
74
|
+
process.disconnect?.();
|
|
75
|
+
};
|
|
76
|
+
const timer = setTimeout(() => done({ kind: "unavailable", reason: "Upgrade lock handoff timed out" }), HANDOFF_TIMEOUT_MS);
|
|
77
|
+
process.on("message", receive);
|
|
78
|
+
process.once("disconnect", disconnected);
|
|
79
|
+
if (!process.send || !process.connected) return disconnected();
|
|
80
|
+
process.send(LOCK_READY, (error) => {
|
|
81
|
+
if (error) disconnected();
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
var claimUpgradeLock = async (request = {}) => {
|
|
85
|
+
let server;
|
|
86
|
+
try {
|
|
87
|
+
const path = canonicalLockPath(request.lockPath ?? autoUpdateLock());
|
|
88
|
+
const inheritedPath = process.env[INHERITED_LOCK_ENV];
|
|
89
|
+
delete process.env[INHERITED_LOCK_ENV];
|
|
90
|
+
if (inheritedPath === path && !heldLocks.has(path)) return await inheritLock(path);
|
|
91
|
+
server = createServer(rejectConnection);
|
|
92
|
+
const listener = server;
|
|
93
|
+
await new Promise((resolve, reject) => {
|
|
94
|
+
listener.once("error", reject);
|
|
95
|
+
listener.listen({ host: LOCK_HOST, port: lockPort(path), exclusive: true }, resolve);
|
|
96
|
+
});
|
|
97
|
+
const record = readLockRecord(path);
|
|
98
|
+
if (record.installationPending) {
|
|
99
|
+
server.close();
|
|
100
|
+
return { kind: "unavailable", reason: `An earlier installation did not finish safely. Stop its npm processes (or restart the computer), then remove ${path} and retry the upgrade.` };
|
|
101
|
+
}
|
|
102
|
+
if (existsSync(path) && !record.usesKernelLock && (record.pid === void 0 || (request.isAlive ?? isProcessAlive)(record.pid))) {
|
|
103
|
+
server.close();
|
|
104
|
+
return { kind: "held", holderPid: record.pid };
|
|
105
|
+
}
|
|
106
|
+
writeJsonAtomic(path, { pid: process.pid, format: KERNEL_LOCK_FORMAT }, 384);
|
|
107
|
+
heldLocks.set(path, server);
|
|
108
|
+
return { kind: "acquired" };
|
|
109
|
+
} catch (error) {
|
|
110
|
+
server?.close();
|
|
111
|
+
if (error instanceof Error && "code" in error && error.code === "EADDRINUSE") {
|
|
112
|
+
return { kind: "held", holderPid: readLockRecord(request.lockPath ?? autoUpdateLock()).pid };
|
|
113
|
+
}
|
|
114
|
+
return { kind: "unavailable", reason: npmErrorMessage(error) };
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
var ownsUpgradeLock = (lockPath) => {
|
|
118
|
+
try {
|
|
119
|
+
return heldLocks.has(canonicalLockPath(lockPath));
|
|
120
|
+
} catch {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
var releaseAutoUpdateLock = (lockPath) => {
|
|
125
|
+
const path = canonicalLockPath(lockPath);
|
|
126
|
+
const server = heldLocks.get(path);
|
|
127
|
+
if (!server) return;
|
|
128
|
+
heldLocks.delete(path);
|
|
129
|
+
try {
|
|
130
|
+
const record = readLockRecord(path);
|
|
131
|
+
if (record.pid === process.pid && !record.installationPending) unlinkSync(path);
|
|
132
|
+
} finally {
|
|
133
|
+
server.close();
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
var finishWithUpgradeLock = (request) => new Promise((resolve, reject) => {
|
|
137
|
+
const path = canonicalLockPath(request.lockPath ?? autoUpdateLock());
|
|
138
|
+
const server = heldLocks.get(path);
|
|
139
|
+
if (!server) return reject(new Error("Cannot finish an upgrade without its lock"));
|
|
140
|
+
const child = fork(request.entry, [...request.args], {
|
|
141
|
+
execArgv: [],
|
|
142
|
+
stdio: request.stdio ?? ["inherit", "inherit", "inherit", "ipc"],
|
|
143
|
+
env: { ...process.env, ...request.env, [INHERITED_LOCK_ENV]: path }
|
|
144
|
+
});
|
|
145
|
+
const timer = setTimeout(() => child.kill("SIGKILL"), FINISH_TIMEOUT_MS);
|
|
146
|
+
child.on("message", (message) => {
|
|
147
|
+
if (message === LOCK_READY) child.send(LOCK_HANDLE, server, (error) => {
|
|
148
|
+
if (error) child.kill();
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
child.once("error", (error) => {
|
|
152
|
+
clearTimeout(timer);
|
|
153
|
+
reject(error);
|
|
154
|
+
});
|
|
155
|
+
child.once("exit", (code, signal) => {
|
|
156
|
+
clearTimeout(timer);
|
|
157
|
+
if (code === 0) resolve();
|
|
158
|
+
else reject(new Error(`Upgrade finish exited with ${signal ?? code}`));
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
var installWithUpgradeLock = (request, lockPath = autoUpdateLock(), runNpm) => {
|
|
162
|
+
const path = canonicalLockPath(lockPath);
|
|
163
|
+
if (!heldLocks.has(path)) throw new Error("Cannot install an upgrade without its lock");
|
|
164
|
+
writeJsonAtomic(path, { pid: process.pid, format: KERNEL_LOCK_FORMAT, installationPending: true }, 384);
|
|
165
|
+
installPackageGlobally(request, runNpm);
|
|
166
|
+
writeJsonAtomic(path, { pid: process.pid, format: KERNEL_LOCK_FORMAT }, 384);
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
export {
|
|
170
|
+
claimUpgradeLock,
|
|
171
|
+
ownsUpgradeLock,
|
|
172
|
+
releaseAutoUpdateLock,
|
|
173
|
+
finishWithUpgradeLock,
|
|
174
|
+
installWithUpgradeLock
|
|
175
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
resolveInstallSourceFor
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-6QSDNXGM.js";
|
|
4
4
|
import {
|
|
5
5
|
backupFile,
|
|
6
6
|
readJsonSafe,
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "./chunk-T7E75EKA.js";
|
|
10
10
|
import {
|
|
11
11
|
configFilePath
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-4SB46XLF.js";
|
|
13
13
|
|
|
14
14
|
// src/shell-alias.ts
|
|
15
15
|
import { homedir } from "os";
|
|
@@ -14,17 +14,18 @@ import {
|
|
|
14
14
|
} from "./chunk-U4TMAANR.js";
|
|
15
15
|
import {
|
|
16
16
|
callMcpTool
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-VH6763OR.js";
|
|
18
18
|
import {
|
|
19
19
|
reportedInstallSource
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-6QSDNXGM.js";
|
|
21
21
|
import {
|
|
22
22
|
NPX_LATEST_COMMAND
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-FVOCQSBG.js";
|
|
24
24
|
import {
|
|
25
|
+
NO_PAIRING_COMPUTER,
|
|
25
26
|
PAIR_TTL_SECONDS,
|
|
26
27
|
isAnswerSource
|
|
27
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-XEIV5QOT.js";
|
|
28
29
|
|
|
29
30
|
// src/reach.ts
|
|
30
31
|
var reachVerdict = (channels) => {
|
|
@@ -737,7 +738,7 @@ var PAIR_BROWSER_FALLBACK_AFTER_MS = 6e4;
|
|
|
737
738
|
var BROWSER_CONNECT_COMMAND = `${NPX_LATEST_COMMAND} setup --connect browser`;
|
|
738
739
|
var PAIR_BROWSER_FALLBACK_LINE = `Still waiting? Sign in with a browser instead: Ctrl-C, then ${BROWSER_CONNECT_COMMAND}`;
|
|
739
740
|
var SYSTEM_PAIR_CLOCK = { now: () => Date.now(), sleep };
|
|
740
|
-
var startPairing = async (cliPublicKey) => {
|
|
741
|
+
var startPairing = async (cliPublicKey, computer) => {
|
|
741
742
|
try {
|
|
742
743
|
const res = await fetch(`${apiBase()}/api/mobile/pair/start`, {
|
|
743
744
|
method: "POST",
|
|
@@ -747,7 +748,7 @@ var startPairing = async (cliPublicKey) => {
|
|
|
747
748
|
// phone that authorizes has the session and mints the key but never saw
|
|
748
749
|
// this terminal. Sending it here is what lets the minted key name its
|
|
749
750
|
// origin. An older server ignores the extra field.
|
|
750
|
-
body: JSON.stringify({ cliPublicKey, installSource: reportedInstallSource() }),
|
|
751
|
+
body: JSON.stringify({ cliPublicKey, installSource: reportedInstallSource(), ...computer }),
|
|
751
752
|
signal: AbortSignal.timeout(1e4)
|
|
752
753
|
});
|
|
753
754
|
if (!res.ok) return null;
|
|
@@ -768,6 +769,8 @@ var describePairFailure = (reason) => {
|
|
|
768
769
|
return "The app could not authorize this terminal. Re-run setup to try again";
|
|
769
770
|
case "payment_required":
|
|
770
771
|
return "Your Pushary workspace has no active subscription. Subscribe in the Pushary app or at pushary.com, then run setup again";
|
|
772
|
+
case "denied":
|
|
773
|
+
return "You denied this computer on your phone. Run setup again if that was a mistake";
|
|
771
774
|
default:
|
|
772
775
|
return "Pairing failed. Re-run setup to try again";
|
|
773
776
|
}
|
|
@@ -830,7 +833,7 @@ var connectViaAppPairing = async (options = {}) => {
|
|
|
830
833
|
const clock = options.clock ?? SYSTEM_PAIR_CLOCK;
|
|
831
834
|
const keypair = generateKeypair();
|
|
832
835
|
const requestedAt = clock.now();
|
|
833
|
-
const started = await startPairing(keypair.publicKeyB64);
|
|
836
|
+
const started = await startPairing(keypair.publicKeyB64, options.computer ?? NO_PAIRING_COMPUTER);
|
|
834
837
|
if (!started) {
|
|
835
838
|
console.log(` ${yellow("!")} Couldn't start pairing. Check your connection and try again.`);
|
|
836
839
|
return pairFailed("unreachable");
|
|
@@ -3,11 +3,11 @@ import {
|
|
|
3
3
|
decodePublicKey,
|
|
4
4
|
generateSessionKey,
|
|
5
5
|
wrapSessionKey
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-FJPC35OW.js";
|
|
7
7
|
import {
|
|
8
8
|
fetchTranscriptRecipients,
|
|
9
9
|
uploadTranscriptRecords
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-PMS3EBD2.js";
|
|
11
11
|
|
|
12
12
|
// src/live-session.ts
|
|
13
13
|
var MAX_TRANSCRIPT_QUEUE = 100;
|
|
@@ -4,18 +4,18 @@ import {
|
|
|
4
4
|
} from "./chunk-POFBE6ZY.js";
|
|
5
5
|
import {
|
|
6
6
|
isNetworkFailure
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-6JTTJIKJ.js";
|
|
8
8
|
import {
|
|
9
9
|
clientReportClaims
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-ZMKEKWNR.js";
|
|
11
11
|
import {
|
|
12
12
|
getApiKey,
|
|
13
13
|
getBaseUrl
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-4SB46XLF.js";
|
|
15
15
|
import {
|
|
16
16
|
CLIENT_REPORT_PATH,
|
|
17
17
|
degradedLine
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-XEIV5QOT.js";
|
|
19
19
|
|
|
20
20
|
// src/client-report-claim.ts
|
|
21
21
|
import { createHash } from "crypto";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ensureCodexTrustsPusharyHooks
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-KR5JASA4.js";
|
|
4
4
|
import {
|
|
5
5
|
addClaudeMcpServer,
|
|
6
6
|
addPusharyHooks,
|
|
7
7
|
addPusharyToolPermissions
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-6Q4NM2LW.js";
|
|
9
9
|
import {
|
|
10
10
|
detectClaudeVersion
|
|
11
11
|
} from "./chunk-RIVNNBEK.js";
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
codexUnprovenHolds,
|
|
16
16
|
codexWired,
|
|
17
17
|
geminiWired
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-5K43TBK4.js";
|
|
19
19
|
import {
|
|
20
20
|
CLAUDE_HOOK_BINARY,
|
|
21
21
|
CLAUDE_HOOK_EVENTS,
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
needsReregistration,
|
|
27
27
|
registrationSignatures,
|
|
28
28
|
supportedClaudeEvents
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-D3RS57MN.js";
|
|
30
30
|
import {
|
|
31
31
|
formatVersion
|
|
32
32
|
} from "./chunk-6ICPEJY5.js";
|
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
registrationHolderOf,
|
|
50
50
|
resolveGlobalBinary,
|
|
51
51
|
vscodePluginMcp
|
|
52
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-ZMKEKWNR.js";
|
|
53
53
|
import {
|
|
54
54
|
readJsonSafe,
|
|
55
55
|
writeFileAtomic,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
registerTranscript
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-WWDPULS3.js";
|
|
4
4
|
import {
|
|
5
5
|
writeDegraded
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-SPB3QRE7.js";
|
|
7
7
|
|
|
8
8
|
// src/tool-hook-input.ts
|
|
9
9
|
var OPTIONAL_TEXT_FIELDS = ["hook_event_name", "session_id", "cwd", "transcript_path", "tool_use_id", "permission_mode"];
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
MCP_BRIDGE_BINARY
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-LJI7U6PM.js";
|
|
4
4
|
import {
|
|
5
5
|
openCodeConfigDirFrom
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-CGRPHFOV.js";
|
|
7
7
|
import {
|
|
8
8
|
KEY_FILE_MODE
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-RJ7ECJSZ.js";
|
|
10
10
|
import {
|
|
11
11
|
NpmMissingError,
|
|
12
12
|
codexHomeFrom,
|
|
13
13
|
resolvePathBinary
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-ZMKEKWNR.js";
|
|
15
15
|
import {
|
|
16
16
|
readJsonSafe,
|
|
17
17
|
writeFileAtomic,
|
|
@@ -19,10 +19,10 @@ import {
|
|
|
19
19
|
} from "./chunk-T7E75EKA.js";
|
|
20
20
|
import {
|
|
21
21
|
NPX_LATEST_COMMAND
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-FVOCQSBG.js";
|
|
23
23
|
import {
|
|
24
24
|
HOOK_COMPATIBLE_PROFILES
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-XEIV5QOT.js";
|
|
26
26
|
|
|
27
27
|
// src/hermes-config.ts
|
|
28
28
|
import { execFileSync } from "child_process";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
keyCheckFromResponse
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-DMA3QUOB.js";
|
|
4
4
|
import {
|
|
5
5
|
installNetworkDefaults
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-6JTTJIKJ.js";
|
|
7
7
|
import {
|
|
8
8
|
getBaseUrl
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-4SB46XLF.js";
|
|
10
10
|
|
|
11
11
|
// src/retry.ts
|
|
12
12
|
var isRetryable = (err) => {
|