@xopcai/xopc 0.0.88 → 0.0.90

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 (275) hide show
  1. package/README.md +8 -1
  2. package/README.zh-CN.md +8 -1
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/extensions/telegram/xopc.extension.json +1 -1
  5. package/dist/gateway/static/root/assets/agents-cPvvYLXo.js +222 -0
  6. package/dist/gateway/static/root/assets/apps-page-Bk1_P5FJ.js +1 -0
  7. package/dist/gateway/static/root/assets/channels-settings-CZoeQwHz.js +1 -0
  8. package/dist/gateway/static/root/assets/{channels-status-swr-DIsl75Y3.js → channels-status-swr-BrtH2VzC.js} +1 -1
  9. package/dist/gateway/static/root/assets/circle-check-C23XjkUj.js +1 -0
  10. package/dist/gateway/static/root/assets/cron-api-CyqbgfHM.js +1 -0
  11. package/dist/gateway/static/root/assets/cron-dreaming-jobs-Ip703-qM.js +2 -0
  12. package/dist/gateway/static/root/assets/cron-page-BpLdiQN8.js +1 -0
  13. package/dist/gateway/static/root/assets/dist-BpAiK86n.js +1 -0
  14. package/dist/gateway/static/root/assets/{extension-debug-page-BVJohZoZ.js → extension-debug-page-D6Ak0STa.js} +1 -1
  15. package/dist/gateway/static/root/assets/{extension-page-BT2tmElC.js → extension-page-Q0P3d6DW.js} +1 -1
  16. package/dist/gateway/static/root/assets/{extension-settings-page-BSS47c2j.js → extension-settings-page-CL55LwU_.js} +1 -1
  17. package/dist/gateway/static/root/assets/eye-DAfL1U7M.js +1 -0
  18. package/dist/gateway/static/root/assets/{fetch-BaFNUtkE.js → fetch-Dqa9iTWl.js} +1 -1
  19. package/dist/gateway/static/root/assets/{field-primitives-QwYEq6Hz.js → field-primitives-HUR6JElP.js} +1 -1
  20. package/dist/gateway/static/root/assets/{heartbeat-config-api-BVSidEDJ.js → heartbeat-config-api-DusckjUX.js} +1 -1
  21. package/dist/gateway/static/root/assets/{index-qNrVJp-y.js → index-BYcGfwcE.js} +97 -97
  22. package/dist/gateway/static/root/assets/index-V7MQ7834.css +1 -0
  23. package/dist/gateway/static/root/assets/{logs-page-DDonPVLn.js → logs-page-_HcZ2fgK.js} +1 -1
  24. package/dist/gateway/static/root/assets/sessions-page-iezSMjho.js +1 -0
  25. package/dist/gateway/static/root/assets/{settings-form-section-B8N3A3Zo.js → settings-form-section-a0qGVOlr.js} +1 -1
  26. package/dist/gateway/static/root/assets/settings-page-C9_nYQwM.js +3 -0
  27. package/dist/gateway/static/root/assets/{share-preview-page-Q7KqkO-u.js → share-preview-page-DExl7CJy.js} +1 -1
  28. package/dist/gateway/static/root/assets/skills-page-BlgGD93t.js +2 -0
  29. package/dist/gateway/static/root/assets/{theme-store-BbRc5ugR.js → theme-store-C0Ehmdo5.js} +1 -1
  30. package/dist/gateway/static/root/assets/url-fxyYANfA.js +3 -0
  31. package/dist/gateway/static/root/assets/{utils-CxDGduqK.js → utils-DRQryzdn.js} +1 -1
  32. package/dist/gateway/static/root/assets/voice-api-key-field-D0viACE2.js +1 -0
  33. package/dist/gateway/static/root/assets/workflow-page.utils-DnG8JBhV.js +1 -0
  34. package/dist/gateway/static/root/assets/workflows-page-BvMobnJP.js +27 -0
  35. package/dist/gateway/static/root/index.html +7 -6
  36. package/dist/package.js +1 -1
  37. package/dist/src/agent/agent-manager.d.ts +2 -0
  38. package/dist/src/agent/agent-manager.js +1 -0
  39. package/dist/src/agent/agent-manager.js.map +1 -1
  40. package/dist/src/agent/service.js +2 -1
  41. package/dist/src/agent/service.js.map +1 -1
  42. package/dist/src/agent/service.types.d.ts +3 -1
  43. package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.js +20 -18
  44. package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.js.map +1 -1
  45. package/dist/src/agent/tools/cronjob-tool.d.ts +6 -0
  46. package/dist/src/agent/tools/cronjob-tool.js +76 -10
  47. package/dist/src/agent/tools/cronjob-tool.js.map +1 -1
  48. package/dist/src/agent/tools/edit.d.ts +5 -1
  49. package/dist/src/agent/tools/edit.js +7 -5
  50. package/dist/src/agent/tools/edit.js.map +1 -1
  51. package/dist/src/agent/tools/factory.d.ts +3 -0
  52. package/dist/src/agent/tools/factory.js +4 -25
  53. package/dist/src/agent/tools/factory.js.map +1 -1
  54. package/dist/src/agent/tools/workflow-tool.d.ts +6 -28
  55. package/dist/src/agent/tools/workflow-tool.js +60 -260
  56. package/dist/src/agent/tools/workflow-tool.js.map +1 -1
  57. package/dist/src/agent/tools/write.d.ts +5 -1
  58. package/dist/src/agent/tools/write.js +7 -5
  59. package/dist/src/agent/tools/write.js.map +1 -1
  60. package/dist/src/agent/workflow/agent-progress.js +2 -0
  61. package/dist/src/agent/workflow/agent-progress.js.map +1 -1
  62. package/dist/src/agent/workflow/builtins/client-proposal.d.ts +12 -0
  63. package/dist/src/agent/workflow/builtins/client-proposal.js +155 -0
  64. package/dist/src/agent/workflow/builtins/client-proposal.js.map +1 -0
  65. package/dist/src/agent/workflow/builtins/competitor-scan.d.ts +12 -0
  66. package/dist/src/agent/workflow/builtins/competitor-scan.js +150 -0
  67. package/dist/src/agent/workflow/builtins/competitor-scan.js.map +1 -0
  68. package/dist/src/agent/workflow/builtins/content-draft.d.ts +13 -0
  69. package/dist/src/agent/workflow/builtins/content-draft.js +146 -0
  70. package/dist/src/agent/workflow/builtins/content-draft.js.map +1 -0
  71. package/dist/src/agent/workflow/builtins/content-repurpose.d.ts +11 -0
  72. package/dist/src/agent/workflow/builtins/content-repurpose.js +137 -0
  73. package/dist/src/agent/workflow/builtins/content-repurpose.js.map +1 -0
  74. package/dist/src/agent/workflow/builtins/decision-compare.d.ts +13 -0
  75. package/dist/src/agent/workflow/builtins/decision-compare.js +173 -0
  76. package/dist/src/agent/workflow/builtins/decision-compare.js.map +1 -0
  77. package/dist/src/agent/workflow/builtins/inbox-triage.d.ts +11 -0
  78. package/dist/src/agent/workflow/builtins/inbox-triage.js +148 -0
  79. package/dist/src/agent/workflow/builtins/inbox-triage.js.map +1 -0
  80. package/dist/src/agent/workflow/builtins/index.d.ts +10 -1
  81. package/dist/src/agent/workflow/builtins/index.js +46 -1
  82. package/dist/src/agent/workflow/builtins/index.js.map +1 -1
  83. package/dist/src/agent/workflow/builtins/meeting-prep.d.ts +12 -0
  84. package/dist/src/agent/workflow/builtins/meeting-prep.js +144 -0
  85. package/dist/src/agent/workflow/builtins/meeting-prep.js.map +1 -0
  86. package/dist/src/agent/workflow/builtins/offer-design.d.ts +12 -0
  87. package/dist/src/agent/workflow/builtins/offer-design.js +161 -0
  88. package/dist/src/agent/workflow/builtins/offer-design.js.map +1 -0
  89. package/dist/src/agent/workflow/builtins/weekly-review.d.ts +12 -0
  90. package/dist/src/agent/workflow/builtins/weekly-review.js +131 -0
  91. package/dist/src/agent/workflow/builtins/weekly-review.js.map +1 -0
  92. package/dist/src/agent/workflow/step-labels.js +2 -2
  93. package/dist/src/agent/workflow/step-labels.js.map +1 -1
  94. package/dist/src/agent/workflow/subagent-runner.js +3 -1
  95. package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
  96. package/dist/src/agent/workflow/types.d.ts +4 -0
  97. package/dist/src/agent/workflow/workflow-child-tools.d.ts +4 -0
  98. package/dist/src/agent/workflow/workflow-child-tools.js +21 -0
  99. package/dist/src/agent/workflow/workflow-child-tools.js.map +1 -0
  100. package/dist/src/auth/credentials.d.ts +14 -2
  101. package/dist/src/auth/credentials.js +38 -13
  102. package/dist/src/auth/credentials.js.map +1 -1
  103. package/dist/src/auth/oauth/types.d.ts +16 -0
  104. package/dist/src/chat-commands/agent-edit.d.ts +4 -0
  105. package/dist/src/chat-commands/agent-edit.js +136 -0
  106. package/dist/src/chat-commands/agent-edit.js.map +1 -0
  107. package/dist/src/chat-commands/index.d.ts +1 -0
  108. package/dist/src/chat-commands/index.js +3 -1
  109. package/dist/src/chat-commands/index.js.map +1 -1
  110. package/dist/src/cli/bin.js +2 -0
  111. package/dist/src/cli/bin.js.map +1 -1
  112. package/dist/src/cli/commands/auth.js +6 -0
  113. package/dist/src/cli/commands/auth.js.map +1 -1
  114. package/dist/src/cli/commands/cron.js +42 -3
  115. package/dist/src/cli/commands/cron.js.map +1 -1
  116. package/dist/src/cli/commands/doctor/checks/session-integrity.js +79 -56
  117. package/dist/src/cli/commands/doctor/checks/session-integrity.js.map +1 -1
  118. package/dist/src/cli/commands/onboard/model.js +6 -0
  119. package/dist/src/cli/commands/onboard/model.js.map +1 -1
  120. package/dist/src/cli/commands/update.js +86 -79
  121. package/dist/src/cli/commands/update.js.map +1 -1
  122. package/dist/src/commands/agents.config.d.ts +3 -2
  123. package/dist/src/commands/agents.config.js +5 -2
  124. package/dist/src/commands/agents.config.js.map +1 -1
  125. package/dist/src/config/agent-typed-models.d.ts +2 -7
  126. package/dist/src/config/agent-typed-models.js +3 -14
  127. package/dist/src/config/agent-typed-models.js.map +1 -1
  128. package/dist/src/config/localized-text.d.ts +6 -0
  129. package/dist/src/config/localized-text.js +42 -0
  130. package/dist/src/config/localized-text.js.map +1 -0
  131. package/dist/src/config/models-json.d.ts +6 -6
  132. package/dist/src/config/schema.d.ts +6 -21
  133. package/dist/src/config/schema.js +4 -4
  134. package/dist/src/config/schema.js.map +1 -1
  135. package/dist/src/cron/executor.d.ts +4 -0
  136. package/dist/src/cron/executor.js +169 -5
  137. package/dist/src/cron/executor.js.map +1 -1
  138. package/dist/src/cron/job-content.js +2 -1
  139. package/dist/src/cron/job-content.js.map +1 -1
  140. package/dist/src/cron/types.d.ts +28 -1
  141. package/dist/src/cron/validation.d.ts +80 -0
  142. package/dist/src/cron/validation.js +30 -4
  143. package/dist/src/cron/validation.js.map +1 -1
  144. package/dist/src/cron/workflow-run-completion.d.ts +23 -0
  145. package/dist/src/cron/workflow-run-completion.js +72 -0
  146. package/dist/src/cron/workflow-run-completion.js.map +1 -0
  147. package/dist/src/extensions/update.d.ts +51 -0
  148. package/dist/src/extensions/update.js +260 -0
  149. package/dist/src/extensions/update.js.map +1 -0
  150. package/dist/src/gateway/agents-admin.d.ts +15 -8
  151. package/dist/src/gateway/agents-admin.js +77 -28
  152. package/dist/src/gateway/agents-admin.js.map +1 -1
  153. package/dist/src/gateway/gateway-workflow-host.types.d.ts +17 -0
  154. package/dist/src/gateway/gateway-workflow-host.types.js +1 -0
  155. package/dist/src/gateway/heartbeat/service.js +1 -1
  156. package/dist/src/gateway/hono/lib/config-payload.d.ts +5 -0
  157. package/dist/src/gateway/hono/lib/config-payload.js +2 -1
  158. package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
  159. package/dist/src/gateway/hono/middleware/auth.d.ts +2 -0
  160. package/dist/src/gateway/hono/middleware/auth.js +12 -7
  161. package/dist/src/gateway/hono/middleware/auth.js.map +1 -1
  162. package/dist/src/gateway/hono/oauth-async.js +40 -15
  163. package/dist/src/gateway/hono/oauth-async.js.map +1 -1
  164. package/dist/src/gateway/hono/oauth.js +31 -6
  165. package/dist/src/gateway/hono/oauth.js.map +1 -1
  166. package/dist/src/gateway/hono/routes/agents.js +55 -12
  167. package/dist/src/gateway/hono/routes/agents.js.map +1 -1
  168. package/dist/src/gateway/hono/routes/config-patch/agents.js +1 -1
  169. package/dist/src/gateway/hono/routes/models.js +11 -5
  170. package/dist/src/gateway/hono/routes/models.js.map +1 -1
  171. package/dist/src/gateway/hono/routes/update.js +55 -107
  172. package/dist/src/gateway/hono/routes/update.js.map +1 -1
  173. package/dist/src/gateway/hono/routes/workflows.js +72 -191
  174. package/dist/src/gateway/hono/routes/workflows.js.map +1 -1
  175. package/dist/src/gateway/server.js +2 -0
  176. package/dist/src/gateway/server.js.map +1 -1
  177. package/dist/src/gateway/service.d.ts +5 -0
  178. package/dist/src/gateway/service.js +24 -3
  179. package/dist/src/gateway/service.js.map +1 -1
  180. package/dist/src/heartbeat/index.js +1 -1
  181. package/dist/src/infra/brew.d.ts +4 -0
  182. package/dist/src/infra/brew.js +20 -0
  183. package/dist/src/infra/brew.js.map +1 -0
  184. package/dist/src/infra/package-json.d.ts +2 -0
  185. package/dist/src/infra/package-json.js +23 -0
  186. package/dist/src/infra/package-json.js.map +1 -0
  187. package/dist/src/infra/package-update-steps.d.ts +35 -0
  188. package/dist/src/infra/package-update-steps.js +304 -0
  189. package/dist/src/infra/package-update-steps.js.map +1 -0
  190. package/dist/src/infra/path-env.d.ts +11 -0
  191. package/dist/src/infra/path-env.js +90 -0
  192. package/dist/src/infra/path-env.js.map +1 -0
  193. package/dist/src/infra/path-prepend.d.ts +7 -0
  194. package/dist/src/infra/path-prepend.js +44 -0
  195. package/dist/src/infra/path-prepend.js.map +1 -0
  196. package/dist/src/infra/stable-node-path.d.ts +2 -0
  197. package/dist/src/infra/stable-node-path.js +28 -0
  198. package/dist/src/infra/stable-node-path.js.map +1 -0
  199. package/dist/src/infra/update-global.d.ts +30 -23
  200. package/dist/src/infra/update-global.js +113 -64
  201. package/dist/src/infra/update-global.js.map +1 -1
  202. package/dist/src/infra/update-log.d.ts +1 -0
  203. package/dist/src/infra/update-log.js +12 -0
  204. package/dist/src/infra/update-log.js.map +1 -0
  205. package/dist/src/infra/update-restart.d.ts +20 -0
  206. package/dist/src/infra/update-restart.js +165 -0
  207. package/dist/src/infra/update-restart.js.map +1 -0
  208. package/dist/src/infra/update-runner.d.ts +89 -1
  209. package/dist/src/infra/update-runner.js +604 -173
  210. package/dist/src/infra/update-runner.js.map +1 -1
  211. package/dist/src/infra/update-startup.d.ts +3 -0
  212. package/dist/src/infra/update-startup.js +8 -4
  213. package/dist/src/infra/update-startup.js.map +1 -1
  214. package/dist/src/providers/index.d.ts +8 -0
  215. package/dist/src/providers/index.js +51 -12
  216. package/dist/src/providers/index.js.map +1 -1
  217. package/dist/src/routing/resolve-route.d.ts +3 -1
  218. package/dist/src/routing/resolve-route.js.map +1 -1
  219. package/dist/src/session/store.d.ts +5 -3
  220. package/dist/src/session/store.js +66 -20
  221. package/dist/src/session/store.js.map +1 -1
  222. package/dist/src/share/site-share-config.d.ts +3 -2
  223. package/dist/src/share/site-share-config.js.map +1 -1
  224. package/dist/src/utils/logger/stats.d.ts +1 -1
  225. package/dist/src/workflows/domain/command.d.ts +2 -1
  226. package/dist/src/workflows/domain/definition-utils.d.ts +14 -0
  227. package/dist/src/workflows/domain/definition-utils.js +50 -0
  228. package/dist/src/workflows/domain/definition-utils.js.map +1 -0
  229. package/dist/src/workflows/domain/event.d.ts +3 -0
  230. package/dist/src/workflows/domain/index.d.ts +2 -0
  231. package/dist/src/workflows/domain/index.js +3 -1
  232. package/dist/src/workflows/domain/run.d.ts +60 -0
  233. package/dist/src/workflows/domain/run.js.map +1 -1
  234. package/dist/src/workflows/domain/validation.d.ts +19 -0
  235. package/dist/src/workflows/domain/validation.js +66 -0
  236. package/dist/src/workflows/domain/validation.js.map +1 -0
  237. package/dist/src/workflows/engine/projector.js +17 -0
  238. package/dist/src/workflows/engine/projector.js.map +1 -1
  239. package/dist/src/workflows/engine/workflow-engine.d.ts +2 -1
  240. package/dist/src/workflows/engine/workflow-engine.js +128 -0
  241. package/dist/src/workflows/engine/workflow-engine.js.map +1 -1
  242. package/dist/src/workflows/index.d.ts +4 -0
  243. package/dist/src/workflows/index.js +9 -2
  244. package/dist/src/workflows/service/run-view-to-snapshot.d.ts +4 -0
  245. package/dist/src/workflows/service/run-view-to-snapshot.js +63 -0
  246. package/dist/src/workflows/service/run-view-to-snapshot.js.map +1 -0
  247. package/dist/src/workflows/service/workflow-run-service.d.ts +37 -0
  248. package/dist/src/workflows/service/workflow-run-service.js +282 -0
  249. package/dist/src/workflows/service/workflow-run-service.js.map +1 -0
  250. package/dist/src/workflows/service/workflow-run-service.types.d.ts +47 -0
  251. package/dist/src/workflows/service/workflow-run-service.types.js +1 -0
  252. package/dist/src/workflows/service/workflow-session-bridge.d.ts +29 -0
  253. package/dist/src/workflows/service/workflow-session-bridge.js +177 -0
  254. package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -0
  255. package/dist/src/workflows/service/workflow-session-key.d.ts +3 -0
  256. package/dist/src/workflows/service/workflow-session-key.js +21 -0
  257. package/dist/src/workflows/service/workflow-session-key.js.map +1 -0
  258. package/dist/src/workflows/store/run-store.js +1 -0
  259. package/dist/src/workflows/store/run-store.js.map +1 -1
  260. package/package.json +1 -1
  261. package/dist/gateway/static/root/assets/agents-CRxETUZx.js +0 -222
  262. package/dist/gateway/static/root/assets/apps-page-wKWf3l57.js +0 -1
  263. package/dist/gateway/static/root/assets/channels-settings-DDbqVNkx.js +0 -1
  264. package/dist/gateway/static/root/assets/copy-SxMW6Xpc.js +0 -1
  265. package/dist/gateway/static/root/assets/cron-api-N9hvuRrn.js +0 -1
  266. package/dist/gateway/static/root/assets/cron-dreaming-jobs-DueM3rBz.js +0 -2
  267. package/dist/gateway/static/root/assets/cron-page-tlNGNxhP.js +0 -1
  268. package/dist/gateway/static/root/assets/dist-CJwfHYvT.js +0 -1
  269. package/dist/gateway/static/root/assets/index-CqZzHNEg.css +0 -1
  270. package/dist/gateway/static/root/assets/sessions-page-DKt-Wmib.js +0 -1
  271. package/dist/gateway/static/root/assets/settings-page-DcJjvvw4.js +0 -3
  272. package/dist/gateway/static/root/assets/skills-page-DuJ4BTO3.js +0 -2
  273. package/dist/gateway/static/root/assets/url-D6jvVYIA.js +0 -7
  274. package/dist/gateway/static/root/assets/voice-api-key-field-CTyHz7L_.js +0 -1
  275. package/dist/gateway/static/root/assets/workflows-page-GacJ41Fv.js +0 -27
