@@ -3,6 +3,7 @@ import * as Path from "@effect/platform/Path"
33import { NodeContext } from "@effect/platform-node"
44import { describe , expect , it } from "@effect/vitest"
55import { Effect } from "effect"
6+ import { vi } from "vitest"
67
78import type { TemplateConfig } from "../../src/core/domain.js"
89import { resolveAutoAgentMode } from "../../src/usecases/agent-auto-select.js"
@@ -62,6 +63,22 @@ describe("resolveAutoAgentMode", () => {
6263 } )
6364 ) . pipe ( Effect . provide ( NodeContext . layer ) ) )
6465
66+ it . effect ( "keeps explicit Claude mode when Claude auth exists" , ( ) =>
67+ withTempDir ( ( root ) =>
68+ Effect . gen ( function * ( _ ) {
69+ const fs = yield * _ ( FileSystem . FileSystem )
70+ const path = yield * _ ( Path . Path )
71+ const config = { ...makeConfig ( root , path ) , agentMode : "claude" as const }
72+ const claudeRoot = path . join ( root , ".orch/auth/claude/default" )
73+
74+ yield * _ ( fs . makeDirectory ( claudeRoot , { recursive : true } ) )
75+ yield * _ ( fs . writeFileString ( path . join ( claudeRoot , ".oauth-token" ) , "token\n" ) )
76+
77+ const mode = yield * _ ( resolveAutoAgentMode ( config ) )
78+ expect ( mode ) . toBe ( "claude" )
79+ } )
80+ ) . pipe ( Effect . provide ( NodeContext . layer ) ) )
81+
6582 it . effect ( "chooses Codex when only Codex auth exists" , ( ) =>
6683 withTempDir ( ( root ) =>
6784 Effect . gen ( function * ( _ ) {
@@ -78,6 +95,89 @@ describe("resolveAutoAgentMode", () => {
7895 } )
7996 ) . pipe ( Effect . provide ( NodeContext . layer ) ) )
8097
98+ it . effect ( "keeps explicit Codex mode when Codex auth exists" , ( ) =>
99+ withTempDir ( ( root ) =>
100+ Effect . gen ( function * ( _ ) {
101+ const fs = yield * _ ( FileSystem . FileSystem )
102+ const path = yield * _ ( Path . Path )
103+ const config = { ...makeConfig ( root , path ) , agentMode : "codex" as const }
104+ const codexRoot = path . join ( root , ".orch/auth/codex" )
105+
106+ yield * _ ( fs . makeDirectory ( codexRoot , { recursive : true } ) )
107+ yield * _ ( fs . writeFileString ( path . join ( codexRoot , "auth.json" ) , "{\"ok\":true}\n" ) )
108+
109+ const mode = yield * _ ( resolveAutoAgentMode ( config ) )
110+ expect ( mode ) . toBe ( "codex" )
111+ } )
112+ ) . pipe ( Effect . provide ( NodeContext . layer ) ) )
113+
114+ it . effect ( "chooses randomly when both Claude and Codex auth exist" , ( ) =>
115+ withTempDir ( ( root ) =>
116+ Effect . gen ( function * ( _ ) {
117+ const fs = yield * _ ( FileSystem . FileSystem )
118+ const path = yield * _ ( Path . Path )
119+ const config = makeConfig ( root , path )
120+ const claudeRoot = path . join ( root , ".orch/auth/claude/default" )
121+ const codexRoot = path . join ( root , ".orch/auth/codex" )
122+
123+ yield * _ ( fs . makeDirectory ( claudeRoot , { recursive : true } ) )
124+ yield * _ ( fs . makeDirectory ( codexRoot , { recursive : true } ) )
125+ yield * _ ( fs . writeFileString ( path . join ( claudeRoot , ".oauth-token" ) , "token\n" ) )
126+ yield * _ ( fs . writeFileString ( path . join ( codexRoot , "auth.json" ) , "{\"ok\":true}\n" ) )
127+
128+ const previousRandom = Math . random
129+ yield * _ ( Effect . addFinalizer ( ( ) =>
130+ Effect . sync ( ( ) => {
131+ Math . random = previousRandom
132+ } )
133+ ) )
134+
135+ yield * _ ( Effect . sync ( ( ) => {
136+ Math . random = vi . fn ( ( ) => 0.1 )
137+ } ) )
138+ const claudeMode = yield * _ ( resolveAutoAgentMode ( config ) )
139+ expect ( claudeMode ) . toBe ( "claude" )
140+
141+ yield * _ ( Effect . sync ( ( ) => {
142+ Math . random = vi . fn ( ( ) => 0.9 )
143+ } ) )
144+ const codexMode = yield * _ ( resolveAutoAgentMode ( config ) )
145+ expect ( codexMode ) . toBe ( "codex" )
146+ } )
147+ ) . pipe ( Effect . provide ( NodeContext . layer ) ) )
148+
149+ it . effect ( "fails explicit Claude mode when Claude auth is missing" , ( ) =>
150+ withTempDir ( ( root ) =>
151+ Effect . gen ( function * ( _ ) {
152+ const path = yield * _ ( Path . Path )
153+ const config = { ...makeConfig ( root , path ) , agentMode : "claude" as const }
154+
155+ const exit = yield * _ (
156+ resolveAutoAgentMode ( config ) . pipe (
157+ Effect . flip ,
158+ Effect . map ( ( error ) => error . _tag )
159+ )
160+ )
161+ expect ( exit ) . toBe ( "InvalidOption" )
162+ } )
163+ ) . pipe ( Effect . provide ( NodeContext . layer ) ) )
164+
165+ it . effect ( "fails explicit Codex mode when Codex auth is missing" , ( ) =>
166+ withTempDir ( ( root ) =>
167+ Effect . gen ( function * ( _ ) {
168+ const path = yield * _ ( Path . Path )
169+ const config = { ...makeConfig ( root , path ) , agentMode : "codex" as const }
170+
171+ const exit = yield * _ (
172+ resolveAutoAgentMode ( config ) . pipe (
173+ Effect . flip ,
174+ Effect . map ( ( error ) => error . _tag )
175+ )
176+ )
177+ expect ( exit ) . toBe ( "InvalidOption" )
178+ } )
179+ ) . pipe ( Effect . provide ( NodeContext . layer ) ) )
180+
81181 it . effect ( "fails when no auth exists" , ( ) =>
82182 withTempDir ( ( root ) =>
83183 Effect . gen ( function * ( _ ) {
0 commit comments