pushary 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/CHANGELOG.md +1943 -0
  2. package/LICENSE +21 -0
  3. package/README.md +330 -0
  4. package/data/SKILL.md +591 -0
  5. package/data/cowork/SKILL.md +77 -0
  6. package/data/cursor-plugin/.cursor-plugin/plugin.json +25 -0
  7. package/data/cursor-plugin/CHANGELOG.md +70 -0
  8. package/data/cursor-plugin/CONTRIBUTING.md +40 -0
  9. package/data/cursor-plugin/LICENSE +21 -0
  10. package/data/cursor-plugin/README.md +113 -0
  11. package/data/cursor-plugin/SECURITY.md +33 -0
  12. package/data/cursor-plugin/assets/logo.png +0 -0
  13. package/data/cursor-plugin/commands/notify-when-done.md +14 -0
  14. package/data/cursor-plugin/commands/pushary-test.md +13 -0
  15. package/data/cursor-plugin/hooks/hooks.json +75 -0
  16. package/data/cursor-plugin/mcp.json +11 -0
  17. package/data/cursor-plugin/rules/pushary.mdc +40 -0
  18. package/data/cursor-plugin/scripts/pushary-gate.mjs +724 -0
  19. package/data/cursor-plugin/scripts/pushary-gate.test.mjs +137 -0
  20. package/data/cursor-plugin/scripts/redaction.mjs +51 -0
  21. package/data/cursor-plugin/skills/pushary/SKILL.md +584 -0
  22. package/data/vscode-plugin/.claude-plugin/plugin.json +28 -0
  23. package/data/vscode-plugin/.mcp.json +11 -0
  24. package/data/vscode-plugin/CHANGELOG.md +49 -0
  25. package/data/vscode-plugin/CONTRIBUTING.md +40 -0
  26. package/data/vscode-plugin/LICENSE +21 -0
  27. package/data/vscode-plugin/README.md +128 -0
  28. package/data/vscode-plugin/SECURITY.md +56 -0
  29. package/data/vscode-plugin/assets/logo.png +0 -0
  30. package/data/vscode-plugin/commands/notify-when-done.md +14 -0
  31. package/data/vscode-plugin/commands/pushary-test.md +13 -0
  32. package/data/vscode-plugin/hooks/hooks.json +60 -0
  33. package/data/vscode-plugin/scripts/pushary-gate.mjs +762 -0
  34. package/data/vscode-plugin/scripts/redaction.mjs +51 -0
  35. package/data/vscode-plugin/skills/pushary/SKILL.md +584 -0
  36. package/dist/bin/pushary-bell-hook.d.ts +1 -0
  37. package/dist/bin/pushary-bell-hook.js +46 -0
  38. package/dist/bin/pushary-bell.d.ts +1 -0
  39. package/dist/bin/pushary-bell.js +146 -0
  40. package/dist/bin/pushary-claude.d.ts +1 -0
  41. package/dist/bin/pushary-claude.js +1916 -0
  42. package/dist/bin/pushary-clean.d.ts +1 -0
  43. package/dist/bin/pushary-clean.js +1300 -0
  44. package/dist/bin/pushary-codex-bridge.d.ts +1 -0
  45. package/dist/bin/pushary-codex-bridge.js +599 -0
  46. package/dist/bin/pushary-codex-hook.d.ts +1 -0
  47. package/dist/bin/pushary-codex-hook.js +886 -0
  48. package/dist/bin/pushary-codex.d.ts +1 -0
  49. package/dist/bin/pushary-codex.js +125 -0
  50. package/dist/bin/pushary-connect.d.ts +1 -0
  51. package/dist/bin/pushary-connect.js +100 -0
  52. package/dist/bin/pushary-cowork.d.ts +1 -0
  53. package/dist/bin/pushary-cowork.js +36 -0
  54. package/dist/bin/pushary-daemon-supervisor.d.ts +1 -0
  55. package/dist/bin/pushary-daemon-supervisor.js +27 -0
  56. package/dist/bin/pushary-daemon.d.ts +1 -0
  57. package/dist/bin/pushary-daemon.js +878 -0
  58. package/dist/bin/pushary-disconnect.d.ts +1 -0
  59. package/dist/bin/pushary-disconnect.js +264 -0
  60. package/dist/bin/pushary-doctor.d.ts +1 -0
  61. package/dist/bin/pushary-doctor.js +1433 -0
  62. package/dist/bin/pushary-elicitation-hook.d.ts +1 -0
  63. package/dist/bin/pushary-elicitation-hook.js +149 -0
  64. package/dist/bin/pushary-gemini-bridge.d.ts +1 -0
  65. package/dist/bin/pushary-gemini-bridge.js +339 -0
  66. package/dist/bin/pushary-gemini-hook.d.ts +1 -0
  67. package/dist/bin/pushary-gemini-hook.js +381 -0
  68. package/dist/bin/pushary-hook.d.ts +1 -0
  69. package/dist/bin/pushary-hook.js +95 -0
  70. package/dist/bin/pushary-login.d.ts +1 -0
  71. package/dist/bin/pushary-login.js +198 -0
  72. package/dist/bin/pushary-logout.d.ts +1 -0
  73. package/dist/bin/pushary-logout.js +147 -0
  74. package/dist/bin/pushary-mcp.d.ts +1 -0
  75. package/dist/bin/pushary-mcp.js +114 -0
  76. package/dist/bin/pushary-mode.d.ts +1 -0
  77. package/dist/bin/pushary-mode.js +130 -0
  78. package/dist/bin/pushary-notification-hook.d.ts +1 -0
  79. package/dist/bin/pushary-notification-hook.js +56 -0
  80. package/dist/bin/pushary-opencode-hook.d.ts +1 -0
  81. package/dist/bin/pushary-opencode-hook.js +338 -0
  82. package/dist/bin/pushary-permission-denied-hook.d.ts +1 -0
  83. package/dist/bin/pushary-permission-denied-hook.js +60 -0
  84. package/dist/bin/pushary-permission-hook.d.ts +1 -0
  85. package/dist/bin/pushary-permission-hook.js +65 -0
  86. package/dist/bin/pushary-post-hook.d.ts +1 -0
  87. package/dist/bin/pushary-post-hook.js +70 -0
  88. package/dist/bin/pushary-prompt-hook.d.ts +1 -0
  89. package/dist/bin/pushary-prompt-hook.js +61 -0
  90. package/dist/bin/pushary-session-end-hook.d.ts +1 -0
  91. package/dist/bin/pushary-session-end-hook.js +59 -0
  92. package/dist/bin/pushary-session-start-hook.d.ts +1 -0
  93. package/dist/bin/pushary-session-start-hook.js +72 -0
  94. package/dist/bin/pushary-setup.d.ts +1 -0
  95. package/dist/bin/pushary-setup.js +2660 -0
  96. package/dist/bin/pushary-stats.d.ts +1 -0
  97. package/dist/bin/pushary-stats.js +44 -0
  98. package/dist/bin/pushary-status.d.ts +1 -0
  99. package/dist/bin/pushary-status.js +262 -0
  100. package/dist/bin/pushary-stop-hook.d.ts +1 -0
  101. package/dist/bin/pushary-stop-hook.js +63 -0
  102. package/dist/bin/pushary-stopfailure-hook.d.ts +1 -0
  103. package/dist/bin/pushary-stopfailure-hook.js +56 -0
  104. package/dist/bin/pushary-suggestions.d.ts +1 -0
  105. package/dist/bin/pushary-suggestions.js +100 -0
  106. package/dist/bin/pushary-transcript-register.d.ts +1 -0
  107. package/dist/bin/pushary-transcript-register.js +40 -0
  108. package/dist/bin/pushary-transcripts.d.ts +1 -0
  109. package/dist/bin/pushary-transcripts.js +77 -0
  110. package/dist/bin/pushary-upgrade.d.ts +1 -0
  111. package/dist/bin/pushary-upgrade.js +599 -0
  112. package/dist/bin/pushary-wait.d.ts +1 -0
  113. package/dist/bin/pushary-wait.js +122 -0
  114. package/dist/bin/pushary.d.ts +1 -0
  115. package/dist/bin/pushary.js +74 -0
  116. package/dist/chunk-2ABTSGFT.js +173 -0
  117. package/dist/chunk-2OY3ZZ5N.js +124 -0
  118. package/dist/chunk-3EGEA4KH.js +44 -0
  119. package/dist/chunk-3EVPNIBE.js +185 -0
  120. package/dist/chunk-5OP5MQI7.js +45 -0
  121. package/dist/chunk-6J2JC2RT.js +149 -0
  122. package/dist/chunk-7QLSKOSU.js +19 -0
  123. package/dist/chunk-7Z7Q4GGS.js +88 -0
  124. package/dist/chunk-A2A2YTMG.js +835 -0
  125. package/dist/chunk-AHV4LNB5.js +377 -0
  126. package/dist/chunk-AXPCESYO.js +197 -0
  127. package/dist/chunk-C2WCPBF7.js +86 -0
  128. package/dist/chunk-CJVVKOSR.js +73 -0
  129. package/dist/chunk-CULUZTWQ.js +2117 -0
  130. package/dist/chunk-CVQYGMSR.js +142 -0
  131. package/dist/chunk-CVWG2N3Y.js +16 -0
  132. package/dist/chunk-D2FX3EPW.js +15 -0
  133. package/dist/chunk-DB3ONZB4.js +44 -0
  134. package/dist/chunk-DE4Y6TCC.js +160 -0
  135. package/dist/chunk-E4FJTUH4.js +249 -0
  136. package/dist/chunk-EPCXUP3P.js +41 -0
  137. package/dist/chunk-EX3GAPA4.js +44 -0
  138. package/dist/chunk-EYK3GSRH.js +143 -0
  139. package/dist/chunk-GMXKITVA.js +70 -0
  140. package/dist/chunk-GPEGOGRJ.js +49 -0
  141. package/dist/chunk-GU3EJCVV.js +43 -0
  142. package/dist/chunk-HQ6G3B5R.js +59 -0
  143. package/dist/chunk-HZVVNGEW.js +22 -0
  144. package/dist/chunk-IPVKH2ST.js +231 -0
  145. package/dist/chunk-J5TIV3J6.js +238 -0
  146. package/dist/chunk-JU6W3XAU.js +64 -0
  147. package/dist/chunk-JYG4B33G.js +227 -0
  148. package/dist/chunk-JZTHGAPA.js +503 -0
  149. package/dist/chunk-KGDWDSNL.js +102 -0
  150. package/dist/chunk-KVQBWI5T.js +99 -0
  151. package/dist/chunk-KZERVKTD.js +16 -0
  152. package/dist/chunk-LXQ5FBBD.js +47 -0
  153. package/dist/chunk-M5ICYGHT.js +138 -0
  154. package/dist/chunk-M5JDZ45W.js +943 -0
  155. package/dist/chunk-MDEPU45E.js +1226 -0
  156. package/dist/chunk-MPWXGONV.js +157 -0
  157. package/dist/chunk-N6IOSZOE.js +185 -0
  158. package/dist/chunk-NGDD6TXY.js +192 -0
  159. package/dist/chunk-NQTHFF4W.js +2830 -0
  160. package/dist/chunk-OKXS7WDZ.js +68 -0
  161. package/dist/chunk-OLQRRFBX.js +21 -0
  162. package/dist/chunk-P7WQEVWA.js +307 -0
  163. package/dist/chunk-POFBE6ZY.js +12 -0
  164. package/dist/chunk-PQ4K74WL.js +30 -0
  165. package/dist/chunk-PUZZELE6.js +37 -0
  166. package/dist/chunk-Q7E4I6UA.js +767 -0
  167. package/dist/chunk-QCGNGEGE.js +15 -0
  168. package/dist/chunk-R7437YI3.js +151 -0
  169. package/dist/chunk-RHR6NARM.js +305 -0
  170. package/dist/chunk-SAXBC4AZ.js +60 -0
  171. package/dist/chunk-SGZJ5LYH.js +76 -0
  172. package/dist/chunk-SIFVFP6T.js +70 -0
  173. package/dist/chunk-SLFABHW3.js +150 -0
  174. package/dist/chunk-T7E75EKA.js +67 -0
  175. package/dist/chunk-TY4JT7W3.js +38 -0
  176. package/dist/chunk-U4TMAANR.js +111 -0
  177. package/dist/chunk-UI36QSBI.js +177 -0
  178. package/dist/chunk-VQKRG3AC.js +339 -0
  179. package/dist/chunk-WE2J62NC.js +1131 -0
  180. package/dist/chunk-XHKBHWLX.js +14 -0
  181. package/dist/chunk-ZSZSSJCV.js +275 -0
  182. package/dist/chunk-ZVSKMPBZ.js +135 -0
  183. package/dist/reapply-CW3MA66V.js +34 -0
  184. package/dist/src/index.d.ts +204 -0
  185. package/dist/src/index.js +64 -0
  186. package/package.json +108 -0
