- Detect and route jj repositories alongside git - Thread VCS kind through status and UI labels - Add jj driver contract coverage and shared freshness helper
Showing the changes to apps/server/src/git/GitWorkflowService.ts (1 of 30 files). Show all
Unified · Split
| @@ -3,6 +3,7 @@ import { Context, Effect, Layer } from "effect"; · 2 unmodified lines | ||
| 3 | 3 | import { |
| 4 | 4 | GitManagerError, |
| 5 | 5 | GitCommandError, |
| 6 | + type VcsDriverKind, | |
| 6 | 7 | type VcsSwitchRefInput, |
| 7 | 8 | type VcsSwitchRefResult, |
| 8 | 9 | type VcsCreateRefInput, |
| @@ -29,6 +30,7 @@ import { · 20 unmodified lines | ||
| 29 | 30 | import { GitManager, type GitRunStackedActionOptions } from "./GitManager.ts"; |
| 30 | 31 | import { GitVcsDriver } from "../vcs/GitVcsDriver.ts"; |
| 31 | 32 | import { VcsDriverRegistry } from "../vcs/VcsDriverRegistry.ts"; |
| 33 | +import { mergeGitStatusParts } from "@t3tools/shared/git"; | |
| 32 | 34 | |
| 33 | 35 | export interface GitWorkflowServiceShape { |
| 34 | 36 | readonly status: ( |
| @@ -92,6 +94,18 @@ const unsupportedGitCommand = (operation: string, cwd: string, detail: string) = · 57 unmodified lines | ||
| 92 | 94 | detail, |
| 93 | 95 | }); |
| 94 | 96 | |
| 97 | +const emptyWorkingTree = { files: [], insertions: 0, deletions: 0 } as const; | |
| 98 | + | |
| 99 | +const nonGitLocalStatus = (kind: VcsDriverKind, isRepo: boolean): VcsStatusLocalResult => ({ | |
| 100 | + kind, | |
| 101 | + isRepo, | |
| 102 | + hasPrimaryRemote: false, | |
| 103 | + isDefaultRef: false, | |
| 104 | + refName: null, | |
| 105 | + hasWorkingTreeChanges: false, | |
| 106 | + workingTree: emptyWorkingTree, | |
| 107 | +}); | |
| 108 | + | |
| 95 | 109 | export const make = Effect.fn("makeGitWorkflowService")(function* () { |
| 96 | 110 | const registry = yield* VcsDriverRegistry; |
| 97 | 111 | const git = yield* GitVcsDriver; |
| @@ -153,10 +167,60 @@ export const make = Effect.fn("makeGitWorkflowService")(function* () { · 55 unmodified lines | ||
| 153 | 167 | (input: Input) => |
| 154 | 168 | ensureGit(operation, input.cwd).pipe(Effect.andThen(run(input))); |
| 155 | 169 | |
| 170 | + const localStatus: GitWorkflowServiceShape["localStatus"] = Effect.fn( | |
| 171 | + "GitWorkflowService.localStatus", | |
| 172 | + )(function* (input) { | |
| 173 | + const handle = yield* registry | |
| 174 | + .detect({ cwd: input.cwd }) | |
| 175 | + .pipe( | |
| 176 | + Effect.mapError((error) => | |
| 177 | + unsupportedGitWorkflow( | |
| 178 | + "GitWorkflowService.localStatus", | |
| 179 | + input.cwd, | |
| 180 | + error instanceof Error ? error.message : String(error), | |
| 181 | + ), | |
| 182 | + ), | |
| 183 | + ); | |
| 184 | + if (!handle) { | |
| 185 | + return nonGitLocalStatus("unknown", false); | |
| 186 | + } | |
| 187 | + if (handle.kind === "git") { | |
| 188 | + return yield* gitManager.localStatus(input); | |
| 189 | + } | |
| 190 | + return nonGitLocalStatus(handle.kind, true); | |
| 191 | + }); | |
| 192 | + | |
| 193 | + const remoteStatus: GitWorkflowServiceShape["remoteStatus"] = Effect.fn( | |
| 194 | + "GitWorkflowService.remoteStatus", | |
| 195 | + )(function* (input) { | |
| 196 | + const handle = yield* registry | |
| 197 | + .detect({ cwd: input.cwd }) | |
| 198 | + .pipe( | |
| 199 | + Effect.mapError((error) => | |
| 200 | + unsupportedGitWorkflow( | |
| 201 | + "GitWorkflowService.remoteStatus", | |
| 202 | + input.cwd, | |
| 203 | + error instanceof Error ? error.message : String(error), | |
| 204 | + ), | |
| 205 | + ), | |
| 206 | + ); | |
| 207 | + if (handle?.kind === "git") { | |
| 208 | + return yield* gitManager.remoteStatus(input); | |
| 209 | + } | |
| 210 | + return null; | |
| 211 | + }); | |
| 212 | + | |
| 213 | + const status: GitWorkflowServiceShape["status"] = Effect.fn("GitWorkflowService.status")( | |
| 214 | + function* (input) { | |
| 215 | + const [local, remote] = yield* Effect.all([localStatus(input), remoteStatus(input)]); | |
| 216 | + return mergeGitStatusParts(local, remote); | |
| 217 | + }, | |
| 218 | + ); | |
| 219 | + | |
| 156 | 220 | return GitWorkflowService.of({ |
| 157 | − status: routeGitManager("GitWorkflowService.status", gitManager.status), | |
| 158 | − localStatus: routeGitManager("GitWorkflowService.localStatus", gitManager.localStatus), | |
| 159 | − remoteStatus: routeGitManager("GitWorkflowService.remoteStatus", gitManager.remoteStatus), | |
| 221 | + status, | |
| 222 | + localStatus, | |
| 223 | + remoteStatus, | |
| 160 | 224 | invalidateLocalStatus: gitManager.invalidateLocalStatus, |
| 161 | 225 | invalidateRemoteStatus: gitManager.invalidateRemoteStatus, |
| 162 | 226 | invalidateStatus: gitManager.invalidateStatus, |