@neuralnomads/codenomad-dev 0.20.0-dev-20260925-25e07c74 → 0.20.0-dev-20260927-a77e37ef
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 +6 -6
- package/dist/opencode/runtime-support.js +1 -1
- package/dist/opencode/runtime-support.js.map +1 -1
- package/dist/opencode/runtime-support.test.js +2 -2
- package/dist/opencode/runtime-support.test.js.map +1 -1
- package/dist/opencode-update/incomplete-installation.js +25 -0
- package/dist/opencode-update/incomplete-installation.js.map +1 -0
- package/dist/opencode-update/incomplete-installation.test.js +99 -0
- package/dist/opencode-update/incomplete-installation.test.js.map +1 -0
- package/dist/opencode-update/service.test.js +7 -7
- package/dist/opencode-update/service.test.js.map +1 -1
- package/dist/opencode-update/shared-installation.js +10 -4
- package/dist/opencode-update/shared-installation.js.map +1 -1
- package/dist/plugins/session-pruning/plugin.mjs +1 -0
- package/package.json +3 -3
- package/public/assets/App-Bt-tnQXl.js +58 -0
- package/public/assets/App-Bt-tnQXl.js.map +1 -0
- package/public/assets/{FilesTab-CIZ1puTy.js → FilesTab-fonqwqxm.js} +3 -3
- package/public/assets/{FilesTab-CIZ1puTy.js.map → FilesTab-fonqwqxm.js.map} +1 -1
- package/public/assets/{GitChangesTab-DwMgRf-D.js → GitChangesTab-DsU2QupN.js} +3 -3
- package/public/assets/{GitChangesTab-DwMgRf-D.js.map → GitChangesTab-DsU2QupN.js.map} +1 -1
- package/public/assets/{SplitFilePanel-BCLtSYpn.js → SplitFilePanel-DVyHD97U.js} +2 -2
- package/public/assets/{SplitFilePanel-BCLtSYpn.js.map → SplitFilePanel-DVyHD97U.js.map} +1 -1
- package/public/assets/{StatusTab-I954HOlT.js → StatusTab-BYOUdsmS.js} +2 -2
- package/public/assets/{StatusTab-I954HOlT.js.map → StatusTab-BYOUdsmS.js.map} +1 -1
- package/public/assets/{align-justify-ClApgjuX.js → align-justify-DmcKEWsB.js} +2 -2
- package/public/assets/{align-justify-ClApgjuX.js.map → align-justify-DmcKEWsB.js.map} +1 -1
- package/public/assets/{bundle-full-Bv-Zo-BN.js → bundle-full-CV_LTEPl.js} +2 -2
- package/public/assets/{bundle-full-Bv-Zo-BN.js.map → bundle-full-CV_LTEPl.js.map} +1 -1
- package/public/assets/{client-state-BUfw9mlB.js → client-state-9tEzHtfW.js} +2 -2
- package/public/assets/{client-state-BUfw9mlB.js.map → client-state-9tEzHtfW.js.map} +1 -1
- package/public/assets/{diff-viewer-DTYmoMJJ.js → diff-viewer-CXCXiyRO.js} +2 -2
- package/public/assets/{diff-viewer-DTYmoMJJ.js.map → diff-viewer-CXCXiyRO.js.map} +1 -1
- package/public/assets/{index-CvvEjI09.js → index-97B_EqpY.js} +2 -2
- package/public/assets/{index-CvvEjI09.js.map → index-97B_EqpY.js.map} +1 -1
- package/public/assets/{index-B7Rzw0N8.js → index-B-_YmFJc.js} +2 -2
- package/public/assets/{index-B7Rzw0N8.js.map → index-B-_YmFJc.js.map} +1 -1
- package/public/assets/{index--pzZg96p.js → index-C5ZxyV3U.js} +2 -2
- package/public/assets/{index--pzZg96p.js.map → index-C5ZxyV3U.js.map} +1 -1
- package/public/assets/index-CDY1e4Uc.js +2 -0
- package/public/assets/{index-cCIfI5Gs.js.map → index-CDY1e4Uc.js.map} +1 -1
- package/public/assets/{index-ByEDZSKg.js → index-CuhtAbYJ.js} +3 -3
- package/public/assets/{index-ByEDZSKg.js.map → index-CuhtAbYJ.js.map} +1 -1
- package/public/assets/{index-kCzCI98C.js → index-CvKnyKel.js} +2 -2
- package/public/assets/{index-kCzCI98C.js.map → index-CvKnyKel.js.map} +1 -1
- package/public/assets/{index-q1q2jGr4.js → index-DX4zzTPL.js} +2 -2
- package/public/assets/{index-q1q2jGr4.js.map → index-DX4zzTPL.js.map} +1 -1
- package/public/assets/{index-QPxBkmUK.js → index-DY9ZO9ld.js} +2 -2
- package/public/assets/{index-QPxBkmUK.js.map → index-DY9ZO9ld.js.map} +1 -1
- package/public/assets/{index-CIsPS6rK.js → index-DqE-g5em.js} +2 -2
- package/public/assets/{index-CIsPS6rK.js.map → index-DqE-g5em.js.map} +1 -1
- package/public/assets/{index-Cq3k5jiZ.js → index-QXZuSZ1s.js} +2 -2
- package/public/assets/{index-Cq3k5jiZ.js.map → index-QXZuSZ1s.js.map} +1 -1
- package/public/assets/{index-DFYhjWFw.js → index-Ropj5M3p.js} +2 -2
- package/public/assets/{index-DFYhjWFw.js.map → index-Ropj5M3p.js.map} +1 -1
- package/public/assets/{index-BpxnUbDV.js → index-XQu8RsTR.js} +2 -2
- package/public/assets/{index-BpxnUbDV.js.map → index-XQu8RsTR.js.map} +1 -1
- package/public/assets/{loading-DUGpBMNV.js → loading-DMhZHPMZ.js} +2 -2
- package/public/assets/{loading-DUGpBMNV.js.map → loading-DMhZHPMZ.js.map} +1 -1
- package/public/assets/{main-CcoQlXKa.js → main-Y9fQI3c9.js} +20 -20
- package/public/assets/main-Y9fQI3c9.js.map +1 -0
- package/public/assets/{markdown-B2LqHvL9.js → markdown-ChsQ8753.js} +4 -4
- package/public/assets/{markdown-B2LqHvL9.js.map → markdown-ChsQ8753.js.map} +1 -1
- package/public/assets/{monaco-viewer-BQXd7g3w.js → monaco-viewer-C2EN1a6C.js} +13 -13
- package/public/assets/monaco-viewer-C2EN1a6C.js.map +1 -0
- package/public/assets/{startup-state-settings-card-BCKRPH7W.js → startup-state-settings-card-DlwE2O3S.js} +2 -2
- package/public/assets/{startup-state-settings-card-BCKRPH7W.js.map → startup-state-settings-card-DlwE2O3S.js.map} +1 -1
- package/public/assets/{terminal-square-BgSAfXCt.js → terminal-square-Br2FaCdg.js} +2 -2
- package/public/assets/{terminal-square-BgSAfXCt.js.map → terminal-square-Br2FaCdg.js.map} +1 -1
- package/public/assets/{tool-call-Df4j6aME.js → tool-call-DNxCNLt7.js} +4 -4
- package/public/assets/{tool-call-Df4j6aME.js.map → tool-call-DNxCNLt7.js.map} +1 -1
- package/public/assets/{unified-picker-DZfkh5jj.js → unified-picker-CPPucpt3.js} +2 -2
- package/public/assets/{unified-picker-DZfkh5jj.js.map → unified-picker-CPPucpt3.js.map} +1 -1
- package/public/assets/{wrap-text-BFsJjS2I.js → wrap-text-BJW9yImb.js} +2 -2
- package/public/assets/{wrap-text-BFsJjS2I.js.map → wrap-text-BJW9yImb.js.map} +1 -1
- package/public/index.html +3 -3
- package/public/loading.html +3 -3
- package/public/sw.js +1 -1
- package/public/sw.js.map +1 -1
- package/public/ui-version.json +1 -1
- package/public/assets/App-DJjznRZ_.js +0 -58
- package/public/assets/App-DJjznRZ_.js.map +0 -1
- package/public/assets/index-cCIfI5Gs.js +0 -2
- package/public/assets/main-CcoQlXKa.js.map +0 -1
- package/public/assets/monaco-viewer-BQXd7g3w.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# CodeNomad Server
|
|
2
2
|
|
|
3
|
-
**CodeNomad Server**
|
|
3
|
+
**CodeNomad Server** connects the desktop and browser UI to your projects and one shared OpenCode V2 background service. It provides workspace access, Git operations, authentication, and live event delivery. OpenCode owns the sessions, messages, and agent execution; closing CodeNomad leaves the shared OpenCode service running.
|
|
4
4
|
|
|
5
5
|
## Features & Capabilities
|
|
6
6
|
|
|
@@ -13,18 +13,18 @@
|
|
|
13
13
|
|
|
14
14
|
### ⚡️ Workspace Power
|
|
15
15
|
|
|
16
|
-
- **
|
|
17
|
-
- **Long
|
|
16
|
+
- **Multiple projects**: Work across project tabs and sessions over the same OpenCode service.
|
|
17
|
+
- **Long conversations**: Bounded transcript loading, full-history search, and timeline navigation.
|
|
18
18
|
- **Deep Task Awareness**: Monitor background tasks and child sessions without losing your flow.
|
|
19
19
|
- **Command Palette**: A single, global palette to jump tabs, launch tools, and fire shortcuts.
|
|
20
20
|
|
|
21
21
|
## Prerequisites
|
|
22
22
|
|
|
23
23
|
- **Git**: A prerequisite in the backend process's `PATH` for repository identity, Git operations and worktree management. Without Git, directory-only conversations in the explicitly opened physical folder remain available so the user can ask the agent for installation help. Owned session prompts/custom commands update the native `codenomad.git-availability` instruction; it reports the backend platform and is removed when Git becomes available. Git/worktree operations still fail explicitly with `503`/`git_required`. Install from https://git-scm.com/downloads and restart the backend after changing `PATH`. A Windows per-user installation is sufficient; Git inside WSL alone is insufficient for a Windows backend.
|
|
24
|
-
- **OpenCode V2**:
|
|
24
|
+
- **OpenCode V2**: For CodeNomad 0.20.0, install `opencode` **2.0.7 or later**, with **2.0.16 recommended and qualified**. The npm package is `@opencode/cli`; see the [V2 installation guide](https://opencode.ai/v2/docs/). CodeNomad prefers the CLI on `PATH` and also supports an explicitly selected executable. It uses the official service lifecycle and validates authenticated daemon metadata and API compatibility. V1 and former V2 beta runtimes are unsupported; custom/prerelease versions are unverified and still undergo contract validation. See [`runtime-support.ts`](src/opencode/runtime-support.ts) for the current requirements.
|
|
25
25
|
- **OpenCode data**: The global daemon owns its platform-default storage, database, and service registration. Configured startup environment applies only when CodeNomad starts a missing daemon; an existing daemon is unchanged.
|
|
26
26
|
- **Windows to WSL**: A configured WSL UNC binary uses Linux `service status`, `service start`, and `service get password`; Windows must have WSL localhost forwarding enabled to reach its loopback service.
|
|
27
|
-
- Node.js
|
|
27
|
+
- **Node.js and npm**: Use Node.js 24 LTS for the standalone server; source and release builds use [`.node-version`](../../.node-version) (currently 24.20.0). Desktop distributions bundle Node/npm.
|
|
28
28
|
- A workspace folder on disk you want to serve.
|
|
29
29
|
- Optional: a Chromium-based browser if you want `--launch` to open the UI automatically.
|
|
30
30
|
|
|
@@ -225,7 +225,7 @@ When running as a server CodeNomad can also be installed as a PWA from any suppo
|
|
|
225
225
|
- **OpenCode V2 sessions, messages, and service registration**: OpenCode's platform-default global locations.
|
|
226
226
|
- **Desktop restore state**: `~/.codenomad/client-state/v2/`
|
|
227
227
|
|
|
228
|
-
CodeNomad owns no private OpenCode port, database, service registration, or daemon PID.
|
|
228
|
+
CodeNomad owns no private OpenCode port, database, service registration, or daemon PID. Allowed profile environment variables and the current `NODE_EXTRA_CA_CERTS` are passed when starting a missing daemon; connecting to an existing daemon does not change its process environment. Separately, CodeNomad applies the profile's complete execution-host environment to the native session before each prompt, custom command, or session shell request, including removal of previously configured values. Legacy `OPENCODE_DB` and `XDG_STATE_HOME` ownership variables are ignored. See [Session Environment](../../dev-docs/SESSION_ENVIRONMENT.md). WSL lifecycle commands run inside Linux and never inspect or signal Linux PIDs from Windows.
|
|
229
229
|
|
|
230
230
|
Explicit **Stop Workspace** evicts that location and its resources from the global service without stopping the daemon. Closing a UI tab or native window only detaches local state and never evicts. Backend shutdown clears only CodeNomad's in-memory connection state and never stops the global service.
|
|
231
231
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export const MINIMUM_OPENCODE_VERSION = "2.0.7";
|
|
7
7
|
/** Qualification target, independent of the technically required minimum. */
|
|
8
|
-
export const RECOMMENDED_OPENCODE_VERSION = "2.0.
|
|
8
|
+
export const RECOMMENDED_OPENCODE_VERSION = "2.0.18";
|
|
9
9
|
export const OPENCODE_UPDATE_REQUIRED = "opencode_update_required";
|
|
10
10
|
export function isBelowOpenCodeMinimum(version) {
|
|
11
11
|
// These historical V2 beta publications predate the stable event contract.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-support.js","sourceRoot":"","sources":["../../src/opencode/runtime-support.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,OAAO,CAAA;AAC/C,6EAA6E;AAC7E,MAAM,CAAC,MAAM,4BAA4B,GAAG,QAAQ,CAAA;AACpD,MAAM,CAAC,MAAM,wBAAwB,GAAG,0BAA0B,CAAA;AAElE,MAAM,UAAU,sBAAsB,CAAC,OAAe;IACpD,2EAA2E;IAC3E,IAAI,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAA;IACnD,MAAM,KAAK,GAAG,qCAAqC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACjE,2EAA2E;IAC3E,4EAA4E;IAC5E,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAA;IACxB,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IACxD,MAAM,CAAC,YAAY,EAAE,YAAY,EAAE,YAAY,CAAC,GAAG,wBAAwB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IAClG,OAAO,KAAM,GAAG,YAAa,IAAI,CAAC,KAAK,KAAK,YAAY,IAAI,CAAC,KAAM,GAAG,YAAa;WAC9E,CAAC,KAAK,KAAK,YAAY,IAAI,KAAM,GAAG,YAAa,CAAC,CAAC,CAAC,CAAA;AAC3D,CAAC;AAID,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IAIjD,YAAqB,aAAqB,EAAW,SAAkC,gBAAgB;QACrG,KAAK,CAAC,GAAG,wBAAwB,cAAc,aAAa,KAAK,MAAM,KAAK,gBAAgB;YAC1F,CAAC,CAAC,iFAAiF,wBAAwB,EAAE;YAC7G,CAAC,CAAC,MAAM,KAAK,qBAAqB,CAAC,CAAC,CAAC,kEAAkE;gBACrG,CAAC,CAAC,gFAAgF,EAAE,CAAC,CAAA;QAJtE,kBAAa,GAAb,aAAa,CAAQ;QAAW,WAAM,GAAN,MAAM,CAA4C;QAH9F,SAAI,GAAG,wBAAwB,CAAA;QAC/B,eAAU,GAAG,GAAG,CAAA;QAChB,mBAAc,GAAG,wBAAwB,CAAA;QAMhD,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAA;IACxC,CAAC;CACF;AAED,MAAM,UAAU,uBAAuB,CAAC,OAAe;IACrD,IAAI,sBAAsB,CAAC,OAAO,CAAC;QAAE,MAAM,IAAI,wBAAwB,CAAC,OAAO,CAAC,CAAA;AAClF,CAAC","sourcesContent":["/**\n * 2.0.7 introduces session.step.started.data.started. The current Solid reducer\n * consumes this native timestamp directly; earlier releases need a retired\n * event adapter. This is a technical floor, not the latest qualified release.\n */\nexport const MINIMUM_OPENCODE_VERSION = \"2.0.7\"\n/** Qualification target, independent of the technically required minimum. */\nexport const RECOMMENDED_OPENCODE_VERSION = \"2.0.
|
|
1
|
+
{"version":3,"file":"runtime-support.js","sourceRoot":"","sources":["../../src/opencode/runtime-support.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,OAAO,CAAA;AAC/C,6EAA6E;AAC7E,MAAM,CAAC,MAAM,4BAA4B,GAAG,QAAQ,CAAA;AACpD,MAAM,CAAC,MAAM,wBAAwB,GAAG,0BAA0B,CAAA;AAElE,MAAM,UAAU,sBAAsB,CAAC,OAAe;IACpD,2EAA2E;IAC3E,IAAI,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAA;IACnD,MAAM,KAAK,GAAG,qCAAqC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACjE,2EAA2E;IAC3E,4EAA4E;IAC5E,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAA;IACxB,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IACxD,MAAM,CAAC,YAAY,EAAE,YAAY,EAAE,YAAY,CAAC,GAAG,wBAAwB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IAClG,OAAO,KAAM,GAAG,YAAa,IAAI,CAAC,KAAK,KAAK,YAAY,IAAI,CAAC,KAAM,GAAG,YAAa;WAC9E,CAAC,KAAK,KAAK,YAAY,IAAI,KAAM,GAAG,YAAa,CAAC,CAAC,CAAC,CAAA;AAC3D,CAAC;AAID,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IAIjD,YAAqB,aAAqB,EAAW,SAAkC,gBAAgB;QACrG,KAAK,CAAC,GAAG,wBAAwB,cAAc,aAAa,KAAK,MAAM,KAAK,gBAAgB;YAC1F,CAAC,CAAC,iFAAiF,wBAAwB,EAAE;YAC7G,CAAC,CAAC,MAAM,KAAK,qBAAqB,CAAC,CAAC,CAAC,kEAAkE;gBACrG,CAAC,CAAC,gFAAgF,EAAE,CAAC,CAAA;QAJtE,kBAAa,GAAb,aAAa,CAAQ;QAAW,WAAM,GAAN,MAAM,CAA4C;QAH9F,SAAI,GAAG,wBAAwB,CAAA;QAC/B,eAAU,GAAG,GAAG,CAAA;QAChB,mBAAc,GAAG,wBAAwB,CAAA;QAMhD,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAA;IACxC,CAAC;CACF;AAED,MAAM,UAAU,uBAAuB,CAAC,OAAe;IACrD,IAAI,sBAAsB,CAAC,OAAO,CAAC;QAAE,MAAM,IAAI,wBAAwB,CAAC,OAAO,CAAC,CAAA;AAClF,CAAC","sourcesContent":["/**\n * 2.0.7 introduces session.step.started.data.started. The current Solid reducer\n * consumes this native timestamp directly; earlier releases need a retired\n * event adapter. This is a technical floor, not the latest qualified release.\n */\nexport const MINIMUM_OPENCODE_VERSION = \"2.0.7\"\n/** Qualification target, independent of the technically required minimum. */\nexport const RECOMMENDED_OPENCODE_VERSION = \"2.0.18\"\nexport const OPENCODE_UPDATE_REQUIRED = \"opencode_update_required\"\n\nexport function isBelowOpenCodeMinimum(version: string): boolean {\n // These historical V2 beta publications predate the stable event contract.\n if (/^0\\.0\\.0-beta-\\d+$/.test(version)) return true\n const match = /^(\\d+)\\.(\\d+)\\.(\\d+)(?:\\+[\\w.-]+)?$/.exec(version)\n // Custom/prerelease labels are unverified, not automatically incompatible.\n // Their authenticated API contract is inspected before functional requests.\n if (!match) return false\n const [major, minor, patch] = match.slice(1).map(Number)\n const [minimumMajor, minimumMinor, minimumPatch] = MINIMUM_OPENCODE_VERSION.split(\".\").map(Number)\n return major! < minimumMajor! || (major === minimumMajor && (minor! < minimumMinor!\n || (minor === minimumMinor && patch! < minimumPatch!)))\n}\n\nexport type OpenCodeIncompatibility = \"step_timestamp\" | \"canonical_api\" | \"session_environment\"\n\nexport class UnsupportedOpenCodeError extends Error {\n readonly code = OPENCODE_UPDATE_REQUIRED\n readonly statusCode = 426\n readonly minimumVersion = MINIMUM_OPENCODE_VERSION\n constructor(readonly actualVersion: string, readonly reason: OpenCodeIncompatibility = \"step_timestamp\") {\n super(`${OPENCODE_UPDATE_REQUIRED}: OpenCode ${actualVersion}; ${reason === \"step_timestamp\"\n ? `requires the native session.step.started.data.started timestamp introduced in ${MINIMUM_OPENCODE_VERSION}`\n : reason === \"session_environment\" ? \"requires PUT /api/session/{sessionID}/environment with variables\"\n : \"does not expose the canonical session, permission, Form and inbox API contract\"}`)\n this.name = \"UnsupportedOpenCodeError\"\n }\n}\n\nexport function assertSupportedOpenCode(version: string): void {\n if (isBelowOpenCodeMinimum(version)) throw new UnsupportedOpenCodeError(version)\n}\n"]}
|
|
@@ -5,8 +5,8 @@ import { rememberRuntime } from "./compatibility/runtime";
|
|
|
5
5
|
import { OpenCodeSharedService } from "../workspaces/opencode-service";
|
|
6
6
|
test("native timestamp minimum is distinct from recommendation and unfamiliar version labels", () => {
|
|
7
7
|
assert.equal(MINIMUM_OPENCODE_VERSION, "2.0.7");
|
|
8
|
-
assert.equal(RECOMMENDED_OPENCODE_VERSION, "2.0.
|
|
9
|
-
for (const version of ["2.0.7", "2.0.8", "2.0.9", "2.0.10", "2.0.11", "2.0.12", "2.0.13", "2.0.14", "2.0.15", "2.0.16", "2.1.0", "2.0.
|
|
8
|
+
assert.equal(RECOMMENDED_OPENCODE_VERSION, "2.0.18");
|
|
9
|
+
for (const version of ["2.0.7", "2.0.8", "2.0.9", "2.0.10", "2.0.11", "2.0.12", "2.0.13", "2.0.14", "2.0.15", "2.0.16", "2.0.17", "2.0.18", "2.1.0", "2.0.18-dev.1", "3.0.0", "custom-build"]) {
|
|
10
10
|
assert.equal(isBelowOpenCodeMinimum(version), false, version);
|
|
11
11
|
}
|
|
12
12
|
for (const version of ["2.0.0", "2.0.4", "2.0.5", "2.0.6", "0.0.0-beta-19507"])
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-support.test.js","sourceRoot":"","sources":["../../src/opencode/runtime-support.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAA;AACvC,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,wBAAwB,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAA;AAC5I,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAA;AAEtE,IAAI,CAAC,wFAAwF,EAAE,GAAG,EAAE;IAClG,MAAM,CAAC,KAAK,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAA;IAC/C,MAAM,CAAC,KAAK,CAAC,4BAA4B,EAAE,QAAQ,CAAC,CAAA;IACpD,KAAK,MAAM,OAAO,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,cAAc,CAAC,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime-support.test.js","sourceRoot":"","sources":["../../src/opencode/runtime-support.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAA;AACvC,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,wBAAwB,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAA;AAC5I,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAA;AAEtE,IAAI,CAAC,wFAAwF,EAAE,GAAG,EAAE;IAClG,MAAM,CAAC,KAAK,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAA;IAC/C,MAAM,CAAC,KAAK,CAAC,4BAA4B,EAAE,QAAQ,CAAC,CAAA;IACpD,KAAK,MAAM,OAAO,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,cAAc,CAAC,EAAE,CAAC;QAC9L,MAAM,CAAC,KAAK,CAAC,sBAAsB,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAA;IAC/D,CAAC;IACD,KAAK,MAAM,OAAO,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,kBAAkB,CAAC;QAAE,MAAM,CAAC,KAAK,CAAC,sBAAsB,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;AAC9I,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,6EAA6E,EAAE,KAAK,IAAI,EAAE;IAC7F,IAAI,WAAW,GAAG,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAA;IACjC,MAAM,QAAQ,GAAa,EAAE,GAAG,EAAE,uBAAuB,EAAE,CAAA;IAC3D,eAAe,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAA;IAC1E,MAAM,OAAO,GAAG,IAAI,qBAAqB,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,aAAa,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,WAAW,EAAE,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,aAAa,CAAC,CAAA,CAAC,CAAC,EAAE,CAAC,CAAA;IACjK,MAAM,OAAO,GAAG,EAAE,IAAI,EAAE,WAAoB,EAAE,QAAQ,EAAE,SAAS;QAC/D,SAAS,EAAE,EAAE,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAA,CAAC,CAAC,EAAE;QACxG,qBAAqB,EAAE,KAAK,IAAI,EAAE,GAAG,QAAQ,EAAE,CAAC,CAAC,OAAO,IAAI,CAAA,CAAC,CAAC,GAC/D,CAAA;IACD,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,KAAc,EAAE,EAAE,CAAC,KAAK,YAAY,wBAAwB;WACtG,KAAK,CAAC,aAAa,KAAK,OAAO,IAAI,KAAK,CAAC,cAAc,KAAK,OAAO,IAAI,KAAK,CAAC,MAAM,KAAK,gBAAgB,CAAC,CAAA;IAC9G,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAA;IAC5B,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;AAC3B,CAAC,CAAC,CAAA","sourcesContent":["import assert from \"node:assert/strict\"\nimport test from \"node:test\"\nimport type { Endpoint } from \"@opencode/client/service\"\nimport { isBelowOpenCodeMinimum, UnsupportedOpenCodeError, MINIMUM_OPENCODE_VERSION, RECOMMENDED_OPENCODE_VERSION } from \"./runtime-support\"\nimport { rememberRuntime } from \"./compatibility/runtime\"\nimport { OpenCodeSharedService } from \"../workspaces/opencode-service\"\n\ntest(\"native timestamp minimum is distinct from recommendation and unfamiliar version labels\", () => {\n assert.equal(MINIMUM_OPENCODE_VERSION, \"2.0.7\")\n assert.equal(RECOMMENDED_OPENCODE_VERSION, \"2.0.18\")\n for (const version of [\"2.0.7\", \"2.0.8\", \"2.0.9\", \"2.0.10\", \"2.0.11\", \"2.0.12\", \"2.0.13\", \"2.0.14\", \"2.0.15\", \"2.0.16\", \"2.0.17\", \"2.0.18\", \"2.1.0\", \"2.0.18-dev.1\", \"3.0.0\", \"custom-build\"]) {\n assert.equal(isBelowOpenCodeMinimum(version), false, version)\n }\n for (const version of [\"2.0.0\", \"2.0.4\", \"2.0.5\", \"2.0.6\", \"0.0.0-beta-19507\"]) assert.equal(isBelowOpenCodeMinimum(version), true, version)\n})\n\ntest(\"refuses old authenticated daemons before client calls or plugin preparation\", async () => {\n let constructed = 0, prepared = 0\n const endpoint: Endpoint = { url: \"http://127.0.0.1:4321\" }\n rememberRuntime(endpoint, { version: \"2.0.6\", pid: 1, discovery: \"info\" })\n const service = new OpenCodeSharedService({ headers: () => ({ authorization: \"fixture\" }), makeClient: () => { constructed++; throw new Error(\"not reached\") } })\n const options = { kind: \"lifecycle\" as const, identity: \"fixture\",\n lifecycle: { discover: async () => endpoint, ensure: async () => { throw new Error(\"must not start\") } },\n prepareDesktopPlugins: async () => { prepared++; return true },\n }\n await assert.rejects(service.client(options), (error: unknown) => error instanceof UnsupportedOpenCodeError\n && error.actualVersion === \"2.0.6\" && error.minimumVersion === \"2.0.7\" && error.reason === \"step_timestamp\")\n assert.equal(constructed, 0)\n assert.equal(prepared, 0)\n})\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
/** npm can remove a failed package but leave its terminal shims behind. Only
|
|
4
|
+
* recognize its exact native-executable shim in the chosen user prefix; never
|
|
5
|
+
* adopt a custom wrapper, another prefix, or an existing executable for repair. */
|
|
6
|
+
export function isIncompleteWindowsNpmShim(command, prefix, binary) {
|
|
7
|
+
if (path.resolve(path.dirname(command)) !== path.resolve(prefix)
|
|
8
|
+
|| !/^opencode2?\.cmd$/i.test(path.basename(command)) || existsSync(binary))
|
|
9
|
+
return false;
|
|
10
|
+
try {
|
|
11
|
+
const script = readFileSync(command, "utf8");
|
|
12
|
+
if (script.length > 4096)
|
|
13
|
+
return false;
|
|
14
|
+
const expected = [
|
|
15
|
+
"@ECHO off", "GOTO start", ":find_dp0", "SET dp0=%~dp0", "EXIT /b", ":start", "SETLOCAL", "CALL :find_dp0",
|
|
16
|
+
'"%dp0%\\node_modules\\@opencode\\cli\\bin\\opencode.exe" %*',
|
|
17
|
+
];
|
|
18
|
+
const lines = script.trim().split(/\r?\n/).map(line => line.trim().replace(/\s+%\*$/, " %*"));
|
|
19
|
+
return lines.length === expected.length && lines.every((line, index) => line === expected[index]);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=incomplete-installation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"incomplete-installation.js","sourceRoot":"","sources":["../../src/opencode-update/incomplete-installation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B;;mFAEmF;AACnF,MAAM,UAAU,0BAA0B,CAAC,OAAe,EAAE,MAAc,EAAE,MAAc;IACxF,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;WAC3D,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAA;IAC3F,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QAC5C,IAAI,MAAM,CAAC,MAAM,GAAG,IAAI;YAAE,OAAO,KAAK,CAAA;QACtC,MAAM,QAAQ,GAAG;YACf,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,gBAAgB;YAC1G,6DAA6D;SAC9D,CAAA;QACD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAA;QAC7F,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,KAAK,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAA;IACnG,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,KAAK,CAAA;IAAC,CAAC;AAC1B,CAAC","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\"\nimport path from \"node:path\"\n\n/** npm can remove a failed package but leave its terminal shims behind. Only\n * recognize its exact native-executable shim in the chosen user prefix; never\n * adopt a custom wrapper, another prefix, or an existing executable for repair. */\nexport function isIncompleteWindowsNpmShim(command: string, prefix: string, binary: string): boolean {\n if (path.resolve(path.dirname(command)) !== path.resolve(prefix)\n || !/^opencode2?\\.cmd$/i.test(path.basename(command)) || existsSync(binary)) return false\n try {\n const script = readFileSync(command, \"utf8\")\n if (script.length > 4096) return false\n const expected = [\n \"@ECHO off\", \"GOTO start\", \":find_dp0\", \"SET dp0=%~dp0\", \"EXIT /b\", \":start\", \"SETLOCAL\", \"CALL :find_dp0\",\n '\"%dp0%\\\\node_modules\\\\@opencode\\\\cli\\\\bin\\\\opencode.exe\" %*',\n ]\n const lines = script.trim().split(/\\r?\\n/).map(line => line.trim().replace(/\\s+%\\*$/, \" %*\"))\n return lines.length === expected.length && lines.every((line, index) => line === expected[index])\n } catch { return false }\n}\n"]}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { mkdtemp, mkdir, writeFile, readFile, rm } from "node:fs/promises";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { isIncompleteWindowsNpmShim } from "./incomplete-installation";
|
|
7
|
+
import { installSharedOpenCode, npmExecutable, resolveDefaultInstallation, sharedInstallPrefix } from "./shared-installation";
|
|
8
|
+
import { OpenCodeUpdateService } from "./service";
|
|
9
|
+
const shim = '@ECHO off\r\nGOTO start\r\n:find_dp0\r\nSET dp0=%~dp0\r\nEXIT /b\r\n:start\r\nSETLOCAL\r\nCALL :find_dp0\r\n"%dp0%\\node_modules\\@opencode\\cli\\bin\\opencode.exe" %*\r\n';
|
|
10
|
+
test("failed npm installation remains repairable with orphan shims and no package manifest", async () => {
|
|
11
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "opencode-incomplete-"));
|
|
12
|
+
try {
|
|
13
|
+
const prefix = path.join(root, "npm");
|
|
14
|
+
await mkdir(prefix);
|
|
15
|
+
const command = path.join(prefix, "opencode2.cmd");
|
|
16
|
+
await writeFile(command, shim);
|
|
17
|
+
await writeFile(path.join(prefix, "opencode.cmd"), shim);
|
|
18
|
+
const host = { home: root, platform: "win32", env: { PATH: "", npm_config_prefix: prefix } };
|
|
19
|
+
assert.equal(sharedInstallPrefix(host), prefix, "initial failure before PATH registration must allow retry");
|
|
20
|
+
host.env.PATH = prefix;
|
|
21
|
+
assert.equal(sharedInstallPrefix(host), prefix);
|
|
22
|
+
assert.deepEqual(resolveDefaultInstallation(host), { path: npmExecutable(prefix, "win32"), source: "user" }, "probe the missing executable instead of reporting an invalid cmd wrapper");
|
|
23
|
+
const binary = npmExecutable(prefix, "win32");
|
|
24
|
+
await mkdir(path.dirname(binary), { recursive: true });
|
|
25
|
+
await writeFile(binary, "existing unverified executable");
|
|
26
|
+
assert.equal(sharedInstallPrefix(host), undefined, "existing unverified binaries are not incomplete installs");
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
await rm(root, { recursive: true, force: true });
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
test("an explicit retry repairs leftover launchers and restores update status", { skip: process.platform !== "win32" }, async () => {
|
|
33
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "opencode-retry-"));
|
|
34
|
+
try {
|
|
35
|
+
const prefix = path.join(root, "npm");
|
|
36
|
+
await mkdir(prefix);
|
|
37
|
+
await writeFile(path.join(prefix, "opencode2.cmd"), shim);
|
|
38
|
+
const host = { home: root, env: { PATH: prefix, npm_config_prefix: prefix } };
|
|
39
|
+
const binary = npmExecutable(prefix);
|
|
40
|
+
const probe = async (file) => {
|
|
41
|
+
try {
|
|
42
|
+
return { valid: true, version: await readFile(file.endsWith(".cmd") ? binary : file, "utf8") };
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return { valid: false, missing: true };
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
let installs = 0;
|
|
49
|
+
const service = new OpenCodeUpdateService({
|
|
50
|
+
resolveBinary: () => ({ ...resolveDefaultInstallation(host), label: "fixture" }),
|
|
51
|
+
probeBinary: probe,
|
|
52
|
+
resolveLatestVersion: async () => "2.0.16",
|
|
53
|
+
canUpgradeBinary: () => Boolean(sharedInstallPrefix(host)),
|
|
54
|
+
upgradeBinary: async (_binary, version) => {
|
|
55
|
+
await installSharedOpenCode(version, { ...host, npm: "fixture-npm.js", probe, registerPath: async () => { },
|
|
56
|
+
execute: async () => {
|
|
57
|
+
installs++;
|
|
58
|
+
await mkdir(path.dirname(binary), { recursive: true });
|
|
59
|
+
await writeFile(binary, version);
|
|
60
|
+
await writeFile(path.join(path.dirname(binary), "../package.json"), JSON.stringify({
|
|
61
|
+
name: "@opencode/cli", bin: { opencode2: "./bin/opencode.exe" },
|
|
62
|
+
}));
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
return { success: true, version };
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
const before = await service.getStatus();
|
|
69
|
+
assert.equal(before.state, "missing");
|
|
70
|
+
assert.equal(before.canUpgrade, true, "the install button remains available after the failed npm cleanup");
|
|
71
|
+
await service.upgrade();
|
|
72
|
+
assert.equal(installs, 1);
|
|
73
|
+
assert.equal(sharedInstallPrefix(host), prefix);
|
|
74
|
+
assert.equal(resolveDefaultInstallation(host).source, "path");
|
|
75
|
+
assert.equal((await service.getStatus()).state, "ready");
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
await rm(root, { recursive: true, force: true });
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
test("incomplete-installation recovery does not adopt custom wrappers or other prefixes", async () => {
|
|
82
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "opencode-incomplete-authority-"));
|
|
83
|
+
try {
|
|
84
|
+
const command = path.join(root, "opencode2.cmd");
|
|
85
|
+
const binary = npmExecutable(root, "win32");
|
|
86
|
+
await writeFile(command, shim);
|
|
87
|
+
assert.equal(isIncompleteWindowsNpmShim(command, root, binary), true);
|
|
88
|
+
assert.equal(isIncompleteWindowsNpmShim(command, path.join(root, "other"), binary), false);
|
|
89
|
+
for (const custom of [shim + 'echo custom\r\n', shim.replace('opencode.exe', 'custom.exe'),
|
|
90
|
+
'@echo off\r\n"%~dp0\\node_modules\\@opencode\\cli\\bin\\opencode.exe" %*\r\n']) {
|
|
91
|
+
await writeFile(command, custom);
|
|
92
|
+
assert.equal(isIncompleteWindowsNpmShim(command, root, binary), false);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
await rm(root, { recursive: true, force: true });
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
//# sourceMappingURL=incomplete-installation.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"incomplete-installation.test.js","sourceRoot":"","sources":["../../src/opencode-update/incomplete-installation.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAA;AACvC,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAA;AAC1E,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAA;AACtE,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAC7H,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAA;AAEjD,MAAM,IAAI,GAAG,+KAA+K,CAAA;AAE5L,IAAI,CAAC,sFAAsF,EAAE,KAAK,IAAI,EAAE;IACtG,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,sBAAsB,CAAC,CAAC,CAAA;IAC1E,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QACrC,MAAM,KAAK,CAAC,MAAM,CAAC,CAAA;QACnB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;QAClD,MAAM,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;QAC9B,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,IAAI,CAAC,CAAA;QACxD,MAAM,IAAI,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAgB,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,EAAE,EAAE,CAAA;QACrG,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,2DAA2D,CAAC,CAAA;QAC5G,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,MAAM,CAAA;QACtB,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAA;QAC/C,MAAM,CAAC,SAAS,CAAC,0BAA0B,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EACzG,0EAA0E,CAAC,CAAA;QAC7E,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC7C,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACtD,MAAM,SAAS,CAAC,MAAM,EAAE,gCAAgC,CAAC,CAAA;QACzD,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,0DAA0D,CAAC,CAAA;IAChH,CAAC;YAAS,CAAC;QAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IAAC,CAAC;AAChE,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,yEAAyE,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,EAAE,KAAK,IAAI,EAAE;IACjI,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAA;IACrE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QACrC,MAAM,KAAK,CAAC,MAAM,CAAC,CAAA;QACnB,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,EAAE,IAAI,CAAC,CAAA;QACzD,MAAM,IAAI,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,EAAE,CAAA;QAC7E,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,CAAA;QACpC,MAAM,KAAK,GAAG,KAAK,EAAE,IAAY,EAAE,EAAE;YACnC,IAAI,CAAC;gBAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAA;YAAC,CAAC;YACtG,MAAM,CAAC;gBAAC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;YAAC,CAAC;QAClD,CAAC,CAAA;QACD,IAAI,QAAQ,GAAG,CAAC,CAAA;QAChB,MAAM,OAAO,GAAG,IAAI,qBAAqB,CAAC;YACxC,aAAa,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,0BAA0B,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;YAChF,WAAW,EAAE,KAAK;YAClB,oBAAoB,EAAE,KAAK,IAAI,EAAE,CAAC,QAAQ;YAC1C,gBAAgB,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;YAC1D,aAAa,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;gBACxC,MAAM,qBAAqB,CAAC,OAAO,EAAE,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,gBAAgB,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;oBACxG,OAAO,EAAE,KAAK,IAAI,EAAE;wBAClB,QAAQ,EAAE,CAAA;wBACV,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;wBACtD,MAAM,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;wBAChC,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC;4BACjF,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,oBAAoB,EAAE;yBAChE,CAAC,CAAC,CAAA;oBACL,CAAC;iBACF,CAAC,CAAA;gBACF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;YACnC,CAAC;SACF,CAAC,CAAA;QACF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,SAAS,EAAE,CAAA;QACxC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA;QACrC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,mEAAmE,CAAC,CAAA;QAC1G,MAAM,OAAO,CAAC,OAAO,EAAE,CAAA;QACvB,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;QACzB,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAA;QAC/C,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAC7D,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;IAC1D,CAAC;YAAS,CAAC;QAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IAAC,CAAC;AAChE,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,mFAAmF,EAAE,KAAK,IAAI,EAAE;IACnG,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,gCAAgC,CAAC,CAAC,CAAA;IACpF,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,eAAe,CAAC,CAAA;QAChD,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;QAC3C,MAAM,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;QAC9B,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,CAAA;QACrE,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,EAAE,KAAK,CAAC,CAAA;QAC1F,KAAK,MAAM,MAAM,IAAI,CAAC,IAAI,GAAG,iBAAiB,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,YAAY,CAAC;YACxF,8EAA8E,CAAC,EAAE,CAAC;YAClF,MAAM,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;YAChC,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,KAAK,CAAC,CAAA;QACxE,CAAC;IACH,CAAC;YAAS,CAAC;QAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IAAC,CAAC;AAChE,CAAC,CAAC,CAAA","sourcesContent":["import assert from \"node:assert/strict\"\nimport test from \"node:test\"\nimport { mkdtemp, mkdir, writeFile, readFile, rm } from \"node:fs/promises\"\nimport os from \"node:os\"\nimport path from \"node:path\"\nimport { isIncompleteWindowsNpmShim } from \"./incomplete-installation\"\nimport { installSharedOpenCode, npmExecutable, resolveDefaultInstallation, sharedInstallPrefix } from \"./shared-installation\"\nimport { OpenCodeUpdateService } from \"./service\"\n\nconst shim = '@ECHO off\\r\\nGOTO start\\r\\n:find_dp0\\r\\nSET dp0=%~dp0\\r\\nEXIT /b\\r\\n:start\\r\\nSETLOCAL\\r\\nCALL :find_dp0\\r\\n\"%dp0%\\\\node_modules\\\\@opencode\\\\cli\\\\bin\\\\opencode.exe\" %*\\r\\n'\n\ntest(\"failed npm installation remains repairable with orphan shims and no package manifest\", async () => {\n const root = await mkdtemp(path.join(os.tmpdir(), \"opencode-incomplete-\"))\n try {\n const prefix = path.join(root, \"npm\")\n await mkdir(prefix)\n const command = path.join(prefix, \"opencode2.cmd\")\n await writeFile(command, shim)\n await writeFile(path.join(prefix, \"opencode.cmd\"), shim)\n const host = { home: root, platform: \"win32\" as const, env: { PATH: \"\", npm_config_prefix: prefix } }\n assert.equal(sharedInstallPrefix(host), prefix, \"initial failure before PATH registration must allow retry\")\n host.env.PATH = prefix\n assert.equal(sharedInstallPrefix(host), prefix)\n assert.deepEqual(resolveDefaultInstallation(host), { path: npmExecutable(prefix, \"win32\"), source: \"user\" },\n \"probe the missing executable instead of reporting an invalid cmd wrapper\")\n const binary = npmExecutable(prefix, \"win32\")\n await mkdir(path.dirname(binary), { recursive: true })\n await writeFile(binary, \"existing unverified executable\")\n assert.equal(sharedInstallPrefix(host), undefined, \"existing unverified binaries are not incomplete installs\")\n } finally { await rm(root, { recursive: true, force: true }) }\n})\n\ntest(\"an explicit retry repairs leftover launchers and restores update status\", { skip: process.platform !== \"win32\" }, async () => {\n const root = await mkdtemp(path.join(os.tmpdir(), \"opencode-retry-\"))\n try {\n const prefix = path.join(root, \"npm\")\n await mkdir(prefix)\n await writeFile(path.join(prefix, \"opencode2.cmd\"), shim)\n const host = { home: root, env: { PATH: prefix, npm_config_prefix: prefix } }\n const binary = npmExecutable(prefix)\n const probe = async (file: string) => {\n try { return { valid: true, version: await readFile(file.endsWith(\".cmd\") ? binary : file, \"utf8\") } }\n catch { return { valid: false, missing: true } }\n }\n let installs = 0\n const service = new OpenCodeUpdateService({\n resolveBinary: () => ({ ...resolveDefaultInstallation(host), label: \"fixture\" }),\n probeBinary: probe,\n resolveLatestVersion: async () => \"2.0.16\",\n canUpgradeBinary: () => Boolean(sharedInstallPrefix(host)),\n upgradeBinary: async (_binary, version) => {\n await installSharedOpenCode(version, { ...host, npm: \"fixture-npm.js\", probe, registerPath: async () => {},\n execute: async () => {\n installs++\n await mkdir(path.dirname(binary), { recursive: true })\n await writeFile(binary, version)\n await writeFile(path.join(path.dirname(binary), \"../package.json\"), JSON.stringify({\n name: \"@opencode/cli\", bin: { opencode2: \"./bin/opencode.exe\" },\n }))\n },\n })\n return { success: true, version }\n },\n })\n const before = await service.getStatus()\n assert.equal(before.state, \"missing\")\n assert.equal(before.canUpgrade, true, \"the install button remains available after the failed npm cleanup\")\n await service.upgrade()\n assert.equal(installs, 1)\n assert.equal(sharedInstallPrefix(host), prefix)\n assert.equal(resolveDefaultInstallation(host).source, \"path\")\n assert.equal((await service.getStatus()).state, \"ready\")\n } finally { await rm(root, { recursive: true, force: true }) }\n})\n\ntest(\"incomplete-installation recovery does not adopt custom wrappers or other prefixes\", async () => {\n const root = await mkdtemp(path.join(os.tmpdir(), \"opencode-incomplete-authority-\"))\n try {\n const command = path.join(root, \"opencode2.cmd\")\n const binary = npmExecutable(root, \"win32\")\n await writeFile(command, shim)\n assert.equal(isIncompleteWindowsNpmShim(command, root, binary), true)\n assert.equal(isIncompleteWindowsNpmShim(command, path.join(root, \"other\"), binary), false)\n for (const custom of [shim + 'echo custom\\r\\n', shim.replace('opencode.exe', 'custom.exe'),\n '@echo off\\r\\n\"%~dp0\\\\node_modules\\\\@opencode\\\\cli\\\\bin\\\\opencode.exe\" %*\\r\\n']) {\n await writeFile(command, custom)\n assert.equal(isIncompleteWindowsNpmShim(command, root, binary), false)\n }\n } finally { await rm(root, { recursive: true, force: true }) }\n})\n"]}
|
|
@@ -262,28 +262,28 @@ test("an in-flight native reload holds shared-service authority across binary ch
|
|
|
262
262
|
test("beta version comparison remains numeric", () => {
|
|
263
263
|
assert.equal(compareOpenCodeVersionStrings("0.0.0-beta-10000", "0.0.0-beta-9999") > 0, true);
|
|
264
264
|
});
|
|
265
|
-
test("2.0.7 through 2.0.
|
|
266
|
-
for (const version of ["2.0.7", "2.0.8", "2.0.9", "2.0.10", "2.0.11", "2.0.12", "2.0.13", "2.0.14", "2.0.15", "2.0.16"]) {
|
|
265
|
+
test("2.0.7 through 2.0.18 remain usable; recommendation only offers an optional update", async () => {
|
|
266
|
+
for (const version of ["2.0.7", "2.0.8", "2.0.9", "2.0.10", "2.0.11", "2.0.12", "2.0.13", "2.0.14", "2.0.15", "2.0.16", "2.0.17", "2.0.18"]) {
|
|
267
267
|
const endpoint = { url: "http://127.0.0.1:9876" };
|
|
268
268
|
rememberRuntime(endpoint, { version, pid: 123, discovery: "info" });
|
|
269
269
|
const service = new OpenCodeUpdateService(deps({
|
|
270
|
-
probeBinary: () => ({ valid: true, version }), resolveLatestVersion: async () => "2.0.
|
|
270
|
+
probeBinary: () => ({ valid: true, version }), resolveLatestVersion: async () => "2.0.18",
|
|
271
271
|
lifecycle: async () => ({ discover: async () => endpoint, ensure: async () => { throw new Error("must retain daemon"); } }),
|
|
272
272
|
}));
|
|
273
273
|
const status = await service.start();
|
|
274
274
|
assert.equal(status.minimumVersion, "2.0.7");
|
|
275
|
-
assert.equal(status.recommendedVersion, "2.0.
|
|
275
|
+
assert.equal(status.recommendedVersion, "2.0.18");
|
|
276
276
|
assert.equal(status.state, "ready");
|
|
277
277
|
assert.equal(status.serviceState, "ready");
|
|
278
|
-
assert.equal(status.versionAssessment, version === "2.0.
|
|
278
|
+
assert.equal(status.versionAssessment, version === "2.0.18" ? "tested" : "untested", "only the current recommendation is release-qualified");
|
|
279
279
|
assert.equal(status.incompatibilityReason, undefined);
|
|
280
|
-
assert.equal(status.canUpgrade, version !== "2.0.
|
|
280
|
+
assert.equal(status.canUpgrade, version !== "2.0.18");
|
|
281
281
|
assert.equal(status.canRestart, false);
|
|
282
282
|
}
|
|
283
283
|
});
|
|
284
284
|
test("a current daemon remains usable through an older selected discovery CLI", async () => {
|
|
285
285
|
const endpoint = { url: "http://127.0.0.1:9876" };
|
|
286
|
-
rememberRuntime(endpoint, { version: "2.0.
|
|
286
|
+
rememberRuntime(endpoint, { version: "2.0.18", pid: 123, discovery: "info" });
|
|
287
287
|
const service = new OpenCodeUpdateService(deps({
|
|
288
288
|
probeBinary: () => ({ valid: true, version: "2.0.3" }),
|
|
289
289
|
lifecycle: async () => ({ discover: async () => endpoint, ensure: async () => { throw new Error("must retain daemon"); } }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.test.js","sourceRoot":"","sources":["../../src/opencode-update/service.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\"\nimport test from \"node:test\"\nimport { OpenCodeUpdateService, OpenCodeUpdateError,\n resolveLatestOpenCodeVersion, compareOpenCodeVersionStrings,\n type OpenCodeUpdateServiceDeps } from \"./service\"\nimport { MINIMUM_OPENCODE_VERSION as minimum } from \"../opencode/runtime-support\"\nimport { rememberRuntime } from \"../opencode/compatibility/runtime\"\nimport type { Endpoint } from \"@opencode/client/service\"\nimport { probeBinaryVersion } from \"../workspaces/spawn\"\n\nfunction deps(overrides: Partial<OpenCodeUpdateServiceDeps> = {}): OpenCodeUpdateServiceDeps {\n let version = \"0.0.0-beta-19271\"\n return {\n resolveBinary: () => ({ path: \"opencode2\", label: \"OpenCode\" }),\n probeBinary: () => ({ valid: true, version }),\n resolveLatestVersion: async () => minimum,\n canUpgradeBinary: () => true,\n upgradeBinary: async (_binary, target) => { version = target; return { success: true, version: target } },\n inspectRuntime: async () => ({ reload: true }),\n ...overrides,\n }\n}\n\ntest(\"missing installs and old releases use one updater; probe failures are not absence\", async () => {\n for (const initial of [undefined, \"0.0.0-beta-19271\", \"2.0.6\"]) {\n let version = initial\n const service = new OpenCodeUpdateService(deps({\n probeBinary: () => version ? { valid: true, version } : { valid: false, missing: true },\n upgradeBinary: async (_binary, target) => { version = target; return { success: true, version: target } },\n }))\n const status = await service.getStatus()\n assert.equal(status.state, initial ? \"update_required\" : \"missing\")\n assert.equal(status.minimumVersion, minimum)\n assert.equal(status.canUpgrade, true)\n assert.deepEqual(await service.upgrade(), { success: true, version: minimum })\n assert.equal((await service.getStatus()).state, \"ready\")\n }\n const invalid = new OpenCodeUpdateService(deps({ probeBinary: () => ({ valid: false, error: \"EACCES\" }) }))\n assert.equal((await invalid.getStatus()).state, \"error\")\n assert.equal((await invalid.getStatus()).canUpgrade, false)\n await assert.rejects(invalid.upgrade(), (error: unknown) => error instanceof OpenCodeUpdateError && error.code === \"binary_unavailable\")\n})\n\ntest(\"offline registry retains local required-update diagnosis\", async () => {\n const service = new OpenCodeUpdateService(deps({ resolveLatestVersion: async () => { throw new Error(\"offline\") } }))\n const status = await service.getStatus()\n assert.equal(status.state, \"update_required\")\n assert.equal(status.checkError, \"update_check_failed\")\n assert.equal(status.canUpgrade, false)\n await assert.rejects(service.upgrade(), (error: unknown) => error instanceof OpenCodeUpdateError && error.code === \"update_check_failed\")\n})\n\ntest(\"custom and WSL executables remain user managed\", async () => {\n const service = new OpenCodeUpdateService(deps({\n resolveBinary: () => ({ path: \"\\\\\\\\wsl.localhost\\\\Ubuntu\\\\usr\\\\bin\\\\opencode\", label: \"WSL\" }),\n canUpgradeBinary: () => false,\n }))\n const status = await service.getStatus()\n assert.equal(status.target, \"wsl\")\n assert.equal(status.canUpgrade, false)\n await assert.rejects(service.upgrade(), (error: unknown) => error instanceof OpenCodeUpdateError && error.code === \"unsupported_binary\")\n})\n\ntest(\"installation re-resolves the executable and rejects false success\", async () => {\n let installed = false\n const service = new OpenCodeUpdateService(deps({\n resolveBinary: () => ({ path: installed ? \"managed\" : \"opencode2\", label: \"OpenCode\" }),\n probeBinary: path => path === \"managed\" ? { valid: true, version: minimum } : { valid: false, missing: true },\n upgradeBinary: async (_binary, target) => { installed = true; return { success: true, version: target } },\n }))\n assert.equal((await service.upgrade()).version, minimum)\n const wrong = new OpenCodeUpdateService(deps({\n probeBinary: () => ({ valid: true, version: \"2.0.6\" }),\n upgradeBinary: async (_binary, target) => ({ success: true, version: target }),\n }))\n await assert.rejects(wrong.upgrade(), (error: unknown) => error instanceof OpenCodeUpdateError && error.code === \"upgrade_verification_failed\")\n})\n\ntest(\"user npm PATH repair remains available without an update and never downgrades\", async () => {\n for (const source of [\"user\"] as const) {\n let migrated = false, installs = 0\n const service = new OpenCodeUpdateService(deps({\n resolveBinary: () => ({ path: migrated ? \"common\" : source, label: \"OpenCode\", source: migrated ? \"path\" : source }),\n probeBinary: () => ({ valid: true, version: \"2.0.15\" }),\n resolveLatestVersion: async () => \"2.0.14\",\n upgradeBinary: async (_binary, target) => {\n assert.equal(target, \"2.0.15\")\n installs++; migrated = true\n return { success: true, version: target }\n },\n }))\n assert.equal((await service.getStatus()).canUpgrade, true)\n assert.equal((await service.getStatus()).needsSharedInstallation, true)\n await service.upgrade()\n assert.equal(installs, 1)\n assert.equal((await service.getStatus()).needsSharedInstallation, false)\n assert.equal((await service.getStatus()).canUpgrade, false)\n }\n})\n\ntest(\"coalesces overlapping installations and never downgrades a newer version\", async () => {\n let upgrades = 0\n let version = \"2.0.6\"\n let release!: () => void\n const gate = new Promise<void>(resolve => { release = resolve })\n const service = new OpenCodeUpdateService(deps({\n probeBinary: () => ({ valid: true, version }),\n upgradeBinary: async (_binary, target) => { upgrades++; await gate; version = target; return { success: true, version: target } },\n }))\n const first = service.upgrade(), second = service.upgrade()\n release()\n await Promise.all([first, second])\n assert.equal(upgrades, 1)\n version = \"2.0.999\"\n assert.equal((await service.getStatus()).updateAvailable, false)\n assert.equal((await service.upgrade()).version, version)\n assert.equal(upgrades, 1)\n})\n\ntest(\"stale daemon needs explicit restart; status and installation never restart it\", async () => {\n let daemonVersion = \"2.0.6\", restarts = 0, reconnects = 0\n const endpoint = () => {\n const value: Endpoint = { url: \"http://127.0.0.1:9876\" }\n rememberRuntime(value, { version: daemonVersion, pid: 123, discovery: \"info\" })\n return value\n }\n const service = new OpenCodeUpdateService(deps({\n probeBinary: () => ({ valid: true, version: minimum }),\n lifecycle: async () => ({ discover: async () => endpoint(), ensure: async () => endpoint(),\n restart: async () => { restarts++; daemonVersion = minimum; return endpoint() } }),\n reconnect: async () => { reconnects++ },\n }))\n assert.equal((await service.getStatus()).serviceState, \"restart_required\")\n assert.equal(restarts, 0)\n await assert.rejects(service.start(), /opencode_update_required/)\n assert.equal(restarts, 0)\n assert.equal(reconnects, 0)\n assert.equal((await service.start(true)).serviceState, \"ready\")\n assert.equal(restarts, 1)\n assert.equal(reconnects, 1)\n})\n\ntest(\"resolves exact stable package versions and rejects malformed/prerelease tags\", async () => {\n assert.equal(await resolveLatestOpenCodeVersion(async (url) => {\n assert.equal(url, \"https://registry.npmjs.org/-/package/%40opencode%2Fcli/dist-tags\")\n return new Response(JSON.stringify({ latest: minimum, beta: \"2.1.0-beta.1\" }))\n }), minimum)\n for (const tags of [{ beta: \"0.0.0-beta-19271\" }, { latest: \"2.1.0-beta.1\" }, { latest: \"2.0.11;whoami\" }]) {\n await assert.rejects(resolveLatestOpenCodeVersion(async () => new Response(JSON.stringify(tags))), /valid version/)\n }\n})\n\ntest(\"activation coalesces repeated clicks and refuses a changed selection before reconnect\", async () => {\n let selected = \"original\", restarts = 0, reconnects = 0\n let release!: () => void\n const gate = new Promise<void>(resolve => { release = resolve })\n const endpoint = (version: string) => {\n const value: Endpoint = { url: \"http://127.0.0.1:9876\" }\n rememberRuntime(value, { version, pid: 123, discovery: \"info\" })\n return value\n }\n const service = new OpenCodeUpdateService(deps({\n resolveBinary: () => ({ path: selected, label: selected }),\n probeBinary: () => ({ valid: true, version: minimum }),\n lifecycle: async () => ({ discover: async () => endpoint(\"2.0.6\"), ensure: async () => endpoint(minimum),\n restart: async () => { restarts++; await gate; return endpoint(minimum) } }),\n reconnect: async () => { reconnects++ },\n }))\n const first = service.start(true), second = service.start(true)\n assert.equal(first, second)\n selected = \"replacement\"\n release()\n await assert.rejects(first, /selection changed/)\n assert.equal(restarts, 0, \"a stale selection must be refused before stopping its daemon\")\n assert.equal(reconnects, 0)\n})\n\ntest(\"an unverified newer major is not blocked but cannot be downgraded by restart\", async () => {\n const value: Endpoint = { url: \"http://127.0.0.1:9876\" }\n rememberRuntime(value, { version: \"3.0.0\", pid: 123, discovery: \"info\" })\n const service = new OpenCodeUpdateService(deps({\n probeBinary: () => ({ valid: true, version: minimum }),\n resolveLatestVersion: async () => minimum,\n lifecycle: async () => ({ discover: async () => value, ensure: async () => value,\n restart: async () => { assert.fail(\"must not restart a newer runtime\") } }),\n }))\n assert.equal((await service.getStatus()).canUpgrade, false)\n assert.equal((await service.getStatus()).canRestart, false)\n assert.equal((await service.start()).serviceState, \"ready\")\n assert.equal((await service.getStatus()).versionAssessment, \"untested\")\n await assert.rejects(service.start(true), /not an older runtime/)\n})\n\ntest(\"optional upgrades retain explicit activation for an admitted but older daemon\", async () => {\n let installed = \"2.0.11\", daemon = \"2.0.11\", restarts = 0\n const endpoint = () => {\n const value: Endpoint = { url: \"http://127.0.0.1:9876\" }\n rememberRuntime(value, { version: daemon, pid: 123, discovery: \"info\" })\n return value\n }\n const service = new OpenCodeUpdateService(deps({\n probeBinary: () => ({ valid: true, version: installed }), resolveLatestVersion: async () => \"2.0.12\",\n upgradeBinary: async () => { installed = \"2.0.12\"; return { success: true, version: installed } },\n lifecycle: async () => ({ discover: async () => endpoint(), ensure: async () => endpoint(),\n restart: async () => { restarts++; daemon = installed; return endpoint() } }),\n }))\n await service.upgrade()\n const available = await service.start()\n assert.equal(available.state, \"ready\")\n assert.equal(available.serviceState, \"restart_available\")\n assert.equal(available.canRestart, true)\n assert.equal(restarts, 0)\n assert.equal((await service.start(true)).serviceState, \"ready\")\n assert.equal(restarts, 1)\n})\n\ntest(\"explicit configuration reload is admitted, fenced and serialized with service actions\", async () => {\n let selected = \"/fixture/opencode\", version = \"2.0.11\", reloads = 0\n let release!: () => void\n let entered!: () => void\n const gate = new Promise<void>(resolve => { release = resolve })\n const reached = new Promise<void>(resolve => { entered = resolve })\n const service = new OpenCodeUpdateService(deps({\n resolveBinary: () => ({ path: selected, label: \"Fixture\" }),\n probeBinary: () => ({ valid: true, version: \"2.0.11\" }),\n lifecycle: async () => ({ discover: async () => {\n const endpoint: Endpoint = { url: \"http://127.0.0.1:9876\" }\n rememberRuntime(endpoint, { version, pid: 123, discovery: \"info\" })\n return endpoint\n }, ensure: async () => { throw new Error(\"reload must not start a daemon\") } }),\n reload: async (_binary, assertCurrent) => { entered(); await gate; assertCurrent(); reloads++ },\n }))\n assert.equal((await service.getStatus()).canReload, true)\n assert.equal(reloads, 0)\n const first = service.reload()\n assert.equal(service.reload(), first)\n await reached\n await assert.rejects(service.start(), /action is in progress/)\n selected = \"/replacement/opencode\"\n await assert.rejects(service.start(true), /action is in progress/, \"changing executables cannot overlap the shared-daemon reload\")\n await assert.rejects(service.reload(), /action is in progress/, \"a different selection must not coalesce with the captured one\")\n release()\n await assert.rejects(first, /selection changed/)\n assert.equal(reloads, 0)\n version = \"2.0.6\"\n await assert.rejects(service.reload(), /opencode_update_required/)\n assert.equal(reloads, 0)\n})\n\ntest(\"an in-flight native reload holds shared-service authority across binary changes\", async () => {\n let selected = \"/fixture/a/opencode\", restarts = 0\n let entered!: () => void, release!: () => void\n const reached = new Promise<void>(resolve => { entered = resolve })\n const gate = new Promise<void>(resolve => { release = resolve })\n const endpoint: Endpoint = { url: \"http://127.0.0.1:9876\" }\n rememberRuntime(endpoint, { version: \"2.0.11\", pid: 123, discovery: \"info\" })\n const service = new OpenCodeUpdateService(deps({\n resolveBinary: () => ({ path: selected, label: \"Fixture\" }),\n probeBinary: () => ({ valid: true, version: \"2.0.12\" }),\n lifecycle: async () => ({ discover: async () => endpoint, ensure: async () => endpoint,\n restart: async () => { restarts++; return endpoint } }),\n reload: async (_binary, assertCurrent) => { assertCurrent(); entered(); await gate },\n }))\n const first = service.reload()\n await reached\n selected = \"/fixture/b/opencode\"\n try {\n await assert.rejects(service.start(true), /action is in progress/)\n await assert.rejects(service.reload(), /action is in progress/)\n assert.equal(restarts, 0)\n } finally { release() }\n await assert.rejects(first, /selection changed/)\n await service.reload()\n})\n\ntest(\"beta version comparison remains numeric\", () => {\n assert.equal(compareOpenCodeVersionStrings(\"0.0.0-beta-10000\", \"0.0.0-beta-9999\") > 0, true)\n})\n\ntest(\"2.0.7 through 2.0.16 remain usable; recommendation only offers an optional update\", async () => {\n for (const version of [\"2.0.7\", \"2.0.8\", \"2.0.9\", \"2.0.10\", \"2.0.11\", \"2.0.12\", \"2.0.13\", \"2.0.14\", \"2.0.15\", \"2.0.16\"]) {\n const endpoint: Endpoint = { url: \"http://127.0.0.1:9876\" }\n rememberRuntime(endpoint, { version, pid: 123, discovery: \"info\" })\n const service = new OpenCodeUpdateService(deps({\n probeBinary: () => ({ valid: true, version }), resolveLatestVersion: async () => \"2.0.16\",\n lifecycle: async () => ({ discover: async () => endpoint, ensure: async () => { throw new Error(\"must retain daemon\") } }),\n }))\n const status = await service.start()\n assert.equal(status.minimumVersion, \"2.0.7\")\n assert.equal(status.recommendedVersion, \"2.0.16\")\n assert.equal(status.state, \"ready\")\n assert.equal(status.serviceState, \"ready\")\n assert.equal(status.versionAssessment, version === \"2.0.16\" ? \"tested\" : \"untested\", \"only the current recommendation is release-qualified\")\n assert.equal(status.incompatibilityReason, undefined)\n assert.equal(status.canUpgrade, version !== \"2.0.16\")\n assert.equal(status.canRestart, false)\n }\n})\n\ntest(\"a current daemon remains usable through an older selected discovery CLI\", async () => {\n const endpoint: Endpoint = { url: \"http://127.0.0.1:9876\" }\n rememberRuntime(endpoint, { version: \"2.0.16\", pid: 123, discovery: \"info\" })\n const service = new OpenCodeUpdateService(deps({\n probeBinary: () => ({ valid: true, version: \"2.0.3\" }),\n lifecycle: async () => ({ discover: async () => endpoint, ensure: async () => { throw new Error(\"must retain daemon\") } }),\n }))\n assert.equal((await service.start()).state, \"ready\")\n assert.equal((await service.getStatus()).versionAssessment, \"tested\")\n})\n\ntest(\"custom labels are unverified, not an update demand; optional reload follows capabilities\", async () => {\n const endpoint: Endpoint = { url: \"http://127.0.0.1:9876\" }\n rememberRuntime(endpoint, { version: \"custom-build\", pid: 123, discovery: \"info\" })\n const service = new OpenCodeUpdateService(deps({\n probeBinary: () => ({ valid: true, version: \"custom-build\" }),\n inspectRuntime: async () => ({ reload: false }),\n lifecycle: async () => ({ discover: async () => endpoint, ensure: async () => { throw new Error(\"must retain daemon\") } }),\n reload: async () => { throw new Error(\"unavailable operation must not be called\") },\n }))\n const status = await service.start()\n assert.equal(status.state, \"ready\")\n assert.equal(status.serviceState, \"ready\")\n assert.equal(status.versionAssessment, \"untested\")\n assert.equal(status.canReload, false)\n assert.equal(status.canUpgrade, false)\n await assert.rejects(service.upgrade(), /custom OpenCode version/)\n await assert.rejects(service.reload(), /does not expose configuration reload/)\n})\n\ntest(\"production stdout parsing preserves custom labels through discovery and activation\", async () => {\n for (const [stdout, label] of [[\"custom-build\\n\", \"custom-build\"], [\"opencode v2.0.7+custom-build\\n\", \"2.0.7+custom-build\"],\n [\"opencode2 vendor-build\\n\", \"vendor-build\"], [\"\", \"unknown\"]]) {\n const endpoint: Endpoint = { url: \"http://127.0.0.1:9876\" }\n rememberRuntime(endpoint, { version: label!, pid: 123, discovery: \"info\" })\n let discoveries = 0, inspected = 0\n const service = new OpenCodeUpdateService(deps({\n probeBinary: () => probeBinaryVersion(process.execPath, () => ({ status: 0, stdout })),\n lifecycle: async () => ({ discover: async () => { discoveries++; return endpoint }, ensure: async () => { throw new Error(\"must retain daemon\") } }),\n inspectRuntime: async () => { inspected++; return { reload: false } },\n }))\n const status = await service.start()\n assert.equal(status.currentVersion, label)\n assert.equal(status.state, \"ready\")\n assert.equal(status.versionAssessment, \"untested\")\n assert.equal(status.canUpgrade, false)\n assert.equal(status.canRestart, false)\n assert.ok(discoveries > 0 && inspected > 0, \"successful custom labels reach authenticated contract inspection\")\n await assert.rejects(service.upgrade(), /custom OpenCode version/)\n }\n})\n"]}
|
|
1
|
+
{"version":3,"file":"service.test.js","sourceRoot":"","sources":["../../src/opencode-update/service.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\"\nimport test from \"node:test\"\nimport { OpenCodeUpdateService, OpenCodeUpdateError,\n resolveLatestOpenCodeVersion, compareOpenCodeVersionStrings,\n type OpenCodeUpdateServiceDeps } from \"./service\"\nimport { MINIMUM_OPENCODE_VERSION as minimum } from \"../opencode/runtime-support\"\nimport { rememberRuntime } from \"../opencode/compatibility/runtime\"\nimport type { Endpoint } from \"@opencode/client/service\"\nimport { probeBinaryVersion } from \"../workspaces/spawn\"\n\nfunction deps(overrides: Partial<OpenCodeUpdateServiceDeps> = {}): OpenCodeUpdateServiceDeps {\n let version = \"0.0.0-beta-19271\"\n return {\n resolveBinary: () => ({ path: \"opencode2\", label: \"OpenCode\" }),\n probeBinary: () => ({ valid: true, version }),\n resolveLatestVersion: async () => minimum,\n canUpgradeBinary: () => true,\n upgradeBinary: async (_binary, target) => { version = target; return { success: true, version: target } },\n inspectRuntime: async () => ({ reload: true }),\n ...overrides,\n }\n}\n\ntest(\"missing installs and old releases use one updater; probe failures are not absence\", async () => {\n for (const initial of [undefined, \"0.0.0-beta-19271\", \"2.0.6\"]) {\n let version = initial\n const service = new OpenCodeUpdateService(deps({\n probeBinary: () => version ? { valid: true, version } : { valid: false, missing: true },\n upgradeBinary: async (_binary, target) => { version = target; return { success: true, version: target } },\n }))\n const status = await service.getStatus()\n assert.equal(status.state, initial ? \"update_required\" : \"missing\")\n assert.equal(status.minimumVersion, minimum)\n assert.equal(status.canUpgrade, true)\n assert.deepEqual(await service.upgrade(), { success: true, version: minimum })\n assert.equal((await service.getStatus()).state, \"ready\")\n }\n const invalid = new OpenCodeUpdateService(deps({ probeBinary: () => ({ valid: false, error: \"EACCES\" }) }))\n assert.equal((await invalid.getStatus()).state, \"error\")\n assert.equal((await invalid.getStatus()).canUpgrade, false)\n await assert.rejects(invalid.upgrade(), (error: unknown) => error instanceof OpenCodeUpdateError && error.code === \"binary_unavailable\")\n})\n\ntest(\"offline registry retains local required-update diagnosis\", async () => {\n const service = new OpenCodeUpdateService(deps({ resolveLatestVersion: async () => { throw new Error(\"offline\") } }))\n const status = await service.getStatus()\n assert.equal(status.state, \"update_required\")\n assert.equal(status.checkError, \"update_check_failed\")\n assert.equal(status.canUpgrade, false)\n await assert.rejects(service.upgrade(), (error: unknown) => error instanceof OpenCodeUpdateError && error.code === \"update_check_failed\")\n})\n\ntest(\"custom and WSL executables remain user managed\", async () => {\n const service = new OpenCodeUpdateService(deps({\n resolveBinary: () => ({ path: \"\\\\\\\\wsl.localhost\\\\Ubuntu\\\\usr\\\\bin\\\\opencode\", label: \"WSL\" }),\n canUpgradeBinary: () => false,\n }))\n const status = await service.getStatus()\n assert.equal(status.target, \"wsl\")\n assert.equal(status.canUpgrade, false)\n await assert.rejects(service.upgrade(), (error: unknown) => error instanceof OpenCodeUpdateError && error.code === \"unsupported_binary\")\n})\n\ntest(\"installation re-resolves the executable and rejects false success\", async () => {\n let installed = false\n const service = new OpenCodeUpdateService(deps({\n resolveBinary: () => ({ path: installed ? \"managed\" : \"opencode2\", label: \"OpenCode\" }),\n probeBinary: path => path === \"managed\" ? { valid: true, version: minimum } : { valid: false, missing: true },\n upgradeBinary: async (_binary, target) => { installed = true; return { success: true, version: target } },\n }))\n assert.equal((await service.upgrade()).version, minimum)\n const wrong = new OpenCodeUpdateService(deps({\n probeBinary: () => ({ valid: true, version: \"2.0.6\" }),\n upgradeBinary: async (_binary, target) => ({ success: true, version: target }),\n }))\n await assert.rejects(wrong.upgrade(), (error: unknown) => error instanceof OpenCodeUpdateError && error.code === \"upgrade_verification_failed\")\n})\n\ntest(\"user npm PATH repair remains available without an update and never downgrades\", async () => {\n for (const source of [\"user\"] as const) {\n let migrated = false, installs = 0\n const service = new OpenCodeUpdateService(deps({\n resolveBinary: () => ({ path: migrated ? \"common\" : source, label: \"OpenCode\", source: migrated ? \"path\" : source }),\n probeBinary: () => ({ valid: true, version: \"2.0.15\" }),\n resolveLatestVersion: async () => \"2.0.14\",\n upgradeBinary: async (_binary, target) => {\n assert.equal(target, \"2.0.15\")\n installs++; migrated = true\n return { success: true, version: target }\n },\n }))\n assert.equal((await service.getStatus()).canUpgrade, true)\n assert.equal((await service.getStatus()).needsSharedInstallation, true)\n await service.upgrade()\n assert.equal(installs, 1)\n assert.equal((await service.getStatus()).needsSharedInstallation, false)\n assert.equal((await service.getStatus()).canUpgrade, false)\n }\n})\n\ntest(\"coalesces overlapping installations and never downgrades a newer version\", async () => {\n let upgrades = 0\n let version = \"2.0.6\"\n let release!: () => void\n const gate = new Promise<void>(resolve => { release = resolve })\n const service = new OpenCodeUpdateService(deps({\n probeBinary: () => ({ valid: true, version }),\n upgradeBinary: async (_binary, target) => { upgrades++; await gate; version = target; return { success: true, version: target } },\n }))\n const first = service.upgrade(), second = service.upgrade()\n release()\n await Promise.all([first, second])\n assert.equal(upgrades, 1)\n version = \"2.0.999\"\n assert.equal((await service.getStatus()).updateAvailable, false)\n assert.equal((await service.upgrade()).version, version)\n assert.equal(upgrades, 1)\n})\n\ntest(\"stale daemon needs explicit restart; status and installation never restart it\", async () => {\n let daemonVersion = \"2.0.6\", restarts = 0, reconnects = 0\n const endpoint = () => {\n const value: Endpoint = { url: \"http://127.0.0.1:9876\" }\n rememberRuntime(value, { version: daemonVersion, pid: 123, discovery: \"info\" })\n return value\n }\n const service = new OpenCodeUpdateService(deps({\n probeBinary: () => ({ valid: true, version: minimum }),\n lifecycle: async () => ({ discover: async () => endpoint(), ensure: async () => endpoint(),\n restart: async () => { restarts++; daemonVersion = minimum; return endpoint() } }),\n reconnect: async () => { reconnects++ },\n }))\n assert.equal((await service.getStatus()).serviceState, \"restart_required\")\n assert.equal(restarts, 0)\n await assert.rejects(service.start(), /opencode_update_required/)\n assert.equal(restarts, 0)\n assert.equal(reconnects, 0)\n assert.equal((await service.start(true)).serviceState, \"ready\")\n assert.equal(restarts, 1)\n assert.equal(reconnects, 1)\n})\n\ntest(\"resolves exact stable package versions and rejects malformed/prerelease tags\", async () => {\n assert.equal(await resolveLatestOpenCodeVersion(async (url) => {\n assert.equal(url, \"https://registry.npmjs.org/-/package/%40opencode%2Fcli/dist-tags\")\n return new Response(JSON.stringify({ latest: minimum, beta: \"2.1.0-beta.1\" }))\n }), minimum)\n for (const tags of [{ beta: \"0.0.0-beta-19271\" }, { latest: \"2.1.0-beta.1\" }, { latest: \"2.0.11;whoami\" }]) {\n await assert.rejects(resolveLatestOpenCodeVersion(async () => new Response(JSON.stringify(tags))), /valid version/)\n }\n})\n\ntest(\"activation coalesces repeated clicks and refuses a changed selection before reconnect\", async () => {\n let selected = \"original\", restarts = 0, reconnects = 0\n let release!: () => void\n const gate = new Promise<void>(resolve => { release = resolve })\n const endpoint = (version: string) => {\n const value: Endpoint = { url: \"http://127.0.0.1:9876\" }\n rememberRuntime(value, { version, pid: 123, discovery: \"info\" })\n return value\n }\n const service = new OpenCodeUpdateService(deps({\n resolveBinary: () => ({ path: selected, label: selected }),\n probeBinary: () => ({ valid: true, version: minimum }),\n lifecycle: async () => ({ discover: async () => endpoint(\"2.0.6\"), ensure: async () => endpoint(minimum),\n restart: async () => { restarts++; await gate; return endpoint(minimum) } }),\n reconnect: async () => { reconnects++ },\n }))\n const first = service.start(true), second = service.start(true)\n assert.equal(first, second)\n selected = \"replacement\"\n release()\n await assert.rejects(first, /selection changed/)\n assert.equal(restarts, 0, \"a stale selection must be refused before stopping its daemon\")\n assert.equal(reconnects, 0)\n})\n\ntest(\"an unverified newer major is not blocked but cannot be downgraded by restart\", async () => {\n const value: Endpoint = { url: \"http://127.0.0.1:9876\" }\n rememberRuntime(value, { version: \"3.0.0\", pid: 123, discovery: \"info\" })\n const service = new OpenCodeUpdateService(deps({\n probeBinary: () => ({ valid: true, version: minimum }),\n resolveLatestVersion: async () => minimum,\n lifecycle: async () => ({ discover: async () => value, ensure: async () => value,\n restart: async () => { assert.fail(\"must not restart a newer runtime\") } }),\n }))\n assert.equal((await service.getStatus()).canUpgrade, false)\n assert.equal((await service.getStatus()).canRestart, false)\n assert.equal((await service.start()).serviceState, \"ready\")\n assert.equal((await service.getStatus()).versionAssessment, \"untested\")\n await assert.rejects(service.start(true), /not an older runtime/)\n})\n\ntest(\"optional upgrades retain explicit activation for an admitted but older daemon\", async () => {\n let installed = \"2.0.11\", daemon = \"2.0.11\", restarts = 0\n const endpoint = () => {\n const value: Endpoint = { url: \"http://127.0.0.1:9876\" }\n rememberRuntime(value, { version: daemon, pid: 123, discovery: \"info\" })\n return value\n }\n const service = new OpenCodeUpdateService(deps({\n probeBinary: () => ({ valid: true, version: installed }), resolveLatestVersion: async () => \"2.0.12\",\n upgradeBinary: async () => { installed = \"2.0.12\"; return { success: true, version: installed } },\n lifecycle: async () => ({ discover: async () => endpoint(), ensure: async () => endpoint(),\n restart: async () => { restarts++; daemon = installed; return endpoint() } }),\n }))\n await service.upgrade()\n const available = await service.start()\n assert.equal(available.state, \"ready\")\n assert.equal(available.serviceState, \"restart_available\")\n assert.equal(available.canRestart, true)\n assert.equal(restarts, 0)\n assert.equal((await service.start(true)).serviceState, \"ready\")\n assert.equal(restarts, 1)\n})\n\ntest(\"explicit configuration reload is admitted, fenced and serialized with service actions\", async () => {\n let selected = \"/fixture/opencode\", version = \"2.0.11\", reloads = 0\n let release!: () => void\n let entered!: () => void\n const gate = new Promise<void>(resolve => { release = resolve })\n const reached = new Promise<void>(resolve => { entered = resolve })\n const service = new OpenCodeUpdateService(deps({\n resolveBinary: () => ({ path: selected, label: \"Fixture\" }),\n probeBinary: () => ({ valid: true, version: \"2.0.11\" }),\n lifecycle: async () => ({ discover: async () => {\n const endpoint: Endpoint = { url: \"http://127.0.0.1:9876\" }\n rememberRuntime(endpoint, { version, pid: 123, discovery: \"info\" })\n return endpoint\n }, ensure: async () => { throw new Error(\"reload must not start a daemon\") } }),\n reload: async (_binary, assertCurrent) => { entered(); await gate; assertCurrent(); reloads++ },\n }))\n assert.equal((await service.getStatus()).canReload, true)\n assert.equal(reloads, 0)\n const first = service.reload()\n assert.equal(service.reload(), first)\n await reached\n await assert.rejects(service.start(), /action is in progress/)\n selected = \"/replacement/opencode\"\n await assert.rejects(service.start(true), /action is in progress/, \"changing executables cannot overlap the shared-daemon reload\")\n await assert.rejects(service.reload(), /action is in progress/, \"a different selection must not coalesce with the captured one\")\n release()\n await assert.rejects(first, /selection changed/)\n assert.equal(reloads, 0)\n version = \"2.0.6\"\n await assert.rejects(service.reload(), /opencode_update_required/)\n assert.equal(reloads, 0)\n})\n\ntest(\"an in-flight native reload holds shared-service authority across binary changes\", async () => {\n let selected = \"/fixture/a/opencode\", restarts = 0\n let entered!: () => void, release!: () => void\n const reached = new Promise<void>(resolve => { entered = resolve })\n const gate = new Promise<void>(resolve => { release = resolve })\n const endpoint: Endpoint = { url: \"http://127.0.0.1:9876\" }\n rememberRuntime(endpoint, { version: \"2.0.11\", pid: 123, discovery: \"info\" })\n const service = new OpenCodeUpdateService(deps({\n resolveBinary: () => ({ path: selected, label: \"Fixture\" }),\n probeBinary: () => ({ valid: true, version: \"2.0.12\" }),\n lifecycle: async () => ({ discover: async () => endpoint, ensure: async () => endpoint,\n restart: async () => { restarts++; return endpoint } }),\n reload: async (_binary, assertCurrent) => { assertCurrent(); entered(); await gate },\n }))\n const first = service.reload()\n await reached\n selected = \"/fixture/b/opencode\"\n try {\n await assert.rejects(service.start(true), /action is in progress/)\n await assert.rejects(service.reload(), /action is in progress/)\n assert.equal(restarts, 0)\n } finally { release() }\n await assert.rejects(first, /selection changed/)\n await service.reload()\n})\n\ntest(\"beta version comparison remains numeric\", () => {\n assert.equal(compareOpenCodeVersionStrings(\"0.0.0-beta-10000\", \"0.0.0-beta-9999\") > 0, true)\n})\n\ntest(\"2.0.7 through 2.0.18 remain usable; recommendation only offers an optional update\", async () => {\n for (const version of [\"2.0.7\", \"2.0.8\", \"2.0.9\", \"2.0.10\", \"2.0.11\", \"2.0.12\", \"2.0.13\", \"2.0.14\", \"2.0.15\", \"2.0.16\", \"2.0.17\", \"2.0.18\"]) {\n const endpoint: Endpoint = { url: \"http://127.0.0.1:9876\" }\n rememberRuntime(endpoint, { version, pid: 123, discovery: \"info\" })\n const service = new OpenCodeUpdateService(deps({\n probeBinary: () => ({ valid: true, version }), resolveLatestVersion: async () => \"2.0.18\",\n lifecycle: async () => ({ discover: async () => endpoint, ensure: async () => { throw new Error(\"must retain daemon\") } }),\n }))\n const status = await service.start()\n assert.equal(status.minimumVersion, \"2.0.7\")\n assert.equal(status.recommendedVersion, \"2.0.18\")\n assert.equal(status.state, \"ready\")\n assert.equal(status.serviceState, \"ready\")\n assert.equal(status.versionAssessment, version === \"2.0.18\" ? \"tested\" : \"untested\", \"only the current recommendation is release-qualified\")\n assert.equal(status.incompatibilityReason, undefined)\n assert.equal(status.canUpgrade, version !== \"2.0.18\")\n assert.equal(status.canRestart, false)\n }\n})\n\ntest(\"a current daemon remains usable through an older selected discovery CLI\", async () => {\n const endpoint: Endpoint = { url: \"http://127.0.0.1:9876\" }\n rememberRuntime(endpoint, { version: \"2.0.18\", pid: 123, discovery: \"info\" })\n const service = new OpenCodeUpdateService(deps({\n probeBinary: () => ({ valid: true, version: \"2.0.3\" }),\n lifecycle: async () => ({ discover: async () => endpoint, ensure: async () => { throw new Error(\"must retain daemon\") } }),\n }))\n assert.equal((await service.start()).state, \"ready\")\n assert.equal((await service.getStatus()).versionAssessment, \"tested\")\n})\n\ntest(\"custom labels are unverified, not an update demand; optional reload follows capabilities\", async () => {\n const endpoint: Endpoint = { url: \"http://127.0.0.1:9876\" }\n rememberRuntime(endpoint, { version: \"custom-build\", pid: 123, discovery: \"info\" })\n const service = new OpenCodeUpdateService(deps({\n probeBinary: () => ({ valid: true, version: \"custom-build\" }),\n inspectRuntime: async () => ({ reload: false }),\n lifecycle: async () => ({ discover: async () => endpoint, ensure: async () => { throw new Error(\"must retain daemon\") } }),\n reload: async () => { throw new Error(\"unavailable operation must not be called\") },\n }))\n const status = await service.start()\n assert.equal(status.state, \"ready\")\n assert.equal(status.serviceState, \"ready\")\n assert.equal(status.versionAssessment, \"untested\")\n assert.equal(status.canReload, false)\n assert.equal(status.canUpgrade, false)\n await assert.rejects(service.upgrade(), /custom OpenCode version/)\n await assert.rejects(service.reload(), /does not expose configuration reload/)\n})\n\ntest(\"production stdout parsing preserves custom labels through discovery and activation\", async () => {\n for (const [stdout, label] of [[\"custom-build\\n\", \"custom-build\"], [\"opencode v2.0.7+custom-build\\n\", \"2.0.7+custom-build\"],\n [\"opencode2 vendor-build\\n\", \"vendor-build\"], [\"\", \"unknown\"]]) {\n const endpoint: Endpoint = { url: \"http://127.0.0.1:9876\" }\n rememberRuntime(endpoint, { version: label!, pid: 123, discovery: \"info\" })\n let discoveries = 0, inspected = 0\n const service = new OpenCodeUpdateService(deps({\n probeBinary: () => probeBinaryVersion(process.execPath, () => ({ status: 0, stdout })),\n lifecycle: async () => ({ discover: async () => { discoveries++; return endpoint }, ensure: async () => { throw new Error(\"must retain daemon\") } }),\n inspectRuntime: async () => { inspected++; return { reload: false } },\n }))\n const status = await service.start()\n assert.equal(status.currentVersion, label)\n assert.equal(status.state, \"ready\")\n assert.equal(status.versionAssessment, \"untested\")\n assert.equal(status.canUpgrade, false)\n assert.equal(status.canRestart, false)\n assert.ok(discoveries > 0 && inspected > 0, \"successful custom labels reach authenticated contract inspection\")\n await assert.rejects(service.upgrade(), /custom OpenCode version/)\n }\n})\n"]}
|
|
@@ -9,6 +9,7 @@ import { assertSupportedOpenCode } from "../opencode/runtime-support";
|
|
|
9
9
|
import { compareVersionStrings } from "../releases/release-monitor";
|
|
10
10
|
import { assertExecutableWritable, withInstallationLock } from "./installation-lock";
|
|
11
11
|
import { upgradeSharedOpenCode } from "./native-upgrade";
|
|
12
|
+
import { isIncompleteWindowsNpmShim } from "./incomplete-installation";
|
|
12
13
|
export function userNpmPrefix(host = {}) {
|
|
13
14
|
const home = host.home ?? os.homedir();
|
|
14
15
|
const env = host.env ?? process.env;
|
|
@@ -114,11 +115,15 @@ export function findPathOpenCode(host = {}) {
|
|
|
114
115
|
}
|
|
115
116
|
}
|
|
116
117
|
export function resolveDefaultInstallation(host = {}) {
|
|
118
|
+
const platform = host.platform ?? process.platform;
|
|
119
|
+
const prefix = userNpmPrefix(host);
|
|
120
|
+
const binary = npmCommand(prefix, platform)?.binary ?? npmExecutable(prefix, platform);
|
|
117
121
|
const command = findPathOpenCode(host);
|
|
118
|
-
if (command)
|
|
122
|
+
if (command) {
|
|
123
|
+
if (platform === "win32" && isIncompleteWindowsNpmShim(command, prefix, binary))
|
|
124
|
+
return { path: binary, source: "user" };
|
|
119
125
|
return { path: command, source: "path" };
|
|
120
|
-
|
|
121
|
-
const binary = npmCommand(prefix, host.platform ?? process.platform)?.binary ?? npmExecutable(prefix, host.platform);
|
|
126
|
+
}
|
|
122
127
|
if (existsSync(binary) && !isRetiredInstallation(binary))
|
|
123
128
|
return { path: binary, source: "user" };
|
|
124
129
|
return { path: "opencode2" };
|
|
@@ -136,7 +141,8 @@ export function sharedInstallPrefix(host = {}) {
|
|
|
136
141
|
return userPrefix;
|
|
137
142
|
const prefix = platform === "win32" ? path.dirname(command) : path.dirname(path.dirname(command));
|
|
138
143
|
try {
|
|
139
|
-
if (!npmLauncher(command, prefix, platform)
|
|
144
|
+
if (!npmLauncher(command, prefix, platform)
|
|
145
|
+
&& !(platform === "win32" && isIncompleteWindowsNpmShim(command, userPrefix, npmExecutable(userPrefix, platform))))
|
|
140
146
|
return undefined;
|
|
141
147
|
accessSync(prefix, constants.W_OK);
|
|
142
148
|
return prefix;
|