@@ -0,0 +1,599 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ describeCodexTrustConfirmation
4
+ } from "../chunk-TY4JT7W3.js";
5
+ import {
6
+ ensureCodexTrustAfterReapply,
7
+ reapplyAllAgents
8
+ } from "../chunk-VQKRG3AC.js";
9
+ import "../chunk-SIFVFP6T.js";
10
+ import "../chunk-RHR6NARM.js";
11
+ import {
12
+ waitForMachineReadiness
13
+ } from "../chunk-DE4Y6TCC.js";
14
+ import "../chunk-AXPCESYO.js";
15
+ import {
16
+ detectProviderLiveCapabilities,
17
+ hasSpawnProvider,
18
+ resolveControlPolicy
19
+ } from "../chunk-HQ6G3B5R.js";
20
+ import {
21
+ AUTO_UPDATE_DISABLE_ENV,
22
+ describeAutoUpdateCheck,
23
+ globalInstallLocation,
24
+ hasPendingUpgradeFinish,
25
+ isAutoUpdateDisabledByEnv,
26
+ parseAutoUpdateFlag,
27
+ readAutoUpdateState,
28
+ updateAutoUpdateState,
29
+ upgradeEntryFor
30
+ } from "../chunk-UI36QSBI.js";
31
+ import "../chunk-6J2JC2RT.js";
32
+ import {
33
+ daemonHasRemoteProof,
34
+ daemonServiceManagerAvailable,
35
+ disableDaemonService,
36
+ ensureDaemonRunning,
37
+ hasDaemonServiceDefinition,
38
+ readDaemonStatus,
39
+ replaceDaemonService,
40
+ stopDaemonService,
41
+ waitForDaemonRemoteProof
42
+ } from "../chunk-WE2J62NC.js";
43
+ import "../chunk-3EVPNIBE.js";
44
+ import "../chunk-XHKBHWLX.js";
45
+ import "../chunk-EPCXUP3P.js";
46
+ import "../chunk-POFBE6ZY.js";
47
+ import {
48
+ exitOnHelpFlag
49
+ } from "../chunk-HZVVNGEW.js";
50
+ import {
51
+ readControlMode
52
+ } from "../chunk-P7WQEVWA.js";
53
+ import "../chunk-LXQ5FBBD.js";
54
+ import {
55
+ EXIT
56
+ } from "../chunk-KZERVKTD.js";
57
+ import "../chunk-DB3ONZB4.js";
58
+ import {
59
+ LATEST_TAG,
60
+ autoUpdateLock,
61
+ autoUpdateLog,
62
+ autoUpdateState,
63
+ claudeJson,
64
+ codexConfigToml,
65
+ cursorPluginDir,
66
+ execNpm,
67
+ fetchLatestPublishedVersion,
68
+ geminiSettings,
69
+ installPackageGlobally,
70
+ npmErrorMessage,
71
+ readGlobalCliInstallAt,
72
+ readGlobalPrefix,
73
+ vscodePluginDir
74
+ } from "../chunk-A2A2YTMG.js";
75
+ import "../chunk-T7E75EKA.js";
76
+ import {
77
+ getApiKey
78
+ } from "../chunk-GPEGOGRJ.js";
79
+ import {
80
+ NPX_LATEST_COMMAND
81
+ } from "../chunk-E4FJTUH4.js";
82
+ import {
83
+ CANONICAL_PACKAGE,
84
+ LEGACY_PACKAGE,
85
+ commandsPackage,
86
+ globalUpgradeEntry,
87
+ isNewerVersion,
88
+ isReleaseVersion,
89
+ isSameMajorVersion,
90
+ ownPackageRoot,
91
+ packageVersionAt
92
+ } from "../chunk-NQTHFF4W.js";
93
+
94
+ // bin/pushary-upgrade.ts
95
+ import { existsSync as existsSync2 } from "fs";
96
+ import { homedir } from "os";
97
+ import { join } from "path";
98
+
99
+ // src/global-upgrade.ts
100
+ import { execFileSync as execFileSync2 } from "child_process";
101
+ import { existsSync } from "fs";
102
+
103
+ // src/auto-update-run.ts
104
+ import { execFileSync } from "child_process";
105
+ import { closeSync, mkdirSync, openSync, readFileSync, statSync, unlinkSync, writeSync } from "fs";
106
+ import { dirname } from "path";
107
+ var FINISH_UPGRADE_FLAG = "--finish-upgrade";
108
+ var LOCK_STALE_MS = 10 * 60 * 1e3;
109
+ var INSTALL_TIMEOUT_MS = 12e4;
110
+ var FINISH_TIMEOUT_MS = 5 * 60 * 1e3;
111
+ var LOG_LIMIT_BYTES = 256 * 1024;
112
+ var UNREADABLE_INSTALLED_VERSION = "could not read the installed version";
113
+ var UNREACHABLE_REGISTRY = "could not read the latest version from the npm registry";
114
+ var MANUAL_UPGRADE_COMMAND = `${NPX_LATEST_COMMAND} upgrade`;
115
+ var isAlreadyExists = (error) => error instanceof Error && "code" in error && error.code === "EEXIST";
116
+ var createLock = (lockPath, now) => {
117
+ const handle = openSync(lockPath, "wx");
118
+ try {
119
+ writeSync(handle, `${JSON.stringify({ pid: process.pid, at: new Date(now).toISOString() })}
120
+ `);
121
+ } finally {
122
+ closeSync(handle);
123
+ }
124
+ };
125
+ var tryCreateLock = (lockPath, now) => {
126
+ try {
127
+ createLock(lockPath, now);
128
+ return "acquired";
129
+ } catch (error) {
130
+ if (isAlreadyExists(error)) return "held";
131
+ throw error;
132
+ }
133
+ };
134
+ var isStaleLock = (lockPath, now) => {
135
+ const modifiedAt = statSync(lockPath, { throwIfNoEntry: false })?.mtimeMs;
136
+ return modifiedAt !== void 0 && now - modifiedAt > LOCK_STALE_MS;
137
+ };
138
+ var takeOverLock = (lockPath, now) => {
139
+ try {
140
+ unlinkSync(lockPath);
141
+ } catch {
142
+ return "held";
143
+ }
144
+ return tryCreateLock(lockPath, now);
145
+ };
146
+ var isAbandonedLock = (evidence) => evidence.stale || evidence.holderPid !== void 0 && !evidence.holderAlive;
147
+ var lockHolderPid = (lockPath) => {
148
+ try {
149
+ const holder = JSON.parse(readFileSync(lockPath, "utf8"));
150
+ const pid = holder && typeof holder === "object" && "pid" in holder ? holder.pid : void 0;
151
+ return typeof pid === "number" && Number.isInteger(pid) && pid > 0 ? pid : void 0;
152
+ } catch {
153
+ return void 0;
154
+ }
155
+ };
156
+ var isProcessAlive = (pid) => {
157
+ try {
158
+ process.kill(pid, 0);
159
+ return true;
160
+ } catch (error) {
161
+ return error instanceof Error && "code" in error && error.code === "EPERM";
162
+ }
163
+ };
164
+ var readLockHolder = (lockPath, now, isAlive) => {
165
+ const holderPid = lockHolderPid(lockPath);
166
+ return {
167
+ holderPid,
168
+ holderAlive: holderPid !== void 0 && isAlive(holderPid),
169
+ stale: isStaleLock(lockPath, now)
170
+ };
171
+ };
172
+ var acquireAutoUpdateLock = (lockPath, now) => {
173
+ mkdirSync(dirname(lockPath), { recursive: true });
174
+ if (tryCreateLock(lockPath, now) === "acquired") return "acquired";
175
+ if (!isStaleLock(lockPath, now)) return "held";
176
+ return takeOverLock(lockPath, now);
177
+ };
178
+ var releaseAutoUpdateLock = (lockPath) => {
179
+ try {
180
+ unlinkSync(lockPath);
181
+ } catch {
182
+ return;
183
+ }
184
+ };
185
+ var upgradeLockVerdict = (evidence) => {
186
+ if (evidence.holderPid !== void 0 && evidence.holderPid === evidence.parentPid) return "inherited";
187
+ if (isAbandonedLock(evidence)) return "take_over";
188
+ return "held";
189
+ };
190
+ var claimUpgradeLockAt = (lockPath, request) => {
191
+ const now = request.now ?? Date.now();
192
+ mkdirSync(dirname(lockPath), { recursive: true });
193
+ if (tryCreateLock(lockPath, now) === "acquired") return { kind: "acquired" };
194
+ const holder = readLockHolder(lockPath, now, request.isAlive ?? isProcessAlive);
195
+ const verdict = upgradeLockVerdict({ ...holder, parentPid: request.parentPid ?? process.ppid });
196
+ if (verdict === "inherited") return { kind: "inherited" };
197
+ if (verdict === "take_over" && takeOverLock(lockPath, now) === "acquired") return { kind: "acquired" };
198
+ return { kind: "held", holderPid: holder.holderPid };
199
+ };
200
+ var claimUpgradeLock = (request = {}) => {
201
+ try {
202
+ return claimUpgradeLockAt(request.lockPath ?? autoUpdateLock(), request);
203
+ } catch {
204
+ return { kind: "unavailable" };
205
+ }
206
+ };
207
+ var openAutoUpdateLog = (logPath) => {
208
+ mkdirSync(dirname(logPath), { recursive: true });
209
+ const size = statSync(logPath, { throwIfNoEntry: false })?.size ?? 0;
210
+ return openSync(logPath, size > LOG_LIMIT_BYTES ? "w" : "a");
211
+ };
212
+ var appendAutoUpdateLog = (logPath, line) => {
213
+ try {
214
+ const handle = openAutoUpdateLog(logPath);
215
+ try {
216
+ writeSync(handle, `${line}
217
+ `);
218
+ } finally {
219
+ closeSync(handle);
220
+ }
221
+ } catch {
222
+ return;
223
+ }
224
+ };
225
+ var finishInNewInstall = (request) => {
226
+ const handle = openAutoUpdateLog(request.logPath);
227
+ try {
228
+ execFileSync(process.execPath, [request.entry, FINISH_UPGRADE_FLAG], {
229
+ stdio: ["ignore", handle, handle],
230
+ env: { ...process.env, npm_config_prefix: request.prefix },
231
+ timeout: FINISH_TIMEOUT_MS
232
+ });
233
+ } finally {
234
+ closeSync(handle);
235
+ }
236
+ };
237
+ var incompleteFinishDetail = (logPath) => `installed, but refreshing the agent configs did not finish cleanly; see ${logPath}`;
238
+ var newMajorDetail = (latest) => `${latest} is a new major version; run ${MANUAL_UPGRADE_COMMAND}`;
239
+ var finishInstalledUpgrade = (context, from, to) => {
240
+ const pending = { result: "finish_pending", from, to, detail: incompleteFinishDetail(context.logPath) };
241
+ recordAutoUpdateCheck(context.statePath, pending, new Date(context.now()).toISOString());
242
+ try {
243
+ context.finish({ entry: upgradeEntryFor(context.location), prefix: context.location.prefix, logPath: context.logPath });
244
+ return { result: "updated", from, to };
245
+ } catch {
246
+ return pending;
247
+ }
248
+ };
249
+ var isInstallableRelease = (latest, installed) => latest !== void 0 && isNewerVersion(latest, installed) && isSameMajorVersion(latest, installed);
250
+ var checkAndInstall = async (context) => {
251
+ const installed = packageVersionAt(context.packageRoot);
252
+ if (installed === void 0 || !isReleaseVersion(installed)) {
253
+ return { result: "failed", from: installed, detail: UNREADABLE_INSTALLED_VERSION };
254
+ }
255
+ const previous = readAutoUpdateState(context.statePath);
256
+ const pendingFinish = hasPendingUpgradeFinish(previous, installed);
257
+ const latest = await fetchLatestPublishedVersion({ packageName: context.location.packageName, fetchImpl: context.fetchImpl });
258
+ if (pendingFinish && !isInstallableRelease(latest, installed)) return finishInstalledUpgrade(context, previous.from, installed);
259
+ if (latest === void 0) return { result: "failed", from: installed, detail: UNREACHABLE_REGISTRY };
260
+ if (!isNewerVersion(latest, installed)) return { result: "current", from: installed };
261
+ if (!isSameMajorVersion(latest, installed)) {
262
+ return { result: "needs_manual", from: installed, to: latest, detail: newMajorDetail(latest) };
263
+ }
264
+ appendAutoUpdateLog(context.logPath, `${new Date(context.now()).toISOString()} installing ${context.location.packageName}@${latest} into ${context.location.prefix}`);
265
+ try {
266
+ installPackageGlobally({
267
+ packageName: context.location.packageName,
268
+ version: latest,
269
+ prefix: context.location.prefix,
270
+ timeoutMs: INSTALL_TIMEOUT_MS
271
+ }, context.runNpm);
272
+ } catch (error) {
273
+ if (pendingFinish) return finishInstalledUpgrade(context, previous.from, installed);
274
+ return { result: "failed", from: installed, to: latest, detail: npmErrorMessage(error) };
275
+ }
276
+ return finishInstalledUpgrade(context, installed, latest);
277
+ };
278
+ var recordAutoUpdateCheck = (statePath, check, at) => updateAutoUpdateState(statePath, {
279
+ lastCheckAt: at,
280
+ lastResult: check.result,
281
+ from: check.from,
282
+ to: check.to,
283
+ at,
284
+ detail: check.detail,
285
+ announced: check.result === "updated" ? false : void 0
286
+ });
287
+ var runAutoUpdate = async (run = {}) => {
288
+ if ((run.platform ?? process.platform) === "linux") return { kind: "linux" };
289
+ const packageRoot = run.packageRoot ?? ownPackageRoot();
290
+ const location = packageRoot === void 0 ? null : globalInstallLocation(packageRoot);
291
+ if (packageRoot === void 0 || location === null) return { kind: "not_global_install" };
292
+ const now = run.now ?? Date.now;
293
+ const lockPath = run.lockPath ?? autoUpdateLock();
294
+ const logPath = run.logPath ?? autoUpdateLog();
295
+ if (acquireAutoUpdateLock(lockPath, now()) === "held") return { kind: "locked" };
296
+ try {
297
+ const check = await checkAndInstall({
298
+ packageRoot,
299
+ statePath: run.statePath ?? autoUpdateState(),
300
+ location,
301
+ logPath,
302
+ now,
303
+ fetchImpl: run.fetchImpl ?? fetch,
304
+ runNpm: run.runNpm ?? execNpm,
305
+ finish: run.finish ?? finishInNewInstall
306
+ });
307
+ const at = new Date(now()).toISOString();
308
+ const state = recordAutoUpdateCheck(run.statePath ?? autoUpdateState(), check, at);
309
+ appendAutoUpdateLog(logPath, `${at} ${describeAutoUpdateCheck(state)}`);
310
+ return { kind: "recorded", state };
311
+ } finally {
312
+ releaseAutoUpdateLock(lockPath);
313
+ }
314
+ };
315
+
316
+ // src/global-upgrade.ts
317
+ var NOT_INSTALLED = { kind: "not_installed" };
318
+ var globalUpgradeSubject = (prefix, install) => {
319
+ if (prefix === void 0) return NOT_INSTALLED;
320
+ const commands = commandsPackage(install);
321
+ if (commands?.version !== void 0) return { kind: "installed", prefix, name: commands.name, version: commands.version };
322
+ return install.kind === "both" ? { kind: "both_installed" } : NOT_INSTALLED;
323
+ };
324
+ var readGlobalUpgradeSubject = (platform = process.platform) => {
325
+ const prefix = readGlobalPrefix();
326
+ return globalUpgradeSubject(prefix, prefix === void 0 ? { kind: "unavailable" } : readGlobalCliInstallAt(prefix, platform));
327
+ };
328
+ var finishWithThisNode = (entry) => {
329
+ execFileSync2(process.execPath, [entry, FINISH_UPGRADE_FLAG], { stdio: "inherit" });
330
+ };
331
+ var finishGlobalUpgrade = (subject, platform = process.platform, runFinish = finishWithThisNode) => {
332
+ const entry = globalUpgradeEntry(subject.prefix, subject.name, platform);
333
+ if (!existsSync(entry)) return { kind: "entry_missing", entry };
334
+ try {
335
+ runFinish(entry);
336
+ return { kind: "finished" };
337
+ } catch {
338
+ return { kind: "failed" };
339
+ }
340
+ };
341
+ var describeHeldUpgradeLock = (holderPid) => `Another Pushary upgrade is already running${holderPid === void 0 ? "" : ` (pid ${holderPid})`}. Try again when it has finished.`;
342
+ var withUpgradeLock = async (run, request = {}) => {
343
+ const claim = claimUpgradeLock(request);
344
+ if (claim.kind === "held") return { kind: "refused", exitCode: EXIT.FAILED, message: describeHeldUpgradeLock(claim.holderPid) };
345
+ try {
346
+ await run();
347
+ } finally {
348
+ if (claim.kind === "acquired") releaseAutoUpdateLock(request.lockPath ?? autoUpdateLock());
349
+ }
350
+ return { kind: "ran" };
351
+ };
352
+ var describeUpgradeStart = (subject, latest) => `Upgrading ${subject.name} ${subject.version} -> ${latest ?? "latest"}`;
353
+ var upgradeInstalledPackage = async (subject, effects) => {
354
+ const pendingFinish = effects.hasPendingFinish(subject.version);
355
+ const latest = await effects.fetchLatest(subject.name);
356
+ const newerPublished = latest !== void 0 && isNewerVersion(latest, subject.version);
357
+ if (pendingFinish && !newerPublished) {
358
+ const finish = effects.finish(subject);
359
+ if (finish.kind !== "finished") return { kind: "pending_finish_failed", finish };
360
+ effects.recordFinished();
361
+ }
362
+ if (latest !== void 0 && !newerPublished) return { kind: "current", version: subject.version };
363
+ effects.announce(describeUpgradeStart(subject, latest));
364
+ try {
365
+ effects.install(subject.name);
366
+ } catch (error) {
367
+ return { kind: "install_failed", detail: npmErrorMessage(error) };
368
+ }
369
+ return { kind: "installed", finish: effects.finish(subject) };
370
+ };
371
+
372
+ // bin/pushary-upgrade.ts
373
+ exitOnHelpFlag("upgrade");
374
+ var detectInstallModes = () => {
375
+ const candidates = [
376
+ {
377
+ label: "Cursor plugin",
378
+ upgrade: "updates itself through Cursor",
379
+ present: existsSync2(cursorPluginDir())
380
+ },
381
+ {
382
+ label: "VS Code plugin",
383
+ upgrade: "npx @pushary/agent-hooks@latest setup --agents vscode",
384
+ present: existsSync2(vscodePluginDir())
385
+ },
386
+ {
387
+ label: "Codex config",
388
+ upgrade: "npx @pushary/agent-hooks@latest setup --agents codex",
389
+ present: existsSync2(codexConfigToml())
390
+ },
391
+ {
392
+ label: "Claude Code config",
393
+ upgrade: "npx @pushary/agent-hooks@latest setup --agents claude_code",
394
+ present: existsSync2(claudeJson())
395
+ },
396
+ {
397
+ label: "Gemini config",
398
+ upgrade: "npx @pushary/agent-hooks@latest setup --agents gemini_cli",
399
+ present: existsSync2(geminiSettings())
400
+ },
401
+ {
402
+ label: "Hermes plugin (pip)",
403
+ upgrade: "npx @pushary/agent-hooks@latest setup --agents hermes",
404
+ present: existsSync2(join(homedir(), ".hermes"))
405
+ }
406
+ ];
407
+ return candidates.filter((candidate) => candidate.present).map(({ label, upgrade }) => ({ label, upgrade }));
408
+ };
409
+ var finishUpgrade = async () => {
410
+ let apiKey;
411
+ try {
412
+ apiKey = getApiKey();
413
+ } catch {
414
+ apiKey = void 0;
415
+ }
416
+ const inspectedAgents = reapplyAllAgents(apiKey);
417
+ const codexTrust = await ensureCodexTrustAfterReapply(inspectedAgents);
418
+ const refreshed = inspectedAgents.filter((agent) => agent.result.reapplied);
419
+ const failedRefreshes = inspectedAgents.filter((agent) => agent.result.failed);
420
+ const configuredControlProviders = inspectedAgents.filter((agent) => agent.result.configured && (agent.id === "claude" || agent.id === "codex" || agent.id === "gemini")).map((agent) => agent.id);
421
+ const controlMode = readControlMode();
422
+ const daemonStatus = readDaemonStatus();
423
+ const serviceWasPresent = daemonStatus.kind !== "absent" || hasDaemonServiceDefinition();
424
+ const controlCapabilities = detectProviderLiveCapabilities(configuredControlProviders);
425
+ const controlPolicy = resolveControlPolicy({
426
+ mode: controlMode,
427
+ providerAvailable: hasSpawnProvider(controlCapabilities),
428
+ managerAvailable: daemonServiceManagerAvailable(),
429
+ servicePresent: serviceWasPresent
430
+ });
431
+ let daemonReady = true;
432
+ let legacyStopFailure = null;
433
+ if (controlPolicy === "disabled" && serviceWasPresent) {
434
+ daemonReady = (await disableDaemonService()).kind === "ok";
435
+ } else if (controlPolicy === "legacy") {
436
+ const stopped = await stopDaemonService();
437
+ legacyStopFailure = stopped.kind === "ok" ? null : stopped.detail;
438
+ daemonReady = false;
439
+ } else if (controlPolicy === "enabled") {
440
+ if (!apiKey) {
441
+ daemonReady = false;
442
+ } else {
443
+ const service = await replaceDaemonService();
444
+ const daemon = service.kind === "ok" ? await ensureDaemonRunning({ spawnDaemon: () => {
445
+ } }) : null;
446
+ const localProof = daemon?.kind === "running" || daemon?.kind === "started" ? await waitForDaemonRemoteProof() : null;
447
+ const serverProof = localProof && daemonHasRemoteProof(localProof) ? await waitForMachineReadiness(apiKey, ["spawn", ...controlCapabilities]) : null;
448
+ daemonReady = service.kind === "ok" && localProof !== null && daemonHasRemoteProof(localProof) && (serverProof?.kind === "ready" || serverProof?.kind === "unsupported");
449
+ }
450
+ } else if (controlMode === "on" && controlPolicy === "unsupported") {
451
+ daemonReady = false;
452
+ }
453
+ console.log();
454
+ if (refreshed.length > 0) {
455
+ console.log("Refreshed so the new hook set is active now:");
456
+ for (const agent of refreshed) {
457
+ const parts = [agent.result.hooks ? "hooks" : null, agent.result.mcp ? "MCP key" : null].filter(Boolean).join(" + ");
458
+ console.log(` ${agent.label.padEnd(14)} ${parts}`);
459
+ }
460
+ if (!apiKey) {
461
+ console.log();
462
+ console.log("No key was readable here, so MCP entries kept the key they already had.");
463
+ }
464
+ } else if (failedRefreshes.length === 0) {
465
+ console.log("No agent config on this machine needed refreshing.");
466
+ }
467
+ if (codexTrust) {
468
+ console.log();
469
+ console.log(describeCodexTrustConfirmation(codexTrust));
470
+ }
471
+ console.log();
472
+ if (!daemonReady) {
473
+ console.error(controlPolicy === "disabled" ? "Upgrade installed, but the disabled background service could not be fully removed. Re-run setup with --control off." : controlPolicy === "legacy" ? legacyStopFailure ? `Upgrade installed, but the legacy background service could not be stopped: ${legacyStopFailure}. Run setup with --control off.` : "Upgrade installed and the legacy background service was stopped, but it cannot be safely adopted. Run setup with --control off, or restore its provider and native service manager." : controlPolicy === "enabled" && !apiKey ? "Upgrade installed, but phone-start could not be reconciled because no API key was readable. Re-run setup." : "Upgrade installed, but the background service did not start. Run: pushary daemon install");
474
+ process.exitCode = 1;
475
+ return;
476
+ }
477
+ if (failedRefreshes.length > 0) {
478
+ console.error(`Upgrade installed, but refreshing agent configuration failed for: ${failedRefreshes.map((agent) => agent.label).join(", ")}. Check the config files and run pushary upgrade again.`);
479
+ process.exitCode = 1;
480
+ return;
481
+ }
482
+ console.log(controlPolicy === "disabled" ? "Done. Your hooks use the new global install; phone-start remains disabled." : controlPolicy === "unsupported" || controlPolicy === "preserve-absent" ? "Done. Your hooks use the new global install; no background service was added." : "Done. Your hooks and background service use the new global install.");
483
+ console.log("Verify with: pushary doctor");
484
+ };
485
+ var AUTO_UPDATE_ON_MESSAGE = "Automatic updates are on. Pushary checks for a new version once a day, when an agent session starts.";
486
+ var AUTO_UPDATE_OFF_MESSAGE = "Automatic updates are off. Turn them back on with: pushary upgrade --auto=on";
487
+ var AUTO_UPDATE_RUN_MESSAGES = {
488
+ linux: `Automatic updates are paused on Linux to protect running sessions. When your sessions have finished, run: ${NPX_LATEST_COMMAND} upgrade`,
489
+ not_global_install: `This copy of Pushary is not a global npm install, so it does not update itself. Run: ${NPX_LATEST_COMMAND} upgrade`,
490
+ locked: "Another automatic update is already running."
491
+ };
492
+ var setAutomaticUpdates = (enabled) => {
493
+ updateAutoUpdateState(autoUpdateState(), { disabled: !enabled });
494
+ console.log(enabled ? AUTO_UPDATE_ON_MESSAGE : AUTO_UPDATE_OFF_MESSAGE);
495
+ if (enabled && isAutoUpdateDisabledByEnv(process.env)) {
496
+ console.log(`${AUTO_UPDATE_DISABLE_ENV} is set in this shell, and it keeps them off wherever it is set.`);
497
+ }
498
+ };
499
+ var runAutomaticUpdate = async () => {
500
+ const outcome = await runAutoUpdate();
501
+ if (outcome.kind !== "recorded") {
502
+ console.log(AUTO_UPDATE_RUN_MESSAGES[outcome.kind]);
503
+ return;
504
+ }
505
+ console.log(`Automatic update: ${describeAutoUpdateCheck(outcome.state)}`);
506
+ if (outcome.state.lastResult === "failed" || outcome.state.lastResult === "finish_pending") process.exitCode = 1;
507
+ };
508
+ var FINISH_FAILED_MESSAGE = "Upgrade installed, but refreshing the agent configs did not finish. Fix the problem printed above, then run pushary upgrade again.";
509
+ var describeFinishFailure = (finish) => finish.kind === "entry_missing" ? `Upgrade installed, but the new pushary-upgrade entry was not found at ${finish.entry}.` : FINISH_FAILED_MESSAGE;
510
+ var reportFinish = (finish) => {
511
+ if (finish.kind === "finished") return;
512
+ console.error(describeFinishFailure(finish));
513
+ process.exitCode = EXIT.FAILED;
514
+ };
515
+ var reportGlobalUpgrade = (outcome) => {
516
+ switch (outcome.kind) {
517
+ case "current":
518
+ console.log(`Already on the latest version (${outcome.version}).`);
519
+ return;
520
+ case "install_failed":
521
+ console.error(`Upgrade failed: ${outcome.detail}`);
522
+ process.exitCode = EXIT.FAILED;
523
+ return;
524
+ case "pending_finish_failed":
525
+ case "installed":
526
+ reportFinish(outcome.finish);
527
+ }
528
+ };
529
+ var BOTH_INSTALLED_MESSAGE = `Both ${CANONICAL_PACKAGE} and ${LEGACY_PACKAGE} are installed globally, and which one runs the Pushary commands could not be read, so nothing was upgraded. Check with: ${NPX_LATEST_COMMAND} doctor`;
530
+ var reportNoGlobalInstall = () => {
531
+ const found = detectInstallModes();
532
+ console.log(`No global install of ${CANONICAL_PACKAGE} or ${LEGACY_PACKAGE} found, so there is nothing to upgrade here.`);
533
+ console.log();
534
+ if (found.length === 0) {
535
+ console.log("Nothing on this machine looks Pushary-configured either.");
536
+ console.log(" Set it up with: npx @pushary/agent-hooks@latest setup");
537
+ } else {
538
+ console.log("What this machine does have:");
539
+ for (const mode of found) {
540
+ console.log(` ${mode.label.padEnd(22)} ${mode.upgrade}`);
541
+ }
542
+ }
543
+ console.log();
544
+ console.log("Check the result with: pushary doctor");
545
+ };
546
+ var upgradeSubject = async (subject) => {
547
+ const outcome = await upgradeInstalledPackage(subject, {
548
+ fetchLatest: (packageName) => fetchLatestPublishedVersion({ packageName }),
549
+ hasPendingFinish: (installed) => hasPendingUpgradeFinish(readAutoUpdateState(autoUpdateState()), installed),
550
+ recordFinished: () => {
551
+ updateAutoUpdateState(autoUpdateState(), { lastResult: "updated", detail: void 0, announced: false });
552
+ },
553
+ announce: (line) => console.log(line),
554
+ install: (packageName) => installPackageGlobally({ packageName, version: LATEST_TAG, timeoutMs: 12e4 }),
555
+ finish: (installedSubject) => finishGlobalUpgrade(installedSubject)
556
+ });
557
+ reportGlobalUpgrade(outcome);
558
+ };
559
+ var upgradeGlobalInstall = async () => {
560
+ const subject = readGlobalUpgradeSubject();
561
+ if (subject.kind === "not_installed") {
562
+ reportNoGlobalInstall();
563
+ return;
564
+ }
565
+ if (subject.kind === "both_installed") {
566
+ console.error(BOTH_INSTALLED_MESSAGE);
567
+ process.exitCode = EXIT.FAILED;
568
+ return;
569
+ }
570
+ await upgradeSubject(subject);
571
+ };
572
+ var runUnderUpgradeLock = async (run) => {
573
+ const locked = await withUpgradeLock(run);
574
+ if (locked.kind === "ran") return;
575
+ console.error(locked.message);
576
+ process.exitCode = locked.exitCode;
577
+ };
578
+ var main = async () => {
579
+ if (process.argv.includes(FINISH_UPGRADE_FLAG)) {
580
+ await runUnderUpgradeLock(finishUpgrade);
581
+ return;
582
+ }
583
+ const autoFlag = parseAutoUpdateFlag(process.argv.slice(2));
584
+ if (autoFlag.kind === "invalid") {
585
+ console.error(`--auto takes on or off (got ${autoFlag.value || "nothing"}).`);
586
+ process.exitCode = EXIT.USAGE;
587
+ return;
588
+ }
589
+ if (autoFlag.kind === "set") {
590
+ setAutomaticUpdates(autoFlag.enabled);
591
+ return;
592
+ }
593
+ if (autoFlag.kind === "run") {
594
+ await runAutomaticUpdate();
595
+ return;
596
+ }
597
+ await runUnderUpgradeLock(upgradeGlobalInstall);
598
+ };
599
+ main();
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node