import * as Schema from "effect/Schema";import { NonNegativeInt, PositiveInt, 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 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, 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 {
NonNegativeInt,
PositiveInt,
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 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,
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);
}
}