@neuralnomads/codenomad-dev 0.20.0-dev-20260923-baf674fc → 0.20.0-dev-20260924-70aae0b1
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/dist/api-types.js.map +1 -1
- package/dist/opencode-update/npm-runtime.js +22 -0
- package/dist/opencode-update/npm-runtime.js.map +1 -0
- package/dist/opencode-update/retired-installation.js +41 -0
- package/dist/opencode-update/retired-installation.js.map +1 -0
- package/dist/opencode-update/retired-installation.test.js +39 -0
- package/dist/opencode-update/retired-installation.test.js.map +1 -0
- package/dist/opencode-update/service.js +4 -3
- package/dist/opencode-update/service.js.map +1 -1
- package/dist/opencode-update/service.test.js +2 -2
- package/dist/opencode-update/service.test.js.map +1 -1
- package/dist/opencode-update/shared-installation.js +8 -5
- package/dist/opencode-update/shared-installation.js.map +1 -1
- package/dist/opencode-update/shared-installation.test.js +4 -2
- package/dist/opencode-update/shared-installation.test.js.map +1 -1
- package/dist/settings/binaries.js +3 -2
- package/dist/settings/binaries.js.map +1 -1
- package/dist/workspaces/spawn.js +7 -2
- package/dist/workspaces/spawn.js.map +1 -1
- package/package.json +1 -1
- package/public/assets/{App-DHe1TgnC.js → App-DXfroBn-.js} +7 -7
- package/public/assets/{App-DHe1TgnC.js.map → App-DXfroBn-.js.map} +1 -1
- package/public/assets/{FilesTab-D8Ik74MT.js → FilesTab-JN0c2Op2.js} +2 -2
- package/public/assets/{FilesTab-D8Ik74MT.js.map → FilesTab-JN0c2Op2.js.map} +1 -1
- package/public/assets/{GitChangesTab-CYn01GSK.js → GitChangesTab-8MxRVYHz.js} +2 -2
- package/public/assets/{GitChangesTab-CYn01GSK.js.map → GitChangesTab-8MxRVYHz.js.map} +1 -1
- package/public/assets/{SplitFilePanel-DxTSWUXW.js → SplitFilePanel-VXkE7jgT.js} +2 -2
- package/public/assets/{SplitFilePanel-DxTSWUXW.js.map → SplitFilePanel-VXkE7jgT.js.map} +1 -1
- package/public/assets/{StatusTab-CLJHjaqS.js → StatusTab-DljyzM07.js} +2 -2
- package/public/assets/{StatusTab-CLJHjaqS.js.map → StatusTab-DljyzM07.js.map} +1 -1
- package/public/assets/{align-justify-DYu1Iipu.js → align-justify-BMi4r2XK.js} +2 -2
- package/public/assets/{align-justify-DYu1Iipu.js.map → align-justify-BMi4r2XK.js.map} +1 -1
- package/public/assets/{bundle-full-DbjjKxlx.js → bundle-full-LgLNZmib.js} +2 -2
- package/public/assets/{bundle-full-DbjjKxlx.js.map → bundle-full-LgLNZmib.js.map} +1 -1
- package/public/assets/{client-state-LGeRE6k3.js → client-state-DTQzqBPJ.js} +2 -2
- package/public/assets/{client-state-LGeRE6k3.js.map → client-state-DTQzqBPJ.js.map} +1 -1
- package/public/assets/{diff-viewer-D_koHVvF.js → diff-viewer-Dxjea-rB.js} +2 -2
- package/public/assets/{diff-viewer-D_koHVvF.js.map → diff-viewer-Dxjea-rB.js.map} +1 -1
- package/public/assets/index-9bba6B1A.js +2 -0
- package/public/assets/index-9bba6B1A.js.map +1 -0
- package/public/assets/index-C5i7ut9u.js +2 -0
- package/public/assets/index-C5i7ut9u.js.map +1 -0
- package/public/assets/index-CLtLzsWy.js +2 -0
- package/public/assets/index-CLtLzsWy.js.map +1 -0
- package/public/assets/index-CTVIWXHZ.js +2 -0
- package/public/assets/index-CTVIWXHZ.js.map +1 -0
- package/public/assets/{index-CXyTJ12Z.js → index-Cgp1TEtC.js} +2 -2
- package/public/assets/{index-CXyTJ12Z.js.map → index-Cgp1TEtC.js.map} +1 -1
- package/public/assets/index-Cqd_P8c4.js +2 -0
- package/public/assets/index-Cqd_P8c4.js.map +1 -0
- package/public/assets/{index-CHztP7Qx.js → index-DTGOXoDH.js} +2 -2
- package/public/assets/{index-CHztP7Qx.js.map → index-DTGOXoDH.js.map} +1 -1
- package/public/assets/index-D_H_gYdX.js +2 -0
- package/public/assets/index-D_H_gYdX.js.map +1 -0
- package/public/assets/index-Dsd7n295.js +2 -0
- package/public/assets/index-Dsd7n295.js.map +1 -0
- package/public/assets/index-DwKq8v48.js +3 -0
- package/public/assets/index-DwKq8v48.js.map +1 -0
- package/public/assets/index-TnTncRlr.js +2 -0
- package/public/assets/index-TnTncRlr.js.map +1 -0
- package/public/assets/index-eb2qu-xk.js +2 -0
- package/public/assets/index-eb2qu-xk.js.map +1 -0
- package/public/assets/{loading-1PhCNPTJ.js → loading-j5J_ghLL.js} +2 -2
- package/public/assets/{loading-1PhCNPTJ.js.map → loading-j5J_ghLL.js.map} +1 -1
- package/public/assets/{main-UjL26F9i.js → main-Cv7E0c7r.js} +7 -7
- package/public/assets/{main-UjL26F9i.js.map → main-Cv7E0c7r.js.map} +1 -1
- package/public/assets/{markdown-BFEzPV6Z.js → markdown-Cg65SCwC.js} +4 -4
- package/public/assets/{markdown-BFEzPV6Z.js.map → markdown-Cg65SCwC.js.map} +1 -1
- package/public/assets/{startup-state-settings-card-X1QA2uNM.js → startup-state-settings-card-DMFtdRoa.js} +2 -2
- package/public/assets/{startup-state-settings-card-X1QA2uNM.js.map → startup-state-settings-card-DMFtdRoa.js.map} +1 -1
- package/public/assets/{terminal-square-BkG0S2-Z.js → terminal-square-DCn_Ac2k.js} +2 -2
- package/public/assets/{terminal-square-BkG0S2-Z.js.map → terminal-square-DCn_Ac2k.js.map} +1 -1
- package/public/assets/{todo-DKme4PqO.js → todo-DyaFCX9E.js} +2 -2
- package/public/assets/{todo-DKme4PqO.js.map → todo-DyaFCX9E.js.map} +1 -1
- package/public/assets/{tool-call-DZIN0BAW.js → tool-call-DlJUX9AW.js} +4 -4
- package/public/assets/{tool-call-DZIN0BAW.js.map → tool-call-DlJUX9AW.js.map} +1 -1
- package/public/assets/{unified-picker-Ml-4x3ux.js → unified-picker-CrW1bp1Y.js} +2 -2
- package/public/assets/{unified-picker-Ml-4x3ux.js.map → unified-picker-CrW1bp1Y.js.map} +1 -1
- package/public/assets/{wrap-text-B_W6fnE7.js → wrap-text-DLR5jp4s.js} +2 -2
- package/public/assets/{wrap-text-B_W6fnE7.js.map → wrap-text-DLR5jp4s.js.map} +1 -1
- package/public/index.html +2 -2
- package/public/loading.html +2 -2
- package/public/sw.js +1 -1
- package/public/sw.js.map +1 -1
- package/dist/opencode-update/managed-installation.js +0 -102
- package/dist/opencode-update/managed-installation.js.map +0 -1
- package/dist/opencode-update/managed-installation.test.js +0 -102
- package/dist/opencode-update/managed-installation.test.js.map +0 -1
- package/public/assets/index-Bme8jj6C.js +0 -2
- package/public/assets/index-Bme8jj6C.js.map +0 -1
- package/public/assets/index-BxPI94Ww.js +0 -2
- package/public/assets/index-BxPI94Ww.js.map +0 -1
- package/public/assets/index-Cm6Bv3OW.js +0 -2
- package/public/assets/index-Cm6Bv3OW.js.map +0 -1
- package/public/assets/index-Cn9xpv8K.js +0 -2
- package/public/assets/index-Cn9xpv8K.js.map +0 -1
- package/public/assets/index-CooBjdE-.js +0 -2
- package/public/assets/index-CooBjdE-.js.map +0 -1
- package/public/assets/index-CvWB7Vfc.js +0 -2
- package/public/assets/index-CvWB7Vfc.js.map +0 -1
- package/public/assets/index-DFCjhysu.js +0 -3
- package/public/assets/index-DFCjhysu.js.map +0 -1
- package/public/assets/index-DR8ddwAP.js +0 -2
- package/public/assets/index-DR8ddwAP.js.map +0 -1
- package/public/assets/index-THD8itHb.js +0 -2
- package/public/assets/index-THD8itHb.js.map +0 -1
- package/public/assets/index-_bmTx26k.js +0 -2
- package/public/assets/index-_bmTx26k.js.map +0 -1
package/dist/api-types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-types.js","sourceRoot":"","sources":["../src/api-types.ts"],"names":[],"mappings":"AAkSA,MAAM,CAAC,MAAM,mBAAmB,GAAG,YAAY,CAAA;AA8E/C,MAAM,CAAC,MAAM,+BAA+B,GAAG,sBAA+B,CAAA;AAC9E,MAAM,CAAC,MAAM,qCAAqC,GAAG,4BAAqC,CAAA","sourcesContent":["import type {\n AgentModelSelection,\n AgentModelSelections,\n ModelPreference,\n OpenCodeBinary,\n Preferences,\n RecentFolder,\n} from \"./config/schema\"\nimport type { OpenCodeEvent } from \"@opencode/client\"\n\n/**\n * Canonical HTTP/SSE contract for the CLI server.\n * These types are consumed by both the CLI implementation and any UI clients.\n */\n\nexport type WorkspaceStatus = \"starting\" | \"ready\" | \"stopped\" | \"error\"\n\nexport interface WorkspaceDescriptor {\n id: string\n /** Correlates creation events with the client request that initiated them. */\n requestId?: string\n /** Absolute path on the server host. */\n path: string\n name?: string\n status: WorkspaceStatus\n /** PID/port are populated when the workspace is running. */\n pid?: number\n port?: number\n /** Canonical proxy path the CLI exposes for this instance. */\n proxyPath: string\n /** Identifier of the binary resolved from config. */\n binaryId: string\n binaryLabel: string\n binaryVersion?: string\n createdAt: string\n updatedAt: string\n /** Present when `status` is \"error\". */\n error?: string\n}\n\nexport interface WorkspaceCreateRequest {\n path: string\n name?: string\n requestId?: string\n}\n\nexport interface WorkspaceCloneRequest {\n repositoryUrl: string\n destinationPath: string\n cleanup?: boolean\n}\n\nexport interface WorkspaceCloneResponse {\n path: string\n}\n\nexport type WorkspaceCreateResponse = WorkspaceDescriptor & {\n /** True when this request did not own creation of the returned workspace. */\n reused?: true\n}\nexport type WorkspaceListResponse = WorkspaceDescriptor[]\nexport type WorkspaceDetailResponse = WorkspaceDescriptor\n\nexport interface WorkspaceDeleteResponse {\n id: string\n status: WorkspaceStatus\n}\n\nexport interface ProviderUsageWindow {\n usedPercent: number | null\n remainingPercent: number | null\n windowSeconds: number | null\n resetAt: number | null\n valueLabel?: string\n}\n\nexport interface ProviderUsageResponse {\n requestedProviderId: string\n providerId: string | null\n providerName: string\n modelId?: string\n supported: boolean\n configured: boolean\n ok: boolean\n windows: Record<string, ProviderUsageWindow>\n fetchedAt: number\n}\n\nexport type WorktreeKind = \"root\" | \"worktree\"\n\nexport interface WorktreeDescriptor {\n /** Stable identifier used by CodeNomad + clients (\"root\" for the selected workspace folder). */\n slug: string\n /** Presentation only; the worktree identifier does not change with its branch. */\n label?: string\n /** Absolute directory path on the server host. */\n directory: string\n /** Equivalent path in the OpenCode service namespace (notably WSL). */\n serviceDirectory?: string\n /** Native checkout root (before mirroring a nested workspace folder). */\n serviceRoot?: string\n /** Exact path registered in Git's worktree inventory. */\n registeredDirectory?: string\n /** Degraded mode: only this exact physical directory authorizes sessions. */\n directoryOnly?: boolean\n kind: WorktreeKind\n /** False for the opened folder and Git's main checkout. */\n removable?: boolean\n /** Optional VCS branch name when available. */\n branch?: string\n /** Commit recorded by the Git worktree inventory. */\n head?: string\n}\n\nexport interface WorktreeListResponse {\n /** False means directory-only degraded mode; repository membership is unknown. */\n gitAvailable?: boolean\n worktrees: WorktreeDescriptor[]\n /** Default creation parent in the OpenCode service namespace. */\n defaultDirectory?: string\n /** True when the workspace folder resolves to a Git repository. */\n isGitRepo?: boolean\n}\n\nexport interface WorktreeCreateRequest {\n slug: string\n fromSlug?: string\n /** Optional branch name (defaults to slug). */\n branch?: string\n}\n\nexport interface WorktreeSessionMoveRequest {\n worktreeSlug: string\n}\n\nexport interface WorktreeSessionMoveResponse {\n rootSessionId: string\n sessionIds: string[]\n worktreeSlug: string\n}\n\nexport type GitChangeKind = \"added\" | \"modified\" | \"deleted\" | \"renamed\" | \"copied\" | \"untracked\" | \"unmerged\"\n\nexport interface WorktreeGitStatusEntry {\n path: string\n originalPath?: string | null\n stagedStatus: GitChangeKind | null\n stagedAdditions: number\n stagedDeletions: number\n unstagedStatus: GitChangeKind | null\n unstagedAdditions: number\n unstagedDeletions: number\n}\n\nexport type WorktreeGitStatusResponse = WorktreeGitStatusEntry[]\n\nexport type WorktreeGitDiffScope = \"staged\" | \"unstaged\"\n\nexport interface WorktreeGitPathsRequest {\n paths: string[]\n}\n\nexport interface WorktreeGitMutationResponse {\n ok: true\n}\n\nexport interface WorktreeGitCommitRequest {\n message: string\n}\n\nexport interface WorktreeGitCommitResponse {\n ok: true\n commitSha?: string\n}\n\nexport interface WorktreeGitDiffResponse {\n path: string\n originalPath?: string | null\n scope: WorktreeGitDiffScope\n before: string\n after: string\n isBinary?: boolean\n}\n\nexport interface WorktreeGitDiffRequest {\n path: string\n originalPath?: string | null\n scope: WorktreeGitDiffScope\n}\n\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\"\n\nexport interface WorkspaceLogEntry {\n workspaceId: string\n timestamp: string\n level: LogLevel\n message: string\n}\n\nexport interface FileSystemEntry {\n name: string\n /**\n * Path identifier for the entry. Relative to the server root in restricted\n * single-root listings (\".\" represents the root itself); absolute in\n * unrestricted, drives, and multi-root top-level listings.\n */\n path: string\n /** Absolute path when available (unrestricted and multi-root listings). */\n absolutePath?: string\n type: \"file\" | \"directory\"\n size?: number\n /** ISO timestamp of last modification when available. */\n modifiedAt?: string\n}\n\nexport type FileSystemScope = \"restricted\" | \"unrestricted\"\nexport type FileSystemPathKind = \"relative\" | \"absolute\" | \"drives\"\n\nexport interface FileSystemListingMetadata {\n scope: FileSystemScope\n /**\n * Canonical identifier of the current view:\n * - \".\" for restricted single-root listings\n * - WINDOWS_DRIVES_ROOT for the Windows drives pseudo-root\n * - absolute path otherwise\n */\n currentPath: string\n /** Optional parent path if navigation upward is allowed. */\n parentPath?: string\n /** Absolute path representing the root or origin point for this listing. */\n rootPath: string\n /** Absolute home directory of the CLI host (useful defaults for unrestricted mode). */\n homePath: string\n /** Human-friendly label for the current path. */\n displayPath: string\n /** Indicates whether entry paths are relative, absolute, or represent the drive pseudo-view. */\n pathKind: FileSystemPathKind\n}\n\nexport interface FileSystemListResponse {\n entries: FileSystemEntry[]\n metadata: FileSystemListingMetadata\n}\n\nexport interface FileSystemCreateFolderRequest {\n /**\n * Path identifier for the currently browsed directory.\n * Matches the `path` parameter used for `/api/filesystem`.\n */\n parentPath?: string\n /** Single folder name (no separators). */\n name: string\n}\n\nexport interface FileSystemCreateFolderResponse {\n /**\n * Path identifier that can be passed back to `/api/filesystem` to browse the new folder.\n * Relative for restricted listings and absolute for unrestricted listings.\n */\n path: string\n /** Absolute folder path on the server host. */\n absolutePath: string\n}\n\nexport interface FileSystemFileContentResponse {\n path: string\n contents: string\n encoding: \"utf-8\" | \"base64\"\n}\n\nexport interface ConfigFileDescriptor {\n id: string\n label: string\n path: string\n language: string\n}\n\nexport type ConfigFileListResponse = ConfigFileDescriptor[]\n\nexport interface ConfigFileContentResponse {\n id: string\n path: string\n contents: string\n exists: boolean\n}\n\nexport interface ConfigFileContentRequest {\n contents: string\n}\n\nexport const WINDOWS_DRIVES_ROOT = \"__drives__\"\n\nexport interface WorkspaceFileResponse {\n workspaceId: string\n relativePath: string\n /** UTF-8 file contents; binary files should be base64 encoded by the caller. */\n contents: string\n encoding?: \"utf-8\" | \"base64\"\n}\n\nexport type WorkspaceFileSearchResponse = FileSystemEntry[]\n\nexport interface InstanceData {\n messageHistory: string[]\n agentModelSelections: AgentModelSelection\n}\n\nexport type InstanceStreamStatus = \"connecting\" | \"connected\" | \"error\" | \"disconnected\"\n\nexport type InstanceStreamEvent = OpenCodeEvent\n\nexport type SideCarKind = \"port\"\n\nexport type SideCarPrefixMode = \"strip\" | \"preserve\"\n\nexport type SideCarStatus = \"running\" | \"stopped\"\n\nexport interface SideCar {\n id: string\n kind: SideCarKind\n name: string\n port: number\n insecure: boolean\n prefixMode: SideCarPrefixMode\n status: SideCarStatus\n createdAt: string\n updatedAt: string\n}\n\nexport interface PreviewSession {\n token: string\n sessionId: string\n targetUrl: string\n proxyUrl: string\n createdAt: string\n}\n\nexport interface BinaryRecord {\n id: string\n path: string\n label: string\n version?: string\n\n /** Indicates that this binary will be picked when workspaces omit an explicit choice. */\n isDefault: boolean\n lastValidatedAt?: string\n validationError?: string\n}\n\nexport type SettingsOwner = string\nexport type SettingsBucket = Record<string, unknown>\nexport type SettingsDoc = Record<string, unknown>\n\nexport interface BinaryListResponse {\n binaries: BinaryRecord[]\n}\n\nexport interface BinaryCreateRequest {\n path: string\n label?: string\n makeDefault?: boolean\n}\n\nexport interface BinaryUpdateRequest {\n label?: string\n makeDefault?: boolean\n}\n\nexport const OPENCODE_V2_REQUIRED_ERROR_CODE = \"opencode_v2_required\" as const\nexport const SESSION_ENVIRONMENT_FAILED_ERROR_CODE = \"session_environment_failed\" as const\n\nexport interface BinaryValidationResult {\n valid: boolean\n version?: string\n error?: string\n errorCode?: typeof OPENCODE_V2_REQUIRED_ERROR_CODE\n}\n\nexport interface OpenCodeUpdateStatus {\n currentVersion: string | null\n latestVersion: string | null\n updateAvailable: boolean | null\n canUpgrade: boolean\n checkError?: \"update_check_failed\"\n minimumVersion: string\n recommendedVersion: string\n versionAssessment: \"tested\" | \"untested\" | \"incompatible\"\n incompatibilityReason?: \"step_timestamp\" | \"canonical_api\" | \"session_environment\"\n state: \"missing\" | \"update_required\" | \"ready\" | \"error\"\n binaryPath: string\n installationSource?: \"path\" | \"user\" | \"legacy\"\n needsSharedInstallation?: boolean\n daemonVersion?: string\n serviceState?: \"stopped\" | \"ready\" | \"restart_required\" | \"restart_available\" | \"incompatible\" | \"error\"\n canReload?: boolean\n serviceError?: string\n target: \"host\" | \"wsl\"\n canRestart: boolean\n}\n\nexport interface OpenCodeUpdateResponse {\n success: boolean\n version: string\n}\n\nexport interface SpeechSegment {\n startMs: number\n endMs: number\n text: string\n}\n\nexport interface SpeechCapabilitiesResponse {\n available: boolean\n configured: boolean\n provider: string\n supportsStt: boolean\n supportsTts: boolean\n supportsStreamingTts: boolean\n baseUrl?: string\n sttModel: string\n ttsModel: string\n ttsVoice: string\n ttsFormats: string[]\n streamingTtsFormats: string[]\n separateProviders?: boolean\n sttConfigured?: boolean\n ttsConfigured?: boolean\n sttBaseUrl?: string\n ttsBaseUrl?: string\n}\n\nexport interface SpeechTranscriptionResponse {\n text: string\n language?: string\n durationMs?: number\n segments?: SpeechSegment[]\n}\n\nexport interface SpeechSynthesisResponse {\n audioBase64: string\n mimeType: string\n}\n\nexport interface YoloStateResponse {\n enabled: boolean\n}\n\nexport interface RemoteServerProfile {\n id: string\n name: string\n baseUrl: string\n skipTlsVerify: boolean\n createdAt: string\n updatedAt: string\n lastConnectedAt?: string\n}\n\nexport interface RemoteServerProbeRequest {\n baseUrl: string\n skipTlsVerify?: boolean\n}\n\nexport interface RemoteServerProbeResponse {\n ok: boolean\n reachable: boolean\n normalizedUrl: string\n skipTlsVerify: boolean\n requiresAuth: boolean\n authenticated: boolean\n error?: string\n errorCode?: string\n}\n\nexport interface RemoteProxySessionCreateRequest {\n baseUrl: string\n skipTlsVerify?: boolean\n}\n\nexport interface RemoteProxySessionCreateResponse {\n sessionId: string\n windowUrl: string\n}\n\nexport type WorkspaceEventType =\n | \"workspace.created\"\n | \"workspace.started\"\n | \"workspace.error\"\n | \"workspace.stopped\"\n | \"workspace.log\"\n | \"workspace.worktreesChanged\"\n | \"sidecar.updated\"\n | \"sidecar.removed\"\n | \"storage.configChanged\"\n | \"storage.stateChanged\"\n | \"instance.dataChanged\"\n | \"instance.event\"\n | \"instance.eventStatus\"\n | \"yolo.stateChanged\"\n | \"yolo.autoAccepted\"\n\nexport type WorkspaceEventPayload =\n | { type: \"workspace.created\"; workspace: WorkspaceDescriptor }\n | { type: \"workspace.started\"; workspace: WorkspaceDescriptor }\n | { type: \"workspace.error\"; workspace: WorkspaceDescriptor }\n | { type: \"workspace.stopped\"; workspaceId: string; reason?: \"deleted\" | \"stopped\" }\n | { type: \"workspace.log\"; entry: WorkspaceLogEntry }\n | { type: \"workspace.worktreesChanged\"; workspaceId: string }\n | { type: \"sidecar.updated\"; sidecar: SideCar }\n | { type: \"sidecar.removed\"; sidecarId: string }\n | { type: \"storage.configChanged\"; owner: SettingsOwner; value: SettingsBucket }\n | { type: \"storage.stateChanged\"; owner: SettingsOwner; value: SettingsBucket }\n | { type: \"instance.dataChanged\"; instanceId: string; data: InstanceData }\n | { type: \"instance.event\"; instanceId: string; event: InstanceStreamEvent }\n | { type: \"instance.eventStatus\"; instanceId: string; status: InstanceStreamStatus; generation: number; reason?: string }\n | { type: \"yolo.stateChanged\"; instanceId: string; sessionId: string; enabled: boolean }\n | { type: \"yolo.autoAccepted\"; instanceId: string; sessionId: string; permissionId: string }\n\nexport interface NetworkAddress {\n ip: string\n family: \"ipv4\" | \"ipv6\"\n scope: \"external\" | \"internal\" | \"loopback\"\n /** Remote URL using the server's remote protocol/port for this IP. */\n remoteUrl: string\n}\n\nexport interface LatestReleaseInfo {\n version: string\n tag: string\n url: string\n channel: \"stable\" | \"dev\"\n publishedAt?: string\n notes?: string\n}\n\nexport interface UiMeta {\n version?: string\n source: \"bundled\" | \"downloaded\" | \"previous\" | \"override\" | \"dev-proxy\" | \"missing\"\n}\n\nexport interface SupportMeta {\n supported: boolean\n message?: string\n minServerVersion?: string\n latestServerVersion?: string\n latestServerUrl?: string\n}\n\nexport interface ServerMeta {\n /** URL desktop apps should use to connect (prefers loopback HTTP when enabled). */\n localUrl: string\n /** URL remote clients should use (prefers HTTPS when enabled). */\n remoteUrl?: string\n /** SSE endpoint advertised to clients (`/api/events` by default). */\n eventsUrl: string\n /** Host the server is bound to (e.g., 127.0.0.1 or 0.0.0.0). */\n host: string\n /** Listening mode derived from host binding. */\n listeningMode: \"local\" | \"all\"\n /** Actual local port in use after binding. */\n localPort: number\n /** Actual remote port in use after binding (when remoteUrl is set). */\n remotePort?: number\n /** Display label for the host (e.g., hostname or friendly name). */\n hostLabel: string\n /** Absolute path of the filesystem root exposed to clients. */\n workspaceRoot: string\n /** Reachable addresses for this server, external first. */\n addresses: NetworkAddress[]\n serverVersion?: string\n ui?: UiMeta\n support?: SupportMeta\n /** Optional update info (dev channel only). */\n update?: LatestReleaseInfo | null\n}\n\nexport type {\n Preferences,\n ModelPreference,\n AgentModelSelections,\n RecentFolder,\n OpenCodeBinary,\n}\nexport type { PruneRequest, PruneResult } from \"./opencode/session-pruning/contract\"\n"]}
|
|
1
|
+
{"version":3,"file":"api-types.js","sourceRoot":"","sources":["../src/api-types.ts"],"names":[],"mappings":"AAkSA,MAAM,CAAC,MAAM,mBAAmB,GAAG,YAAY,CAAA;AA8E/C,MAAM,CAAC,MAAM,+BAA+B,GAAG,sBAA+B,CAAA;AAC9E,MAAM,CAAC,MAAM,qCAAqC,GAAG,4BAAqC,CAAA","sourcesContent":["import type {\n AgentModelSelection,\n AgentModelSelections,\n ModelPreference,\n OpenCodeBinary,\n Preferences,\n RecentFolder,\n} from \"./config/schema\"\nimport type { OpenCodeEvent } from \"@opencode/client\"\n\n/**\n * Canonical HTTP/SSE contract for the CLI server.\n * These types are consumed by both the CLI implementation and any UI clients.\n */\n\nexport type WorkspaceStatus = \"starting\" | \"ready\" | \"stopped\" | \"error\"\n\nexport interface WorkspaceDescriptor {\n id: string\n /** Correlates creation events with the client request that initiated them. */\n requestId?: string\n /** Absolute path on the server host. */\n path: string\n name?: string\n status: WorkspaceStatus\n /** PID/port are populated when the workspace is running. */\n pid?: number\n port?: number\n /** Canonical proxy path the CLI exposes for this instance. */\n proxyPath: string\n /** Identifier of the binary resolved from config. */\n binaryId: string\n binaryLabel: string\n binaryVersion?: string\n createdAt: string\n updatedAt: string\n /** Present when `status` is \"error\". */\n error?: string\n}\n\nexport interface WorkspaceCreateRequest {\n path: string\n name?: string\n requestId?: string\n}\n\nexport interface WorkspaceCloneRequest {\n repositoryUrl: string\n destinationPath: string\n cleanup?: boolean\n}\n\nexport interface WorkspaceCloneResponse {\n path: string\n}\n\nexport type WorkspaceCreateResponse = WorkspaceDescriptor & {\n /** True when this request did not own creation of the returned workspace. */\n reused?: true\n}\nexport type WorkspaceListResponse = WorkspaceDescriptor[]\nexport type WorkspaceDetailResponse = WorkspaceDescriptor\n\nexport interface WorkspaceDeleteResponse {\n id: string\n status: WorkspaceStatus\n}\n\nexport interface ProviderUsageWindow {\n usedPercent: number | null\n remainingPercent: number | null\n windowSeconds: number | null\n resetAt: number | null\n valueLabel?: string\n}\n\nexport interface ProviderUsageResponse {\n requestedProviderId: string\n providerId: string | null\n providerName: string\n modelId?: string\n supported: boolean\n configured: boolean\n ok: boolean\n windows: Record<string, ProviderUsageWindow>\n fetchedAt: number\n}\n\nexport type WorktreeKind = \"root\" | \"worktree\"\n\nexport interface WorktreeDescriptor {\n /** Stable identifier used by CodeNomad + clients (\"root\" for the selected workspace folder). */\n slug: string\n /** Presentation only; the worktree identifier does not change with its branch. */\n label?: string\n /** Absolute directory path on the server host. */\n directory: string\n /** Equivalent path in the OpenCode service namespace (notably WSL). */\n serviceDirectory?: string\n /** Native checkout root (before mirroring a nested workspace folder). */\n serviceRoot?: string\n /** Exact path registered in Git's worktree inventory. */\n registeredDirectory?: string\n /** Degraded mode: only this exact physical directory authorizes sessions. */\n directoryOnly?: boolean\n kind: WorktreeKind\n /** False for the opened folder and Git's main checkout. */\n removable?: boolean\n /** Optional VCS branch name when available. */\n branch?: string\n /** Commit recorded by the Git worktree inventory. */\n head?: string\n}\n\nexport interface WorktreeListResponse {\n /** False means directory-only degraded mode; repository membership is unknown. */\n gitAvailable?: boolean\n worktrees: WorktreeDescriptor[]\n /** Default creation parent in the OpenCode service namespace. */\n defaultDirectory?: string\n /** True when the workspace folder resolves to a Git repository. */\n isGitRepo?: boolean\n}\n\nexport interface WorktreeCreateRequest {\n slug: string\n fromSlug?: string\n /** Optional branch name (defaults to slug). */\n branch?: string\n}\n\nexport interface WorktreeSessionMoveRequest {\n worktreeSlug: string\n}\n\nexport interface WorktreeSessionMoveResponse {\n rootSessionId: string\n sessionIds: string[]\n worktreeSlug: string\n}\n\nexport type GitChangeKind = \"added\" | \"modified\" | \"deleted\" | \"renamed\" | \"copied\" | \"untracked\" | \"unmerged\"\n\nexport interface WorktreeGitStatusEntry {\n path: string\n originalPath?: string | null\n stagedStatus: GitChangeKind | null\n stagedAdditions: number\n stagedDeletions: number\n unstagedStatus: GitChangeKind | null\n unstagedAdditions: number\n unstagedDeletions: number\n}\n\nexport type WorktreeGitStatusResponse = WorktreeGitStatusEntry[]\n\nexport type WorktreeGitDiffScope = \"staged\" | \"unstaged\"\n\nexport interface WorktreeGitPathsRequest {\n paths: string[]\n}\n\nexport interface WorktreeGitMutationResponse {\n ok: true\n}\n\nexport interface WorktreeGitCommitRequest {\n message: string\n}\n\nexport interface WorktreeGitCommitResponse {\n ok: true\n commitSha?: string\n}\n\nexport interface WorktreeGitDiffResponse {\n path: string\n originalPath?: string | null\n scope: WorktreeGitDiffScope\n before: string\n after: string\n isBinary?: boolean\n}\n\nexport interface WorktreeGitDiffRequest {\n path: string\n originalPath?: string | null\n scope: WorktreeGitDiffScope\n}\n\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\"\n\nexport interface WorkspaceLogEntry {\n workspaceId: string\n timestamp: string\n level: LogLevel\n message: string\n}\n\nexport interface FileSystemEntry {\n name: string\n /**\n * Path identifier for the entry. Relative to the server root in restricted\n * single-root listings (\".\" represents the root itself); absolute in\n * unrestricted, drives, and multi-root top-level listings.\n */\n path: string\n /** Absolute path when available (unrestricted and multi-root listings). */\n absolutePath?: string\n type: \"file\" | \"directory\"\n size?: number\n /** ISO timestamp of last modification when available. */\n modifiedAt?: string\n}\n\nexport type FileSystemScope = \"restricted\" | \"unrestricted\"\nexport type FileSystemPathKind = \"relative\" | \"absolute\" | \"drives\"\n\nexport interface FileSystemListingMetadata {\n scope: FileSystemScope\n /**\n * Canonical identifier of the current view:\n * - \".\" for restricted single-root listings\n * - WINDOWS_DRIVES_ROOT for the Windows drives pseudo-root\n * - absolute path otherwise\n */\n currentPath: string\n /** Optional parent path if navigation upward is allowed. */\n parentPath?: string\n /** Absolute path representing the root or origin point for this listing. */\n rootPath: string\n /** Absolute home directory of the CLI host (useful defaults for unrestricted mode). */\n homePath: string\n /** Human-friendly label for the current path. */\n displayPath: string\n /** Indicates whether entry paths are relative, absolute, or represent the drive pseudo-view. */\n pathKind: FileSystemPathKind\n}\n\nexport interface FileSystemListResponse {\n entries: FileSystemEntry[]\n metadata: FileSystemListingMetadata\n}\n\nexport interface FileSystemCreateFolderRequest {\n /**\n * Path identifier for the currently browsed directory.\n * Matches the `path` parameter used for `/api/filesystem`.\n */\n parentPath?: string\n /** Single folder name (no separators). */\n name: string\n}\n\nexport interface FileSystemCreateFolderResponse {\n /**\n * Path identifier that can be passed back to `/api/filesystem` to browse the new folder.\n * Relative for restricted listings and absolute for unrestricted listings.\n */\n path: string\n /** Absolute folder path on the server host. */\n absolutePath: string\n}\n\nexport interface FileSystemFileContentResponse {\n path: string\n contents: string\n encoding: \"utf-8\" | \"base64\"\n}\n\nexport interface ConfigFileDescriptor {\n id: string\n label: string\n path: string\n language: string\n}\n\nexport type ConfigFileListResponse = ConfigFileDescriptor[]\n\nexport interface ConfigFileContentResponse {\n id: string\n path: string\n contents: string\n exists: boolean\n}\n\nexport interface ConfigFileContentRequest {\n contents: string\n}\n\nexport const WINDOWS_DRIVES_ROOT = \"__drives__\"\n\nexport interface WorkspaceFileResponse {\n workspaceId: string\n relativePath: string\n /** UTF-8 file contents; binary files should be base64 encoded by the caller. */\n contents: string\n encoding?: \"utf-8\" | \"base64\"\n}\n\nexport type WorkspaceFileSearchResponse = FileSystemEntry[]\n\nexport interface InstanceData {\n messageHistory: string[]\n agentModelSelections: AgentModelSelection\n}\n\nexport type InstanceStreamStatus = \"connecting\" | \"connected\" | \"error\" | \"disconnected\"\n\nexport type InstanceStreamEvent = OpenCodeEvent\n\nexport type SideCarKind = \"port\"\n\nexport type SideCarPrefixMode = \"strip\" | \"preserve\"\n\nexport type SideCarStatus = \"running\" | \"stopped\"\n\nexport interface SideCar {\n id: string\n kind: SideCarKind\n name: string\n port: number\n insecure: boolean\n prefixMode: SideCarPrefixMode\n status: SideCarStatus\n createdAt: string\n updatedAt: string\n}\n\nexport interface PreviewSession {\n token: string\n sessionId: string\n targetUrl: string\n proxyUrl: string\n createdAt: string\n}\n\nexport interface BinaryRecord {\n id: string\n path: string\n label: string\n version?: string\n\n /** Indicates that this binary will be picked when workspaces omit an explicit choice. */\n isDefault: boolean\n lastValidatedAt?: string\n validationError?: string\n}\n\nexport type SettingsOwner = string\nexport type SettingsBucket = Record<string, unknown>\nexport type SettingsDoc = Record<string, unknown>\n\nexport interface BinaryListResponse {\n binaries: BinaryRecord[]\n}\n\nexport interface BinaryCreateRequest {\n path: string\n label?: string\n makeDefault?: boolean\n}\n\nexport interface BinaryUpdateRequest {\n label?: string\n makeDefault?: boolean\n}\n\nexport const OPENCODE_V2_REQUIRED_ERROR_CODE = \"opencode_v2_required\" as const\nexport const SESSION_ENVIRONMENT_FAILED_ERROR_CODE = \"session_environment_failed\" as const\n\nexport interface BinaryValidationResult {\n valid: boolean\n version?: string\n error?: string\n errorCode?: typeof OPENCODE_V2_REQUIRED_ERROR_CODE\n}\n\nexport interface OpenCodeUpdateStatus {\n currentVersion: string | null\n latestVersion: string | null\n updateAvailable: boolean | null\n canUpgrade: boolean\n checkError?: \"update_check_failed\"\n minimumVersion: string\n recommendedVersion: string\n versionAssessment: \"tested\" | \"untested\" | \"incompatible\"\n incompatibilityReason?: \"step_timestamp\" | \"canonical_api\" | \"session_environment\"\n state: \"missing\" | \"update_required\" | \"ready\" | \"error\"\n binaryPath: string\n installationSource?: \"path\" | \"user\"\n needsSharedInstallation?: boolean\n daemonVersion?: string\n serviceState?: \"stopped\" | \"ready\" | \"restart_required\" | \"restart_available\" | \"incompatible\" | \"error\"\n canReload?: boolean\n serviceError?: string\n target: \"host\" | \"wsl\"\n canRestart: boolean\n}\n\nexport interface OpenCodeUpdateResponse {\n success: boolean\n version: string\n}\n\nexport interface SpeechSegment {\n startMs: number\n endMs: number\n text: string\n}\n\nexport interface SpeechCapabilitiesResponse {\n available: boolean\n configured: boolean\n provider: string\n supportsStt: boolean\n supportsTts: boolean\n supportsStreamingTts: boolean\n baseUrl?: string\n sttModel: string\n ttsModel: string\n ttsVoice: string\n ttsFormats: string[]\n streamingTtsFormats: string[]\n separateProviders?: boolean\n sttConfigured?: boolean\n ttsConfigured?: boolean\n sttBaseUrl?: string\n ttsBaseUrl?: string\n}\n\nexport interface SpeechTranscriptionResponse {\n text: string\n language?: string\n durationMs?: number\n segments?: SpeechSegment[]\n}\n\nexport interface SpeechSynthesisResponse {\n audioBase64: string\n mimeType: string\n}\n\nexport interface YoloStateResponse {\n enabled: boolean\n}\n\nexport interface RemoteServerProfile {\n id: string\n name: string\n baseUrl: string\n skipTlsVerify: boolean\n createdAt: string\n updatedAt: string\n lastConnectedAt?: string\n}\n\nexport interface RemoteServerProbeRequest {\n baseUrl: string\n skipTlsVerify?: boolean\n}\n\nexport interface RemoteServerProbeResponse {\n ok: boolean\n reachable: boolean\n normalizedUrl: string\n skipTlsVerify: boolean\n requiresAuth: boolean\n authenticated: boolean\n error?: string\n errorCode?: string\n}\n\nexport interface RemoteProxySessionCreateRequest {\n baseUrl: string\n skipTlsVerify?: boolean\n}\n\nexport interface RemoteProxySessionCreateResponse {\n sessionId: string\n windowUrl: string\n}\n\nexport type WorkspaceEventType =\n | \"workspace.created\"\n | \"workspace.started\"\n | \"workspace.error\"\n | \"workspace.stopped\"\n | \"workspace.log\"\n | \"workspace.worktreesChanged\"\n | \"sidecar.updated\"\n | \"sidecar.removed\"\n | \"storage.configChanged\"\n | \"storage.stateChanged\"\n | \"instance.dataChanged\"\n | \"instance.event\"\n | \"instance.eventStatus\"\n | \"yolo.stateChanged\"\n | \"yolo.autoAccepted\"\n\nexport type WorkspaceEventPayload =\n | { type: \"workspace.created\"; workspace: WorkspaceDescriptor }\n | { type: \"workspace.started\"; workspace: WorkspaceDescriptor }\n | { type: \"workspace.error\"; workspace: WorkspaceDescriptor }\n | { type: \"workspace.stopped\"; workspaceId: string; reason?: \"deleted\" | \"stopped\" }\n | { type: \"workspace.log\"; entry: WorkspaceLogEntry }\n | { type: \"workspace.worktreesChanged\"; workspaceId: string }\n | { type: \"sidecar.updated\"; sidecar: SideCar }\n | { type: \"sidecar.removed\"; sidecarId: string }\n | { type: \"storage.configChanged\"; owner: SettingsOwner; value: SettingsBucket }\n | { type: \"storage.stateChanged\"; owner: SettingsOwner; value: SettingsBucket }\n | { type: \"instance.dataChanged\"; instanceId: string; data: InstanceData }\n | { type: \"instance.event\"; instanceId: string; event: InstanceStreamEvent }\n | { type: \"instance.eventStatus\"; instanceId: string; status: InstanceStreamStatus; generation: number; reason?: string }\n | { type: \"yolo.stateChanged\"; instanceId: string; sessionId: string; enabled: boolean }\n | { type: \"yolo.autoAccepted\"; instanceId: string; sessionId: string; permissionId: string }\n\nexport interface NetworkAddress {\n ip: string\n family: \"ipv4\" | \"ipv6\"\n scope: \"external\" | \"internal\" | \"loopback\"\n /** Remote URL using the server's remote protocol/port for this IP. */\n remoteUrl: string\n}\n\nexport interface LatestReleaseInfo {\n version: string\n tag: string\n url: string\n channel: \"stable\" | \"dev\"\n publishedAt?: string\n notes?: string\n}\n\nexport interface UiMeta {\n version?: string\n source: \"bundled\" | \"downloaded\" | \"previous\" | \"override\" | \"dev-proxy\" | \"missing\"\n}\n\nexport interface SupportMeta {\n supported: boolean\n message?: string\n minServerVersion?: string\n latestServerVersion?: string\n latestServerUrl?: string\n}\n\nexport interface ServerMeta {\n /** URL desktop apps should use to connect (prefers loopback HTTP when enabled). */\n localUrl: string\n /** URL remote clients should use (prefers HTTPS when enabled). */\n remoteUrl?: string\n /** SSE endpoint advertised to clients (`/api/events` by default). */\n eventsUrl: string\n /** Host the server is bound to (e.g., 127.0.0.1 or 0.0.0.0). */\n host: string\n /** Listening mode derived from host binding. */\n listeningMode: \"local\" | \"all\"\n /** Actual local port in use after binding. */\n localPort: number\n /** Actual remote port in use after binding (when remoteUrl is set). */\n remotePort?: number\n /** Display label for the host (e.g., hostname or friendly name). */\n hostLabel: string\n /** Absolute path of the filesystem root exposed to clients. */\n workspaceRoot: string\n /** Reachable addresses for this server, external first. */\n addresses: NetworkAddress[]\n serverVersion?: string\n ui?: UiMeta\n support?: SupportMeta\n /** Optional update info (dev channel only). */\n update?: LatestReleaseInfo | null\n}\n\nexport type {\n Preferences,\n ModelPreference,\n AgentModelSelections,\n RecentFolder,\n OpenCodeBinary,\n}\nexport type { PruneRequest, PruneResult } from \"./opencode/session-pruning/contract\"\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
/** npm from the official Node archive, beside the backend runtime on both hosts. */
|
|
5
|
+
export function bundledNpm(execPath = process.execPath) {
|
|
6
|
+
const directory = path.dirname(execPath);
|
|
7
|
+
const candidates = [path.join(directory, "node_modules", "npm", "bin", "npm-cli.js"),
|
|
8
|
+
path.join(directory, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")];
|
|
9
|
+
return candidates.find(candidate => existsSync(candidate));
|
|
10
|
+
}
|
|
11
|
+
export function executeInstaller(file, args, env) {
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
execFile(file, args, { env, windowsHide: true, timeout: 300_000, maxBuffer: 1024 * 1024 }, error => {
|
|
14
|
+
// Do not return npm's environment/config diagnostics to the browser.
|
|
15
|
+
if (error)
|
|
16
|
+
reject(new Error(`OpenCode installation failed (${error.killed ? "timeout" : error.code ?? "execution"})`));
|
|
17
|
+
else
|
|
18
|
+
resolve();
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=npm-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"npm-runtime.js","sourceRoot":"","sources":["../../src/opencode-update/npm-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,oFAAoF;AACpF,MAAM,UAAU,UAAU,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ;IACpD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IACxC,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC;QAClF,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAA;IAChF,OAAO,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAA;AAC5D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,IAAc,EAAE,GAAsB;IACnF,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,GAAG,IAAI,EAAE,EAAE,KAAK,CAAC,EAAE;YACjG,qEAAqE;YACrE,IAAI,KAAK;gBAAE,MAAM,CAAC,IAAI,KAAK,CAAC,iCAAiC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,IAAI,WAAW,GAAG,CAAC,CAAC,CAAA;;gBACjH,OAAO,EAAE,CAAA;QAChB,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import { execFile } from \"node:child_process\"\nimport { existsSync } from \"node:fs\"\nimport path from \"node:path\"\n\n/** npm from the official Node archive, beside the backend runtime on both hosts. */\nexport function bundledNpm(execPath = process.execPath): string | undefined {\n const directory = path.dirname(execPath)\n const candidates = [path.join(directory, \"node_modules\", \"npm\", \"bin\", \"npm-cli.js\"),\n path.join(directory, \"..\", \"lib\", \"node_modules\", \"npm\", \"bin\", \"npm-cli.js\")]\n return candidates.find(candidate => existsSync(candidate))\n}\n\nexport function executeInstaller(file: string, args: string[], env: NodeJS.ProcessEnv): Promise<void> {\n return new Promise((resolve, reject) => {\n execFile(file, args, { env, windowsHide: true, timeout: 300_000, maxBuffer: 1024 * 1024 }, error => {\n // Do not return npm's environment/config diagnostics to the browser.\n if (error) reject(new Error(`OpenCode installation failed (${error.killed ? \"timeout\" : error.code ?? \"execution\"})`))\n else resolve()\n })\n })\n}\n"]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { accessSync, constants, realpathSync, statSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
// The prerelease private runtime is no longer an executable source, including
|
|
4
|
+
// saved selections and PATH aliases. Do not read receipts or delete its files.
|
|
5
|
+
export function isRetiredInstallation(binary) {
|
|
6
|
+
const retired = (value) => /(?:^|\/)\.local\/share\/codenomad\/opencode(?:\/|$)/i
|
|
7
|
+
.test(path.posix.normalize(value.replaceAll("\\", "/")));
|
|
8
|
+
if (retired(binary))
|
|
9
|
+
return true;
|
|
10
|
+
// WSL/network paths are checked lexically, never synchronously probed through
|
|
11
|
+
// the host filesystem just to decide whether this local tree was retired.
|
|
12
|
+
if (/^(?:\\\\|\/\/)/.test(binary))
|
|
13
|
+
return false;
|
|
14
|
+
try {
|
|
15
|
+
return retired(realpathSync(binary));
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function assertCurrentInstallation(binary, env = process.env) {
|
|
22
|
+
if (process.platform !== "win32" && !binary.includes("/")) {
|
|
23
|
+
for (const directory of (env.PATH ?? "").split(path.delimiter)) {
|
|
24
|
+
const candidate = path.resolve(directory || ".", binary);
|
|
25
|
+
try {
|
|
26
|
+
if (!statSync(candidate).isFile())
|
|
27
|
+
continue;
|
|
28
|
+
accessSync(candidate, constants.X_OK);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
binary = candidate;
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (isRetiredInstallation(binary)) {
|
|
38
|
+
throw Object.assign(new Error("opencode_private_installation_retired"), { code: "ENOENT" });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=retired-installation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retired-installation.js","sourceRoot":"","sources":["../../src/opencode-update/retired-installation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AACvE,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,8EAA8E;AAC9E,+EAA+E;AAC/E,MAAM,UAAU,qBAAqB,CAAC,MAAc;IAClD,MAAM,OAAO,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,sDAAsD;SACtF,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;IAC1D,IAAI,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAA;IAChC,8EAA8E;IAC9E,0EAA0E;IAC1E,IAAI,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAA;IAC/C,IAAI,CAAC;QAAC,OAAO,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAA;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,KAAK,CAAA;IAAC,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,MAAc,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG;IACzE,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1D,KAAK,MAAM,SAAS,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YAC/D,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,GAAG,EAAE,MAAM,CAAC,CAAA;YACxD,IAAI,CAAC;gBACH,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE;oBAAE,SAAQ;gBAC3C,UAAU,CAAC,SAAS,EAAE,SAAS,CAAC,IAAI,CAAC,CAAA;YACvC,CAAC;YAAC,MAAM,CAAC;gBAAC,SAAQ;YAAC,CAAC;YACpB,MAAM,GAAG,SAAS,CAAA;YAClB,MAAK;QACP,CAAC;IACH,CAAC;IACD,IAAI,qBAAqB,CAAC,MAAM,CAAC,EAAE,CAAC;QAClC,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,uCAAuC,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAA;IAC7F,CAAC;AACH,CAAC","sourcesContent":["import { accessSync, constants, realpathSync, statSync } from \"node:fs\"\nimport path from \"node:path\"\n\n// The prerelease private runtime is no longer an executable source, including\n// saved selections and PATH aliases. Do not read receipts or delete its files.\nexport function isRetiredInstallation(binary: string): boolean {\n const retired = (value: string) => /(?:^|\\/)\\.local\\/share\\/codenomad\\/opencode(?:\\/|$)/i\n .test(path.posix.normalize(value.replaceAll(\"\\\\\", \"/\")))\n if (retired(binary)) return true\n // WSL/network paths are checked lexically, never synchronously probed through\n // the host filesystem just to decide whether this local tree was retired.\n if (/^(?:\\\\\\\\|\\/\\/)/.test(binary)) return false\n try { return retired(realpathSync(binary)) } catch { return false }\n}\n\nexport function assertCurrentInstallation(binary: string, env = process.env): void {\n if (process.platform !== \"win32\" && !binary.includes(\"/\")) {\n for (const directory of (env.PATH ?? \"\").split(path.delimiter)) {\n const candidate = path.resolve(directory || \".\", binary)\n try {\n if (!statSync(candidate).isFile()) continue\n accessSync(candidate, constants.X_OK)\n } catch { continue }\n binary = candidate\n break\n }\n }\n if (isRetiredInstallation(binary)) {\n throw Object.assign(new Error(\"opencode_private_installation_retired\"), { code: \"ENOENT\" })\n }\n}\n"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { mkdtemp, mkdir, writeFile, rm } from "node:fs/promises";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { BinaryResolver } from "../settings/binaries";
|
|
7
|
+
import { buildServiceLaunchSpec, buildSpawnSpec, probeOpenCodeBinary } from "../workspaces/spawn";
|
|
8
|
+
import { resolveDefaultInstallation, sharedInstallPrefix, userNpmPrefix } from "./shared-installation";
|
|
9
|
+
test("private executables are rejected before validation or launch, including an explicit selection", async () => {
|
|
10
|
+
const binary = path.join(os.homedir(), ".local/share/codenomad/opencode/2.0.15/node_modules/@opencode/cli/bin/opencode.exe");
|
|
11
|
+
let executed = false;
|
|
12
|
+
const validation = await probeOpenCodeBinary(binary, async () => { executed = true; return { status: 0, stdout: "opencode v2.0.15" }; });
|
|
13
|
+
assert.equal(validation.valid, false);
|
|
14
|
+
assert.equal(executed, false);
|
|
15
|
+
assert.throws(() => buildSpawnSpec(binary, ["service", "start"]), /opencode_private_installation_retired/);
|
|
16
|
+
assert.throws(() => buildServiceLaunchSpec(binary), /opencode_private_installation_retired/);
|
|
17
|
+
const settings = { getOwner: (scope) => scope === "config"
|
|
18
|
+
? { opencodeBinary: binary } : { opencodeBinaries: [{ path: binary }, { path: "custom" }] } };
|
|
19
|
+
const resolver = new BinaryResolver(settings, () => ({ path: "opencode2" }));
|
|
20
|
+
assert.equal(resolver.resolveDefault().path, "opencode2");
|
|
21
|
+
assert.deepEqual(resolver.list(), [{ path: "custom" }]);
|
|
22
|
+
});
|
|
23
|
+
test("private PATH entries cannot be launched or selected as a shared install prefix", async () => {
|
|
24
|
+
const home = await mkdtemp(path.join(os.tmpdir(), "retired-opencode-"));
|
|
25
|
+
try {
|
|
26
|
+
const directory = path.join(home, ".local/share/codenomad/opencode/2.0.15/bin");
|
|
27
|
+
await mkdir(directory, { recursive: true });
|
|
28
|
+
await writeFile(path.join(directory, process.platform === "win32" ? "opencode2.exe" : "opencode2"), "retired", { mode: 0o755 });
|
|
29
|
+
const host = { home, env: { PATH: directory, APPDATA: path.join(home, "AppData") } };
|
|
30
|
+
assert.deepEqual(resolveDefaultInstallation(host), { path: "opencode2" });
|
|
31
|
+
assert.equal(sharedInstallPrefix(host), userNpmPrefix(host));
|
|
32
|
+
assert.throws(() => buildSpawnSpec("opencode2", ["service", "start"], { env: host.env }), /opencode_private_installation_retired/);
|
|
33
|
+
assert.equal(sharedInstallPrefix({ ...host, env: { ...host.env, npm_config_prefix: directory } }), undefined);
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
await rm(home, { recursive: true, force: true });
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
//# sourceMappingURL=retired-installation.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retired-installation.test.js","sourceRoot":"","sources":["../../src/opencode-update/retired-installation.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\"\nimport test from \"node:test\"\nimport { mkdtemp, mkdir, writeFile, rm } from \"node:fs/promises\"\nimport os from \"node:os\"\nimport path from \"node:path\"\nimport { BinaryResolver } from \"../settings/binaries\"\nimport type { SettingsService } from \"../settings/service\"\nimport { buildServiceLaunchSpec, buildSpawnSpec, probeOpenCodeBinary } from \"../workspaces/spawn\"\nimport { resolveDefaultInstallation, sharedInstallPrefix, userNpmPrefix } from \"./shared-installation\"\n\ntest(\"private executables are rejected before validation or launch, including an explicit selection\", async () => {\n const binary = path.join(os.homedir(), \".local/share/codenomad/opencode/2.0.15/node_modules/@opencode/cli/bin/opencode.exe\")\n let executed = false\n const validation = await probeOpenCodeBinary(binary, async () => { executed = true; return { status: 0, stdout: \"opencode v2.0.15\" } })\n assert.equal(validation.valid, false)\n assert.equal(executed, false)\n assert.throws(() => buildSpawnSpec(binary, [\"service\", \"start\"]), /opencode_private_installation_retired/)\n assert.throws(() => buildServiceLaunchSpec(binary), /opencode_private_installation_retired/)\n const settings = { getOwner: (scope: string) => scope === \"config\"\n ? { opencodeBinary: binary } : { opencodeBinaries: [{ path: binary }, { path: \"custom\" }] } } as unknown as SettingsService\n const resolver = new BinaryResolver(settings, () => ({ path: \"opencode2\" }))\n assert.equal(resolver.resolveDefault().path, \"opencode2\")\n assert.deepEqual(resolver.list(), [{ path: \"custom\" }])\n})\n\ntest(\"private PATH entries cannot be launched or selected as a shared install prefix\", async () => {\n const home = await mkdtemp(path.join(os.tmpdir(), \"retired-opencode-\"))\n try {\n const directory = path.join(home, \".local/share/codenomad/opencode/2.0.15/bin\")\n await mkdir(directory, { recursive: true })\n await writeFile(path.join(directory, process.platform === \"win32\" ? \"opencode2.exe\" : \"opencode2\"), \"retired\", { mode: 0o755 })\n const host = { home, env: { PATH: directory, APPDATA: path.join(home, \"AppData\") } }\n assert.deepEqual(resolveDefaultInstallation(host), { path: \"opencode2\" })\n assert.equal(sharedInstallPrefix(host), userNpmPrefix(host))\n assert.throws(() => buildSpawnSpec(\"opencode2\", [\"service\", \"start\"], { env: host.env }), /opencode_private_installation_retired/)\n assert.equal(sharedInstallPrefix({ ...host, env: { ...host.env, npm_config_prefix: directory } }), undefined)\n } finally { await rm(home, { recursive: true, force: true }) }\n})\n"]}
|
|
@@ -5,7 +5,8 @@ import { compareVersionStrings, stripTagPrefix } from "../releases/release-monit
|
|
|
5
5
|
import { assertSupportedOpenCode, isBelowOpenCodeMinimum, MINIMUM_OPENCODE_VERSION, RECOMMENDED_OPENCODE_VERSION, UnsupportedOpenCodeError } from "../opencode/runtime-support";
|
|
6
6
|
import { contractProfile, runtimeIdentity } from "../opencode/compatibility/runtime";
|
|
7
7
|
import { createRuntimeTransport } from "../opencode/compatibility/transport";
|
|
8
|
-
import { bundledNpm } from "./
|
|
8
|
+
import { bundledNpm } from "./npm-runtime";
|
|
9
|
+
import { isRetiredInstallation } from "./retired-installation";
|
|
9
10
|
import { installSharedOpenCode, sharedInstallPrefix } from "./shared-installation";
|
|
10
11
|
import { InstallationBusyError } from "./installation-lock";
|
|
11
12
|
import { parseWslUncPath } from "../workspaces/spawn";
|
|
@@ -270,7 +271,7 @@ export function createOpenCodeUpdateService(settings, workspaceManager) {
|
|
|
270
271
|
resolveLatestVersion: resolveLatestOpenCodeVersion,
|
|
271
272
|
canUpgradeBinary: binary => {
|
|
272
273
|
const configured = settings.getOwner("config", "server").opencodeBinary;
|
|
273
|
-
return !parseWslUncPath(binary.path) && (!configured || configured === "opencode" || configured === "opencode2") && Boolean(bundledNpm()) && Boolean(sharedInstallPrefix());
|
|
274
|
+
return !parseWslUncPath(binary.path) && (!configured || configured === "opencode" || configured === "opencode2" || (typeof configured === "string" && isRetiredInstallation(configured))) && Boolean(bundledNpm()) && Boolean(sharedInstallPrefix());
|
|
274
275
|
},
|
|
275
276
|
upgradeBinary: async (_binary, version) => {
|
|
276
277
|
await installSharedOpenCode(version);
|
|
@@ -286,6 +287,6 @@ function comparableVersion(version) {
|
|
|
286
287
|
return /^\d+\.\d+\.\d+$/.test(version) || /^0\.0\.0-beta-\d+$/.test(version);
|
|
287
288
|
}
|
|
288
289
|
function needsSharedInstallation(binary) {
|
|
289
|
-
return binary.source === "
|
|
290
|
+
return binary.source === "user";
|
|
290
291
|
}
|
|
291
292
|
//# sourceMappingURL=service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/opencode-update/service.ts"],"names":[],"mappings":"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","sourcesContent":["import { fetch } from \"undici\"\nimport type { OpenCodeUpdateResponse, OpenCodeUpdateStatus } from \"../api-types\"\nimport type { SettingsService } from \"../settings/service\"\nimport { BinaryResolver, type ResolvedBinary } from \"../settings/binaries\"\nimport type { WorkspaceManager } from \"../workspaces/manager\"\nimport { probeBinaryVersion, probeBinaryVersionAsync } from \"../workspaces/spawn\"\nimport { compareVersionStrings, stripTagPrefix } from \"../releases/release-monitor\"\nimport { assertSupportedOpenCode, isBelowOpenCodeMinimum, MINIMUM_OPENCODE_VERSION, RECOMMENDED_OPENCODE_VERSION, UnsupportedOpenCodeError } from \"../opencode/runtime-support\"\nimport { contractProfile, runtimeIdentity } from \"../opencode/compatibility/runtime\"\nimport { createRuntimeTransport } from \"../opencode/compatibility/transport\"\nimport type { Endpoint } from \"@opencode/client/service\"\nimport { bundledNpm } from \"./managed-installation\"\nimport { installSharedOpenCode, sharedInstallPrefix } from \"./shared-installation\"\nimport { InstallationBusyError } from \"./installation-lock\"\nimport type { OpenCodeServiceLifecycle } from \"../workspaces/opencode-service\"\nimport { parseWslUncPath } from \"../workspaces/spawn\"\n\nconst OPENCODE_REGISTRY_URL = \"https://registry.npmjs.org/-/package/%40opencode%2Fcli/dist-tags\"\nexport const TARGET_OPENCODE_CHANNEL = \"latest\"\nconst inFlightUpgrades = new Map<string, Promise<OpenCodeUpdateResponse>>()\ntype ServiceAction = \"start\" | \"restart\" | \"reload\"\n\ntype UpgradeResult = { success: true; version: string } | { success: false; error: string }\n\nexport interface OpenCodeUpdateServiceDeps {\n resolveBinary: () => ResolvedBinary\n probeBinary: (path: string) => ReturnType<typeof probeBinaryVersion> | Promise<ReturnType<typeof probeBinaryVersion>>\n resolveLatestVersion: () => Promise<string>\n canUpgradeBinary: (binary: ResolvedBinary) => boolean\n upgradeBinary: (binary: ResolvedBinary, target: string) => Promise<UpgradeResult>\n lifecycle?: (binary: ResolvedBinary) => Promise<OpenCodeServiceLifecycle>\n reconnect?: (binary: ResolvedBinary) => Promise<void>\n admitActivation?: (binary: ResolvedBinary) => void\n reload?: (binary: ResolvedBinary, assertCurrent: () => void) => Promise<void>\n inspectRuntime?: (endpoint: Endpoint) => Promise<{ reload: boolean }>\n}\n\nexport class OpenCodeUpdateError extends Error {\n constructor(\n readonly code:\n | \"binary_unavailable\"\n | \"unsupported_binary\"\n | \"update_check_failed\"\n | \"upgrade_failed\"\n | \"upgrade_verification_failed\",\n message: string,\n ) {\n super(message)\n this.name = \"OpenCodeUpdateError\"\n }\n}\n\nexport class OpenCodeUpdateService {\n private activation?: { binaryPath: string; action: ServiceAction; pending: Promise<OpenCodeUpdateStatus> }\n\n constructor(private readonly deps: OpenCodeUpdateServiceDeps) {}\n\n async getStatus(): Promise<OpenCodeUpdateStatus> {\n const binary = this.deps.resolveBinary()\n let currentVersion: string | null = null\n let missing = false\n let invalid = false\n const probe = await this.deps.probeBinary(binary.path)\n try { currentVersion = await this.readCurrentVersion(binary.path, probe) }\n catch { missing = probe.missing === true; invalid = !missing }\n let latestVersion: string | null = null\n try { latestVersion = await this.readLatestVersion() } catch { /* Local admission remains available offline. */ }\n const state = invalid ? \"error\" : missing ? \"missing\"\n : currentVersion && !isBelowOpenCodeMinimum(currentVersion) ? \"ready\" : \"update_required\"\n const updateAvailable = latestVersion && (!currentVersion || comparableVersion(currentVersion))\n ? !currentVersion || compareOpenCodeVersionStrings(latestVersion, currentVersion) > 0 : null\n const status: OpenCodeUpdateStatus = {\n currentVersion, latestVersion, updateAvailable,\n canUpgrade: !invalid && Boolean(updateAvailable || needsSharedInstallation(binary)) && Boolean(latestVersion && !isBelowOpenCodeMinimum(latestVersion)) && this.deps.canUpgradeBinary(binary),\n minimumVersion: MINIMUM_OPENCODE_VERSION, recommendedVersion: RECOMMENDED_OPENCODE_VERSION,\n versionAssessment: \"untested\", state, binaryPath: binary.path,\n installationSource: binary.source, needsSharedInstallation: needsSharedInstallation(binary),\n target: parseWslUncPath(binary.path) ? \"wsl\" : \"host\", canRestart: false,\n ...(!latestVersion ? { checkError: \"update_check_failed\" as const } : {}),\n }\n if (!missing && !invalid && this.deps.lifecycle) {\n try {\n const lifecycle = await this.deps.lifecycle(binary)\n const endpoint = await lifecycle.discover()\n const identity = endpoint && runtimeIdentity(endpoint)\n status.daemonVersion = identity?.version\n const olderDaemon = identity && currentVersion && comparableVersion(identity.version) && comparableVersion(currentVersion)\n && compareOpenCodeVersionStrings(currentVersion, identity.version) > 0\n status.serviceState = \"stopped\"\n if (endpoint) {\n try {\n const capabilities = await this.inspectRuntime(endpoint)\n status.serviceState = olderDaemon ? \"restart_available\" : \"ready\"\n // The running daemon, not an older discovery CLI, serves requests.\n status.state = \"ready\"\n status.canReload = Boolean(this.deps.reload) && capabilities.reload\n } catch (error) {\n if (!(error instanceof UnsupportedOpenCodeError)) throw error\n status.incompatibilityReason = error.reason\n status.serviceState = olderDaemon ? \"restart_required\" : \"incompatible\"\n }\n }\n status.canRestart = Boolean(lifecycle.restart) && state === \"ready\"\n && (status.serviceState === \"restart_required\" || status.serviceState === \"restart_available\")\n } catch { status.serviceState = \"error\"; status.serviceError = \"service_check_failed\" }\n }\n const effectiveVersion = status.daemonVersion ?? currentVersion\n if (!status.incompatibilityReason && effectiveVersion && isBelowOpenCodeMinimum(effectiveVersion)) status.incompatibilityReason = \"step_timestamp\"\n status.versionAssessment = status.incompatibilityReason ? \"incompatible\"\n : effectiveVersion === RECOMMENDED_OPENCODE_VERSION ? \"tested\" : \"untested\"\n return status\n }\n\n private async inspectRuntime(endpoint: Endpoint): Promise<{ reload: boolean }> {\n const identity = runtimeIdentity(endpoint)\n if (!identity) throw new Error(\"OpenCode did not report an authenticated runtime version\")\n assertSupportedOpenCode(identity.version)\n if (this.deps.inspectRuntime) return this.deps.inspectRuntime(endpoint)\n await createRuntimeTransport(endpoint).profile()\n return { reload: identity.contract?.reload ?? contractProfile(identity) === \"modern\" }\n }\n\n start(restart = false): Promise<OpenCodeUpdateStatus> {\n return this.runServiceAction(restart ? \"restart\" : \"start\")\n }\n\n reload(): Promise<OpenCodeUpdateStatus> {\n return this.runServiceAction(\"reload\")\n }\n\n private runServiceAction(action: ServiceAction): Promise<OpenCodeUpdateStatus> {\n const binary = this.deps.resolveBinary()\n // One updater owns one manager/shared-service authority. Executable selection\n // is mutable and cannot be the lock key for daemon-wide operations.\n const existing = this.activation\n if (existing) return existing.action === action && existing.binaryPath === binary.path\n ? existing.pending : Promise.reject(new Error(\"Another OpenCode service action is in progress\"))\n const pending = this.activate(binary, action).finally(() => {\n if (this.activation?.pending === pending) this.activation = undefined\n })\n this.activation = { binaryPath: binary.path, action, pending }\n return pending\n }\n\n private async activate(binary: ResolvedBinary, action: ServiceAction): Promise<OpenCodeUpdateStatus> {\n const restart = action === \"restart\"\n const installedVersion = await this.readCurrentVersion(binary.path)\n const lifecycle = await this.deps.lifecycle?.(binary)\n if (!lifecycle) throw new Error(\"OpenCode service lifecycle unavailable\")\n const previous = await lifecycle.discover()\n if (!previous || restart) assertSupportedOpenCode(installedVersion)\n if (restart && previous) {\n const identity = runtimeIdentity(previous)\n if (!identity || !comparableVersion(identity.version) || !comparableVersion(installedVersion)\n || compareOpenCodeVersionStrings(installedVersion, identity.version) <= 0) {\n throw new Error(\"The shared daemon is not an older runtime eligible for this update\")\n }\n }\n const assertCurrent = () => {\n if (this.deps.resolveBinary().path !== binary.path) throw new Error(\"OpenCode selection changed during activation\")\n this.deps.admitActivation?.(binary)\n }\n assertCurrent()\n if (action === \"reload\") {\n const identity = previous && runtimeIdentity(previous)\n if (!identity || !this.deps.reload) throw new Error(\"OpenCode configuration reload unavailable\")\n const capabilities = await this.inspectRuntime(previous!)\n if (!capabilities.reload) throw new Error(\"OpenCode does not expose configuration reload\")\n assertCurrent()\n // Explicit daemon-wide mutation: never use this as an automatic watcher\n // fallback, because native reload cancels pending Forms and permissions.\n await this.deps.reload(binary, assertCurrent)\n assertCurrent()\n return this.getStatus()\n }\n const endpoint = restart && previous ? await lifecycle.restart?.() : previous ?? await lifecycle.ensure()\n const identity = endpoint && runtimeIdentity(endpoint)\n if (!identity) throw new Error(\"OpenCode did not report an authenticated runtime version\")\n await this.inspectRuntime(endpoint!)\n if (this.deps.resolveBinary().path !== binary.path) throw new Error(\"OpenCode selection changed during activation\")\n await this.deps.reconnect?.(binary)\n return this.getStatus()\n }\n\n upgrade(): Promise<OpenCodeUpdateResponse> {\n const binary = this.deps.resolveBinary()\n const existing = inFlightUpgrades.get(binary.path)\n if (existing) return existing\n\n const pending = this.performUpgrade(binary).finally(() => {\n if (inFlightUpgrades.get(binary.path) === pending) inFlightUpgrades.delete(binary.path)\n })\n inFlightUpgrades.set(binary.path, pending)\n return pending\n }\n\n private async performUpgrade(binary: ResolvedBinary): Promise<OpenCodeUpdateResponse> {\n const probe = await this.deps.probeBinary(binary.path)\n const currentVersion = probe.missing ? null : await this.readCurrentVersion(binary.path, probe)\n const latestVersion = await this.readLatestVersion()\n assertSupportedOpenCode(latestVersion)\n\n if (currentVersion && !comparableVersion(currentVersion)) {\n throw new OpenCodeUpdateError(\"unsupported_binary\", \"Cannot order this custom OpenCode version for an automatic update\")\n }\n\n if (currentVersion && compareOpenCodeVersionStrings(latestVersion, currentVersion) <= 0 && !needsSharedInstallation(binary)) {\n return { success: true, version: currentVersion }\n }\n\n if (!this.deps.canUpgradeBinary(binary)) {\n throw new OpenCodeUpdateError(\n \"unsupported_binary\",\n \"Automatic updates require the default command and a writable npm installation\",\n )\n }\n\n try {\n const targetVersion = currentVersion && compareOpenCodeVersionStrings(currentVersion, latestVersion) > 0 ? currentVersion : latestVersion\n const result = await this.deps.upgradeBinary(binary, targetVersion)\n if (!result.success) {\n throw new OpenCodeUpdateError(\"upgrade_failed\", result.error)\n }\n const installedVersion = await this.readCurrentVersion(this.deps.resolveBinary().path)\n if (isBelowOpenCodeMinimum(installedVersion) || !/^\\d+\\.\\d+\\.\\d+$/.test(installedVersion) || compareOpenCodeVersionStrings(installedVersion, targetVersion) < 0) {\n throw new OpenCodeUpdateError(\n \"upgrade_verification_failed\",\n `OpenCode reported ${result.version}, but the configured binary is ${installedVersion} instead of ${latestVersion}`,\n )\n }\n return { success: true, version: installedVersion }\n } catch (error) {\n if (error instanceof OpenCodeUpdateError || error instanceof InstallationBusyError) throw error\n throw new OpenCodeUpdateError(\n \"upgrade_failed\",\n error instanceof Error ? error.message : \"OpenCode upgrade failed\",\n )\n }\n }\n\n private async readCurrentVersion(binaryPath: string, probe?: ReturnType<typeof probeBinaryVersion>): Promise<string> {\n if (process.platform === \"win32\" && /[\"\\r\\n]/.test(binaryPath)) {\n throw new OpenCodeUpdateError(\"binary_unavailable\", \"The configured OpenCode binary path is invalid\")\n }\n const result = probe ?? await this.deps.probeBinary(binaryPath)\n if (!result.valid) {\n throw new OpenCodeUpdateError(\"binary_unavailable\", result.error ?? \"Unable to read OpenCode version\")\n }\n // Successful unknown/empty labels are diagnostic information. Admission is\n // established against the authenticated daemon, not inferred from this label.\n return result.version?.trim() || \"unknown\"\n }\n\n private async readLatestVersion(): Promise<string> {\n try {\n const version = stripTagPrefix(await this.deps.resolveLatestVersion())\n if (!version) throw new Error(`The ${TARGET_OPENCODE_CHANNEL} channel did not resolve to a version`)\n return version\n } catch (error) {\n throw new OpenCodeUpdateError(\n \"update_check_failed\",\n error instanceof Error ? error.message : \"Unable to resolve the latest stable OpenCode release\",\n )\n }\n }\n}\n\nexport function compareOpenCodeVersionStrings(left: string, right: string): number {\n const leftBeta = stripTagPrefix(left)?.match(/^0\\.0\\.0-beta-(\\d+)$/)\n const rightBeta = stripTagPrefix(right)?.match(/^0\\.0\\.0-beta-(\\d+)$/)\n if (leftBeta && rightBeta) return Number(leftBeta[1]) - Number(rightBeta[1])\n return compareVersionStrings(left, right)\n}\n\ntype RegistryFetch = (\n url: string,\n init: Parameters<typeof fetch>[1],\n) => Promise<Pick<Awaited<ReturnType<typeof fetch>>, \"ok\" | \"status\" | \"json\">>\n\nexport async function resolveLatestOpenCodeVersion(fetchRegistry: RegistryFetch = fetch): Promise<string> {\n const response = await fetchRegistry(OPENCODE_REGISTRY_URL, {\n headers: { Accept: \"application/json\" },\n signal: AbortSignal.timeout(10_000),\n })\n if (!response.ok) throw new Error(`OpenCode registry responded with ${response.status}`)\n\n const metadata = (await response.json()) as Record<string, unknown>\n const version = metadata[TARGET_OPENCODE_CHANNEL]\n if (typeof version !== \"string\" || !/^\\d+\\.\\d+\\.\\d+$/.test(version)) {\n throw new Error(`The ${TARGET_OPENCODE_CHANNEL} channel did not resolve to a valid version`)\n }\n return version\n}\n\nexport function createOpenCodeUpdateService(\n settings: SettingsService,\n workspaceManager: WorkspaceManager,\n): OpenCodeUpdateService {\n const binaryResolver = new BinaryResolver(settings)\n return new OpenCodeUpdateService({\n resolveBinary: () => {\n const binary = binaryResolver.resolveDefault()\n return { ...binary, path: workspaceManager.resolveBinaryPath(binary.path) }\n },\n probeBinary: probeBinaryVersionAsync,\n resolveLatestVersion: resolveLatestOpenCodeVersion,\n canUpgradeBinary: binary => {\n const configured = settings.getOwner(\"config\", \"server\").opencodeBinary\n return !parseWslUncPath(binary.path) && (!configured || configured === \"opencode\" || configured === \"opencode2\") && Boolean(bundledNpm()) && Boolean(sharedInstallPrefix())\n },\n upgradeBinary: async (_binary, version) => {\n await installSharedOpenCode(version)\n return { success: true, version }\n },\n lifecycle: binary => workspaceManager.setupServiceOptions(binary.path).then(options => options.lifecycle),\n reconnect: binary => workspaceManager.reconnectAfterSetup(binary.path),\n admitActivation: binary => workspaceManager.assertSetupExecutionHost(binary.path),\n reload: (binary, assertCurrent) => workspaceManager.reloadConfigurationAfterSetup(binary.path, assertCurrent),\n })\n}\n\nfunction comparableVersion(version: string): boolean {\n return /^\\d+\\.\\d+\\.\\d+$/.test(version) || /^0\\.0\\.0-beta-\\d+$/.test(version)\n}\n\nfunction needsSharedInstallation(binary: ResolvedBinary): boolean {\n return binary.source === \"legacy\" || binary.source === \"user\"\n}\n"]}
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/opencode-update/service.ts"],"names":[],"mappings":"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","sourcesContent":["import { fetch } from \"undici\"\nimport type { OpenCodeUpdateResponse, OpenCodeUpdateStatus } from \"../api-types\"\nimport type { SettingsService } from \"../settings/service\"\nimport { BinaryResolver, type ResolvedBinary } from \"../settings/binaries\"\nimport type { WorkspaceManager } from \"../workspaces/manager\"\nimport { probeBinaryVersion, probeBinaryVersionAsync } from \"../workspaces/spawn\"\nimport { compareVersionStrings, stripTagPrefix } from \"../releases/release-monitor\"\nimport { assertSupportedOpenCode, isBelowOpenCodeMinimum, MINIMUM_OPENCODE_VERSION, RECOMMENDED_OPENCODE_VERSION, UnsupportedOpenCodeError } from \"../opencode/runtime-support\"\nimport { contractProfile, runtimeIdentity } from \"../opencode/compatibility/runtime\"\nimport { createRuntimeTransport } from \"../opencode/compatibility/transport\"\nimport type { Endpoint } from \"@opencode/client/service\"\nimport { bundledNpm } from \"./npm-runtime\"\nimport { isRetiredInstallation } from \"./retired-installation\"\nimport { installSharedOpenCode, sharedInstallPrefix } from \"./shared-installation\"\nimport { InstallationBusyError } from \"./installation-lock\"\nimport type { OpenCodeServiceLifecycle } from \"../workspaces/opencode-service\"\nimport { parseWslUncPath } from \"../workspaces/spawn\"\n\nconst OPENCODE_REGISTRY_URL = \"https://registry.npmjs.org/-/package/%40opencode%2Fcli/dist-tags\"\nexport const TARGET_OPENCODE_CHANNEL = \"latest\"\nconst inFlightUpgrades = new Map<string, Promise<OpenCodeUpdateResponse>>()\ntype ServiceAction = \"start\" | \"restart\" | \"reload\"\n\ntype UpgradeResult = { success: true; version: string } | { success: false; error: string }\n\nexport interface OpenCodeUpdateServiceDeps {\n resolveBinary: () => ResolvedBinary\n probeBinary: (path: string) => ReturnType<typeof probeBinaryVersion> | Promise<ReturnType<typeof probeBinaryVersion>>\n resolveLatestVersion: () => Promise<string>\n canUpgradeBinary: (binary: ResolvedBinary) => boolean\n upgradeBinary: (binary: ResolvedBinary, target: string) => Promise<UpgradeResult>\n lifecycle?: (binary: ResolvedBinary) => Promise<OpenCodeServiceLifecycle>\n reconnect?: (binary: ResolvedBinary) => Promise<void>\n admitActivation?: (binary: ResolvedBinary) => void\n reload?: (binary: ResolvedBinary, assertCurrent: () => void) => Promise<void>\n inspectRuntime?: (endpoint: Endpoint) => Promise<{ reload: boolean }>\n}\n\nexport class OpenCodeUpdateError extends Error {\n constructor(\n readonly code:\n | \"binary_unavailable\"\n | \"unsupported_binary\"\n | \"update_check_failed\"\n | \"upgrade_failed\"\n | \"upgrade_verification_failed\",\n message: string,\n ) {\n super(message)\n this.name = \"OpenCodeUpdateError\"\n }\n}\n\nexport class OpenCodeUpdateService {\n private activation?: { binaryPath: string; action: ServiceAction; pending: Promise<OpenCodeUpdateStatus> }\n\n constructor(private readonly deps: OpenCodeUpdateServiceDeps) {}\n\n async getStatus(): Promise<OpenCodeUpdateStatus> {\n const binary = this.deps.resolveBinary()\n let currentVersion: string | null = null\n let missing = false\n let invalid = false\n const probe = await this.deps.probeBinary(binary.path)\n try { currentVersion = await this.readCurrentVersion(binary.path, probe) }\n catch { missing = probe.missing === true; invalid = !missing }\n let latestVersion: string | null = null\n try { latestVersion = await this.readLatestVersion() } catch { /* Local admission remains available offline. */ }\n const state = invalid ? \"error\" : missing ? \"missing\"\n : currentVersion && !isBelowOpenCodeMinimum(currentVersion) ? \"ready\" : \"update_required\"\n const updateAvailable = latestVersion && (!currentVersion || comparableVersion(currentVersion))\n ? !currentVersion || compareOpenCodeVersionStrings(latestVersion, currentVersion) > 0 : null\n const status: OpenCodeUpdateStatus = {\n currentVersion, latestVersion, updateAvailable,\n canUpgrade: !invalid && Boolean(updateAvailable || needsSharedInstallation(binary)) && Boolean(latestVersion && !isBelowOpenCodeMinimum(latestVersion)) && this.deps.canUpgradeBinary(binary),\n minimumVersion: MINIMUM_OPENCODE_VERSION, recommendedVersion: RECOMMENDED_OPENCODE_VERSION,\n versionAssessment: \"untested\", state, binaryPath: binary.path,\n installationSource: binary.source, needsSharedInstallation: needsSharedInstallation(binary),\n target: parseWslUncPath(binary.path) ? \"wsl\" : \"host\", canRestart: false,\n ...(!latestVersion ? { checkError: \"update_check_failed\" as const } : {}),\n }\n if (!missing && !invalid && this.deps.lifecycle) {\n try {\n const lifecycle = await this.deps.lifecycle(binary)\n const endpoint = await lifecycle.discover()\n const identity = endpoint && runtimeIdentity(endpoint)\n status.daemonVersion = identity?.version\n const olderDaemon = identity && currentVersion && comparableVersion(identity.version) && comparableVersion(currentVersion)\n && compareOpenCodeVersionStrings(currentVersion, identity.version) > 0\n status.serviceState = \"stopped\"\n if (endpoint) {\n try {\n const capabilities = await this.inspectRuntime(endpoint)\n status.serviceState = olderDaemon ? \"restart_available\" : \"ready\"\n // The running daemon, not an older discovery CLI, serves requests.\n status.state = \"ready\"\n status.canReload = Boolean(this.deps.reload) && capabilities.reload\n } catch (error) {\n if (!(error instanceof UnsupportedOpenCodeError)) throw error\n status.incompatibilityReason = error.reason\n status.serviceState = olderDaemon ? \"restart_required\" : \"incompatible\"\n }\n }\n status.canRestart = Boolean(lifecycle.restart) && state === \"ready\"\n && (status.serviceState === \"restart_required\" || status.serviceState === \"restart_available\")\n } catch { status.serviceState = \"error\"; status.serviceError = \"service_check_failed\" }\n }\n const effectiveVersion = status.daemonVersion ?? currentVersion\n if (!status.incompatibilityReason && effectiveVersion && isBelowOpenCodeMinimum(effectiveVersion)) status.incompatibilityReason = \"step_timestamp\"\n status.versionAssessment = status.incompatibilityReason ? \"incompatible\"\n : effectiveVersion === RECOMMENDED_OPENCODE_VERSION ? \"tested\" : \"untested\"\n return status\n }\n\n private async inspectRuntime(endpoint: Endpoint): Promise<{ reload: boolean }> {\n const identity = runtimeIdentity(endpoint)\n if (!identity) throw new Error(\"OpenCode did not report an authenticated runtime version\")\n assertSupportedOpenCode(identity.version)\n if (this.deps.inspectRuntime) return this.deps.inspectRuntime(endpoint)\n await createRuntimeTransport(endpoint).profile()\n return { reload: identity.contract?.reload ?? contractProfile(identity) === \"modern\" }\n }\n\n start(restart = false): Promise<OpenCodeUpdateStatus> {\n return this.runServiceAction(restart ? \"restart\" : \"start\")\n }\n\n reload(): Promise<OpenCodeUpdateStatus> {\n return this.runServiceAction(\"reload\")\n }\n\n private runServiceAction(action: ServiceAction): Promise<OpenCodeUpdateStatus> {\n const binary = this.deps.resolveBinary()\n // One updater owns one manager/shared-service authority. Executable selection\n // is mutable and cannot be the lock key for daemon-wide operations.\n const existing = this.activation\n if (existing) return existing.action === action && existing.binaryPath === binary.path\n ? existing.pending : Promise.reject(new Error(\"Another OpenCode service action is in progress\"))\n const pending = this.activate(binary, action).finally(() => {\n if (this.activation?.pending === pending) this.activation = undefined\n })\n this.activation = { binaryPath: binary.path, action, pending }\n return pending\n }\n\n private async activate(binary: ResolvedBinary, action: ServiceAction): Promise<OpenCodeUpdateStatus> {\n const restart = action === \"restart\"\n const installedVersion = await this.readCurrentVersion(binary.path)\n const lifecycle = await this.deps.lifecycle?.(binary)\n if (!lifecycle) throw new Error(\"OpenCode service lifecycle unavailable\")\n const previous = await lifecycle.discover()\n if (!previous || restart) assertSupportedOpenCode(installedVersion)\n if (restart && previous) {\n const identity = runtimeIdentity(previous)\n if (!identity || !comparableVersion(identity.version) || !comparableVersion(installedVersion)\n || compareOpenCodeVersionStrings(installedVersion, identity.version) <= 0) {\n throw new Error(\"The shared daemon is not an older runtime eligible for this update\")\n }\n }\n const assertCurrent = () => {\n if (this.deps.resolveBinary().path !== binary.path) throw new Error(\"OpenCode selection changed during activation\")\n this.deps.admitActivation?.(binary)\n }\n assertCurrent()\n if (action === \"reload\") {\n const identity = previous && runtimeIdentity(previous)\n if (!identity || !this.deps.reload) throw new Error(\"OpenCode configuration reload unavailable\")\n const capabilities = await this.inspectRuntime(previous!)\n if (!capabilities.reload) throw new Error(\"OpenCode does not expose configuration reload\")\n assertCurrent()\n // Explicit daemon-wide mutation: never use this as an automatic watcher\n // fallback, because native reload cancels pending Forms and permissions.\n await this.deps.reload(binary, assertCurrent)\n assertCurrent()\n return this.getStatus()\n }\n const endpoint = restart && previous ? await lifecycle.restart?.() : previous ?? await lifecycle.ensure()\n const identity = endpoint && runtimeIdentity(endpoint)\n if (!identity) throw new Error(\"OpenCode did not report an authenticated runtime version\")\n await this.inspectRuntime(endpoint!)\n if (this.deps.resolveBinary().path !== binary.path) throw new Error(\"OpenCode selection changed during activation\")\n await this.deps.reconnect?.(binary)\n return this.getStatus()\n }\n\n upgrade(): Promise<OpenCodeUpdateResponse> {\n const binary = this.deps.resolveBinary()\n const existing = inFlightUpgrades.get(binary.path)\n if (existing) return existing\n\n const pending = this.performUpgrade(binary).finally(() => {\n if (inFlightUpgrades.get(binary.path) === pending) inFlightUpgrades.delete(binary.path)\n })\n inFlightUpgrades.set(binary.path, pending)\n return pending\n }\n\n private async performUpgrade(binary: ResolvedBinary): Promise<OpenCodeUpdateResponse> {\n const probe = await this.deps.probeBinary(binary.path)\n const currentVersion = probe.missing ? null : await this.readCurrentVersion(binary.path, probe)\n const latestVersion = await this.readLatestVersion()\n assertSupportedOpenCode(latestVersion)\n\n if (currentVersion && !comparableVersion(currentVersion)) {\n throw new OpenCodeUpdateError(\"unsupported_binary\", \"Cannot order this custom OpenCode version for an automatic update\")\n }\n\n if (currentVersion && compareOpenCodeVersionStrings(latestVersion, currentVersion) <= 0 && !needsSharedInstallation(binary)) {\n return { success: true, version: currentVersion }\n }\n\n if (!this.deps.canUpgradeBinary(binary)) {\n throw new OpenCodeUpdateError(\n \"unsupported_binary\",\n \"Automatic updates require the default command and a writable npm installation\",\n )\n }\n\n try {\n const targetVersion = currentVersion && compareOpenCodeVersionStrings(currentVersion, latestVersion) > 0 ? currentVersion : latestVersion\n const result = await this.deps.upgradeBinary(binary, targetVersion)\n if (!result.success) {\n throw new OpenCodeUpdateError(\"upgrade_failed\", result.error)\n }\n const installedVersion = await this.readCurrentVersion(this.deps.resolveBinary().path)\n if (isBelowOpenCodeMinimum(installedVersion) || !/^\\d+\\.\\d+\\.\\d+$/.test(installedVersion) || compareOpenCodeVersionStrings(installedVersion, targetVersion) < 0) {\n throw new OpenCodeUpdateError(\n \"upgrade_verification_failed\",\n `OpenCode reported ${result.version}, but the configured binary is ${installedVersion} instead of ${latestVersion}`,\n )\n }\n return { success: true, version: installedVersion }\n } catch (error) {\n if (error instanceof OpenCodeUpdateError || error instanceof InstallationBusyError) throw error\n throw new OpenCodeUpdateError(\n \"upgrade_failed\",\n error instanceof Error ? error.message : \"OpenCode upgrade failed\",\n )\n }\n }\n\n private async readCurrentVersion(binaryPath: string, probe?: ReturnType<typeof probeBinaryVersion>): Promise<string> {\n if (process.platform === \"win32\" && /[\"\\r\\n]/.test(binaryPath)) {\n throw new OpenCodeUpdateError(\"binary_unavailable\", \"The configured OpenCode binary path is invalid\")\n }\n const result = probe ?? await this.deps.probeBinary(binaryPath)\n if (!result.valid) {\n throw new OpenCodeUpdateError(\"binary_unavailable\", result.error ?? \"Unable to read OpenCode version\")\n }\n // Successful unknown/empty labels are diagnostic information. Admission is\n // established against the authenticated daemon, not inferred from this label.\n return result.version?.trim() || \"unknown\"\n }\n\n private async readLatestVersion(): Promise<string> {\n try {\n const version = stripTagPrefix(await this.deps.resolveLatestVersion())\n if (!version) throw new Error(`The ${TARGET_OPENCODE_CHANNEL} channel did not resolve to a version`)\n return version\n } catch (error) {\n throw new OpenCodeUpdateError(\n \"update_check_failed\",\n error instanceof Error ? error.message : \"Unable to resolve the latest stable OpenCode release\",\n )\n }\n }\n}\n\nexport function compareOpenCodeVersionStrings(left: string, right: string): number {\n const leftBeta = stripTagPrefix(left)?.match(/^0\\.0\\.0-beta-(\\d+)$/)\n const rightBeta = stripTagPrefix(right)?.match(/^0\\.0\\.0-beta-(\\d+)$/)\n if (leftBeta && rightBeta) return Number(leftBeta[1]) - Number(rightBeta[1])\n return compareVersionStrings(left, right)\n}\n\ntype RegistryFetch = (\n url: string,\n init: Parameters<typeof fetch>[1],\n) => Promise<Pick<Awaited<ReturnType<typeof fetch>>, \"ok\" | \"status\" | \"json\">>\n\nexport async function resolveLatestOpenCodeVersion(fetchRegistry: RegistryFetch = fetch): Promise<string> {\n const response = await fetchRegistry(OPENCODE_REGISTRY_URL, {\n headers: { Accept: \"application/json\" },\n signal: AbortSignal.timeout(10_000),\n })\n if (!response.ok) throw new Error(`OpenCode registry responded with ${response.status}`)\n\n const metadata = (await response.json()) as Record<string, unknown>\n const version = metadata[TARGET_OPENCODE_CHANNEL]\n if (typeof version !== \"string\" || !/^\\d+\\.\\d+\\.\\d+$/.test(version)) {\n throw new Error(`The ${TARGET_OPENCODE_CHANNEL} channel did not resolve to a valid version`)\n }\n return version\n}\n\nexport function createOpenCodeUpdateService(\n settings: SettingsService,\n workspaceManager: WorkspaceManager,\n): OpenCodeUpdateService {\n const binaryResolver = new BinaryResolver(settings)\n return new OpenCodeUpdateService({\n resolveBinary: () => {\n const binary = binaryResolver.resolveDefault()\n return { ...binary, path: workspaceManager.resolveBinaryPath(binary.path) }\n },\n probeBinary: probeBinaryVersionAsync,\n resolveLatestVersion: resolveLatestOpenCodeVersion,\n canUpgradeBinary: binary => {\n const configured = settings.getOwner(\"config\", \"server\").opencodeBinary\n return !parseWslUncPath(binary.path) && (!configured || configured === \"opencode\" || configured === \"opencode2\" || (typeof configured === \"string\" && isRetiredInstallation(configured))) && Boolean(bundledNpm()) && Boolean(sharedInstallPrefix())\n },\n upgradeBinary: async (_binary, version) => {\n await installSharedOpenCode(version)\n return { success: true, version }\n },\n lifecycle: binary => workspaceManager.setupServiceOptions(binary.path).then(options => options.lifecycle),\n reconnect: binary => workspaceManager.reconnectAfterSetup(binary.path),\n admitActivation: binary => workspaceManager.assertSetupExecutionHost(binary.path),\n reload: (binary, assertCurrent) => workspaceManager.reloadConfigurationAfterSetup(binary.path, assertCurrent),\n })\n}\n\nfunction comparableVersion(version: string): boolean {\n return /^\\d+\\.\\d+\\.\\d+$/.test(version) || /^0\\.0\\.0-beta-\\d+$/.test(version)\n}\n\nfunction needsSharedInstallation(binary: ResolvedBinary): boolean {\n return binary.source === \"user\"\n}\n"]}
|
|
@@ -67,8 +67,8 @@ test("installation re-resolves the executable and rejects false success", async
|
|
|
67
67
|
}));
|
|
68
68
|
await assert.rejects(wrong.upgrade(), (error) => error instanceof OpenCodeUpdateError && error.code === "upgrade_verification_failed");
|
|
69
69
|
});
|
|
70
|
-
test("
|
|
71
|
-
for (const source of ["
|
|
70
|
+
test("user npm PATH repair remains available without an update and never downgrades", async () => {
|
|
71
|
+
for (const source of ["user"]) {
|
|
72
72
|
let migrated = false, installs = 0;
|
|
73
73
|
const service = new OpenCodeUpdateService(deps({
|
|
74
74
|
resolveBinary: () => ({ path: migrated ? "common" : source, label: "OpenCode", source: migrated ? "path" : source }),
|