fix(server): resolve Claude SDK executable path on Windows npm installs - #3740
juliusmarminge merged 7 commits into
Effect Service Conventions: No issues found
No Effect service convention violations found in the changed scope.
The new apps/server/src/provider/Drivers/ClaudeExecutable.ts follows the established patterns:
- Namespace imports for Effect modules (
effect/Context,effect/Effect) and Node builtins; named imports for theHostProcessPlatformandSpawnExecutableResolutionservice tags, matching the ~30 existing consumers acrossapps/server. ClaudeExecutableFileCheckusesContext.Referencewith adefaultValue, mirroring its sibling servicesHostProcessPlatformandSpawnExecutableResolutionin@t3tools/shared; it is a legitimate, explicitly overridable test seam rather than hidden/fake dependency injection.resolveClaudeSdkExecutablePathacquires its dependencies from the environment viayield*and takes only pure configuration (binaryPath: string,environment), not service instances.- No
ManagedRuntime.make,runPromise/runPromiseExit, orLayer.succeedmisuse; no new error types requiringSchema.TaggedErrorClassreview. - The added test file covers genuine new backend behavior (Windows launcher-shim resolution) and uses
Effect.provideServiceseams for platform, command resolution, and file existence.
Details
Note
Your check run agent prompt is: .macroscope/check-run-agents/effect-service-conventions.md
More information about how Check Run Agents work can be found in our Help Center.
Files examined:
apps/server/src/provider/Drivers/ClaudeExecutable.ts(new)apps/server/src/provider/Drivers/ClaudeExecutable.test.ts(new)apps/server/src/provider/Layers/ClaudeAdapter.ts(call site)apps/server/src/provider/Layers/ClaudeProvider.ts(call site)
Context verified: packages/shared/src/hostProcess.ts and packages/shared/src/shell.ts define HostProcessPlatform and SpawnExecutableResolution via Context.Reference with default values, the same pattern the new ClaudeExecutableFileCheck follows. Named-import style for these tags is consistent with all existing consumers in the repo, so it is not flagged. The call-site changes in ClaudeAdapter.ts and ClaudeProvider.ts simply consume the new helper by yielding it and passing pure config; no violations.
🔍 Agent activity — 2 tool calls
💭 I'm examining the new
ClaudeExecutable.tsfile to check for Effect service convention violations. The module introduces an injectable serviceClaudeExecutableFileCheckusingContext.Referenceand exports a function to resolve the Claude SDK executable path. The imports follow proper namespace conventions with subpath imports from effect and Node modules. Now I'm checking whether the named imports from@t3tools/shared/hostProcessand@t3tools/shared/shellshould be namespace imports instead. The convention allows named imports when accessing service tags from external packages, so this appears acceptable. I need to dig deeper into howClaudeExecutableFileCheckis being used as a dependency injection seam and whether it violates any core conventions. Looking atisExistingFile- it's a synchronous file check wrapped in a Context.Reference with a defaultValue, which serves as a test seam. This is actually a legitimate callback strategy rather than a hidden dependency in a Layer implementation, so it should be fine. Similarly,SpawnExecutableResolutionis a service used in tests that returns the resolved command, which follows the same pattern. TheresolveClaudeSdkExecutablePathfunction takes pure configuration inputs (binaryPath and environment) and usesEffect.fnto yield services from the environment, which is correct. The warning log includes file paths in its payload, which aren't sensitive data, so that's acceptable. Now I need to trace through howSpawnExecutableResolutionis actually defined and used to verify there's no real violation here. Looking at the key requirement about applying checks when a pull request creates or consumes an Effect service—this module introduces aContext.Referenceservice calledClaudeExecutableFileCheck, but it's not a full service module with the typicalContext.Service,make, andlayerexports. It's more of a helper module that provides utilities. I should examine how other modules in the codebase handle similar patterns, particularly looking at the shared/shell and hostProcess modules to understand the conventions better.
1. github_api_read_only — Show me the definition of SpawnExecutableResolution in @t3tools/shared/shell and HostProcessPlatform in @t3tools/shared/hostProcess. How are they defined as Effect services (Context.Reference, Context.Tag, Context.Service)? Provide the full source.
💭 The
ClaudeExecutableFileCheckfollows the established pattern forContext.Referenceservices with default values, which aligns with how the codebase handles these dependencies. The module's use of namespace imports for effect modules and named imports for service references is consistent with existing conventions, so this is a valid test seam. Now I need to review the changes in ClaudeAdapter.ts and ClaudeProvider.ts to check for any violations. TheExecutableFileCheckcallback is a valid test seam pattern, and the imports follow the codebase conventions—these are service tags where named imports are acceptable. I should verify how existing code imports these same modules to ensure consistency.
2. github_api_read_only — How is HostProcessPlatform from @t3tools/shared/hostProcess and SpawnExecutableResolution from @t3tools/shared/shell imported by other consumers in apps/server (named import vs namespace import)? Show example import statements from existing files.
💭 The import style aligns with the rest of the codebase, and the new module follows the same
Context.Referencepattern as existing ones. The service tag mirrors the naming conventions of similar tags, and there are no violations of the error handling or dependency injection patterns used throughout.
Agent Credits: 77 credits