refactor(npm): use object-based package spec for install API (#23181)

This commit is contained in:
Dax
2026-04-17 17:30:50 -04:00
committed by GitHub
parent 0068ccec35
commit cded68a2e2
3 changed files with 23 additions and 7 deletions

View File

@@ -158,7 +158,12 @@ export const layer = Layer.effect(
(dir) => (dir) =>
npm npm
.install(dir, { .install(dir, {
add: ["@opencode-ai/plugin" + (InstallationLocal ? "" : "@" + InstallationVersion)], add: [
{
name: "@opencode-ai/plugin",
version: InstallationLocal ? undefined : InstallationVersion,
},
],
}) })
.pipe(Effect.forkScoped), .pipe(Effect.forkScoped),
{ {

View File

@@ -518,7 +518,12 @@ export const layer = Layer.effect(
const dep = yield* npmSvc const dep = yield* npmSvc
.install(dir, { .install(dir, {
add: ["@opencode-ai/plugin" + (InstallationLocal ? "" : "@" + InstallationVersion)], add: [
{
name: "@opencode-ai/plugin",
version: InstallationLocal ? undefined : InstallationVersion,
},
],
}) })
.pipe( .pipe(
Effect.exit, Effect.exit,

View File

@@ -25,7 +25,12 @@ export interface Interface {
readonly add: (pkg: string) => Effect.Effect<EntryPoint, InstallFailedError | EffectFlock.LockError> readonly add: (pkg: string) => Effect.Effect<EntryPoint, InstallFailedError | EffectFlock.LockError>
readonly install: ( readonly install: (
dir: string, dir: string,
input?: { add: string[] }, input?: {
add: {
name: string
version?: string
}[]
},
) => Effect.Effect<void, EffectFlock.LockError | InstallFailedError> ) => Effect.Effect<void, EffectFlock.LockError | InstallFailedError>
readonly outdated: (pkg: string, cachedVersion: string) => Effect.Effect<boolean> readonly outdated: (pkg: string, cachedVersion: string) => Effect.Effect<boolean>
readonly which: (pkg: string) => Effect.Effect<Option.Option<string>> readonly which: (pkg: string) => Effect.Effect<Option.Option<string>>
@@ -137,17 +142,18 @@ export const layer = Layer.effect(
return resolveEntryPoint(first.name, first.path) return resolveEntryPoint(first.name, first.path)
}, Effect.scoped) }, Effect.scoped)
const install = Effect.fn("Npm.install")(function* (dir: string, input?: { add: string[] }) { const install: Interface["install"] = Effect.fn("Npm.install")(function* (dir, input) {
const canWrite = yield* afs.access(dir, { writable: true }).pipe( const canWrite = yield* afs.access(dir, { writable: true }).pipe(
Effect.as(true), Effect.as(true),
Effect.orElseSucceed(() => false), Effect.orElseSucceed(() => false),
) )
if (!canWrite) return if (!canWrite) return
const add = input?.add.map((pkg) => [pkg.name, pkg.version].filter(Boolean).join("@")) ?? []
yield* Effect.gen(function* () { yield* Effect.gen(function* () {
const nodeModulesExists = yield* afs.existsSafe(path.join(dir, "node_modules")) const nodeModulesExists = yield* afs.existsSafe(path.join(dir, "node_modules"))
if (!nodeModulesExists) { if (!nodeModulesExists) {
yield* reify({ add: input?.add, dir }) yield* reify({ add, dir })
return return
} }
}).pipe(Effect.withSpan("Npm.checkNodeModules")) }).pipe(Effect.withSpan("Npm.checkNodeModules"))
@@ -163,7 +169,7 @@ export const layer = Layer.effect(
...Object.keys(pkgAny?.devDependencies || {}), ...Object.keys(pkgAny?.devDependencies || {}),
...Object.keys(pkgAny?.peerDependencies || {}), ...Object.keys(pkgAny?.peerDependencies || {}),
...Object.keys(pkgAny?.optionalDependencies || {}), ...Object.keys(pkgAny?.optionalDependencies || {}),
...(input?.add || []), ...(input?.add || []).map((pkg) => pkg.name),
]) ])
const root = lockAny?.packages?.[""] || {} const root = lockAny?.packages?.[""] || {}
@@ -176,7 +182,7 @@ export const layer = Layer.effect(
for (const name of declared) { for (const name of declared) {
if (!locked.has(name)) { if (!locked.has(name)) {
yield* reify({ dir, add: input?.add }) yield* reify({ dir, add })
return return
} }
} }