| ... | ... | @@ -59,7 +59,7 @@ export class ProjectSetupScriptProjectNotFoundError extends Schema.TaggedErrorCl |
| 59 | 59 | }, |
| 60 | 60 | ) { |
| 61 | 61 | override get message(): string { |
| 62 | | return "Project was not found for setup script execution."; |
| 62 | return `Project was not found for setup script execution for thread '${this.threadId}' in '${this.worktreePath}'.`; |
| 63 | 63 | } |
| 64 | 64 | } |
| 65 | 65 | |
| ... | ... | @@ -78,32 +78,6 @@ export class ProjectSetupScriptRunner extends Context.Service< |
| 78 | 78 | } |
| 79 | 79 | >()("t3/project/ProjectSetupScriptRunner") {} |
| 80 | 80 | |
| 81 | | const isProjectSetupScriptRunnerError = Schema.is(ProjectSetupScriptRunnerError); |
| 82 | | |
| 83 | | function operationError( |
| 84 | | input: ProjectSetupScriptRunnerInput, |
| 85 | | operation: ProjectSetupScriptOperationError["operation"], |
| 86 | | cause: unknown, |
| 87 | | ): ProjectSetupScriptOperationError { |
| 88 | | return new ProjectSetupScriptOperationError({ |
| 89 | | threadId: input.threadId, |
| 90 | | worktreePath: input.worktreePath, |
| 91 | | operation, |
| 92 | | cause, |
| 93 | | ...(input.projectId === undefined ? {} : { projectId: input.projectId }), |
| 94 | | ...(input.projectCwd === undefined ? {} : { projectCwd: input.projectCwd }), |
| 95 | | }); |
| 96 | | } |
| 97 | | |
| 98 | | function mapRunnerError( |
| 99 | | input: ProjectSetupScriptRunnerInput, |
| 100 | | operation: ProjectSetupScriptOperationError["operation"], |
| 101 | | ) { |
| 102 | | return Effect.mapError((cause: unknown) => |
| 103 | | isProjectSetupScriptRunnerError(cause) ? cause : operationError(input, operation, cause), |
| 104 | | ); |
| 105 | | } |
| 106 | | |
| 107 | 81 | export const make = Effect.gen(function* () { |
| 108 | 82 | const projectionSnapshotQuery = yield* ProjectionSnapshotQuery.ProjectionSnapshotQuery; |
| 109 | 83 | const terminalManager = yield* TerminalManager.TerminalManager; |
| ... | ... | @@ -111,26 +85,43 @@ export const make = Effect.gen(function* () { |
| 111 | 85 | const runForThread: ProjectSetupScriptRunner["Service"]["runForThread"] = Effect.fn( |
| 112 | 86 | "ProjectSetupScriptRunner.runForThread", |
| 113 | 87 | )(function* (input) { |
| 88 | const errorContext = { |
| 89 | threadId: input.threadId, |
| 90 | worktreePath: input.worktreePath, |
| 91 | ...(input.projectId === undefined ? {} : { projectId: input.projectId }), |
| 92 | ...(input.projectCwd === undefined ? {} : { projectCwd: input.projectCwd }), |
| 93 | }; |
| 114 | 94 | const projectById = input.projectId |
| 115 | | ? yield* projectionSnapshotQuery |
| 116 | | .getProjectShellById(ProjectId.make(input.projectId)) |
| 117 | | .pipe(Effect.map(Option.getOrUndefined), mapRunnerError(input, "resolveProject")) |
| 95 | ? yield* projectionSnapshotQuery.getProjectShellById(ProjectId.make(input.projectId)).pipe( |
| 96 | Effect.map(Option.getOrUndefined), |
| 97 | Effect.mapError( |
| 98 | (cause) => |
| 99 | new ProjectSetupScriptOperationError({ |
| 100 | ...errorContext, |
| 101 | operation: "resolveProject", |
| 102 | cause, |
| 103 | }), |
| 104 | ), |
| 105 | ) |
| 118 | 106 | : null; |
| 119 | 107 | const project = |
| 120 | 108 | projectById ?? |
| 121 | 109 | (input.projectCwd |
| 122 | | ? yield* projectionSnapshotQuery |
| 123 | | .getActiveProjectByWorkspaceRoot(input.projectCwd) |
| 124 | | .pipe(Effect.map(Option.getOrUndefined), mapRunnerError(input, "resolveProject")) |
| 110 | ? yield* projectionSnapshotQuery.getActiveProjectByWorkspaceRoot(input.projectCwd).pipe( |
| 111 | Effect.map(Option.getOrUndefined), |
| 112 | Effect.mapError( |
| 113 | (cause) => |
| 114 | new ProjectSetupScriptOperationError({ |
| 115 | ...errorContext, |
| 116 | operation: "resolveProject", |
| 117 | cause, |
| 118 | }), |
| 119 | ), |
| 120 | ) |
| 125 | 121 | : null); |
| 126 | 122 | |
| 127 | 123 | if (!project) { |
| 128 | | return yield* new ProjectSetupScriptProjectNotFoundError({ |
| 129 | | threadId: input.threadId, |
| 130 | | worktreePath: input.worktreePath, |
| 131 | | ...(input.projectId === undefined ? {} : { projectId: input.projectId }), |
| 132 | | ...(input.projectCwd === undefined ? {} : { projectCwd: input.projectCwd }), |
| 133 | | }); |
| 124 | return yield* new ProjectSetupScriptProjectNotFoundError(errorContext); |
| 134 | 125 | } |
| 135 | 126 | |
| 136 | 127 | const script = setupProjectScript(project.scripts); |
| ... | ... | @@ -155,14 +146,32 @@ export const make = Effect.gen(function* () { |
| 155 | 146 | worktreePath: input.worktreePath, |
| 156 | 147 | env, |
| 157 | 148 | }) |
| 158 | | .pipe(mapRunnerError(input, "openTerminal")); |
| 149 | .pipe( |
| 150 | Effect.mapError( |
| 151 | (cause) => |
| 152 | new ProjectSetupScriptOperationError({ |
| 153 | ...errorContext, |
| 154 | operation: "openTerminal", |
| 155 | cause, |
| 156 | }), |
| 157 | ), |
| 158 | ); |
| 159 | 159 | yield* terminalManager |
| 160 | 160 | .write({ |
| 161 | 161 | threadId: input.threadId, |
| 162 | 162 | terminalId, |
| 163 | 163 | data: `${script.command}\r`, |
| 164 | 164 | }) |
| 165 | | .pipe(mapRunnerError(input, "writeCommand")); |
| 165 | .pipe( |
| 166 | Effect.mapError( |
| 167 | (cause) => |
| 168 | new ProjectSetupScriptOperationError({ |
| 169 | ...errorContext, |
| 170 | operation: "writeCommand", |
| 171 | cause, |
| 172 | }), |
| 173 | ), |
| 174 | ); |
| 166 | 175 | |
| 167 | 176 | return { |
| 168 | 177 | status: "started", |