@xopcai/xopc 0.0.89 → 0.0.91
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -12
- package/README.zh-CN.md +36 -12
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/Combination-HAlzriaz.js +41 -0
- package/dist/gateway/static/root/assets/agents-bVWUlrlD.js +222 -0
- package/dist/gateway/static/root/assets/apps-page-CIC8bmvZ.js +1 -0
- package/dist/gateway/static/root/assets/{attachment-preview-renderer-CpyoFbs4.js → attachment-preview-renderer-DBAxQXb-.js} +2 -2
- package/dist/gateway/static/root/assets/{attachment-process-heavy-CqVriadb.js → attachment-process-heavy-Csq3TrrP.js} +4 -4
- package/dist/gateway/static/root/assets/channels-settings-C8G8RAAP.js +1 -0
- package/dist/gateway/static/root/assets/{channels-status-swr-DaHGkRF1.js → channels-status-swr-CYWL5DLD.js} +1 -1
- package/dist/gateway/static/root/assets/circle-check-C23XjkUj.js +1 -0
- package/dist/gateway/static/root/assets/copy-Dv6d4Dvw.js +1 -0
- package/dist/gateway/static/root/assets/cron-api-TVqLlGAC.js +1 -0
- package/dist/gateway/static/root/assets/cron-dreaming-jobs-Ip703-qM.js +2 -0
- package/dist/gateway/static/root/assets/cron-page-BtcFYlvv.js +1 -0
- package/dist/gateway/static/root/assets/dist-CUV1uY5f.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-CtuKJ9tE.js → extension-debug-page-mTLHRDp1.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-ykzjOkR5.js → extension-page-iI8BI7WK.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-Ce2qrdpO.js → extension-settings-page-ByXcdubM.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-C9FFJjuH.js → fetch-BWtQq_Ys.js} +1 -1
- package/dist/gateway/static/root/assets/{field-primitives-BFcrNeTU.js → field-primitives-BsZ-4VT5.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-CEg4Vr9R.js → heartbeat-config-api-WjTsRLCU.js} +1 -1
- package/dist/gateway/static/root/assets/{index-CZfy9oxs.js → index-CKkR-v9U.js} +101 -97
- package/dist/gateway/static/root/assets/index-VlELBY99.css +1 -0
- package/dist/gateway/static/root/assets/logs-page-ClnIpxfd.js +1 -0
- package/dist/gateway/static/root/assets/note-detail-page-B91pLkEI.css +1 -0
- package/dist/gateway/static/root/assets/note-detail-page-DJ2Mb4x7.js +179 -0
- package/dist/gateway/static/root/assets/note-time-JLBPSLzK.js +1 -0
- package/dist/gateway/static/root/assets/notes-page-BE-75qz9.js +1 -0
- package/dist/gateway/static/root/assets/{pdf-BnEvgIXZ.js → pdf-epILhEOn.js} +1 -1
- package/dist/gateway/static/root/assets/preload-helper-zJ_50EbN.js +1 -0
- package/dist/gateway/static/root/assets/sessions-page-bJJkWtTl.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-BqdzA28u.js → settings-form-section-DSYCknxM.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-WcMXLq2U.js +3 -0
- package/dist/gateway/static/root/assets/share-preview-page-awRqs4hV.js +2 -0
- package/dist/gateway/static/root/assets/skills-page-Lu-i1JG7.js +2 -0
- package/dist/gateway/static/root/assets/{theme-store-CNqbmTNV.js → theme-store-BC-42BoZ.js} +1 -1
- package/dist/gateway/static/root/assets/toast-z0toXu32.js +1 -0
- package/dist/gateway/static/root/assets/url-CY1RQKTU.js +3 -0
- package/dist/gateway/static/root/assets/{utils-BWm2tG2w.js → utils-DX3TQuap.js} +1 -1
- package/dist/gateway/static/root/assets/vendor-codemirror-DYoKfS8f.js +45 -0
- package/dist/gateway/static/root/assets/voice-api-key-field-B5uKlDqA.js +1 -0
- package/dist/gateway/static/root/assets/workflow-page.utils-ClC37yEp.js +1 -0
- package/dist/gateway/static/root/assets/workflows-page-C7VhIXtR.js +27 -0
- package/dist/gateway/static/root/index.html +11 -7
- package/dist/package.js +1 -1
- package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.js +20 -18
- package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.js.map +1 -1
- package/dist/src/agent/tools/cronjob-tool.d.ts +6 -0
- package/dist/src/agent/tools/cronjob-tool.js +74 -9
- package/dist/src/agent/tools/cronjob-tool.js.map +1 -1
- package/dist/src/agent/tools/edit.d.ts +5 -1
- package/dist/src/agent/tools/edit.js +7 -5
- package/dist/src/agent/tools/edit.js.map +1 -1
- package/dist/src/agent/tools/factory.js +2 -2
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/write.d.ts +5 -1
- package/dist/src/agent/tools/write.js +7 -5
- package/dist/src/agent/tools/write.js.map +1 -1
- package/dist/src/agent/workflow/agent-progress.js +2 -0
- package/dist/src/agent/workflow/agent-progress.js.map +1 -1
- package/dist/src/agent/workflow/builtins/client-proposal.d.ts +12 -0
- package/dist/src/agent/workflow/builtins/client-proposal.js +155 -0
- package/dist/src/agent/workflow/builtins/client-proposal.js.map +1 -0
- package/dist/src/agent/workflow/builtins/competitor-scan.d.ts +12 -0
- package/dist/src/agent/workflow/builtins/competitor-scan.js +150 -0
- package/dist/src/agent/workflow/builtins/competitor-scan.js.map +1 -0
- package/dist/src/agent/workflow/builtins/content-draft.d.ts +13 -0
- package/dist/src/agent/workflow/builtins/content-draft.js +146 -0
- package/dist/src/agent/workflow/builtins/content-draft.js.map +1 -0
- package/dist/src/agent/workflow/builtins/content-repurpose.d.ts +11 -0
- package/dist/src/agent/workflow/builtins/content-repurpose.js +137 -0
- package/dist/src/agent/workflow/builtins/content-repurpose.js.map +1 -0
- package/dist/src/agent/workflow/builtins/decision-compare.d.ts +13 -0
- package/dist/src/agent/workflow/builtins/decision-compare.js +173 -0
- package/dist/src/agent/workflow/builtins/decision-compare.js.map +1 -0
- package/dist/src/agent/workflow/builtins/inbox-triage.d.ts +11 -0
- package/dist/src/agent/workflow/builtins/inbox-triage.js +148 -0
- package/dist/src/agent/workflow/builtins/inbox-triage.js.map +1 -0
- package/dist/src/agent/workflow/builtins/index.d.ts +10 -1
- package/dist/src/agent/workflow/builtins/index.js +46 -1
- package/dist/src/agent/workflow/builtins/index.js.map +1 -1
- package/dist/src/agent/workflow/builtins/meeting-prep.d.ts +12 -0
- package/dist/src/agent/workflow/builtins/meeting-prep.js +144 -0
- package/dist/src/agent/workflow/builtins/meeting-prep.js.map +1 -0
- package/dist/src/agent/workflow/builtins/offer-design.d.ts +12 -0
- package/dist/src/agent/workflow/builtins/offer-design.js +161 -0
- package/dist/src/agent/workflow/builtins/offer-design.js.map +1 -0
- package/dist/src/agent/workflow/builtins/weekly-review.d.ts +12 -0
- package/dist/src/agent/workflow/builtins/weekly-review.js +131 -0
- package/dist/src/agent/workflow/builtins/weekly-review.js.map +1 -0
- package/dist/src/agent/workflow/step-labels.js +2 -2
- package/dist/src/agent/workflow/step-labels.js.map +1 -1
- package/dist/src/agent/workflow/subagent-runner.js +3 -1
- package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
- package/dist/src/agent/workflow/types.d.ts +4 -0
- package/dist/src/chat-commands/agent-edit.d.ts +4 -0
- package/dist/src/chat-commands/agent-edit.js +136 -0
- package/dist/src/chat-commands/agent-edit.js.map +1 -0
- package/dist/src/chat-commands/index.d.ts +1 -0
- package/dist/src/chat-commands/index.js +3 -1
- package/dist/src/chat-commands/index.js.map +1 -1
- package/dist/src/cli/bin.js +2 -0
- package/dist/src/cli/bin.js.map +1 -1
- package/dist/src/cli/commands/cron.js +42 -3
- package/dist/src/cli/commands/cron.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/session-integrity.js +79 -56
- package/dist/src/cli/commands/doctor/checks/session-integrity.js.map +1 -1
- package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
- package/dist/src/cli/commands/update.js +86 -79
- package/dist/src/cli/commands/update.js.map +1 -1
- package/dist/src/commands/agents.config.d.ts +3 -2
- package/dist/src/commands/agents.config.js +5 -2
- package/dist/src/commands/agents.config.js.map +1 -1
- package/dist/src/config/agent-typed-models.d.ts +2 -7
- package/dist/src/config/agent-typed-models.js +3 -14
- package/dist/src/config/agent-typed-models.js.map +1 -1
- package/dist/src/config/localized-text.d.ts +6 -0
- package/dist/src/config/localized-text.js +42 -0
- package/dist/src/config/localized-text.js.map +1 -0
- package/dist/src/config/models-json.d.ts +6 -6
- package/dist/src/config/schema.d.ts +6 -21
- package/dist/src/config/schema.js +4 -4
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/cron/executor.d.ts +2 -0
- package/dist/src/cron/executor.js +111 -1
- package/dist/src/cron/executor.js.map +1 -1
- package/dist/src/cron/types.d.ts +8 -1
- package/dist/src/cron/validation.d.ts +4 -0
- package/dist/src/cron/validation.js +4 -3
- package/dist/src/cron/validation.js.map +1 -1
- package/dist/src/cron/workflow-run-completion.d.ts +23 -0
- package/dist/src/cron/workflow-run-completion.js +72 -0
- package/dist/src/cron/workflow-run-completion.js.map +1 -0
- package/dist/src/extensions/update.d.ts +51 -0
- package/dist/src/extensions/update.js +260 -0
- package/dist/src/extensions/update.js.map +1 -0
- package/dist/src/gateway/agents-admin.d.ts +15 -8
- package/dist/src/gateway/agents-admin.js +77 -28
- package/dist/src/gateway/agents-admin.js.map +1 -1
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +6 -0
- package/dist/src/gateway/hono/lib/config-payload.js +3 -1
- package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
- package/dist/src/gateway/hono/middleware/auth.d.ts +2 -0
- package/dist/src/gateway/hono/middleware/auth.js +11 -7
- package/dist/src/gateway/hono/middleware/auth.js.map +1 -1
- package/dist/src/gateway/hono/routes/agents.js +55 -12
- package/dist/src/gateway/hono/routes/agents.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/agents.js +1 -1
- package/dist/src/gateway/hono/routes/config-patch/gateway.d.ts +2 -2
- package/dist/src/gateway/hono/routes/config-patch/gateway.js +12 -0
- package/dist/src/gateway/hono/routes/config-patch/gateway.js.map +1 -1
- package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/notes.d.ts +3 -0
- package/dist/src/gateway/hono/routes/notes.js +274 -0
- package/dist/src/gateway/hono/routes/notes.js.map +1 -0
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/hono/routes/update.js +55 -107
- package/dist/src/gateway/hono/routes/update.js.map +1 -1
- package/dist/src/gateway/hono/routes/workflows.js +3 -1
- package/dist/src/gateway/hono/routes/workflows.js.map +1 -1
- package/dist/src/gateway/server.js +2 -0
- package/dist/src/gateway/server.js.map +1 -1
- package/dist/src/gateway/service.d.ts +3 -0
- package/dist/src/gateway/service.js +12 -1
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/workspace-ripgrep.d.ts +6 -0
- package/dist/src/gateway/workspace-ripgrep.js +62 -11
- package/dist/src/gateway/workspace-ripgrep.js.map +1 -1
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/infra/brew.d.ts +4 -0
- package/dist/src/infra/brew.js +20 -0
- package/dist/src/infra/brew.js.map +1 -0
- package/dist/src/infra/package-json.d.ts +2 -0
- package/dist/src/infra/package-json.js +23 -0
- package/dist/src/infra/package-json.js.map +1 -0
- package/dist/src/infra/package-update-steps.d.ts +35 -0
- package/dist/src/infra/package-update-steps.js +304 -0
- package/dist/src/infra/package-update-steps.js.map +1 -0
- package/dist/src/infra/path-env.d.ts +11 -0
- package/dist/src/infra/path-env.js +90 -0
- package/dist/src/infra/path-env.js.map +1 -0
- package/dist/src/infra/path-prepend.d.ts +7 -0
- package/dist/src/infra/path-prepend.js +44 -0
- package/dist/src/infra/path-prepend.js.map +1 -0
- package/dist/src/infra/stable-node-path.d.ts +2 -0
- package/dist/src/infra/stable-node-path.js +28 -0
- package/dist/src/infra/stable-node-path.js.map +1 -0
- package/dist/src/infra/update-global.d.ts +30 -23
- package/dist/src/infra/update-global.js +113 -64
- package/dist/src/infra/update-global.js.map +1 -1
- package/dist/src/infra/update-log.d.ts +1 -0
- package/dist/src/infra/update-log.js +12 -0
- package/dist/src/infra/update-log.js.map +1 -0
- package/dist/src/infra/update-restart.d.ts +20 -0
- package/dist/src/infra/update-restart.js +165 -0
- package/dist/src/infra/update-restart.js.map +1 -0
- package/dist/src/infra/update-runner.d.ts +89 -1
- package/dist/src/infra/update-runner.js +604 -173
- package/dist/src/infra/update-runner.js.map +1 -1
- package/dist/src/infra/update-startup.d.ts +3 -0
- package/dist/src/infra/update-startup.js +8 -4
- package/dist/src/infra/update-startup.js.map +1 -1
- package/dist/src/notes/attachment-ref.d.ts +9 -0
- package/dist/src/notes/attachment-ref.js +27 -0
- package/dist/src/notes/attachment-ref.js.map +1 -0
- package/dist/src/notes/index.d.ts +4 -0
- package/dist/src/notes/index.js +4 -0
- package/dist/src/notes/note-attachment-sync.d.ts +7 -0
- package/dist/src/notes/note-attachment-sync.js +46 -0
- package/dist/src/notes/note-attachment-sync.js.map +1 -0
- package/dist/src/notes/note-index-meta.d.ts +14 -0
- package/dist/src/notes/note-index-meta.js +87 -0
- package/dist/src/notes/note-index-meta.js.map +1 -0
- package/dist/src/notes/paths.d.ts +5 -0
- package/dist/src/notes/paths.js +23 -0
- package/dist/src/notes/paths.js.map +1 -0
- package/dist/src/notes/service.d.ts +42 -0
- package/dist/src/notes/service.js +331 -0
- package/dist/src/notes/service.js.map +1 -0
- package/dist/src/notes/store.d.ts +33 -0
- package/dist/src/notes/store.js +317 -0
- package/dist/src/notes/store.js.map +1 -0
- package/dist/src/notes/types.d.ts +162 -0
- package/dist/src/notes/types.js +1 -0
- package/dist/src/routing/resolve-route.d.ts +3 -1
- package/dist/src/routing/resolve-route.js.map +1 -1
- package/dist/src/session/store.d.ts +5 -3
- package/dist/src/session/store.js +66 -20
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/utils/logger/stats.d.ts +1 -1
- package/dist/src/workflows/domain/event.d.ts +3 -0
- package/dist/src/workflows/domain/run.d.ts +3 -0
- package/dist/src/workflows/domain/run.js.map +1 -1
- package/dist/src/workflows/engine/projector.js +17 -0
- package/dist/src/workflows/engine/projector.js.map +1 -1
- package/dist/src/workflows/engine/workflow-engine.js +127 -0
- package/dist/src/workflows/engine/workflow-engine.js.map +1 -1
- package/dist/src/workflows/index.js +1 -1
- package/dist/src/workflows/service/run-view-to-snapshot.js +3 -1
- package/dist/src/workflows/service/run-view-to-snapshot.js.map +1 -1
- package/dist/src/workflows/service/workflow-run-service.d.ts +1 -0
- package/dist/src/workflows/service/workflow-run-service.js +4 -1
- package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
- package/dist/src/workflows/service/workflow-session-bridge.js +1 -1
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/agents-B6PJB07W.js +0 -222
- package/dist/gateway/static/root/assets/apps-page-BOr0B1wv.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-BelUKggl.js +0 -1
- package/dist/gateway/static/root/assets/cron-api-CjOg-BIj.js +0 -1
- package/dist/gateway/static/root/assets/cron-dreaming-jobs-DueM3rBz.js +0 -2
- package/dist/gateway/static/root/assets/cron-page-DhoZmZXb.js +0 -1
- package/dist/gateway/static/root/assets/dist-6LecgDx5.js +0 -1
- package/dist/gateway/static/root/assets/dist-BTWC-BTN.js +0 -45
- package/dist/gateway/static/root/assets/index-CiN1cQiQ.css +0 -1
- package/dist/gateway/static/root/assets/logs-page-BwWLfqvd.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-DV5WN8uk.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-CfOBRbPX.js +0 -3
- package/dist/gateway/static/root/assets/share-preview-page-Di5Bzh4g.js +0 -2
- package/dist/gateway/static/root/assets/skills-page-D0H5Kaxg.js +0 -2
- package/dist/gateway/static/root/assets/url-aYn-Rj1C.js +0 -7
- package/dist/gateway/static/root/assets/vendor-codemirror-D0yxdRpg.js +0 -58
- package/dist/gateway/static/root/assets/voice-api-key-field-X2UfnHeq.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-BOPpO3NG.js +0 -27
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { CommandRunner } from './run-command.js';
|
|
2
|
+
import { type ResolvedGlobalInstallTarget } from './update-global.js';
|
|
3
|
+
export type PackageUpdateStepResult = {
|
|
4
|
+
name: string;
|
|
5
|
+
command: string;
|
|
6
|
+
cwd: string;
|
|
7
|
+
durationMs: number;
|
|
8
|
+
exitCode: number | null;
|
|
9
|
+
stdoutTail?: string | null;
|
|
10
|
+
stderrTail?: string | null;
|
|
11
|
+
};
|
|
12
|
+
export type PackageUpdateStepRunner = (params: {
|
|
13
|
+
name: string;
|
|
14
|
+
argv: string[];
|
|
15
|
+
cwd?: string;
|
|
16
|
+
timeoutMs: number;
|
|
17
|
+
env?: NodeJS.ProcessEnv;
|
|
18
|
+
}) => Promise<PackageUpdateStepResult>;
|
|
19
|
+
export declare function runGlobalPackageUpdateSteps(params: {
|
|
20
|
+
installTarget: ResolvedGlobalInstallTarget;
|
|
21
|
+
installSpec: string;
|
|
22
|
+
packageName: string;
|
|
23
|
+
packageRoot?: string | null;
|
|
24
|
+
runCommand: CommandRunner;
|
|
25
|
+
runStep: PackageUpdateStepRunner;
|
|
26
|
+
timeoutMs: number;
|
|
27
|
+
env?: NodeJS.ProcessEnv;
|
|
28
|
+
installCwd?: string;
|
|
29
|
+
}): Promise<{
|
|
30
|
+
steps: PackageUpdateStepResult[];
|
|
31
|
+
verifiedPackageRoot: string | null;
|
|
32
|
+
afterVersion: string | null;
|
|
33
|
+
failedStep: PackageUpdateStepResult | null;
|
|
34
|
+
}>;
|
|
35
|
+
export declare const DEFAULT_PACKAGE_NAME = "@xopcai/xopc";
|
|
@@ -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 path from "node:path";
|
|
4
|
+
import fs from "node:fs/promises";
|
|
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 os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import fs from "node:fs";
|
|
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,28 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
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"}
|