@@ -0,0 +1,304 @@
1
+ import { readPackageVersion } from "./package-json.js";
2
+ import { XOPC_PACKAGE_NAME, collectInstalledGlobalPackageErrors, globalInstallArgs, globalInstallFallbackArgs, resolveExpectedInstalledVersionFromSpec, resolveGlobalInstallTarget, resolveNpmGlobalPrefixLayoutFromGlobalRoot, resolveNpmGlobalPrefixLayoutFromPrefix } from "./update-global.js";
3
+ import fs from "node:fs/promises";
4
+ import path from "node:path";
5
+ //#region src/infra/package-update-steps.ts
6
+ function formatError(err) {
7
+ return err instanceof Error ? err.message : String(err);
8
+ }
9
+ async function pathExists(targetPath) {
10
+ try {
11
+ await fs.access(targetPath);
12
+ return true;
13
+ } catch {
14
+ return false;
15
+ }
16
+ }
17
+ async function readPackageVersionIfPresent(packageRoot) {
18
+ if (!packageRoot) return null;
19
+ try {
20
+ return await readPackageVersion(packageRoot);
21
+ } catch {
22
+ return null;
23
+ }
24
+ }
25
+ async function createStagedNpmInstall(installTarget, packageName) {
26
+ if (installTarget.manager !== "npm") return null;
27
+ const targetLayout = resolveNpmGlobalPrefixLayoutFromGlobalRoot(installTarget.globalRoot);
28
+ if (!targetLayout) return null;
29
+ await fs.mkdir(targetLayout.globalRoot, { recursive: true });
30
+ const prefix = await fs.mkdtemp(path.join(targetLayout.globalRoot, ".xopc-update-stage-"));
31
+ const layout = resolveNpmGlobalPrefixLayoutFromPrefix(prefix);
32
+ return {
33
+ prefix,
34
+ layout,
35
+ packageRoot: path.join(layout.globalRoot, packageName)
36
+ };
37
+ }
38
+ async function prepareStagedNpmInstall(installTarget, packageName) {
39
+ const startedAt = Date.now();
40
+ try {
41
+ return {
42
+ stagedInstall: await createStagedNpmInstall(installTarget, packageName),
43
+ failedStep: null
44
+ };
45
+ } catch (err) {
46
+ return {
47
+ stagedInstall: null,
48
+ failedStep: {
49
+ name: "global install stage",
50
+ command: "prepare staged npm install",
51
+ cwd: (installTarget.manager === "npm" ? resolveNpmGlobalPrefixLayoutFromGlobalRoot(installTarget.globalRoot) : null)?.prefix ?? installTarget.globalRoot ?? process.cwd(),
52
+ durationMs: Date.now() - startedAt,
53
+ exitCode: 1,
54
+ stdoutTail: null,
55
+ stderrTail: formatError(err)
56
+ }
57
+ };
58
+ }
59
+ }
60
+ async function cleanupStagedNpmInstall(stage) {
61
+ if (!stage) return;
62
+ await fs.rm(stage.prefix, {
63
+ recursive: true,
64
+ force: true
65
+ }).catch(() => void 0);
66
+ }
67
+ async function copyPathEntry(source, destination) {
68
+ const stat = await fs.lstat(source);
69
+ await fs.rm(destination, {
70
+ recursive: true,
71
+ force: true
72
+ }).catch(() => void 0);
73
+ if (stat.isSymbolicLink()) {
74
+ await fs.symlink(await fs.readlink(source), destination);
75
+ return;
76
+ }
77
+ if (stat.isDirectory()) {
78
+ await fs.cp(source, destination, {
79
+ recursive: true,
80
+ force: true,
81
+ preserveTimestamps: false
82
+ });
83
+ return;
84
+ }
85
+ await fs.copyFile(source, destination);
86
+ await fs.chmod(destination, stat.mode).catch(() => void 0);
87
+ }
88
+ async function replaceNpmBinShims(params) {
89
+ let entries = [];
90
+ try {
91
+ entries = await fs.readdir(params.stageLayout.binDir);
92
+ } catch {
93
+ return;
94
+ }
95
+ const names = new Set([params.packageName, "xopc"]);
96
+ const shimEntries = entries.filter((entry) => {
97
+ const parsed = path.parse(entry);
98
+ return names.has(entry) || names.has(parsed.name);
99
+ });
100
+ if (shimEntries.length === 0) return;
101
+ const backup = {
102
+ backupDir: await fs.mkdtemp(path.join(params.targetLayout.globalRoot, ".xopc-shim-backup-")),
103
+ targetBinDir: params.targetLayout.binDir,
104
+ entries: []
105
+ };
106
+ try {
107
+ await fs.mkdir(params.targetLayout.binDir, { recursive: true });
108
+ for (const entry of shimEntries) {
109
+ const destination = path.join(params.targetLayout.binDir, entry);
110
+ const hadExisting = await pathExists(destination);
111
+ backup.entries.push({
112
+ name: entry,
113
+ hadExisting
114
+ });
115
+ if (hadExisting) await copyPathEntry(destination, path.join(backup.backupDir, entry));
116
+ }
117
+ for (const entry of shimEntries) await copyPathEntry(path.join(params.stageLayout.binDir, entry), path.join(params.targetLayout.binDir, entry));
118
+ } catch (err) {
119
+ await restoreNpmBinShimBackup(backup);
120
+ throw err;
121
+ } finally {
122
+ await fs.rm(backup.backupDir, {
123
+ recursive: true,
124
+ force: true
125
+ }).catch(() => void 0);
126
+ }
127
+ }
128
+ async function restoreNpmBinShimBackup(backup) {
129
+ await fs.mkdir(backup.targetBinDir, { recursive: true });
130
+ for (const entry of backup.entries) {
131
+ const destination = path.join(backup.targetBinDir, entry.name);
132
+ await fs.rm(destination, {
133
+ recursive: true,
134
+ force: true
135
+ }).catch(() => void 0);
136
+ if (entry.hadExisting) await copyPathEntry(path.join(backup.backupDir, entry.name), destination);
137
+ }
138
+ }
139
+ async function swapStagedNpmInstall(params) {
140
+ const startedAt = Date.now();
141
+ const targetLayout = resolveNpmGlobalPrefixLayoutFromGlobalRoot(params.installTarget.globalRoot);
142
+ const targetPackageRoot = params.installTarget.packageRoot;
143
+ if (!targetLayout || !targetPackageRoot) return {
144
+ name: "global install swap",
145
+ command: "swap staged npm install",
146
+ cwd: params.stage.prefix,
147
+ durationMs: Date.now() - startedAt,
148
+ exitCode: 1,
149
+ stdoutTail: null,
150
+ stderrTail: "cannot resolve npm global prefix layout"
151
+ };
152
+ const backupRoot = path.join(targetLayout.globalRoot, `.xopc-${process.pid}-${Date.now()}`);
153
+ let movedExisting = false;
154
+ let movedStaged = false;
155
+ try {
156
+ await fs.mkdir(targetLayout.globalRoot, { recursive: true });
157
+ if (await pathExists(targetPackageRoot)) {
158
+ await fs.rename(targetPackageRoot, backupRoot);
159
+ movedExisting = true;
160
+ }
161
+ await fs.rename(params.stage.packageRoot, targetPackageRoot);
162
+ movedStaged = true;
163
+ await replaceNpmBinShims({
164
+ stageLayout: params.stage.layout,
165
+ targetLayout,
166
+ packageName: params.packageName
167
+ });
168
+ if (movedExisting) await fs.rm(backupRoot, {
169
+ recursive: true,
170
+ force: true
171
+ });
172
+ return {
173
+ name: "global install swap",
174
+ command: `swap ${params.stage.packageRoot} -> ${targetPackageRoot}`,
175
+ cwd: targetLayout.globalRoot,
176
+ durationMs: Date.now() - startedAt,
177
+ exitCode: 0,
178
+ stdoutTail: movedExisting ? `replaced ${params.packageName}` : `installed ${params.packageName}`,
179
+ stderrTail: null
180
+ };
181
+ } catch (err) {
182
+ if (movedStaged) await fs.rm(targetPackageRoot, {
183
+ recursive: true,
184
+ force: true
185
+ }).catch(() => void 0);
186
+ if (movedExisting) await fs.rename(backupRoot, targetPackageRoot).catch(() => void 0);
187
+ return {
188
+ name: "global install swap",
189
+ command: `swap ${params.stage.packageRoot} -> ${targetPackageRoot}`,
190
+ cwd: targetLayout.globalRoot,
191
+ durationMs: Date.now() - startedAt,
192
+ exitCode: 1,
193
+ stdoutTail: null,
194
+ stderrTail: formatError(err)
195
+ };
196
+ }
197
+ }
198
+ async function runGlobalPackageUpdateSteps(params) {
199
+ const installCwd = params.installCwd === void 0 ? {} : { cwd: params.installCwd };
200
+ const installEnv = params.env === void 0 ? {} : { env: params.env };
201
+ let stagedInstall = null;
202
+ try {
203
+ const preparedInstall = await prepareStagedNpmInstall(params.installTarget, params.packageName);
204
+ stagedInstall = preparedInstall.stagedInstall;
205
+ if (preparedInstall.failedStep) return {
206
+ steps: [preparedInstall.failedStep],
207
+ verifiedPackageRoot: params.packageRoot ?? null,
208
+ afterVersion: null,
209
+ failedStep: preparedInstall.failedStep
210
+ };
211
+ const updateStep = await params.runStep({
212
+ name: "global update",
213
+ argv: globalInstallArgs(params.installTarget, params.installSpec, params.packageRoot, stagedInstall?.prefix),
214
+ ...installCwd,
215
+ ...installEnv,
216
+ timeoutMs: params.timeoutMs
217
+ });
218
+ const steps = [updateStep];
219
+ let finalInstallStep = updateStep;
220
+ if (updateStep.exitCode !== 0) {
221
+ await cleanupStagedNpmInstall(stagedInstall);
222
+ stagedInstall = null;
223
+ const preparedFallbackInstall = await prepareStagedNpmInstall(params.installTarget, params.packageName);
224
+ stagedInstall = preparedFallbackInstall.stagedInstall;
225
+ if (preparedFallbackInstall.failedStep) {
226
+ steps.push(preparedFallbackInstall.failedStep);
227
+ return {
228
+ steps,
229
+ verifiedPackageRoot: params.packageRoot ?? null,
230
+ afterVersion: null,
231
+ failedStep: preparedFallbackInstall.failedStep
232
+ };
233
+ }
234
+ const fallbackArgv = globalInstallFallbackArgs(params.installTarget, params.installSpec, params.packageRoot, stagedInstall?.prefix);
235
+ if (fallbackArgv) {
236
+ const fallbackStep = await params.runStep({
237
+ name: "global update (omit optional)",
238
+ argv: fallbackArgv,
239
+ ...installCwd,
240
+ ...installEnv,
241
+ timeoutMs: params.timeoutMs
242
+ });
243
+ steps.push(fallbackStep);
244
+ finalInstallStep = fallbackStep;
245
+ } else {
246
+ await cleanupStagedNpmInstall(stagedInstall);
247
+ stagedInstall = null;
248
+ }
249
+ }
250
+ const livePackageRoot = params.installTarget.packageRoot ?? params.packageRoot ?? (await resolveGlobalInstallTarget({
251
+ manager: params.installTarget,
252
+ runCommand: params.runCommand,
253
+ timeoutMs: params.timeoutMs,
254
+ pkgRoot: params.packageRoot
255
+ })).packageRoot ?? null;
256
+ const verificationPackageRoot = stagedInstall?.packageRoot ?? livePackageRoot;
257
+ let verifiedPackageRoot = livePackageRoot ?? verificationPackageRoot;
258
+ let afterVersion = null;
259
+ if (finalInstallStep.exitCode === 0 && verificationPackageRoot) {
260
+ const candidateVersion = await readPackageVersion(verificationPackageRoot);
261
+ if (!stagedInstall) afterVersion = candidateVersion;
262
+ const verificationErrors = await collectInstalledGlobalPackageErrors({
263
+ packageRoot: verificationPackageRoot,
264
+ expectedVersion: resolveExpectedInstalledVersionFromSpec(params.installSpec)
265
+ });
266
+ if (verificationErrors.length > 0) steps.push({
267
+ name: "global install verify",
268
+ command: `verify ${verificationPackageRoot}`,
269
+ cwd: verificationPackageRoot,
270
+ durationMs: 0,
271
+ exitCode: 1,
272
+ stderrTail: verificationErrors.join("\n"),
273
+ stdoutTail: null
274
+ });
275
+ if (stagedInstall && verificationErrors.length === 0) {
276
+ const swapStep = await swapStagedNpmInstall({
277
+ stage: stagedInstall,
278
+ installTarget: params.installTarget,
279
+ packageName: params.packageName
280
+ });
281
+ steps.push(swapStep);
282
+ if (swapStep.exitCode === 0) {
283
+ verifiedPackageRoot = params.installTarget.packageRoot ?? verifiedPackageRoot;
284
+ afterVersion = candidateVersion;
285
+ }
286
+ }
287
+ }
288
+ if (steps.find((step) => (step.name === "global install verify" || step.name === "global install swap") && step.exitCode !== 0) && stagedInstall) afterVersion = await readPackageVersionIfPresent(livePackageRoot);
289
+ const failedStep = finalInstallStep.exitCode !== 0 ? finalInstallStep : steps.find((step) => step !== updateStep && step.exitCode !== 0) ?? null;
290
+ return {
291
+ steps,
292
+ verifiedPackageRoot,
293
+ afterVersion,
294
+ failedStep
295
+ };
296
+ } finally {
297
+ await cleanupStagedNpmInstall(stagedInstall);
298
+ }
299
+ }
300
+ const DEFAULT_PACKAGE_NAME = XOPC_PACKAGE_NAME;
301
+ //#endregion
302
+ export { DEFAULT_PACKAGE_NAME, runGlobalPackageUpdateSteps };
303
+
304
+ //# sourceMappingURL=package-update-steps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-update-steps.js","names":[],"sources":["../../../src/infra/package-update-steps.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport { readPackageVersion } from './package-json.js';\nimport type { CommandRunner } from './run-command.js';\nimport {\n collectInstalledGlobalPackageErrors,\n globalInstallArgs,\n globalInstallFallbackArgs,\n resolveNpmGlobalPrefixLayoutFromGlobalRoot,\n resolveNpmGlobalPrefixLayoutFromPrefix,\n resolveExpectedInstalledVersionFromSpec,\n resolveGlobalInstallTarget,\n XOPC_PACKAGE_NAME,\n type NpmGlobalPrefixLayout,\n type ResolvedGlobalInstallTarget,\n} from './update-global.js';\n\nexport type PackageUpdateStepResult = {\n name: string;\n command: string;\n cwd: string;\n durationMs: number;\n exitCode: number | null;\n stdoutTail?: string | null;\n stderrTail?: string | null;\n};\n\nexport type PackageUpdateStepRunner = (params: {\n name: string;\n argv: string[];\n cwd?: string;\n timeoutMs: number;\n env?: NodeJS.ProcessEnv;\n}) => Promise<PackageUpdateStepResult>;\n\ntype StagedNpmInstall = {\n prefix: string;\n layout: NpmGlobalPrefixLayout;\n packageRoot: string;\n};\n\ntype NpmBinShimBackup = {\n backupDir: string;\n targetBinDir: string;\n entries: Array<{ name: string; hadExisting: boolean }>;\n};\n\nfunction formatError(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\nasync function pathExists(targetPath: string): Promise<boolean> {\n try {\n await fs.access(targetPath);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function readPackageVersionIfPresent(packageRoot: string | null): Promise<string | null> {\n if (!packageRoot) return null;\n try {\n return await readPackageVersion(packageRoot);\n } catch {\n return null;\n }\n}\n\nasync function createStagedNpmInstall(\n installTarget: ResolvedGlobalInstallTarget,\n packageName: string,\n): Promise<StagedNpmInstall | null> {\n if (installTarget.manager !== 'npm') return null;\n const targetLayout = resolveNpmGlobalPrefixLayoutFromGlobalRoot(installTarget.globalRoot);\n if (!targetLayout) return null;\n await fs.mkdir(targetLayout.globalRoot, { recursive: true });\n const prefix = await fs.mkdtemp(path.join(targetLayout.globalRoot, '.xopc-update-stage-'));\n const layout = resolveNpmGlobalPrefixLayoutFromPrefix(prefix);\n return {\n prefix,\n layout,\n packageRoot: path.join(layout.globalRoot, packageName),\n };\n}\n\nasync function prepareStagedNpmInstall(\n installTarget: ResolvedGlobalInstallTarget,\n packageName: string,\n): Promise<{ stagedInstall: StagedNpmInstall | null; failedStep: PackageUpdateStepResult | null }> {\n const startedAt = Date.now();\n try {\n return { stagedInstall: await createStagedNpmInstall(installTarget, packageName), failedStep: null };\n } catch (err) {\n const targetLayout =\n installTarget.manager === 'npm'\n ? resolveNpmGlobalPrefixLayoutFromGlobalRoot(installTarget.globalRoot)\n : null;\n return {\n stagedInstall: null,\n failedStep: {\n name: 'global install stage',\n command: 'prepare staged npm install',\n cwd: targetLayout?.prefix ?? installTarget.globalRoot ?? process.cwd(),\n durationMs: Date.now() - startedAt,\n exitCode: 1,\n stdoutTail: null,\n stderrTail: formatError(err),\n },\n };\n }\n}\n\nasync function cleanupStagedNpmInstall(stage: StagedNpmInstall | null): Promise<void> {\n if (!stage) return;\n await fs.rm(stage.prefix, { recursive: true, force: true }).catch(() => undefined);\n}\n\nasync function copyPathEntry(source: string, destination: string): Promise<void> {\n const stat = await fs.lstat(source);\n await fs.rm(destination, { recursive: true, force: true }).catch(() => undefined);\n if (stat.isSymbolicLink()) {\n await fs.symlink(await fs.readlink(source), destination);\n return;\n }\n if (stat.isDirectory()) {\n await fs.cp(source, destination, { recursive: true, force: true, preserveTimestamps: false });\n return;\n }\n await fs.copyFile(source, destination);\n await fs.chmod(destination, stat.mode).catch(() => undefined);\n}\n\nasync function replaceNpmBinShims(params: {\n stageLayout: NpmGlobalPrefixLayout;\n targetLayout: NpmGlobalPrefixLayout;\n packageName: string;\n}): Promise<void> {\n let entries: string[] = [];\n try {\n entries = await fs.readdir(params.stageLayout.binDir);\n } catch {\n return;\n }\n\n const names = new Set([params.packageName, 'xopc']);\n const shimEntries = entries.filter((entry) => {\n const parsed = path.parse(entry);\n return names.has(entry) || names.has(parsed.name);\n });\n if (shimEntries.length === 0) return;\n\n const backup: NpmBinShimBackup = {\n backupDir: await fs.mkdtemp(path.join(params.targetLayout.globalRoot, '.xopc-shim-backup-')),\n targetBinDir: params.targetLayout.binDir,\n entries: [],\n };\n\n try {\n await fs.mkdir(params.targetLayout.binDir, { recursive: true });\n for (const entry of shimEntries) {\n const destination = path.join(params.targetLayout.binDir, entry);\n const hadExisting = await pathExists(destination);\n backup.entries.push({ name: entry, hadExisting });\n if (hadExisting) {\n await copyPathEntry(destination, path.join(backup.backupDir, entry));\n }\n }\n for (const entry of shimEntries) {\n await copyPathEntry(\n path.join(params.stageLayout.binDir, entry),\n path.join(params.targetLayout.binDir, entry),\n );\n }\n } catch (err) {\n await restoreNpmBinShimBackup(backup);\n throw err;\n } finally {\n await fs.rm(backup.backupDir, { recursive: true, force: true }).catch(() => undefined);\n }\n}\n\nasync function restoreNpmBinShimBackup(backup: NpmBinShimBackup): Promise<void> {\n await fs.mkdir(backup.targetBinDir, { recursive: true });\n for (const entry of backup.entries) {\n const destination = path.join(backup.targetBinDir, entry.name);\n await fs.rm(destination, { recursive: true, force: true }).catch(() => undefined);\n if (entry.hadExisting) {\n await copyPathEntry(path.join(backup.backupDir, entry.name), destination);\n }\n }\n}\n\nasync function swapStagedNpmInstall(params: {\n stage: StagedNpmInstall;\n installTarget: ResolvedGlobalInstallTarget;\n packageName: string;\n}): Promise<PackageUpdateStepResult> {\n const startedAt = Date.now();\n const targetLayout = resolveNpmGlobalPrefixLayoutFromGlobalRoot(params.installTarget.globalRoot);\n const targetPackageRoot = params.installTarget.packageRoot;\n if (!targetLayout || !targetPackageRoot) {\n return {\n name: 'global install swap',\n command: 'swap staged npm install',\n cwd: params.stage.prefix,\n durationMs: Date.now() - startedAt,\n exitCode: 1,\n stdoutTail: null,\n stderrTail: 'cannot resolve npm global prefix layout',\n };\n }\n\n const backupRoot = path.join(targetLayout.globalRoot, `.xopc-${process.pid}-${Date.now()}`);\n let movedExisting = false;\n let movedStaged = false;\n try {\n await fs.mkdir(targetLayout.globalRoot, { recursive: true });\n if (await pathExists(targetPackageRoot)) {\n await fs.rename(targetPackageRoot, backupRoot);\n movedExisting = true;\n }\n await fs.rename(params.stage.packageRoot, targetPackageRoot);\n movedStaged = true;\n await replaceNpmBinShims({\n stageLayout: params.stage.layout,\n targetLayout,\n packageName: params.packageName,\n });\n if (movedExisting) {\n await fs.rm(backupRoot, { recursive: true, force: true });\n }\n return {\n name: 'global install swap',\n command: `swap ${params.stage.packageRoot} -> ${targetPackageRoot}`,\n cwd: targetLayout.globalRoot,\n durationMs: Date.now() - startedAt,\n exitCode: 0,\n stdoutTail: movedExisting ? `replaced ${params.packageName}` : `installed ${params.packageName}`,\n stderrTail: null,\n };\n } catch (err) {\n if (movedStaged) {\n await fs.rm(targetPackageRoot, { recursive: true, force: true }).catch(() => undefined);\n }\n if (movedExisting) {\n await fs.rename(backupRoot, targetPackageRoot).catch(() => undefined);\n }\n return {\n name: 'global install swap',\n command: `swap ${params.stage.packageRoot} -> ${targetPackageRoot}`,\n cwd: targetLayout.globalRoot,\n durationMs: Date.now() - startedAt,\n exitCode: 1,\n stdoutTail: null,\n stderrTail: formatError(err),\n };\n }\n}\n\nexport async function runGlobalPackageUpdateSteps(params: {\n installTarget: ResolvedGlobalInstallTarget;\n installSpec: string;\n packageName: string;\n packageRoot?: string | null;\n runCommand: CommandRunner;\n runStep: PackageUpdateStepRunner;\n timeoutMs: number;\n env?: NodeJS.ProcessEnv;\n installCwd?: string;\n}): Promise<{\n steps: PackageUpdateStepResult[];\n verifiedPackageRoot: string | null;\n afterVersion: string | null;\n failedStep: PackageUpdateStepResult | null;\n}> {\n const installCwd = params.installCwd === undefined ? {} : { cwd: params.installCwd };\n const installEnv = params.env === undefined ? {} : { env: params.env };\n let stagedInstall: StagedNpmInstall | null = null;\n\n try {\n const preparedInstall = await prepareStagedNpmInstall(params.installTarget, params.packageName);\n stagedInstall = preparedInstall.stagedInstall;\n if (preparedInstall.failedStep) {\n return {\n steps: [preparedInstall.failedStep],\n verifiedPackageRoot: params.packageRoot ?? null,\n afterVersion: null,\n failedStep: preparedInstall.failedStep,\n };\n }\n\n const updateStep = await params.runStep({\n name: 'global update',\n argv: globalInstallArgs(\n params.installTarget,\n params.installSpec,\n params.packageRoot,\n stagedInstall?.prefix,\n ),\n ...installCwd,\n ...installEnv,\n timeoutMs: params.timeoutMs,\n });\n\n const steps = [updateStep];\n let finalInstallStep = updateStep;\n if (updateStep.exitCode !== 0) {\n await cleanupStagedNpmInstall(stagedInstall);\n stagedInstall = null;\n const preparedFallbackInstall = await prepareStagedNpmInstall(\n params.installTarget,\n params.packageName,\n );\n stagedInstall = preparedFallbackInstall.stagedInstall;\n if (preparedFallbackInstall.failedStep) {\n steps.push(preparedFallbackInstall.failedStep);\n return {\n steps,\n verifiedPackageRoot: params.packageRoot ?? null,\n afterVersion: null,\n failedStep: preparedFallbackInstall.failedStep,\n };\n }\n\n const fallbackArgv = globalInstallFallbackArgs(\n params.installTarget,\n params.installSpec,\n params.packageRoot,\n stagedInstall?.prefix,\n );\n if (fallbackArgv) {\n const fallbackStep = await params.runStep({\n name: 'global update (omit optional)',\n argv: fallbackArgv,\n ...installCwd,\n ...installEnv,\n timeoutMs: params.timeoutMs,\n });\n steps.push(fallbackStep);\n finalInstallStep = fallbackStep;\n } else {\n await cleanupStagedNpmInstall(stagedInstall);\n stagedInstall = null;\n }\n }\n\n const livePackageRoot =\n params.installTarget.packageRoot ??\n params.packageRoot ??\n (\n await resolveGlobalInstallTarget({\n manager: params.installTarget,\n runCommand: params.runCommand,\n timeoutMs: params.timeoutMs,\n pkgRoot: params.packageRoot,\n })\n ).packageRoot ??\n null;\n const verificationPackageRoot = stagedInstall?.packageRoot ?? livePackageRoot;\n let verifiedPackageRoot = livePackageRoot ?? verificationPackageRoot;\n\n let afterVersion: string | null = null;\n if (finalInstallStep.exitCode === 0 && verificationPackageRoot) {\n const candidateVersion = await readPackageVersion(verificationPackageRoot);\n if (!stagedInstall) {\n afterVersion = candidateVersion;\n }\n const expectedVersion = resolveExpectedInstalledVersionFromSpec(params.installSpec);\n const verificationErrors = await collectInstalledGlobalPackageErrors({\n packageRoot: verificationPackageRoot,\n expectedVersion,\n });\n if (verificationErrors.length > 0) {\n steps.push({\n name: 'global install verify',\n command: `verify ${verificationPackageRoot}`,\n cwd: verificationPackageRoot,\n durationMs: 0,\n exitCode: 1,\n stderrTail: verificationErrors.join('\\n'),\n stdoutTail: null,\n });\n }\n\n if (stagedInstall && verificationErrors.length === 0) {\n const swapStep = await swapStagedNpmInstall({\n stage: stagedInstall,\n installTarget: params.installTarget,\n packageName: params.packageName,\n });\n steps.push(swapStep);\n if (swapStep.exitCode === 0) {\n verifiedPackageRoot = params.installTarget.packageRoot ?? verifiedPackageRoot;\n afterVersion = candidateVersion;\n }\n }\n }\n\n const failedVerifyOrSwap = steps.find(\n (step) =>\n (step.name === 'global install verify' || step.name === 'global install swap') &&\n step.exitCode !== 0,\n );\n if (failedVerifyOrSwap && stagedInstall) {\n afterVersion = await readPackageVersionIfPresent(livePackageRoot);\n }\n\n const failedStep =\n finalInstallStep.exitCode !== 0\n ? finalInstallStep\n : (steps.find((step) => step !== updateStep && step.exitCode !== 0) ?? null);\n\n return { steps, verifiedPackageRoot, afterVersion, failedStep };\n } finally {\n await cleanupStagedNpmInstall(stagedInstall);\n }\n}\n\nexport const DEFAULT_PACKAGE_NAME = XOPC_PACKAGE_NAME;\n"],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ type EnsureXopcPathOpts = {
2
+ execPath?: string;
3
+ cwd?: string;
4
+ homeDir?: string;
5
+ platform?: NodeJS.Platform;
6
+ pathEnv?: string;
7
+ };
8
+ /** Bootstrap PATH for launchd/daemon environments (npm/pnpm/git subprocesses). */
9
+ export declare function ensureXopcCliOnPath(opts?: EnsureXopcPathOpts): void;
10
+ export declare function resolveExecPathBinPrepend(): string[];
11
+ export {};
@@ -0,0 +1,90 @@
1
+ import { resolveBrewPathDirs } from "./brew.js";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import os from "node:os";
5
+ //#region src/infra/path-env.ts
6
+ function isTruthyEnvValue(value) {
7
+ if (!value) return false;
8
+ const normalized = value.trim().toLowerCase();
9
+ return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
10
+ }
11
+ function isExecutable(filePath) {
12
+ try {
13
+ fs.accessSync(filePath, fs.constants.X_OK);
14
+ return true;
15
+ } catch {
16
+ return false;
17
+ }
18
+ }
19
+ function isDirectory(dirPath) {
20
+ try {
21
+ return fs.statSync(dirPath).isDirectory();
22
+ } catch {
23
+ return false;
24
+ }
25
+ }
26
+ function mergePath(params) {
27
+ const partsExisting = params.existing.split(path.delimiter).map((part) => part.trim()).filter(Boolean);
28
+ const partsPrepend = (params.prepend ?? []).map((part) => part.trim()).filter(Boolean);
29
+ const partsAppend = (params.append ?? []).map((part) => part.trim()).filter(Boolean);
30
+ const seen = /* @__PURE__ */ new Set();
31
+ const merged = [];
32
+ for (const part of [
33
+ ...partsPrepend,
34
+ ...partsExisting,
35
+ ...partsAppend
36
+ ]) {
37
+ if (seen.has(part)) continue;
38
+ seen.add(part);
39
+ merged.push(part);
40
+ }
41
+ return merged.join(path.delimiter);
42
+ }
43
+ function candidateBinDirs(opts) {
44
+ const execPath = opts.execPath ?? process.execPath;
45
+ const homeDir = opts.homeDir ?? os.homedir();
46
+ const platform = opts.platform ?? process.platform;
47
+ const prepend = [];
48
+ const append = [];
49
+ try {
50
+ const execDir = path.dirname(execPath);
51
+ if (isExecutable(execPath)) prepend.push(execDir);
52
+ } catch {}
53
+ try {
54
+ const execDir = path.dirname(execPath);
55
+ if (isExecutable(path.join(execDir, "xopc"))) prepend.push(execDir);
56
+ } catch {}
57
+ prepend.push("/usr/bin", "/bin");
58
+ append.push(...resolveBrewPathDirs({ homeDir }));
59
+ if (platform === "darwin") append.push(path.join(homeDir, "Library", "pnpm"));
60
+ if (process.env.XDG_BIN_HOME) append.push(process.env.XDG_BIN_HOME);
61
+ append.push(path.join(homeDir, ".local", "bin"), path.join(homeDir, ".local", "share", "pnpm"), path.join(homeDir, ".bun", "bin"), path.join(homeDir, ".nvm", "versions", "node"));
62
+ return {
63
+ prepend: prepend.filter(isDirectory),
64
+ append: append.filter(isDirectory)
65
+ };
66
+ }
67
+ /** Bootstrap PATH for launchd/daemon environments (npm/pnpm/git subprocesses). */
68
+ function ensureXopcCliOnPath(opts = {}) {
69
+ if (isTruthyEnvValue(process.env.XOPC_PATH_BOOTSTRAPPED)) return;
70
+ process.env.XOPC_PATH_BOOTSTRAPPED = "1";
71
+ const existing = opts.pathEnv ?? process.env.PATH ?? "";
72
+ const { prepend, append } = candidateBinDirs(opts);
73
+ if (prepend.length === 0 && append.length === 0) return;
74
+ const merged = mergePath({
75
+ existing,
76
+ prepend,
77
+ append
78
+ });
79
+ if (merged) process.env.PATH = merged;
80
+ }
81
+ function resolveExecPathBinPrepend() {
82
+ const execPath = process.execPath?.trim();
83
+ if (!execPath) return [];
84
+ const execDir = path.dirname(execPath);
85
+ return isDirectory(execDir) ? [execDir] : [];
86
+ }
87
+ //#endregion
88
+ export { ensureXopcCliOnPath, resolveExecPathBinPrepend };
89
+
90
+ //# sourceMappingURL=path-env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-env.js","names":[],"sources":["../../../src/infra/path-env.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { resolveBrewPathDirs } from './brew.js';\n\ntype EnsureXopcPathOpts = {\n execPath?: string;\n cwd?: string;\n homeDir?: string;\n platform?: NodeJS.Platform;\n pathEnv?: string;\n};\n\nfunction isTruthyEnvValue(value: string | undefined): boolean {\n if (!value) return false;\n const normalized = value.trim().toLowerCase();\n return normalized === '1' || normalized === 'true' || normalized === 'yes' || normalized === 'on';\n}\n\nfunction isExecutable(filePath: string): boolean {\n try {\n fs.accessSync(filePath, fs.constants.X_OK);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isDirectory(dirPath: string): boolean {\n try {\n return fs.statSync(dirPath).isDirectory();\n } catch {\n return false;\n }\n}\n\nfunction mergePath(params: { existing: string; prepend?: string[]; append?: string[] }): string {\n const partsExisting = params.existing\n .split(path.delimiter)\n .map((part) => part.trim())\n .filter(Boolean);\n const partsPrepend = (params.prepend ?? []).map((part) => part.trim()).filter(Boolean);\n const partsAppend = (params.append ?? []).map((part) => part.trim()).filter(Boolean);\n const seen = new Set<string>();\n const merged: string[] = [];\n for (const part of [...partsPrepend, ...partsExisting, ...partsAppend]) {\n if (seen.has(part)) continue;\n seen.add(part);\n merged.push(part);\n }\n return merged.join(path.delimiter);\n}\n\nfunction candidateBinDirs(opts: EnsureXopcPathOpts): { prepend: string[]; append: string[] } {\n const execPath = opts.execPath ?? process.execPath;\n const homeDir = opts.homeDir ?? os.homedir();\n const platform = opts.platform ?? process.platform;\n const prepend: string[] = [];\n const append: string[] = [];\n\n try {\n const execDir = path.dirname(execPath);\n if (isExecutable(execPath)) prepend.push(execDir);\n } catch {\n // ignore\n }\n\n try {\n const execDir = path.dirname(execPath);\n const siblingCli = path.join(execDir, 'xopc');\n if (isExecutable(siblingCli)) prepend.push(execDir);\n } catch {\n // ignore\n }\n\n prepend.push('/usr/bin', '/bin');\n append.push(...resolveBrewPathDirs({ homeDir }));\n if (platform === 'darwin') append.push(path.join(homeDir, 'Library', 'pnpm'));\n if (process.env.XDG_BIN_HOME) append.push(process.env.XDG_BIN_HOME);\n append.push(\n path.join(homeDir, '.local', 'bin'),\n path.join(homeDir, '.local', 'share', 'pnpm'),\n path.join(homeDir, '.bun', 'bin'),\n path.join(homeDir, '.nvm', 'versions', 'node'),\n );\n\n return { prepend: prepend.filter(isDirectory), append: append.filter(isDirectory) };\n}\n\n/** Bootstrap PATH for launchd/daemon environments (npm/pnpm/git subprocesses). */\nexport function ensureXopcCliOnPath(opts: EnsureXopcPathOpts = {}): void {\n if (isTruthyEnvValue(process.env.XOPC_PATH_BOOTSTRAPPED)) return;\n process.env.XOPC_PATH_BOOTSTRAPPED = '1';\n\n const existing = opts.pathEnv ?? process.env.PATH ?? '';\n const { prepend, append } = candidateBinDirs(opts);\n if (prepend.length === 0 && append.length === 0) return;\n\n const merged = mergePath({ existing, prepend, append });\n if (merged) process.env.PATH = merged;\n}\n\nexport function resolveExecPathBinPrepend(): string[] {\n const execPath = process.execPath?.trim();\n if (!execPath) return [];\n const execDir = path.dirname(execPath);\n return isDirectory(execDir) ? [execDir] : [];\n}\n"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /** Find the actual key used for PATH (Windows may use `Path`). */
2
+ export declare function findPathKey(env: Record<string, string>): string;
3
+ export declare function normalizePathPrepend(entries?: string[]): string[];
4
+ export declare function mergePathPrepend(existing: string | undefined, prepend: string[]): string;
5
+ export declare function applyPathPrepend(env: Record<string, string>, prepend: string[] | undefined, options?: {
6
+ requireExisting?: boolean;
7
+ }): void;
@@ -0,0 +1,44 @@
1
+ import path from "node:path";
2
+ //#region src/infra/path-prepend.ts
3
+ /** Find the actual key used for PATH (Windows may use `Path`). */
4
+ function findPathKey(env) {
5
+ if ("PATH" in env) return "PATH";
6
+ for (const key of Object.keys(env)) if (key.toUpperCase() === "PATH") return key;
7
+ return "PATH";
8
+ }
9
+ function normalizePathPrepend(entries) {
10
+ if (!Array.isArray(entries)) return [];
11
+ const seen = /* @__PURE__ */ new Set();
12
+ const normalized = [];
13
+ for (const entry of entries) {
14
+ if (typeof entry !== "string") continue;
15
+ const trimmed = entry.trim();
16
+ if (!trimmed || seen.has(trimmed)) continue;
17
+ seen.add(trimmed);
18
+ normalized.push(trimmed);
19
+ }
20
+ return normalized;
21
+ }
22
+ function mergePathPrepend(existing, prepend) {
23
+ if (prepend.length === 0) return existing ?? "";
24
+ const partsExisting = (existing ?? "").split(path.delimiter).map((part) => part.trim()).filter(Boolean);
25
+ const merged = [];
26
+ const seen = /* @__PURE__ */ new Set();
27
+ for (const part of [...prepend, ...partsExisting]) {
28
+ if (seen.has(part)) continue;
29
+ seen.add(part);
30
+ merged.push(part);
31
+ }
32
+ return merged.join(path.delimiter);
33
+ }
34
+ function applyPathPrepend(env, prepend, options) {
35
+ if (!Array.isArray(prepend) || prepend.length === 0) return;
36
+ const pathKey = findPathKey(env);
37
+ if (options?.requireExisting && !env[pathKey]) return;
38
+ const merged = mergePathPrepend(env[pathKey], prepend);
39
+ if (merged) env[pathKey] = merged;
40
+ }
41
+ //#endregion
42
+ export { applyPathPrepend, findPathKey, mergePathPrepend, normalizePathPrepend };
43
+
44
+ //# sourceMappingURL=path-prepend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-prepend.js","names":[],"sources":["../../../src/infra/path-prepend.ts"],"sourcesContent":["import path from 'node:path';\n\n/** Find the actual key used for PATH (Windows may use `Path`). */\nexport function findPathKey(env: Record<string, string>): string {\n if ('PATH' in env) return 'PATH';\n for (const key of Object.keys(env)) {\n if (key.toUpperCase() === 'PATH') return key;\n }\n return 'PATH';\n}\n\nexport function normalizePathPrepend(entries?: string[]): string[] {\n if (!Array.isArray(entries)) return [];\n const seen = new Set<string>();\n const normalized: string[] = [];\n for (const entry of entries) {\n if (typeof entry !== 'string') continue;\n const trimmed = entry.trim();\n if (!trimmed || seen.has(trimmed)) continue;\n seen.add(trimmed);\n normalized.push(trimmed);\n }\n return normalized;\n}\n\nexport function mergePathPrepend(existing: string | undefined, prepend: string[]): string {\n if (prepend.length === 0) return existing ?? '';\n const partsExisting = (existing ?? '')\n .split(path.delimiter)\n .map((part) => part.trim())\n .filter(Boolean);\n const merged: string[] = [];\n const seen = new Set<string>();\n for (const part of [...prepend, ...partsExisting]) {\n if (seen.has(part)) continue;\n seen.add(part);\n merged.push(part);\n }\n return merged.join(path.delimiter);\n}\n\nexport function applyPathPrepend(\n env: Record<string, string>,\n prepend: string[] | undefined,\n options?: { requireExisting?: boolean },\n): void {\n if (!Array.isArray(prepend) || prepend.length === 0) return;\n const pathKey = findPathKey(env);\n if (options?.requireExisting && !env[pathKey]) return;\n const merged = mergePathPrepend(env[pathKey], prepend);\n if (merged) env[pathKey] = merged;\n}\n"],"mappings":";;;AAGA,SAAgB,YAAY,KAAqC;AAC/D,KAAI,UAAU,IAAK,QAAO;AAC1B,MAAK,MAAM,OAAO,OAAO,KAAK,IAAI,CAChC,KAAI,IAAI,aAAa,KAAK,OAAQ,QAAO;AAE3C,QAAO;;AAGT,SAAgB,qBAAqB,SAA8B;AACjE,KAAI,CAAC,MAAM,QAAQ,QAAQ,CAAE,QAAO,EAAE;CACtC,MAAM,uBAAO,IAAI,KAAa;CAC9B,MAAM,aAAuB,EAAE;AAC/B,MAAK,MAAM,SAAS,SAAS;AAC3B,MAAI,OAAO,UAAU,SAAU;EAC/B,MAAM,UAAU,MAAM,MAAM;AAC5B,MAAI,CAAC,WAAW,KAAK,IAAI,QAAQ,CAAE;AACnC,OAAK,IAAI,QAAQ;AACjB,aAAW,KAAK,QAAQ;;AAE1B,QAAO;;AAGT,SAAgB,iBAAiB,UAA8B,SAA2B;AACxF,KAAI,QAAQ,WAAW,EAAG,QAAO,YAAY;CAC7C,MAAM,iBAAiB,YAAY,IAChC,MAAM,KAAK,UAAU,CACrB,KAAK,SAAS,KAAK,MAAM,CAAC,CAC1B,OAAO,QAAQ;CAClB,MAAM,SAAmB,EAAE;CAC3B,MAAM,uBAAO,IAAI,KAAa;AAC9B,MAAK,MAAM,QAAQ,CAAC,GAAG,SAAS,GAAG,cAAc,EAAE;AACjD,MAAI,KAAK,IAAI,KAAK,CAAE;AACpB,OAAK,IAAI,KAAK;AACd,SAAO,KAAK,KAAK;;AAEnB,QAAO,OAAO,KAAK,KAAK,UAAU;;AAGpC,SAAgB,iBACd,KACA,SACA,SACM;AACN,KAAI,CAAC,MAAM,QAAQ,QAAQ,IAAI,QAAQ,WAAW,EAAG;CACrD,MAAM,UAAU,YAAY,IAAI;AAChC,KAAI,SAAS,mBAAmB,CAAC,IAAI,SAAU;CAC/C,MAAM,SAAS,iBAAiB,IAAI,UAAU,QAAQ;AACtD,KAAI,OAAQ,KAAI,WAAW"}
@@ -0,0 +1,2 @@
1
+ /** Resolve Homebrew Cellar node paths to stable opt/bin symlinks. */
2
+ export declare function resolveStableNodePath(nodePath: string): Promise<string>;
@@ -0,0 +1,28 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ //#region src/infra/stable-node-path.ts
4
+ /** Resolve Homebrew Cellar node paths to stable opt/bin symlinks. */
5
+ async function resolveStableNodePath(nodePath) {
6
+ const cellarMatch = nodePath.match(/^(.+?)[\\/]Cellar[\\/]([^\\/]+)[\\/][^\\/]+[\\/]bin[\\/]node$/);
7
+ if (!cellarMatch) return nodePath;
8
+ const prefix = cellarMatch[1];
9
+ const formula = cellarMatch[2];
10
+ const pathModule = nodePath.includes("\\") ? path.win32 : path.posix;
11
+ const optPath = pathModule.join(prefix, "opt", formula, "bin", "node");
12
+ try {
13
+ await fs.access(optPath);
14
+ return optPath;
15
+ } catch {}
16
+ if (formula === "node") {
17
+ const binPath = pathModule.join(prefix, "bin", "node");
18
+ try {
19
+ await fs.access(binPath);
20
+ return binPath;
21
+ } catch {}
22
+ }
23
+ return nodePath;
24
+ }
25
+ //#endregion
26
+ export { resolveStableNodePath };
27
+
28
+ //# sourceMappingURL=stable-node-path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stable-node-path.js","names":[],"sources":["../../../src/infra/stable-node-path.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\n\n/** Resolve Homebrew Cellar node paths to stable opt/bin symlinks. */\nexport async function resolveStableNodePath(nodePath: string): Promise<string> {\n const cellarMatch = nodePath.match(\n /^(.+?)[\\\\/]Cellar[\\\\/]([^\\\\/]+)[\\\\/][^\\\\/]+[\\\\/]bin[\\\\/]node$/,\n );\n if (!cellarMatch) return nodePath;\n\n const prefix = cellarMatch[1];\n const formula = cellarMatch[2];\n const pathModule = nodePath.includes('\\\\') ? path.win32 : path.posix;\n const optPath = pathModule.join(prefix, 'opt', formula, 'bin', 'node');\n try {\n await fs.access(optPath);\n return optPath;\n } catch {\n // fall through\n }\n\n if (formula === 'node') {\n const binPath = pathModule.join(prefix, 'bin', 'node');\n try {\n await fs.access(binPath);\n return binPath;\n } catch {\n // fall through\n }\n }\n\n return nodePath;\n}\n"],"mappings":";;;;AAIA,eAAsB,sBAAsB,UAAmC;CAC7E,MAAM,cAAc,SAAS,MAC3B,gEACD;AACD,KAAI,CAAC,YAAa,QAAO;CAEzB,MAAM,SAAS,YAAY;CAC3B,MAAM,UAAU,YAAY;CAC5B,MAAM,aAAa,SAAS,SAAS,KAAK,GAAG,KAAK,QAAQ,KAAK;CAC/D,MAAM,UAAU,WAAW,KAAK,QAAQ,OAAO,SAAS,OAAO,OAAO;AACtE,KAAI;AACF,QAAM,GAAG,OAAO,QAAQ;AACxB,SAAO;SACD;AAIR,KAAI,YAAY,QAAQ;EACtB,MAAM,UAAU,WAAW,KAAK,QAAQ,OAAO,OAAO;AACtD,MAAI;AACF,SAAM,GAAG,OAAO,QAAQ;AACxB,UAAO;UACD;;AAKV,QAAO"}
@@ -5,41 +5,48 @@ export type ResolvedGlobalInstallCommand = {
5
5
  manager: GlobalInstallManager;
6
6
  command: string;
7
7
  };
