import * as Effect from "effect/Effect";import * as Schema from "effect/Schema";import { NonNegativeInt, PositiveInt, ThreadId, TrimmedNonEmptyString } from "./baseSchemas.ts";import { SourceControlProviderError, SourceControlProviderInfo } from "./sourceControl.ts";import { VcsDriverKind } from "./vcs.ts"; const TrimmedNonEmptyStringSchema = TrimmedNonEmptyString;const GIT_LIST_BRANCHES_MAX_LIMIT = 200; // Domain Types export const GitStackedAction = Schema.Literals([ "commit", "push", "create_pr", "commit_push", "commit_push_pr",]);export type GitStackedAction = typeof GitStackedAction.Type;export const GitActionProgressPhase = Schema.Literals(["branch", "commit", "push", "pr"]);export type GitActionProgressPhase = typeof GitActionProgressPhase.Type;export const GitActionProgressKind = Schema.Literals([ "action_started", "phase_started", "hook_started", "hook_output", "hook_finished", "action_finished", "action_failed",]);export type GitActionProgressKind = typeof GitActionProgressKind.Type;export const GitActionProgressStream = Schema.Literals(["stdout", "stderr"]);export type GitActionProgressStream = typeof GitActionProgressStream.Type;const GitCommitStepStatus = Schema.Literals([ "created", "skipped_no_changes", "skipped_not_requested",]);const GitPushStepStatus = Schema.Literals([ "pushed", "skipped_not_requested", "skipped_up_to_date",]);const GitBranchStepStatus = Schema.Literals(["created", "skipped_not_requested"]);const GitPrStepStatus = Schema.Literals(["created", "opened_existing", "skipped_not_requested"]);const VcsStatusChangeRequestState = Schema.Literals(["open", "closed", "merged"]);const GitPullRequestReference = TrimmedNonEmptyStringSchema;const GitPullRequestState = Schema.Literals(["open", "closed", "merged"]);const GitPreparePullRequestThreadMode = Schema.Literals(["local", "worktree"]);export const GitRunStackedActionToastRunAction = Schema.Struct({ kind: GitStackedAction,});export type GitRunStackedActionToastRunAction = typeof GitRunStackedActionToastRunAction.Type;const GitRunStackedActionToastCta = Schema.Union([ Schema.Struct({ kind: Schema.Literal("none"), }), Schema.Struct({ kind: Schema.Literal("open_pr"), label: TrimmedNonEmptyStringSchema, url: Schema.String, }), Schema.Struct({ kind: Schema.Literal("run_action"), label: TrimmedNonEmptyStringSchema, action: GitRunStackedActionToastRunAction, }),]);export type GitRunStackedActionToastCta = typeof GitRunStackedActionToastCta.Type;const GitRunStackedActionToast = Schema.Struct({ title: TrimmedNonEmptyStringSchema, description: Schema.optional(TrimmedNonEmptyStringSchema), cta: GitRunStackedActionToastCta,});export type GitRunStackedActionToast = typeof GitRunStackedActionToast.Type; export const VcsRef = Schema.Struct({ name: TrimmedNonEmptyStringSchema, isRemote: Schema.optional(Schema.Boolean), remoteName: Schema.optional(TrimmedNonEmptyStringSchema), current: Schema.Boolean, isDefault: Schema.Boolean, worktreePath: TrimmedNonEmptyStringSchema.pipe(Schema.NullOr),});export type VcsRef = typeof VcsRef.Type; const VcsWorktree = Schema.Struct({ path: TrimmedNonEmptyStringSchema, refName: TrimmedNonEmptyStringSchema,});const GitResolvedPullRequest = Schema.Struct({ number: PositiveInt, title: TrimmedNonEmptyStringSchema, url: Schema.String, baseBranch: TrimmedNonEmptyStringSchema, headBranch: TrimmedNonEmptyStringSchema, state: GitPullRequestState,});export type GitResolvedPullRequest = typeof GitResolvedPullRequest.Type; // RPC Inputs export const VcsStatusInput = Schema.Struct({ cwd: TrimmedNonEmptyStringSchema,});export type VcsStatusInput = typeof VcsStatusInput.Type; export const VcsPullInput = Schema.Struct({ cwd: TrimmedNonEmptyStringSchema,});export type VcsPullInput = typeof VcsPullInput.Type; export const GitRunStackedActionInput = Schema.Struct({ actionId: TrimmedNonEmptyStringSchema, cwd: TrimmedNonEmptyStringSchema, action: GitStackedAction, commitMessage: Schema.optional(TrimmedNonEmptyStringSchema.check(Schema.isMaxLength(10_000))), featureBranch: Schema.optional(Schema.Boolean), filePaths: Schema.optional( Schema.Array(TrimmedNonEmptyStringSchema).check(Schema.isMinLength(1)), ), /** The thread the action runs beside; a pull request it creates is linked to it. */ threadId: Schema.optional(ThreadId),});export type GitRunStackedActionInput = typeof GitRunStackedActionInput.Type; export const VcsListRefsInput = Schema.Struct({ cwd: TrimmedNonEmptyStringSchema, query: Schema.optional(TrimmedNonEmptyStringSchema.check(Schema.isMaxLength(256))), cursor: Schema.optional(NonNegativeInt), includeMatchingRemoteRefs: Schema.optional(Schema.Boolean), refKind: Schema.optional(Schema.Literals(["all", "local", "remote"])), refresh: Schema.optional(Schema.Boolean), limit: Schema.optional( PositiveInt.check(Schema.isLessThanOrEqualTo(GIT_LIST_BRANCHES_MAX_LIMIT)), ),});export type VcsListRefsInput = typeof VcsListRefsInput.Type; export const VcsCreateWorktreeInput = Schema.Struct({ cwd: TrimmedNonEmptyStringSchema, refName: TrimmedNonEmptyStringSchema, newRefName: Schema.optional(TrimmedNonEmptyStringSchema), baseRefName: Schema.optional(TrimmedNonEmptyStringSchema), path: Schema.NullOr(TrimmedNonEmptyStringSchema),});export type VcsCreateWorktreeInput = typeof VcsCreateWorktreeInput.Type; export const GitPullRequestRefInput = Schema.Struct({ cwd: TrimmedNonEmptyStringSchema, reference: GitPullRequestReference,});export type GitPullRequestRefInput = typeof GitPullRequestRefInput.Type; export const GitPreparePullRequestThreadInput = Schema.Struct({ cwd: TrimmedNonEmptyStringSchema, reference: GitPullRequestReference, mode: GitPreparePullRequestThreadMode, threadId: Schema.optional(ThreadId),});export type GitPreparePullRequestThreadInput = typeof GitPreparePullRequestThreadInput.Type; export const VcsRemoveWorktreeInput = Schema.Struct({ cwd: TrimmedNonEmptyStringSchema, path: TrimmedNonEmptyStringSchema, force: Schema.optional(Schema.Boolean),});export type VcsRemoveWorktreeInput = typeof VcsRemoveWorktreeInput.Type; export const VcsCreateRefInput = Schema.Struct({ cwd: TrimmedNonEmptyStringSchema, refName: TrimmedNonEmptyStringSchema, switchRef: Schema.optional(Schema.Boolean),});export type VcsCreateRefInput = typeof VcsCreateRefInput.Type; export const VcsCreateRefResult = Schema.Struct({ refName: TrimmedNonEmptyStringSchema,});export type VcsCreateRefResult = typeof VcsCreateRefResult.Type; export const VcsSwitchRefInput = Schema.Struct({ cwd: TrimmedNonEmptyStringSchema, refName: TrimmedNonEmptyStringSchema,});export type VcsSwitchRefInput = typeof VcsSwitchRefInput.Type; export const VcsInitInput = Schema.Struct({ cwd: TrimmedNonEmptyStringSchema, kind: Schema.optional(VcsDriverKind),});export type VcsInitInput = typeof VcsInitInput.Type; // RPC Results const VcsStatusChangeRequest = Schema.Struct({ number: PositiveInt, title: TrimmedNonEmptyStringSchema, url: Schema.String, baseRef: TrimmedNonEmptyStringSchema, headRef: TrimmedNonEmptyStringSchema, state: VcsStatusChangeRequestState, /** Optional for compatibility with older servers and providers. */ isDraft: Schema.optional(Schema.Boolean), /** * Last provider-side activity (ISO), including comments and metadata edits. * This is not the time a change request closed or merged. Optional for old * servers and providers whose lookups do not report it. */ updatedAt: Schema.optional(Schema.NullOr(Schema.String)),}); const VcsStatusLocalShape = { isRepo: Schema.Boolean, sourceControlProvider: Schema.optional(SourceControlProviderInfo), hasPrimaryRemote: Schema.Boolean, isDefaultRef: Schema.Boolean, refName: Schema.NullOr(TrimmedNonEmptyStringSchema), hasWorkingTreeChanges: Schema.Boolean, workingTree: Schema.Struct({ files: Schema.Array( Schema.Struct({ path: TrimmedNonEmptyStringSchema, insertions: NonNegativeInt, deletions: NonNegativeInt, }), ), insertions: NonNegativeInt, deletions: NonNegativeInt, }),}; const VcsStatusRemoteShape = { hasUpstream: Schema.Boolean, aheadCount: NonNegativeInt, behindCount: NonNegativeInt, aheadOfDefaultCount: Schema.optional(NonNegativeInt), pr: Schema.NullOr(VcsStatusChangeRequest),}; export const VcsStatusLocalResult = Schema.Struct(VcsStatusLocalShape);export type VcsStatusLocalResult = typeof VcsStatusLocalResult.Type; export const VcsStatusRemoteResult = Schema.Struct(VcsStatusRemoteShape);export type VcsStatusRemoteResult = typeof VcsStatusRemoteResult.Type; export const VcsStatusResult = Schema.Struct({ ...VcsStatusLocalShape, ...VcsStatusRemoteShape,});export type VcsStatusResult = typeof VcsStatusResult.Type; export const VcsStatusStreamEvent = Schema.Union([ Schema.TaggedStruct("snapshot", { local: VcsStatusLocalResult, remote: Schema.NullOr(VcsStatusRemoteResult), }), Schema.TaggedStruct("localUpdated", { local: VcsStatusLocalResult, }), Schema.TaggedStruct("remoteUpdated", { remote: Schema.NullOr(VcsStatusRemoteResult), }),]);export type VcsStatusStreamEvent = typeof VcsStatusStreamEvent.Type; export const VcsListRefsResult = Schema.Struct({ refs: Schema.Array(VcsRef), isRepo: Schema.Boolean, hasPrimaryRemote: Schema.Boolean, nextCursor: NonNegativeInt.pipe(Schema.NullOr), totalCount: NonNegativeInt,});export type VcsListRefsResult = typeof VcsListRefsResult.Type; export const VcsCreateWorktreeResult = Schema.Struct({ worktree: VcsWorktree,});export type VcsCreateWorktreeResult = typeof VcsCreateWorktreeResult.Type; export const GitResolvePullRequestResult = Schema.Struct({ pullRequest: GitResolvedPullRequest,});export type GitResolvePullRequestResult = typeof GitResolvePullRequestResult.Type; export const GitPreparePullRequestThreadResult = Schema.Struct({ pullRequest: GitResolvedPullRequest, branch: TrimmedNonEmptyStringSchema, worktreePath: TrimmedNonEmptyStringSchema.pipe(Schema.NullOr), /** * False when the checkout could not be brought to the pull request head — a reused worktree * holding local commits or uncommitted changes keeps its own state, so the code being handed * over is older than the pull request. */ isOnPullRequestHead: Schema.Boolean.pipe(Schema.withDecodingDefaultKey(Effect.succeed(true))),});export type GitPreparePullRequestThreadResult = typeof GitPreparePullRequestThreadResult.Type; export const VcsSwitchRefResult = Schema.Struct({ refName: Schema.NullOr(TrimmedNonEmptyStringSchema),});export type VcsSwitchRefResult = typeof VcsSwitchRefResult.Type; export const GitRunStackedActionResult = Schema.Struct({ action: GitStackedAction, branch: Schema.Struct({ status: GitBranchStepStatus, name: Schema.optional(TrimmedNonEmptyStringSchema), }), commit: Schema.Struct({ status: GitCommitStepStatus, commitSha: Schema.optional(TrimmedNonEmptyStringSchema), subject: Schema.optional(TrimmedNonEmptyStringSchema), }), push: Schema.Struct({ status: GitPushStepStatus, branch: Schema.optional(TrimmedNonEmptyStringSchema), upstreamBranch: Schema.optional(TrimmedNonEmptyStringSchema), setUpstream: Schema.optional(Schema.Boolean), }), pr: Schema.Struct({ status: GitPrStepStatus, url: Schema.optional(Schema.String), number: Schema.optional(PositiveInt), baseBranch: Schema.optional(TrimmedNonEmptyStringSchema), headBranch: Schema.optional(TrimmedNonEmptyStringSchema), title: Schema.optional(TrimmedNonEmptyStringSchema), }), toast: GitRunStackedActionToast,});export type GitRunStackedActionResult = typeof GitRunStackedActionResult.Type; export const VcsPullResult = Schema.Struct({ status: Schema.Literals(["pulled", "skipped_up_to_date"]), refName: TrimmedNonEmptyStringSchema, upstreamRef: TrimmedNonEmptyStringSchema.pipe(Schema.NullOr),});export type VcsPullResult = typeof VcsPullResult.Type; // RPC / domain errorsexport class GitCommandError extends Schema.TaggedError<GitCommandError>()("GitCommandError", { operation: Schema.String, command: Schema.String, cwd: Schema.String, argumentCount: Schema.optional(Schema.Number), exitCode: Schema.optional(Schema.Number), stdoutLength: Schema.optional(Schema.Number), stderrLength: Schema.optional(Schema.Number), outputLength: Schema.optional(Schema.Number), detail: Schema.String, cause: Schema.optional(Schema.Defect()),}) { override get message(): string { return `Git command failed in ${this.operation} (${this.cwd}): ${this.detail}`; }} export class TextGenerationError extends Schema.TaggedError<TextGenerationError>()( "TextGenerationError", { operation: Schema.String, detail: Schema.String, cause: Schema.optional(Schema.Defect()), },) { override get message(): string { return `Text generation failed in ${this.operation}: ${this.detail}`; }} export class GitManagerError extends Schema.TaggedError<GitManagerError>()("GitManagerError", { operation: Schema.String, cwd: Schema.String, detail: Schema.String, cause: Schema.optional(Schema.Defect()),}) { override get message(): string { return `Git manager failed in ${this.operation}: ${this.detail}`; }} export class GitPullRequestMaterializationError extends Schema.TaggedError<GitPullRequestMaterializationError>()( "GitPullRequestMaterializationError", { cwd: TrimmedNonEmptyStringSchema, pullRequestNumber: PositiveInt, headRepository: Schema.NullOr(TrimmedNonEmptyStringSchema), headBranch: TrimmedNonEmptyStringSchema, localBranch: TrimmedNonEmptyStringSchema, cause: Schema.Defect(), },) { override get message(): string { return `Failed to materialize pull request #${this.pullRequestNumber} branch ${this.headBranch} as ${this.localBranch}.`; }} export const GitManagerServiceError = Schema.Union([ GitManagerError, GitPullRequestMaterializationError, GitCommandError, SourceControlProviderError, TextGenerationError,]);export type GitManagerServiceError = typeof GitManagerServiceError.Type; const GitActionProgressBase = Schema.Struct({ actionId: TrimmedNonEmptyStringSchema, cwd: TrimmedNonEmptyStringSchema, action: GitStackedAction,}); const GitActionStartedEvent = Schema.Struct({ ...GitActionProgressBase.fields, kind: Schema.Literal("action_started"), phases: Schema.Array(GitActionProgressPhase),});const GitActionPhaseStartedEvent = Schema.Struct({ ...GitActionProgressBase.fields, kind: Schema.Literal("phase_started"), phase: GitActionProgressPhase, label: TrimmedNonEmptyStringSchema,});const GitActionHookStartedEvent = Schema.Struct({ ...GitActionProgressBase.fields, kind: Schema.Literal("hook_started"), hookName: TrimmedNonEmptyStringSchema,});const GitActionHookOutputEvent = Schema.Struct({ ...GitActionProgressBase.fields, kind: Schema.Literal("hook_output"), hookName: Schema.NullOr(TrimmedNonEmptyStringSchema), stream: GitActionProgressStream, text: TrimmedNonEmptyStringSchema,});const GitActionHookFinishedEvent = Schema.Struct({ ...GitActionProgressBase.fields, kind: Schema.Literal("hook_finished"), hookName: TrimmedNonEmptyStringSchema, exitCode: Schema.NullOr(Schema.Int), durationMs: Schema.NullOr(NonNegativeInt),});const GitActionFinishedEvent = Schema.Struct({ ...GitActionProgressBase.fields, kind: Schema.Literal("action_finished"), result: GitRunStackedActionResult,});const GitActionFailedEvent = Schema.Struct({ ...GitActionProgressBase.fields, kind: Schema.Literal("action_failed"), phase: Schema.NullOr(GitActionProgressPhase), message: TrimmedNonEmptyStringSchema,}); export const GitActionProgressEvent = Schema.Union([ GitActionStartedEvent, GitActionPhaseStartedEvent, GitActionHookStartedEvent, GitActionHookOutputEvent, GitActionHookFinishedEvent, GitActionFinishedEvent, GitActionFailedEvent,]);export type GitActionProgressEvent = typeof GitActionProgressEvent.Type;
import * as Effect from "effect/Effect";
import * as Schema from "effect/Schema";
import { NonNegativeInt, PositiveInt, ThreadId, TrimmedNonEmptyString } from "./baseSchemas.ts";
import { SourceControlProviderError, SourceControlProviderInfo } from "./sourceControl.ts";
import { VcsDriverKind } from "./vcs.ts";
const TrimmedNonEmptyStringSchema = TrimmedNonEmptyString;
const GIT_LIST_BRANCHES_MAX_LIMIT = 200;
// Domain Types
export const GitStackedAction = Schema.Literals([
"commit",
"push",
"create_pr",
"commit_push",
"commit_push_pr",
]);
export type GitStackedAction = typeof GitStackedAction.Type;
export const GitActionProgressPhase = Schema.Literals(["branch", "commit", "push", "pr"]);
export type GitActionProgressPhase = typeof GitActionProgressPhase.Type;
export const GitActionProgressKind = Schema.Literals([
"action_started",
"phase_started",
"hook_started",
"hook_output",
"hook_finished",
"action_finished",
"action_failed",
]);
export type GitActionProgressKind = typeof GitActionProgressKind.Type;
export const GitActionProgressStream = Schema.Literals(["stdout", "stderr"]);
export type GitActionProgressStream = typeof GitActionProgressStream.Type;
const GitCommitStepStatus = Schema.Literals([
"created",
"skipped_no_changes",
"skipped_not_requested",
]);
const GitPushStepStatus = Schema.Literals([
"pushed",
"skipped_not_requested",
"skipped_up_to_date",
]);
const GitBranchStepStatus = Schema.Literals(["created", "skipped_not_requested"]);
const GitPrStepStatus = Schema.Literals(["created", "opened_existing", "skipped_not_requested"]);
const VcsStatusChangeRequestState = Schema.Literals(["open", "closed", "merged"]);
const GitPullRequestReference = TrimmedNonEmptyStringSchema;
const GitPullRequestState = Schema.Literals(["open", "closed", "merged"]);
const GitPreparePullRequestThreadMode = Schema.Literals(["local", "worktree"]);
export const GitRunStackedActionToastRunAction = Schema.Struct({
kind: GitStackedAction,
});
export type GitRunStackedActionToastRunAction = typeof GitRunStackedActionToastRunAction.Type;
const GitRunStackedActionToastCta = Schema.Union([
Schema.Struct({
kind: Schema.Literal("none"),
}),
Schema.Struct({
kind: Schema.Literal("open_pr"),
label: TrimmedNonEmptyStringSchema,
url: Schema.String,
}),
Schema.Struct({
kind: Schema.Literal("run_action"),
label: TrimmedNonEmptyStringSchema,
action: GitRunStackedActionToastRunAction,
}),
]);
export type GitRunStackedActionToastCta = typeof GitRunStackedActionToastCta.Type;
const GitRunStackedActionToast = Schema.Struct({
title: TrimmedNonEmptyStringSchema,
description: Schema.optional(TrimmedNonEmptyStringSchema),
cta: GitRunStackedActionToastCta,
});
export type GitRunStackedActionToast = typeof GitRunStackedActionToast.Type;
export const VcsRef = Schema.Struct({
name: TrimmedNonEmptyStringSchema,
isRemote: Schema.optional(Schema.Boolean),
remoteName: Schema.optional(TrimmedNonEmptyStringSchema),
current: Schema.Boolean,
isDefault: Schema.Boolean,
worktreePath: TrimmedNonEmptyStringSchema.pipe(Schema.NullOr),
});
export type VcsRef = typeof VcsRef.Type;
const VcsWorktree = Schema.Struct({
path: TrimmedNonEmptyStringSchema,
refName: TrimmedNonEmptyStringSchema,
});
const GitResolvedPullRequest = Schema.Struct({
number: PositiveInt,
title: TrimmedNonEmptyStringSchema,
url: Schema.String,
baseBranch: TrimmedNonEmptyStringSchema,
headBranch: TrimmedNonEmptyStringSchema,
state: GitPullRequestState,
});
export type GitResolvedPullRequest = typeof GitResolvedPullRequest.Type;
// RPC Inputs
export const VcsStatusInput = Schema.Struct({
cwd: TrimmedNonEmptyStringSchema,
});
export type VcsStatusInput = typeof VcsStatusInput.Type;
export const VcsPullInput = Schema.Struct({
cwd: TrimmedNonEmptyStringSchema,
});
export type VcsPullInput = typeof VcsPullInput.Type;
export const GitRunStackedActionInput = Schema.Struct({
actionId: TrimmedNonEmptyStringSchema,
cwd: TrimmedNonEmptyStringSchema,
action: GitStackedAction,
commitMessage: Schema.optional(TrimmedNonEmptyStringSchema.check(Schema.isMaxLength(10_000))),
featureBranch: Schema.optional(Schema.Boolean),
filePaths: Schema.optional(
Schema.Array(TrimmedNonEmptyStringSchema).check(Schema.isMinLength(1)),
),
/** The thread the action runs beside; a pull request it creates is linked to it. */
threadId: Schema.optional(ThreadId),
});
export type GitRunStackedActionInput = typeof GitRunStackedActionInput.Type;
export const VcsListRefsInput = Schema.Struct({
cwd: TrimmedNonEmptyStringSchema,
query: Schema.optional(TrimmedNonEmptyStringSchema.check(Schema.isMaxLength(256))),
cursor: Schema.optional(NonNegativeInt),
includeMatchingRemoteRefs: Schema.optional(Schema.Boolean),
refKind: Schema.optional(Schema.Literals(["all", "local", "remote"])),
refresh: Schema.optional(Schema.Boolean),
limit: Schema.optional(
PositiveInt.check(Schema.isLessThanOrEqualTo(GIT_LIST_BRANCHES_MAX_LIMIT)),
),
});
export type VcsListRefsInput = typeof VcsListRefsInput.Type;
export const VcsCreateWorktreeInput = Schema.Struct({
cwd: TrimmedNonEmptyStringSchema,
refName: TrimmedNonEmptyStringSchema,
newRefName: Schema.optional(TrimmedNonEmptyStringSchema),
baseRefName: Schema.optional(TrimmedNonEmptyStringSchema),
path: Schema.NullOr(TrimmedNonEmptyStringSchema),
});
export type VcsCreateWorktreeInput = typeof VcsCreateWorktreeInput.Type;
export const GitPullRequestRefInput = Schema.Struct({
cwd: TrimmedNonEmptyStringSchema,
reference: GitPullRequestReference,
});
export type GitPullRequestRefInput = typeof GitPullRequestRefInput.Type;
export const GitPreparePullRequestThreadInput = Schema.Struct({
cwd: TrimmedNonEmptyStringSchema,
reference: GitPullRequestReference,
mode: GitPreparePullRequestThreadMode,
threadId: Schema.optional(ThreadId),
});
export type GitPreparePullRequestThreadInput = typeof GitPreparePullRequestThreadInput.Type;
export const VcsRemoveWorktreeInput = Schema.Struct({
cwd: TrimmedNonEmptyStringSchema,
path: TrimmedNonEmptyStringSchema,
force: Schema.optional(Schema.Boolean),
});
export type VcsRemoveWorktreeInput = typeof VcsRemoveWorktreeInput.Type;
export const VcsCreateRefInput = Schema.Struct({
cwd: TrimmedNonEmptyStringSchema,
refName: TrimmedNonEmptyStringSchema,
switchRef: Schema.optional(Schema.Boolean),
});
export type VcsCreateRefInput = typeof VcsCreateRefInput.Type;
export const VcsCreateRefResult = Schema.Struct({
refName: TrimmedNonEmptyStringSchema,
});
export type VcsCreateRefResult = typeof VcsCreateRefResult.Type;
export const VcsSwitchRefInput = Schema.Struct({
cwd: TrimmedNonEmptyStringSchema,
refName: TrimmedNonEmptyStringSchema,
});
export type VcsSwitchRefInput = typeof VcsSwitchRefInput.Type;
export const VcsInitInput = Schema.Struct({
cwd: TrimmedNonEmptyStringSchema,
kind: Schema.optional(VcsDriverKind),
});
export type VcsInitInput = typeof VcsInitInput.Type;
// RPC Results
const VcsStatusChangeRequest = Schema.Struct({
number: PositiveInt,
title: TrimmedNonEmptyStringSchema,
url: Schema.String,
baseRef: TrimmedNonEmptyStringSchema,
headRef: TrimmedNonEmptyStringSchema,
state: VcsStatusChangeRequestState,
/** Optional for compatibility with older servers and providers. */
isDraft: Schema.optional(Schema.Boolean),
/**
* Last provider-side activity (ISO), including comments and metadata edits.
* This is not the time a change request closed or merged. Optional for old
* servers and providers whose lookups do not report it.
*/
updatedAt: Schema.optional(Schema.NullOr(Schema.String)),
});
const VcsStatusLocalShape = {
isRepo: Schema.Boolean,
sourceControlProvider: Schema.optional(SourceControlProviderInfo),
hasPrimaryRemote: Schema.Boolean,
isDefaultRef: Schema.Boolean,
refName: Schema.NullOr(TrimmedNonEmptyStringSchema),
hasWorkingTreeChanges: Schema.Boolean,
workingTree: Schema.Struct({
files: Schema.Array(
Schema.Struct({
path: TrimmedNonEmptyStringSchema,
insertions: NonNegativeInt,
deletions: NonNegativeInt,
}),
),
insertions: NonNegativeInt,
deletions: NonNegativeInt,
}),
};
const VcsStatusRemoteShape = {
hasUpstream: Schema.Boolean,
aheadCount: NonNegativeInt,
behindCount: NonNegativeInt,
aheadOfDefaultCount: Schema.optional(NonNegativeInt),
pr: Schema.NullOr(VcsStatusChangeRequest),
};
export const VcsStatusLocalResult = Schema.Struct(VcsStatusLocalShape);
export type VcsStatusLocalResult = typeof VcsStatusLocalResult.Type;
export const VcsStatusRemoteResult = Schema.Struct(VcsStatusRemoteShape);
export type VcsStatusRemoteResult = typeof VcsStatusRemoteResult.Type;
export const VcsStatusResult = Schema.Struct({
...VcsStatusLocalShape,
...VcsStatusRemoteShape,
});
export type VcsStatusResult = typeof VcsStatusResult.Type;
export const VcsStatusStreamEvent = Schema.Union([
Schema.TaggedStruct("snapshot", {
local: VcsStatusLocalResult,
remote: Schema.NullOr(VcsStatusRemoteResult),
}),
Schema.TaggedStruct("localUpdated", {
local: VcsStatusLocalResult,
}),
Schema.TaggedStruct("remoteUpdated", {
remote: Schema.NullOr(VcsStatusRemoteResult),
}),
]);
export type VcsStatusStreamEvent = typeof VcsStatusStreamEvent.Type;
export const VcsListRefsResult = Schema.Struct({
refs: Schema.Array(VcsRef),
isRepo: Schema.Boolean,
hasPrimaryRemote: Schema.Boolean,
nextCursor: NonNegativeInt.pipe(Schema.NullOr),
totalCount: NonNegativeInt,
});
export type VcsListRefsResult = typeof VcsListRefsResult.Type;
export const VcsCreateWorktreeResult = Schema.Struct({
worktree: VcsWorktree,
});
export type VcsCreateWorktreeResult = typeof VcsCreateWorktreeResult.Type;
export const GitResolvePullRequestResult = Schema.Struct({
pullRequest: GitResolvedPullRequest,
});
export type GitResolvePullRequestResult = typeof GitResolvePullRequestResult.Type;
export const GitPreparePullRequestThreadResult = Schema.Struct({
pullRequest: GitResolvedPullRequest,
branch: TrimmedNonEmptyStringSchema,
worktreePath: TrimmedNonEmptyStringSchema.pipe(Schema.NullOr),
/**
* False when the checkout could not be brought to the pull request head — a reused worktree
* holding local commits or uncommitted changes keeps its own state, so the code being handed
* over is older than the pull request.
*/
isOnPullRequestHead: Schema.Boolean.pipe(Schema.withDecodingDefaultKey(Effect.succeed(true))),
});
export type GitPreparePullRequestThreadResult = typeof GitPreparePullRequestThreadResult.Type;
export const VcsSwitchRefResult = Schema.Struct({
refName: Schema.NullOr(TrimmedNonEmptyStringSchema),
});
export type VcsSwitchRefResult = typeof VcsSwitchRefResult.Type;
export const GitRunStackedActionResult = Schema.Struct({
action: GitStackedAction,
branch: Schema.Struct({
status: GitBranchStepStatus,
name: Schema.optional(TrimmedNonEmptyStringSchema),
}),
commit: Schema.Struct({
status: GitCommitStepStatus,
commitSha: Schema.optional(TrimmedNonEmptyStringSchema),
subject: Schema.optional(TrimmedNonEmptyStringSchema),
}),
push: Schema.Struct({
status: GitPushStepStatus,
branch: Schema.optional(TrimmedNonEmptyStringSchema),
upstreamBranch: Schema.optional(TrimmedNonEmptyStringSchema),
setUpstream: Schema.optional(Schema.Boolean),
}),
pr: Schema.Struct({
status: GitPrStepStatus,
url: Schema.optional(Schema.String),
number: Schema.optional(PositiveInt),
baseBranch: Schema.optional(TrimmedNonEmptyStringSchema),
headBranch: Schema.optional(TrimmedNonEmptyStringSchema),
title: Schema.optional(TrimmedNonEmptyStringSchema),
}),
toast: GitRunStackedActionToast,
});
export type GitRunStackedActionResult = typeof GitRunStackedActionResult.Type;
export const VcsPullResult = Schema.Struct({
status: Schema.Literals(["pulled", "skipped_up_to_date"]),
refName: TrimmedNonEmptyStringSchema,
upstreamRef: TrimmedNonEmptyStringSchema.pipe(Schema.NullOr),
});
export type VcsPullResult = typeof VcsPullResult.Type;
// RPC / domain errors
export class GitCommandError extends Schema.TaggedError<GitCommandError>()("GitCommandError", {
operation: Schema.String,
command: Schema.String,
cwd: Schema.String,
argumentCount: Schema.optional(Schema.Number),
exitCode: Schema.optional(Schema.Number),
stdoutLength: Schema.optional(Schema.Number),
stderrLength: Schema.optional(Schema.Number),
outputLength: Schema.optional(Schema.Number),
detail: Schema.String,
cause: Schema.optional(Schema.Defect()),
}) {
override get message(): string {
return `Git command failed in ${this.operation} (${this.cwd}): ${this.detail}`;
}
}
export class TextGenerationError extends Schema.TaggedError<TextGenerationError>()(
"TextGenerationError",
{
operation: Schema.String,
detail: Schema.String,
cause: Schema.optional(Schema.Defect()),
},
) {
override get message(): string {
return `Text generation failed in ${this.operation}: ${this.detail}`;
}
}
export class GitManagerError extends Schema.TaggedError<GitManagerError>()("GitManagerError", {
operation: Schema.String,
cwd: Schema.String,
detail: Schema.String,
cause: Schema.optional(Schema.Defect()),
}) {
override get message(): string {
return `Git manager failed in ${this.operation}: ${this.detail}`;
}
}
export class GitPullRequestMaterializationError extends Schema.TaggedError<GitPullRequestMaterializationError>()(
"GitPullRequestMaterializationError",
{
cwd: TrimmedNonEmptyStringSchema,
pullRequestNumber: PositiveInt,
headRepository: Schema.NullOr(TrimmedNonEmptyStringSchema),
headBranch: TrimmedNonEmptyStringSchema,
localBranch: TrimmedNonEmptyStringSchema,
cause: Schema.Defect(),
},
) {
override get message(): string {
return `Failed to materialize pull request #${this.pullRequestNumber} branch ${this.headBranch} as ${this.localBranch}.`;
}
}
export const GitManagerServiceError = Schema.Union([
GitManagerError,
GitPullRequestMaterializationError,
GitCommandError,
SourceControlProviderError,
TextGenerationError,
]);
export type GitManagerServiceError = typeof GitManagerServiceError.Type;
const GitActionProgressBase = Schema.Struct({
actionId: TrimmedNonEmptyStringSchema,
cwd: TrimmedNonEmptyStringSchema,
action: GitStackedAction,
});
const GitActionStartedEvent = Schema.Struct({
...GitActionProgressBase.fields,
kind: Schema.Literal("action_started"),
phases: Schema.Array(GitActionProgressPhase),
});
const GitActionPhaseStartedEvent = Schema.Struct({
...GitActionProgressBase.fields,
kind: Schema.Literal("phase_started"),
phase: GitActionProgressPhase,
label: TrimmedNonEmptyStringSchema,
});
const GitActionHookStartedEvent = Schema.Struct({
...GitActionProgressBase.fields,
kind: Schema.Literal("hook_started"),
hookName: TrimmedNonEmptyStringSchema,
});
const GitActionHookOutputEvent = Schema.Struct({
...GitActionProgressBase.fields,
kind: Schema.Literal("hook_output"),
hookName: Schema.NullOr(TrimmedNonEmptyStringSchema),
stream: GitActionProgressStream,
text: TrimmedNonEmptyStringSchema,
});
const GitActionHookFinishedEvent = Schema.Struct({
...GitActionProgressBase.fields,
kind: Schema.Literal("hook_finished"),
hookName: TrimmedNonEmptyStringSchema,
exitCode: Schema.NullOr(Schema.Int),
durationMs: Schema.NullOr(NonNegativeInt),
});
const GitActionFinishedEvent = Schema.Struct({
...GitActionProgressBase.fields,
kind: Schema.Literal("action_finished"),
result: GitRunStackedActionResult,
});
const GitActionFailedEvent = Schema.Struct({
...GitActionProgressBase.fields,
kind: Schema.Literal("action_failed"),
phase: Schema.NullOr(GitActionProgressPhase),
message: TrimmedNonEmptyStringSchema,
});
export const GitActionProgressEvent = Schema.Union([
GitActionStartedEvent,
GitActionPhaseStartedEvent,
GitActionHookStartedEvent,
GitActionHookOutputEvent,
GitActionHookFinishedEvent,
GitActionFinishedEvent,
GitActionFailedEvent,
]);
export type GitActionProgressEvent = typeof GitActionProgressEvent.Type;