@@ -20,28 +20,25 @@ import {
2020} from "jsonc-parser"
2121import { Instance , type InstanceContext } from "../project/instance"
2222import { LSPServer } from "../lsp/server"
23- import { BunProc } from "@/bun"
2423import { Installation } from "@/installation"
2524import { ConfigMarkdown } from "./markdown"
2625import { constants , existsSync } from "fs"
2726import { Bus } from "@/bus"
2827import { GlobalBus } from "@/bus/global"
2928import { Event } from "../server/event"
3029import { Glob } from "../util/glob"
31- import { PackageRegistry } from "@/bun/registry"
32- import { online , proxied } from "@/util/network"
3330import { iife } from "@/util/iife"
3431import { Account } from "@/account"
3532import { isRecord } from "@/util/record"
3633import { ConfigPaths } from "./paths"
3734import { Filesystem } from "@/util/filesystem"
38- import { Process } from "@/util/process"
3935import { AppFileSystem } from "@/filesystem"
4036import { InstanceState } from "@/effect/instance-state"
4137import { makeRuntime } from "@/effect/run-service"
4238import { Duration , Effect , Layer , Option , ServiceMap } from "effect"
4339import { Flock } from "@/util/flock"
4440import { isPathPluginSpec , parsePluginSpecifier , resolvePathPluginTarget } from "@/plugin/shared"
41+ import { Npm } from "@/npm"
4542
4643export namespace Config {
4744 const ModelId = z . string ( ) . meta ( { $ref : "https://models.dev/model-schema.json#/$defs/Model" } )
@@ -90,8 +87,7 @@ export namespace Config {
9087 }
9188
9289 export async function installDependencies ( dir : string , input ?: InstallInput ) {
93- if ( ! ( await needsInstall ( dir ) ) ) return
94-
90+ if ( ! ( await isWritable ( dir ) ) ) return
9591 await using _ = await Flock . acquire ( `config-install:${ Filesystem . resolve ( dir ) } ` , {
9692 signal : input ?. signal ,
9793 onWait : ( tick ) =>
@@ -102,13 +98,10 @@ export namespace Config {
10298 waited : tick . waited ,
10399 } ) ,
104100 } )
105-
106101 input ?. signal ?. throwIfAborted ( )
107- if ( ! ( await needsInstall ( dir ) ) ) return
108102
109103 const pkg = path . join ( dir , "package.json" )
110104 const target = Installation . isLocal ( ) ? "*" : Installation . VERSION
111-
112105 const json = await Filesystem . readJson < { dependencies ?: Record < string , string > } > ( pkg ) . catch ( ( ) => ( {
113106 dependencies : { } ,
114107 } ) )
@@ -126,49 +119,7 @@ export namespace Config {
126119 [ "node_modules" , "package.json" , "package-lock.json" , "bun.lock" , ".gitignore" ] . join ( "\n" ) ,
127120 )
128121 }
129-
130- // Bun can race cache writes on Windows when installs run in parallel across dirs.
131- // Serialize installs globally on win32, but keep parallel installs on other platforms.
132- await using __ =
133- process . platform === "win32"
134- ? await Flock . acquire ( "config-install:bun" , {
135- signal : input ?. signal ,
136- } )
137- : undefined
138-
139- await BunProc . run (
140- [
141- "install" ,
142- // TODO: get rid of this case (see: https://github.com/oven-sh/bun/issues/19936)
143- ...( proxied ( ) || process . env . CI ? [ "--no-cache" ] : [ ] ) ,
144- ] ,
145- {
146- cwd : dir ,
147- abort : input ?. signal ,
148- } ,
149- ) . catch ( ( err ) => {
150- if ( err instanceof Process . RunFailedError ) {
151- const detail = {
152- dir,
153- cmd : err . cmd ,
154- code : err . code ,
155- stdout : err . stdout . toString ( ) ,
156- stderr : err . stderr . toString ( ) ,
157- }
158- if ( Flag . OPENCODE_STRICT_CONFIG_DEPS ) {
159- log . error ( "failed to install dependencies" , detail )
160- throw err
161- }
162- log . warn ( "failed to install dependencies" , detail )
163- return
164- }
165-
166- if ( Flag . OPENCODE_STRICT_CONFIG_DEPS ) {
167- log . error ( "failed to install dependencies" , { dir, error : err } )
168- throw err
169- }
170- log . warn ( "failed to install dependencies" , { dir, error : err } )
171- } )
122+ await Npm . install ( dir )
172123 }
173124
174125 async function isWritable ( dir : string ) {
@@ -180,42 +131,6 @@ export namespace Config {
180131 }
181132 }
182133
183- export async function needsInstall ( dir : string ) {
184- // Some config dirs may be read-only.
185- // Installing deps there will fail; skip installation in that case.
186- const writable = await isWritable ( dir )
187- if ( ! writable ) {
188- log . debug ( "config dir is not writable, skipping dependency install" , { dir } )
189- return false
190- }
191-
192- const mod = path . join ( dir , "node_modules" , "@opencode-ai" , "plugin" )
193- if ( ! existsSync ( mod ) ) return true
194-
195- const pkg = path . join ( dir , "package.json" )
196- const pkgExists = await Filesystem . exists ( pkg )
197- if ( ! pkgExists ) return true
198-
199- const parsed = await Filesystem . readJson < { dependencies ?: Record < string , string > } > ( pkg ) . catch ( ( ) => null )
200- const dependencies = parsed ?. dependencies ?? { }
201- const depVersion = dependencies [ "@opencode-ai/plugin" ]
202- if ( ! depVersion ) return true
203-
204- const targetVersion = Installation . isLocal ( ) ? "latest" : Installation . VERSION
205- if ( targetVersion === "latest" ) {
206- if ( ! online ( ) ) return false
207- const stale = await PackageRegistry . isOutdated ( "@opencode-ai/plugin" , depVersion , dir )
208- if ( ! stale ) return false
209- log . info ( "Cached version is outdated, proceeding with install" , {
210- pkg : "@opencode-ai/plugin" ,
211- cachedVersion : depVersion ,
212- } )
213- return true
214- }
215- if ( depVersion === targetVersion ) return false
216- return true
217- }
218-
219134 function rel ( item : string , patterns : string [ ] ) {
220135 const normalizedItem = item . replaceAll ( "\\" , "/" )
221136 for ( const pattern of patterns ) {
@@ -1355,8 +1270,7 @@ export namespace Config {
13551270 }
13561271
13571272 const dep = iife ( async ( ) => {
1358- const stale = await needsInstall ( dir )
1359- if ( stale ) await installDependencies ( dir )
1273+ await installDependencies ( dir )
13601274 } )
13611275 void dep . catch ( ( err ) => {
13621276 log . warn ( "background dependency install failed" , { dir, error : err } )
0 commit comments