| ... | @@ -102,4 +102,120 @@ it.layer(testLayer)("CodexDriver", (it) => { | ... | @@ -102,4 +102,120 @@ it.layer(testLayer)("CodexDriver", (it) => { |
| 102 | expect((yield* instance.snapshot.resolveMaintenance()).update).toBeNull(); | 102 | expect((yield* instance.snapshot.resolveMaintenance()).update).toBeNull(); |
| 103 | }).pipe(Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, noSpawn), Effect.scoped), | 103 | }).pipe(Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, noSpawn), Effect.scoped), |
| 104 | ); | 104 | ); |
| | 105 | |
| | 106 | for (const fixture of [ |
| | 107 | { |
| | 108 | name: "leaves mise npm-backend installations manual-only", |
| | 109 | installSegments: ["mise", "installs", "npm-openai-codex", "0.110.0"], |
| | 110 | npmOwned: false, |
| | 111 | }, |
| | 112 | { |
| | 113 | name: "leaves mise tool aliases backed by npm manual-only", |
| | 114 | installSegments: ["mise", "installs", "codex", "0.110.0"], |
| | 115 | npmOwned: false, |
| | 116 | }, |
| | 117 | { |
| | 118 | name: "keeps npm updates for globals in a mise Node installation", |
| | 119 | installSegments: ["mise", "installs", "node", "24.0.0"], |
| | 120 | npmOwned: true, |
| | 121 | }, |
| | 122 | { |
| | 123 | name: "keeps npm updates for ordinary global installations", |
| | 124 | installSegments: ["npm-global"], |
| | 125 | npmOwned: true, |
| | 126 | }, |
| | 127 | ] as const) { |
| | 128 | it.effect.skipIf(windowsHost)(fixture.name, () => |
| | 129 | Effect.gen(function* () { |
| | 130 | const fs = yield* FileSystem.FileSystem; |
| | 131 | const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-codex-installer-" }); |
| | 132 | const installPath = NodePath.join(tempDir, ...fixture.installSegments); |
| | 133 | const realBinaryPath = NodePath.join( |
| | 134 | installPath, |
| | 135 | "lib", |
| | 136 | "node_modules", |
| | 137 | "@openai", |
| | 138 | "codex", |
| | 139 | "bin", |
| | 140 | "codex.js", |
| | 141 | ); |
| | 142 | const binaryPath = NodePath.join(tempDir, "bin", "codex"); |
| | 143 | yield* fs.makeDirectory(NodePath.dirname(realBinaryPath), { recursive: true }); |
| | 144 | yield* fs.makeDirectory(NodePath.dirname(binaryPath), { recursive: true }); |
| | 145 | yield* fs.writeFileString(realBinaryPath, "#!/bin/sh\n"); |
| | 146 | yield* fs.chmod(realBinaryPath, 0o755); |
| | 147 | yield* fs.symlink(realBinaryPath, binaryPath); |
| | 148 | |
| | 149 | const instance = yield* CodexDriver.create({ |
| | 150 | instanceId: ProviderInstanceId.make("codex-installer"), |
| | 151 | displayName: "Codex installer test", |
| | 152 | enabled: false, |
| | 153 | environment: [], |
| | 154 | config: { |
| | 155 | ...CodexDriver.defaultConfig(), |
| | 156 | binaryPath, |
| | 157 | homePath: NodePath.join(tempDir, "codex-home"), |
| | 158 | }, |
| | 159 | }); |
| | 160 | |
| | 161 | const update = (yield* instance.snapshot.resolveMaintenance()).update; |
| | 162 | if (fixture.npmOwned) { |
| | 163 | expect(update).toMatchObject({ |
| | 164 | executable: "npm", |
| | 165 | args: [ |
| | 166 | "install", |
| | 167 | "-g", |
| | 168 | "--prefix", |
| | 169 | installPath, |
| | 170 | "--allow-scripts=@openai/codex", |
| | 171 | "@openai/codex@latest", |
| | 172 | ], |
| | 173 | }); |
| | 174 | } else { |
| | 175 | expect(update).toBeNull(); |
| | 176 | } |
| | 177 | }).pipe( |
| | 178 | Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, noSpawn), |
| | 179 | Effect.scoped, |
| | 180 | ), |
| | 181 | ); |
| | 182 | } |
| | 183 | |
| | 184 | for (const layout of ["direct", "wrapper"] as const) { |
| | 185 | it.effect.skipIf(windowsHost)(`leaves a mise ${layout} installation manual-only`, () => |
| | 186 | Effect.gen(function* () { |
| | 187 | const fs = yield* FileSystem.FileSystem; |
| | 188 | const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: `t3-codex-mise-${layout}-` }); |
| | 189 | const binaryPath = |
| | 190 | layout === "direct" |
| | 191 | ? NodePath.join(tempDir, "mise", "installs", "codex", "0.110.0", "codex") |
| | 192 | : NodePath.join(tempDir, "omarchy", "bin", "codex"); |
| | 193 | yield* fs.makeDirectory(NodePath.dirname(binaryPath), { recursive: true }); |
| | 194 | yield* fs.writeFileString( |
| | 195 | binaryPath, |
| | 196 | layout === "direct" |
| | 197 | ? "#!/bin/sh\n" |
| | 198 | : '#!/bin/sh\nmise use -g --quiet "codex" || exit 1\nexec mise x "codex" -- "codex" "$@"\n', |
| | 199 | ); |
| | 200 | yield* fs.chmod(binaryPath, 0o755); |
| | 201 | |
| | 202 | const instance = yield* CodexDriver.create({ |
| | 203 | instanceId: ProviderInstanceId.make(`codex-mise-${layout}`), |
| | 204 | displayName: "Codex mise test", |
| | 205 | enabled: false, |
| | 206 | environment: [], |
| | 207 | config: { |
| | 208 | ...CodexDriver.defaultConfig(), |
| | 209 | binaryPath, |
| | 210 | homePath: NodePath.join(tempDir, "codex-home"), |
| | 211 | }, |
| | 212 | }); |
| | 213 | |
| | 214 | expect((yield* instance.snapshot.resolveMaintenance()).update).toBeNull(); |
| | 215 | }).pipe( |
| | 216 | Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, noSpawn), |
| | 217 | Effect.scoped, |
| | 218 | ), |
| | 219 | ); |
| | 220 | } |
| 105 | }); | 221 | }); |