| ... | @@ -59,7 +59,7 @@ export class ProjectSetupScriptProjectNotFoundError extends Schema.TaggedErrorCl | ... | @@ -59,7 +59,7 @@ export class ProjectSetupScriptProjectNotFoundError extends Schema.TaggedErrorCl |
| 59 | }, | 59 | }, |
| 60 | ) { | 60 | ) { |
| 61 | override get message(): string { | 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,32 +78,6 @@ export class ProjectSetupScriptRunner extends Context.Service< |
| 78 | } | 78 | } |
| 79 | >()("t3/project/ProjectSetupScriptRunner") {} | 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 | export const make = Effect.gen(function* () { | 81 | export const make = Effect.gen(function* () { |
| 108 | const projectionSnapshotQuery = yield* ProjectionSnapshotQuery.ProjectionSnapshotQuery; | 82 | const projectionSnapshotQuery = yield* ProjectionSnapshotQuery.ProjectionSnapshotQuery; |
| 109 | const terminalManager = yield* TerminalManager.TerminalManager; | 83 | const terminalManager = yield* TerminalManager.TerminalManager; |
| ... | @@ -111,26 +85,43 @@ export const make = Effect.gen(function* () { | ... | @@ -111,26 +85,43 @@ export const make = Effect.gen(function* () { |
| 111 | const runForThread: ProjectSetupScriptRunner["Service"]["runForThread"] = Effect.fn( | 85 | const runForThread: ProjectSetupScriptRunner["Service"]["runForThread"] = Effect.fn( |
| 112 | "ProjectSetupScriptRunner.runForThread", | 86 | "ProjectSetupScriptRunner.runForThread", |
| 113 | )(function* (input) { | 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 | const projectById = input.projectId | 94 | const projectById = input.projectId |
| 115 | ? yield* projectionSnapshotQuery | 95 | ? yield* projectionSnapshotQuery.getProjectShellById(ProjectId.make(input.projectId)).pipe( |
| 116 | .getProjectShellById(ProjectId.make(input.projectId)) | 96 | Effect.map(Option.getOrUndefined), |
| 117 | .pipe(Effect.map(Option.getOrUndefined), mapRunnerError(input, "resolveProject")) | 97 | Effect.mapError( |
| | 98 | (cause) => |
| | 99 | new ProjectSetupScriptOperationError({ |
| | 100 | ...errorContext, |
| | 101 | operation: "resolveProject", |
| | 102 | cause, |
| | 103 | }), |
| | 104 | ), |
| | 105 | ) |
| 118 | : null; | 106 | : null; |
| 119 | const project = | 107 | const project = |
| 120 | projectById ?? | 108 | projectById ?? |
| 121 | (input.projectCwd | 109 | (input.projectCwd |
| 122 | ? yield* projectionSnapshotQuery | 110 | ? yield* projectionSnapshotQuery.getActiveProjectByWorkspaceRoot(input.projectCwd).pipe( |
| 123 | .getActiveProjectByWorkspaceRoot(input.projectCwd) | 111 | Effect.map(Option.getOrUndefined), |
| 124 | .pipe(Effect.map(Option.getOrUndefined), mapRunnerError(input, "resolveProject")) | 112 | Effect.mapError( |
| | 113 | (cause) => |
| | 114 | new ProjectSetupScriptOperationError({ |
| | 115 | ...errorContext, |
| | 116 | operation: "resolveProject", |
| | 117 | cause, |
| | 118 | }), |
| | 119 | ), |
| | 120 | ) |
| 125 | : null); | 121 | : null); |
| 126 | | 122 | |
| 127 | if (!project) { | 123 | if (!project) { |
| 128 | return yield* new ProjectSetupScriptProjectNotFoundError({ | 124 | return yield* new ProjectSetupScriptProjectNotFoundError(errorContext); |
| 129 | threadId: input.threadId, | | |
| 130 | worktreePath: input.worktreePath, | | |
| 131 | ...(input.projectId === undefined ? {} : { projectId: input.projectId }), | | |
| 132 | ...(input.projectCwd === undefined ? {} : { projectCwd: input.projectCwd }), | | |
| 133 | }); | | |
| 134 | } | 125 | } |
| 135 | | 126 | |
| 136 | const script = setupProjectScript(project.scripts); | 127 | const script = setupProjectScript(project.scripts); |
| ... | @@ -155,14 +146,32 @@ export const make = Effect.gen(function* () { | ... | @@ -155,14 +146,32 @@ export const make = Effect.gen(function* () { |
| 155 | worktreePath: input.worktreePath, | 146 | worktreePath: input.worktreePath, |
| 156 | env, | 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 | yield* terminalManager | 159 | yield* terminalManager |
| 160 | .write({ | 160 | .write({ |
| 161 | threadId: input.threadId, | 161 | threadId: input.threadId, |
| 162 | terminalId, | 162 | terminalId, |
| 163 | data: `${script.command}\r`, | 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 | return { | 176 | return { |
| 168 | status: "started", | 177 | status: "started", |