8
- export type GlobalInstallRunResult = {
9
- exitCode: number;
10
- stdout: string;
11
- stderr: string;
12
- packageManager: GlobalInstallManager;
13
- usedFallback: boolean;
8
+ export type ResolvedGlobalInstallTarget = ResolvedGlobalInstallCommand & {
9
+ globalRoot: string | null;
10
+ packageRoot: string | null;
11
+ };
12
+ export type NpmGlobalPrefixLayout = {
13
+ prefix: string;
14
+ globalRoot: string;
15
+ binDir: string;
14
16
  };
15
17
  export declare function joinGlobalPackagePath(globalRoot: string): string;
16
18
  export declare function resolveGlobalInstallCommand(manager: GlobalInstallManager, pkgRoot?: string | null): ResolvedGlobalInstallCommand;
19
+ export declare function resolveNpmGlobalPrefixLayoutFromGlobalRoot(globalRoot?: string | null): NpmGlobalPrefixLayout | null;
20
+ export declare function resolveNpmGlobalPrefixLayoutFromPrefix(prefix: string): NpmGlobalPrefixLayout;
17
21
  export declare function createGlobalInstallEnv(env?: NodeJS.ProcessEnv): Promise<NodeJS.ProcessEnv | undefined>;
18
22
  export declare function resolveGlobalInstallSpec(params: {
19
23
  version: string;
20
24
  env?: NodeJS.ProcessEnv;
21
25
  }): string;
26
+ export declare function resolveExpectedInstalledVersionFromSpec(spec: string): string | null;
27
+ export declare function collectInstalledGlobalPackageErrors(params: {
28
+ packageRoot: string;
29
+ expectedVersion?: string | null;
30
+ }): Promise<string[]>;
22
31
  export declare function resolveGlobalRoot(managerOrCommand: GlobalInstallManager | ResolvedGlobalInstallCommand, runCommand: CommandRunner, timeoutMs: number, pkgRoot?: string | null): Promise<string | null>;
23
- export declare function globalInstallArgs(managerOrCommand: GlobalInstallManager | ResolvedGlobalInstallCommand, spec: string, pkgRoot?: string | null): string[];
24
- export declare function globalInstallFallbackArgs(managerOrCommand: GlobalInstallManager | ResolvedGlobalInstallCommand, spec: string, pkgRoot?: string | null): string[] | null;
32
+ export declare function resolveGlobalPackageRoot(managerOrCommand: GlobalInstallManager | ResolvedGlobalInstallCommand, runCommand: CommandRunner, timeoutMs: number, pkgRoot?: string | null): Promise<string | null>;
33
+ export declare function resolveGlobalInstallTarget(params: {
34
+ manager: GlobalInstallManager | ResolvedGlobalInstallCommand;
35
+ runCommand: CommandRunner;
36
+ timeoutMs: number;
37
+ pkgRoot?: string | null;
38
+ }): Promise<ResolvedGlobalInstallTarget>;
39
+ export declare function globalInstallArgs(managerOrCommand: GlobalInstallManager | ResolvedGlobalInstallCommand, spec: string, pkgRoot?: string | null, installPrefix?: string | null): string[];
40
+ export declare function globalInstallFallbackArgs(managerOrCommand: GlobalInstallManager | ResolvedGlobalInstallCommand, spec: string, pkgRoot?: string | null, installPrefix?: string | null): string[] | null;
41
+ export declare function cleanupGlobalRenameDirs(params: {
42
+ globalRoot: string;
43
+ packageName: string;
44
+ }): Promise<{
45
+ removed: string[];
46
+ }>;
25
47
  export declare function detectGlobalInstallManagerForRoot(runCommand: CommandRunner, pkgRoot: string, timeoutMs: number): Promise<GlobalInstallManager | null>;
26
48
  export declare function detectGlobalInstallManagerByPresence(runCommand: CommandRunner, timeoutMs: number): Promise<GlobalInstallManager | null>;
27
49
  export declare function resolveGlobalManager(params: {
28
50
  root: string | null;
29
51
  timeoutMs?: number;
30
52
  }): Promise<GlobalInstallManager>;
31
- export declare function runGlobalPackageInstall(params: {
32
- manager: GlobalInstallManager;
33
- spec: string;
34
- pkgRoot: string | null;
35
- timeoutMs?: number;
36
- /** Echo install output to the parent process (CLI interactive). */
37
- echoToTerminal?: boolean;
38
- }): Promise<GlobalInstallRunResult>;
39
- export declare function formatGlobalInstallFailure(params: {
40
- packageManager: GlobalInstallManager;
41
- spec: string;
42
- exitCode: number;
43
- stderr: string;
44
- usedFallback: boolean;
45
- }): string;