import * as Schema from "effect/Schema";import { RepositoryIdentity, ThreadEnvMode } from "./environment.ts";import { ModelSelection } from "./modelSelection.ts";import { CommandId, IsoDateTime, NonNegativeInt, PositiveInt, ProjectId, TrimmedNonEmptyString, TrimmedString,} from "./baseSchemas.ts"; const PROJECT_SEARCH_ENTRIES_MAX_LIMIT = 200;const PROJECT_SEARCH_CONTENTS_MAX_LIMIT = 500;const PROJECT_WRITE_FILE_PATH_MAX_LENGTH = 512;const PROJECT_READ_FILE_PATH_MAX_LENGTH = 512; export const ProjectScriptIcon = Schema.Literals([ "play", "test", "lint", "configure", "build", "debug",]);export type ProjectScriptIcon = typeof ProjectScriptIcon.Type; export const ProjectScript = Schema.Struct({ id: TrimmedNonEmptyString, name: TrimmedNonEmptyString, command: TrimmedNonEmptyString, icon: ProjectScriptIcon, runOnWorktreeCreate: Schema.Boolean, previewUrl: Schema.optional(TrimmedNonEmptyString), autoOpenPreview: Schema.optional(Schema.Boolean),});export type ProjectScript = typeof ProjectScript.Type; export const ProjectIconColor = Schema.Literals([ "gray", "red", "orange", "amber", "yellow", "lime", "green", "emerald", "teal", "cyan", "sky", "blue", "indigo", "violet", "purple", "fuchsia", "pink", "rose",]);export type ProjectIconColor = typeof ProjectIconColor.Type; const ProjectLucideIconName = TrimmedNonEmptyString.check( Schema.isMaxLength(64), Schema.isPattern(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),); const ProjectEmoji = TrimmedNonEmptyString.check(Schema.isMaxLength(32)); export const ProjectIconOverride = Schema.Union([ Schema.Struct({ kind: Schema.Literal("lucide"), name: ProjectLucideIconName, color: ProjectIconColor, }), Schema.Struct({ kind: Schema.Literal("emoji"), emoji: ProjectEmoji, }),]);export type ProjectIconOverride = typeof ProjectIconOverride.Type; export const Project = Schema.Struct({ id: ProjectId, title: TrimmedNonEmptyString, workspaceRoot: TrimmedNonEmptyString, repositoryIdentity: Schema.optional(Schema.NullOr(RepositoryIdentity)), faviconPath: Schema.optional(Schema.NullOr(TrimmedNonEmptyString)), projectIcon: Schema.optional(Schema.NullOr(ProjectIconOverride)), defaultModelSelection: Schema.NullOr(ModelSelection), defaultThreadEnvMode: Schema.optional(Schema.NullOr(ThreadEnvMode)), // Opt-in because background sync performs network I/O and may move the checkout. autoPull: Schema.optional(Schema.Boolean), scripts: Schema.Array(ProjectScript), createdAt: IsoDateTime, updatedAt: IsoDateTime, deletedAt: Schema.NullOr(IsoDateTime),});export type Project = typeof Project.Type; export const ProjectSnapshot = Schema.Struct({ projects: Schema.Array(Project), updatedAt: IsoDateTime,});export type ProjectSnapshot = typeof ProjectSnapshot.Type; export const ProjectChange = Schema.Union([ Schema.Struct({ type: Schema.Literal("project.upserted"), project: Project }), Schema.Struct({ type: Schema.Literal("project.deleted"), projectId: ProjectId, deletedAt: IsoDateTime, }),]);export type ProjectChange = typeof ProjectChange.Type; export const ProjectMutation = Schema.Union([ Schema.Struct({ type: Schema.Literal("project.create"), commandId: CommandId, projectId: ProjectId, title: TrimmedNonEmptyString, workspaceRoot: TrimmedNonEmptyString, createWorkspaceRootIfMissing: Schema.optional(Schema.Boolean), defaultModelSelection: Schema.optional(Schema.NullOr(ModelSelection)), scripts: Schema.optional(Schema.Array(ProjectScript)), }), Schema.Struct({ type: Schema.Literal("project.update"), commandId: CommandId, projectId: ProjectId, title: Schema.optional(TrimmedNonEmptyString), workspaceRoot: Schema.optional(TrimmedNonEmptyString), defaultModelSelection: Schema.optional(Schema.NullOr(ModelSelection)), autoPull: Schema.optional(Schema.Boolean), projectIcon: Schema.optional(Schema.NullOr(ProjectIconOverride)), faviconPath: Schema.optional(Schema.NullOr(TrimmedNonEmptyString)), defaultThreadEnvMode: Schema.optional(Schema.NullOr(ThreadEnvMode)), scripts: Schema.optional(Schema.Array(ProjectScript)), }), Schema.Struct({ type: Schema.Literal("project.delete"), commandId: CommandId, projectId: ProjectId, force: Schema.optional(Schema.Boolean), }),]);export type ProjectMutation = typeof ProjectMutation.Type; export class ProjectMutationError extends Schema.TaggedErrorClass<ProjectMutationError>()( "ProjectMutationError", { commandId: CommandId, message: Schema.String, cause: Schema.optional(Schema.Defect()), },) {} export const ProjectEntryKind = Schema.Literals(["file", "directory"]);export type ProjectEntryKind = typeof ProjectEntryKind.Type; export const ProjectSearchEntriesInput = Schema.Struct({ cwd: TrimmedNonEmptyString, // An empty query is a bounded browse: the index returns frecency-ordered // entries, which the file picker uses for its initial results. query: TrimmedString.check(Schema.isMaxLength(256)), limit: PositiveInt.check(Schema.isLessThanOrEqualTo(PROJECT_SEARCH_ENTRIES_MAX_LIMIT)), kind: Schema.optional(ProjectEntryKind), imageOnly: Schema.optional(Schema.Boolean),});export type ProjectSearchEntriesInput = typeof ProjectSearchEntriesInput.Type; export const ProjectEntry = Schema.Struct({ path: TrimmedNonEmptyString, kind: ProjectEntryKind,});export type ProjectEntry = typeof ProjectEntry.Type; export const ProjectSearchEntriesResult = Schema.Struct({ entries: Schema.Array(ProjectEntry), truncated: Schema.Boolean,});export type ProjectSearchEntriesResult = typeof ProjectSearchEntriesResult.Type; export const ProjectSearchContentsInput = Schema.Struct({ cwd: TrimmedNonEmptyString, // Whitespace is significant in content queries (" foo", regex trailing // spaces), so the query is deliberately not trimmed on the wire. query: Schema.String.check(Schema.isNonEmpty(), Schema.isMaxLength(256)), limit: PositiveInt.check(Schema.isLessThanOrEqualTo(PROJECT_SEARCH_CONTENTS_MAX_LIMIT)), caseSensitive: Schema.Boolean, wholeWord: Schema.Boolean, useRegex: Schema.Boolean,});export type ProjectSearchContentsInput = typeof ProjectSearchContentsInput.Type; export const ProjectContentMatchRange = Schema.Struct({ start: NonNegativeInt, end: NonNegativeInt,});export type ProjectContentMatchRange = typeof ProjectContentMatchRange.Type; export const ProjectContentMatch = Schema.Struct({ path: TrimmedNonEmptyString, lineNumber: PositiveInt, lineContent: Schema.String, matchRanges: Schema.Array(ProjectContentMatchRange),});export type ProjectContentMatch = typeof ProjectContentMatch.Type; export const ProjectSearchContentsResult = Schema.Struct({ matches: Schema.Array(ProjectContentMatch), truncated: Schema.Boolean, regexFallbackError: Schema.optional(Schema.String),});export type ProjectSearchContentsResult = typeof ProjectSearchContentsResult.Type; export const ProjectListEntriesInput = Schema.Struct({ cwd: TrimmedNonEmptyString,});export type ProjectListEntriesInput = typeof ProjectListEntriesInput.Type; export const ProjectListEntriesResult = Schema.Struct({ entries: Schema.Array(ProjectEntry), truncated: Schema.Boolean,});export type ProjectListEntriesResult = typeof ProjectListEntriesResult.Type; export const ProjectEntriesFailure = Schema.Literals([ "workspace_root_not_found", "workspace_root_create_failed", "workspace_root_stat_failed", "workspace_root_not_directory", "search_index_create_failed", "search_index_scan_timed_out", "search_index_search_failed",]);export type ProjectEntriesFailure = typeof ProjectEntriesFailure.Type; type ProjectEntriesFailureContext = { readonly failure: ProjectEntriesFailure; readonly normalizedCwd?: string; readonly timeout?: string; readonly detail?: string; readonly cause?: unknown;}; function decodedProjectErrorMessage(props: object): string | undefined { if (!("message" in props)) return undefined; return typeof props.message === "string" ? props.message : undefined;} export class ProjectSearchEntriesError extends Schema.TaggedErrorClass<ProjectSearchEntriesError>()( "ProjectSearchEntriesError", { cwd: Schema.optional(TrimmedNonEmptyString), queryLength: Schema.optional(NonNegativeInt), limit: Schema.optional(PositiveInt), failure: Schema.optional(ProjectEntriesFailure), normalizedCwd: Schema.optional(TrimmedNonEmptyString), timeout: Schema.optional(TrimmedNonEmptyString), detail: Schema.optional(TrimmedNonEmptyString), message: TrimmedNonEmptyString, cause: Schema.optional(Schema.Defect()), },) { // The structured fields are optional on the wire so newer peers can decode legacy message-only // failures. New application code must provide them through this constructor. // @effect-diagnostics-next-line overriddenSchemaConstructor:off constructor( props: ProjectEntriesFailureContext & { readonly cwd: string; readonly queryLength: number; readonly limit: number; }, ) { super({ ...props, message: decodedProjectErrorMessage(props) ?? `Failed to search workspace entries in '${props.cwd}'.`, } as any); }} export class ProjectSearchContentsError extends Schema.TaggedErrorClass<ProjectSearchContentsError>()( "ProjectSearchContentsError", { cwd: Schema.optional(TrimmedNonEmptyString), queryLength: Schema.optional(NonNegativeInt), limit: Schema.optional(PositiveInt), failure: Schema.optional(ProjectEntriesFailure), normalizedCwd: Schema.optional(TrimmedNonEmptyString), timeout: Schema.optional(TrimmedNonEmptyString), detail: Schema.optional(TrimmedNonEmptyString), message: TrimmedNonEmptyString, cause: Schema.optional(Schema.Defect()), },) { // @effect-diagnostics-next-line overriddenSchemaConstructor:off constructor( props: ProjectEntriesFailureContext & { readonly cwd: string; readonly queryLength: number; readonly limit: number; }, ) { super({ ...props, message: decodedProjectErrorMessage(props) ?? `Failed to search workspace contents in '${props.cwd}'.`, } as any); }} export class ProjectListEntriesError extends Schema.TaggedErrorClass<ProjectListEntriesError>()( "ProjectListEntriesError", { cwd: Schema.optional(TrimmedNonEmptyString), failure: Schema.optional(ProjectEntriesFailure), normalizedCwd: Schema.optional(TrimmedNonEmptyString), timeout: Schema.optional(TrimmedNonEmptyString), detail: Schema.optional(TrimmedNonEmptyString), message: TrimmedNonEmptyString, cause: Schema.optional(Schema.Defect()), },) { // @effect-diagnostics-next-line overriddenSchemaConstructor:off constructor(props: ProjectEntriesFailureContext & { readonly cwd: string }) { super({ ...props, message: decodedProjectErrorMessage(props) ?? `Failed to list workspace entries in '${props.cwd}'.`, } as any); }} export const ProjectReadFileInput = Schema.Struct({ cwd: TrimmedNonEmptyString, // Workspace-relative, or an absolute host path for a file outside the // workspace. Only workspace-relative paths can be written back. relativePath: TrimmedNonEmptyString.check(Schema.isMaxLength(PROJECT_READ_FILE_PATH_MAX_LENGTH)),});export type ProjectReadFileInput = typeof ProjectReadFileInput.Type; export const ProjectReadFileResult = Schema.Struct({ relativePath: TrimmedNonEmptyString, contents: Schema.String, byteLength: NonNegativeInt, truncated: Schema.Boolean,});export type ProjectReadFileResult = typeof ProjectReadFileResult.Type; export const ProjectFileFailure = Schema.Literals([ "workspace_path_outside_root", "resolved_path_outside_root", "path_not_file", "binary_file", "operation_failed",]);export type ProjectFileFailure = typeof ProjectFileFailure.Type; export const ProjectFileOperation = Schema.Literals([ "realpath-workspace-root", "realpath-target", "open", "stat", "read", "close", "make-directory", "write-file",]);export type ProjectFileOperation = typeof ProjectFileOperation.Type; type ProjectFileFailureContext = { readonly cwd: string; readonly relativePath: string; readonly failure: ProjectFileFailure; readonly resolvedPath?: string; readonly resolvedWorkspaceRoot?: string; readonly operation?: ProjectFileOperation; readonly operationPath?: string; readonly cause?: unknown;}; export class ProjectReadFileError extends Schema.TaggedErrorClass<ProjectReadFileError>()( "ProjectReadFileError", { cwd: Schema.optional(TrimmedNonEmptyString), relativePath: Schema.optional(TrimmedNonEmptyString), failure: Schema.optional(ProjectFileFailure), resolvedPath: Schema.optional(TrimmedNonEmptyString), resolvedWorkspaceRoot: Schema.optional(TrimmedNonEmptyString), operation: Schema.optional(ProjectFileOperation), operationPath: Schema.optional(TrimmedNonEmptyString), message: TrimmedNonEmptyString, cause: Schema.optional(Schema.Defect()), },) { // @effect-diagnostics-next-line overriddenSchemaConstructor:off constructor(props: ProjectFileFailureContext) { super({ ...props, message: decodedProjectErrorMessage(props) ?? `Failed to read workspace file '${props.relativePath}' in '${props.cwd}'.`, } as any); }} export const ProjectWriteFileInput = Schema.Struct({ cwd: TrimmedNonEmptyString, relativePath: TrimmedNonEmptyString.check(Schema.isMaxLength(PROJECT_WRITE_FILE_PATH_MAX_LENGTH)), contents: Schema.String,});export type ProjectWriteFileInput = typeof ProjectWriteFileInput.Type; export const ProjectWriteFileResult = Schema.Struct({ relativePath: TrimmedNonEmptyString,});export type ProjectWriteFileResult = typeof ProjectWriteFileResult.Type; export class ProjectWriteFileError extends Schema.TaggedErrorClass<ProjectWriteFileError>()( "ProjectWriteFileError", { cwd: Schema.optional(TrimmedNonEmptyString), relativePath: Schema.optional(TrimmedNonEmptyString), failure: Schema.optional(ProjectFileFailure), resolvedPath: Schema.optional(TrimmedNonEmptyString), resolvedWorkspaceRoot: Schema.optional(TrimmedNonEmptyString), operation: Schema.optional(ProjectFileOperation), operationPath: Schema.optional(TrimmedNonEmptyString), message: TrimmedNonEmptyString, cause: Schema.optional(Schema.Defect()), },) { // @effect-diagnostics-next-line overriddenSchemaConstructor:off constructor(props: ProjectFileFailureContext) { super({ ...props, message: decodedProjectErrorMessage(props) ?? `Failed to write workspace file '${props.relativePath}' in '${props.cwd}'.`, } as any); }}
import * as Schema from "effect/Schema";
import { RepositoryIdentity, ThreadEnvMode } from "./environment.ts";
import { ModelSelection } from "./modelSelection.ts";
import {
CommandId,
IsoDateTime,
NonNegativeInt,
PositiveInt,
ProjectId,
TrimmedNonEmptyString,
TrimmedString,
} from "./baseSchemas.ts";
const PROJECT_SEARCH_ENTRIES_MAX_LIMIT = 200;
const PROJECT_SEARCH_CONTENTS_MAX_LIMIT = 500;
const PROJECT_WRITE_FILE_PATH_MAX_LENGTH = 512;
const PROJECT_READ_FILE_PATH_MAX_LENGTH = 512;
export const ProjectScriptIcon = Schema.Literals([
"play",
"test",
"lint",
"configure",
"build",
"debug",
]);
export type ProjectScriptIcon = typeof ProjectScriptIcon.Type;
export const ProjectScript = Schema.Struct({
id: TrimmedNonEmptyString,
name: TrimmedNonEmptyString,
command: TrimmedNonEmptyString,
icon: ProjectScriptIcon,
runOnWorktreeCreate: Schema.Boolean,
previewUrl: Schema.optional(TrimmedNonEmptyString),
autoOpenPreview: Schema.optional(Schema.Boolean),
});
export type ProjectScript = typeof ProjectScript.Type;
export const ProjectIconColor = Schema.Literals([
"gray",
"red",
"orange",
"amber",
"yellow",
"lime",
"green",
"emerald",
"teal",
"cyan",
"sky",
"blue",
"indigo",
"violet",
"purple",
"fuchsia",
"pink",
"rose",
]);
export type ProjectIconColor = typeof ProjectIconColor.Type;
const ProjectLucideIconName = TrimmedNonEmptyString.check(
Schema.isMaxLength(64),
Schema.isPattern(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
);
const ProjectEmoji = TrimmedNonEmptyString.check(Schema.isMaxLength(32));
export const ProjectIconOverride = Schema.Union([
Schema.Struct({
kind: Schema.Literal("lucide"),
name: ProjectLucideIconName,
color: ProjectIconColor,
}),
Schema.Struct({
kind: Schema.Literal("emoji"),
emoji: ProjectEmoji,
}),
]);
export type ProjectIconOverride = typeof ProjectIconOverride.Type;
export const Project = Schema.Struct({
id: ProjectId,
title: TrimmedNonEmptyString,
workspaceRoot: TrimmedNonEmptyString,
repositoryIdentity: Schema.optional(Schema.NullOr(RepositoryIdentity)),
faviconPath: Schema.optional(Schema.NullOr(TrimmedNonEmptyString)),
projectIcon: Schema.optional(Schema.NullOr(ProjectIconOverride)),
defaultModelSelection: Schema.NullOr(ModelSelection),
defaultThreadEnvMode: Schema.optional(Schema.NullOr(ThreadEnvMode)),
// Opt-in because background sync performs network I/O and may move the checkout.
autoPull: Schema.optional(Schema.Boolean),
scripts: Schema.Array(ProjectScript),
createdAt: IsoDateTime,
updatedAt: IsoDateTime,
deletedAt: Schema.NullOr(IsoDateTime),
});
export type Project = typeof Project.Type;
export const ProjectSnapshot = Schema.Struct({
projects: Schema.Array(Project),
updatedAt: IsoDateTime,
});
export type ProjectSnapshot = typeof ProjectSnapshot.Type;
export const ProjectChange = Schema.Union([
Schema.Struct({ type: Schema.Literal("project.upserted"), project: Project }),
Schema.Struct({
type: Schema.Literal("project.deleted"),
projectId: ProjectId,
deletedAt: IsoDateTime,
}),
]);
export type ProjectChange = typeof ProjectChange.Type;
export const ProjectMutation = Schema.Union([
Schema.Struct({
type: Schema.Literal("project.create"),
commandId: CommandId,
projectId: ProjectId,
title: TrimmedNonEmptyString,
workspaceRoot: TrimmedNonEmptyString,
createWorkspaceRootIfMissing: Schema.optional(Schema.Boolean),
defaultModelSelection: Schema.optional(Schema.NullOr(ModelSelection)),
scripts: Schema.optional(Schema.Array(ProjectScript)),
}),
Schema.Struct({
type: Schema.Literal("project.update"),
commandId: CommandId,
projectId: ProjectId,
title: Schema.optional(TrimmedNonEmptyString),
workspaceRoot: Schema.optional(TrimmedNonEmptyString),
defaultModelSelection: Schema.optional(Schema.NullOr(ModelSelection)),
autoPull: Schema.optional(Schema.Boolean),
projectIcon: Schema.optional(Schema.NullOr(ProjectIconOverride)),
faviconPath: Schema.optional(Schema.NullOr(TrimmedNonEmptyString)),
defaultThreadEnvMode: Schema.optional(Schema.NullOr(ThreadEnvMode)),
scripts: Schema.optional(Schema.Array(ProjectScript)),
}),
Schema.Struct({
type: Schema.Literal("project.delete"),
commandId: CommandId,
projectId: ProjectId,
force: Schema.optional(Schema.Boolean),
}),
]);
export type ProjectMutation = typeof ProjectMutation.Type;
export class ProjectMutationError extends Schema.TaggedErrorClass<ProjectMutationError>()(
"ProjectMutationError",
{
commandId: CommandId,
message: Schema.String,
cause: Schema.optional(Schema.Defect()),
},
) {}
export const ProjectEntryKind = Schema.Literals(["file", "directory"]);
export type ProjectEntryKind = typeof ProjectEntryKind.Type;
export const ProjectSearchEntriesInput = Schema.Struct({
cwd: TrimmedNonEmptyString,
// An empty query is a bounded browse: the index returns frecency-ordered
// entries, which the file picker uses for its initial results.
query: TrimmedString.check(Schema.isMaxLength(256)),
limit: PositiveInt.check(Schema.isLessThanOrEqualTo(PROJECT_SEARCH_ENTRIES_MAX_LIMIT)),
kind: Schema.optional(ProjectEntryKind),
imageOnly: Schema.optional(Schema.Boolean),
});
export type ProjectSearchEntriesInput = typeof ProjectSearchEntriesInput.Type;
export const ProjectEntry = Schema.Struct({
path: TrimmedNonEmptyString,
kind: ProjectEntryKind,
});
export type ProjectEntry = typeof ProjectEntry.Type;
export const ProjectSearchEntriesResult = Schema.Struct({
entries: Schema.Array(ProjectEntry),
truncated: Schema.Boolean,
});
export type ProjectSearchEntriesResult = typeof ProjectSearchEntriesResult.Type;
export const ProjectSearchContentsInput = Schema.Struct({
cwd: TrimmedNonEmptyString,
// Whitespace is significant in content queries (" foo", regex trailing
// spaces), so the query is deliberately not trimmed on the wire.
query: Schema.String.check(Schema.isNonEmpty(), Schema.isMaxLength(256)),
limit: PositiveInt.check(Schema.isLessThanOrEqualTo(PROJECT_SEARCH_CONTENTS_MAX_LIMIT)),
caseSensitive: Schema.Boolean,
wholeWord: Schema.Boolean,
useRegex: Schema.Boolean,
});
export type ProjectSearchContentsInput = typeof ProjectSearchContentsInput.Type;
export const ProjectContentMatchRange = Schema.Struct({
start: NonNegativeInt,
end: NonNegativeInt,
});
export type ProjectContentMatchRange = typeof ProjectContentMatchRange.Type;
export const ProjectContentMatch = Schema.Struct({
path: TrimmedNonEmptyString,
lineNumber: PositiveInt,
lineContent: Schema.String,
matchRanges: Schema.Array(ProjectContentMatchRange),
});
export type ProjectContentMatch = typeof ProjectContentMatch.Type;
export const ProjectSearchContentsResult = Schema.Struct({
matches: Schema.Array(ProjectContentMatch),
truncated: Schema.Boolean,
regexFallbackError: Schema.optional(Schema.String),
});
export type ProjectSearchContentsResult = typeof ProjectSearchContentsResult.Type;
export const ProjectListEntriesInput = Schema.Struct({
cwd: TrimmedNonEmptyString,
});
export type ProjectListEntriesInput = typeof ProjectListEntriesInput.Type;
export const ProjectListEntriesResult = Schema.Struct({
entries: Schema.Array(ProjectEntry),
truncated: Schema.Boolean,
});
export type ProjectListEntriesResult = typeof ProjectListEntriesResult.Type;
export const ProjectEntriesFailure = Schema.Literals([
"workspace_root_not_found",
"workspace_root_create_failed",
"workspace_root_stat_failed",
"workspace_root_not_directory",
"search_index_create_failed",
"search_index_scan_timed_out",
"search_index_search_failed",
]);
export type ProjectEntriesFailure = typeof ProjectEntriesFailure.Type;
type ProjectEntriesFailureContext = {
readonly failure: ProjectEntriesFailure;
readonly normalizedCwd?: string;
readonly timeout?: string;
readonly detail?: string;
readonly cause?: unknown;
};
function decodedProjectErrorMessage(props: object): string | undefined {
if (!("message" in props)) return undefined;
return typeof props.message === "string" ? props.message : undefined;
}
export class ProjectSearchEntriesError extends Schema.TaggedErrorClass<ProjectSearchEntriesError>()(
"ProjectSearchEntriesError",
{
cwd: Schema.optional(TrimmedNonEmptyString),
queryLength: Schema.optional(NonNegativeInt),
limit: Schema.optional(PositiveInt),
failure: Schema.optional(ProjectEntriesFailure),
normalizedCwd: Schema.optional(TrimmedNonEmptyString),
timeout: Schema.optional(TrimmedNonEmptyString),
detail: Schema.optional(TrimmedNonEmptyString),
message: TrimmedNonEmptyString,
cause: Schema.optional(Schema.Defect()),
},
) {
// The structured fields are optional on the wire so newer peers can decode legacy message-only
// failures. New application code must provide them through this constructor.
// @effect-diagnostics-next-line overriddenSchemaConstructor:off
constructor(
props: ProjectEntriesFailureContext & {
readonly cwd: string;
readonly queryLength: number;
readonly limit: number;
},
) {
super({
...props,
message:
decodedProjectErrorMessage(props) ??
`Failed to search workspace entries in '${props.cwd}'.`,
} as any);
}
}
export class ProjectSearchContentsError extends Schema.TaggedErrorClass<ProjectSearchContentsError>()(
"ProjectSearchContentsError",
{
cwd: Schema.optional(TrimmedNonEmptyString),
queryLength: Schema.optional(NonNegativeInt),
limit: Schema.optional(PositiveInt),
failure: Schema.optional(ProjectEntriesFailure),
normalizedCwd: Schema.optional(TrimmedNonEmptyString),
timeout: Schema.optional(TrimmedNonEmptyString),
detail: Schema.optional(TrimmedNonEmptyString),
message: TrimmedNonEmptyString,
cause: Schema.optional(Schema.Defect()),
},
) {
// @effect-diagnostics-next-line overriddenSchemaConstructor:off
constructor(
props: ProjectEntriesFailureContext & {
readonly cwd: string;
readonly queryLength: number;
readonly limit: number;
},
) {
super({
...props,
message:
decodedProjectErrorMessage(props) ??
`Failed to search workspace contents in '${props.cwd}'.`,
} as any);
}
}
export class ProjectListEntriesError extends Schema.TaggedErrorClass<ProjectListEntriesError>()(
"ProjectListEntriesError",
{
cwd: Schema.optional(TrimmedNonEmptyString),
failure: Schema.optional(ProjectEntriesFailure),
normalizedCwd: Schema.optional(TrimmedNonEmptyString),
timeout: Schema.optional(TrimmedNonEmptyString),
detail: Schema.optional(TrimmedNonEmptyString),
message: TrimmedNonEmptyString,
cause: Schema.optional(Schema.Defect()),
},
) {
// @effect-diagnostics-next-line overriddenSchemaConstructor:off
constructor(props: ProjectEntriesFailureContext & { readonly cwd: string }) {
super({
...props,
message:
decodedProjectErrorMessage(props) ?? `Failed to list workspace entries in '${props.cwd}'.`,
} as any);
}
}
export const ProjectReadFileInput = Schema.Struct({
cwd: TrimmedNonEmptyString,
// Workspace-relative, or an absolute host path for a file outside the
// workspace. Only workspace-relative paths can be written back.
relativePath: TrimmedNonEmptyString.check(Schema.isMaxLength(PROJECT_READ_FILE_PATH_MAX_LENGTH)),
});
export type ProjectReadFileInput = typeof ProjectReadFileInput.Type;
export const ProjectReadFileResult = Schema.Struct({
relativePath: TrimmedNonEmptyString,
contents: Schema.String,
byteLength: NonNegativeInt,
truncated: Schema.Boolean,
});
export type ProjectReadFileResult = typeof ProjectReadFileResult.Type;
export const ProjectFileFailure = Schema.Literals([
"workspace_path_outside_root",
"resolved_path_outside_root",
"path_not_file",
"binary_file",
"operation_failed",
]);
export type ProjectFileFailure = typeof ProjectFileFailure.Type;
export const ProjectFileOperation = Schema.Literals([
"realpath-workspace-root",
"realpath-target",
"open",
"stat",
"read",
"close",
"make-directory",
"write-file",
]);
export type ProjectFileOperation = typeof ProjectFileOperation.Type;
type ProjectFileFailureContext = {
readonly cwd: string;
readonly relativePath: string;
readonly failure: ProjectFileFailure;
readonly resolvedPath?: string;
readonly resolvedWorkspaceRoot?: string;
readonly operation?: ProjectFileOperation;
readonly operationPath?: string;
readonly cause?: unknown;
};
export class ProjectReadFileError extends Schema.TaggedErrorClass<ProjectReadFileError>()(
"ProjectReadFileError",
{
cwd: Schema.optional(TrimmedNonEmptyString),
relativePath: Schema.optional(TrimmedNonEmptyString),
failure: Schema.optional(ProjectFileFailure),
resolvedPath: Schema.optional(TrimmedNonEmptyString),
resolvedWorkspaceRoot: Schema.optional(TrimmedNonEmptyString),
operation: Schema.optional(ProjectFileOperation),
operationPath: Schema.optional(TrimmedNonEmptyString),
message: TrimmedNonEmptyString,
cause: Schema.optional(Schema.Defect()),
},
) {
// @effect-diagnostics-next-line overriddenSchemaConstructor:off
constructor(props: ProjectFileFailureContext) {
super({
...props,
message:
decodedProjectErrorMessage(props) ??
`Failed to read workspace file '${props.relativePath}' in '${props.cwd}'.`,
} as any);
}
}
export const ProjectWriteFileInput = Schema.Struct({
cwd: TrimmedNonEmptyString,
relativePath: TrimmedNonEmptyString.check(Schema.isMaxLength(PROJECT_WRITE_FILE_PATH_MAX_LENGTH)),
contents: Schema.String,
});
export type ProjectWriteFileInput = typeof ProjectWriteFileInput.Type;
export const ProjectWriteFileResult = Schema.Struct({
relativePath: TrimmedNonEmptyString,
});
export type ProjectWriteFileResult = typeof ProjectWriteFileResult.Type;
export class ProjectWriteFileError extends Schema.TaggedErrorClass<ProjectWriteFileError>()(
"ProjectWriteFileError",
{
cwd: Schema.optional(TrimmedNonEmptyString),
relativePath: Schema.optional(TrimmedNonEmptyString),
failure: Schema.optional(ProjectFileFailure),
resolvedPath: Schema.optional(TrimmedNonEmptyString),
resolvedWorkspaceRoot: Schema.optional(TrimmedNonEmptyString),
operation: Schema.optional(ProjectFileOperation),
operationPath: Schema.optional(TrimmedNonEmptyString),
message: TrimmedNonEmptyString,
cause: Schema.optional(Schema.Defect()),
},
) {
// @effect-diagnostics-next-line overriddenSchemaConstructor:off
constructor(props: ProjectFileFailureContext) {
super({
...props,
message:
decodedProjectErrorMessage(props) ??
`Failed to write workspace file '${props.relativePath}' in '${props.cwd}'.`,
} as any);
}
}