1import * as Schema from "effect/Schema";
2
3import { IsoDateTime, NonNegativeInt, ThreadId, TrimmedNonEmptyString } from "./baseSchemas.ts";
4
5/** Producers clamp free text to these before publishing so encoding never fails. */
6export const WORKTREE_SETUP_DETAIL_MAX_LENGTH = 200;
7export const WORKTREE_SETUP_TAIL_LINE_MAX_LENGTH = 400;
8export const WORKTREE_SETUP_ERROR_MAX_LENGTH = 1000;
9
10export const WorktreeSetupStageId = Schema.Literals([
11 "fetch",
12 "checkout",
13 "submodules",
14 "setup-script",
15 "agent",
16]);
17export type WorktreeSetupStageId = typeof WorktreeSetupStageId.Type;
18
19export const WorktreeSetupStageStatus = Schema.Literals([
20 "pending",
21 "running",
22 "done",
23 "skipped",
24 "warning",
25 "failed",
26]);
27export type WorktreeSetupStageStatus = typeof WorktreeSetupStageStatus.Type;
28
29export const WorktreeSetupStage = Schema.Struct({
30 id: WorktreeSetupStageId,
31 status: WorktreeSetupStageStatus,
32 startedAt: Schema.NullOr(IsoDateTime),
33 endedAt: Schema.NullOr(IsoDateTime),
34 percent: Schema.NullOr(Schema.Int.check(Schema.isBetween({ minimum: 0, maximum: 100 }))),
35 detail: Schema.NullOr(Schema.String.check(Schema.isMaxLength(WORKTREE_SETUP_DETAIL_MAX_LENGTH))),
36 tail: Schema.Array(Schema.String.check(Schema.isMaxLength(WORKTREE_SETUP_TAIL_LINE_MAX_LENGTH))),
37});
38export type WorktreeSetupStage = typeof WorktreeSetupStage.Type;
39
40export const WorktreeSetupPhase = Schema.Literals(["running", "done", "failed", "cancelled"]);
41export type WorktreeSetupPhase = typeof WorktreeSetupPhase.Type;
42
43export const WorktreeSetupSnapshot = Schema.Struct({
44 threadId: ThreadId,
45 phase: WorktreeSetupPhase,
46 startedAt: IsoDateTime,
47 endedAt: Schema.NullOr(IsoDateTime),
48 branch: Schema.NullOr(TrimmedNonEmptyString),
49 baseRef: Schema.NullOr(TrimmedNonEmptyString),
50 worktreePath: Schema.NullOr(TrimmedNonEmptyString),
51 setupScript: Schema.NullOr(
52 Schema.Struct({
53 name: TrimmedNonEmptyString,
54 command: TrimmedNonEmptyString,
55 terminalId: TrimmedNonEmptyString,
56 }),
57 ),
58 stages: Schema.Array(WorktreeSetupStage),
59 error: Schema.NullOr(Schema.String.check(Schema.isMaxLength(WORKTREE_SETUP_ERROR_MAX_LENGTH))),
60 sequence: NonNegativeInt,
61});
62export type WorktreeSetupSnapshot = typeof WorktreeSetupSnapshot.Type;
63
64export const WorktreeSetupSubscribeInput = Schema.Struct({
65 threadId: ThreadId,
66});
67export type WorktreeSetupSubscribeInput = typeof WorktreeSetupSubscribeInput.Type;
68
69export const WorktreeSetupStreamEvent = Schema.NullOr(WorktreeSetupSnapshot);
70export type WorktreeSetupStreamEvent = typeof WorktreeSetupStreamEvent.Type;
71
72export const WorktreeSetupCancelInput = Schema.Struct({
73 threadId: ThreadId,
74});
75export type WorktreeSetupCancelInput = typeof WorktreeSetupCancelInput.Type;
76
77export const WorktreeSetupCancelResult = Schema.Struct({
78 cancelled: Schema.Boolean,
79});
80export type WorktreeSetupCancelResult = typeof WorktreeSetupCancelResult.Type;
81
82export const WORKTREE_SETUP_STAGE_ORDER: ReadonlyArray<WorktreeSetupStageId> = [
83 "fetch",
84 "checkout",
85 "submodules",
86 "setup-script",
87 "agent",
88];
89
90export function worktreeSetupStageLabel(id: WorktreeSetupStageId): string {
91 switch (id) {
92 case "fetch":
93 return "Fetch base branch";
94 case "checkout":
95 return "Check out files";
96 case "submodules":
97 return "Init submodules";
98 case "setup-script":
99 return "Run setup script";
100 case "agent":
101 return "Start agent";
102 }
103}