feat: migrate workspace worker and companion domains to ServerApi

This commit is contained in:
2026-09-23 10:00:56 +09:00
parent ad12d77ad4
commit 89024d3b01
28 changed files with 7471 additions and 819 deletions
@@ -1,30 +1,36 @@
// Generated by `cargo run -p server-api --features typescript --example generate_companion_api_types`.
// Do not edit manually.
// @generated by yoi-companion-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:550383b600fe2a2e55630849c7de7a6a24463ad41d0c18dc5d254a3d14328f07)
// Options: companion-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
// Output: web/workspace/src/lib/generated/companion-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_companion_api_types -- --check
export type DiagnosticSeverity = "info" | "warning" | "error";
export type Diagnostic = { code: string, severity: DiagnosticSeverity, message: string, };
export type WorkspaceWorkerSubject = { "kind": "runtime_worker", runtime_id: string, worker_id: string, };
export type WorkspaceWorkerDiscoveryItem = { subject: WorkspaceWorkerSubject, resource_key: string, display_name: string, profile: string | null, status?: string | null, };
export type CompanionCancelRequest = { reason?: string | null; };
export type CompanionLifecycleState = "idle" | "running" | "stopped";
export type CompanionMessageDisposition = "accepted" | "rejected";
export type CompanionTransportSummary = { mode: string, available: boolean, };
export type CompanionMessageRequest = { content: string; };
export type CompanionStatusResponse = { state: CompanionLifecycleState, worker: WorkspaceWorkerDiscoveryItem | null, transport: CompanionTransportSummary, diagnostics: Array<Diagnostic>, };
export type CompanionMessageResponse = { message: string; state: CompanionMessageDisposition; };
export type CompanionMessageRequest = { content: string, };
export type CompanionStatusResponse = { diagnostics?: Array<Diagnostic>; state: CompanionLifecycleState; transport: CompanionTransportSummary; worker?: WorkspaceWorkerDiscoveryItem | null; };
export type CompanionCancelRequest = { reason?: string | null, };
export type CompanionTranscriptItem = { content: string; created_at: string; role: CompanionTranscriptRole; sequence: number; };
export type CompanionMessageResponse = { state: CompanionMessageDisposition, message: string, };
export type CompanionTranscriptProjection = { items: Array<CompanionTranscriptItem>; limit: number; next?: number | null; start: number; state: CompanionLifecycleState; total: number; };
export type CompanionTranscriptRole = "user" | "assistant";
export type CompanionTranscriptItem = { sequence: number, role: CompanionTranscriptRole, content: string, created_at: string, };
export type CompanionTransportSummary = { available: boolean; mode: string; };
export type CompanionTranscriptProjection = { state: CompanionLifecycleState, start: number, limit: number, total: number, next: number | null, items: Array<CompanionTranscriptItem>, };
export type Diagnostic = { code: string; message: string; severity: DiagnosticSeverity; };
export type DiagnosticSeverity = "info" | "warning" | "error";
export type RepositoryApiError = { diagnostics?: Array<Diagnostic>; error: string; message: string; };
export type WorkspaceWorkerDiscoveryItem = { display_name: string; profile?: string | null; resource_key: string; status?: string | null; subject: WorkspaceWorkerSubject; };
export type WorkspaceWorkerSubject = { kind: "runtime_worker"; runtime_id: string; worker_id: string; };
@@ -1,6 +1,6 @@
// @generated by yoi-repository-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:67e56d1ffd3b27bc8653ef791bd68b5150ac7d507ccbe4e65b2e00320834d718)
// Input contract: 0.1.0 (sha256:550383b600fe2a2e55630849c7de7a6a24463ad41d0c18dc5d254a3d14328f07)
// Options: repository-operation-schema-closure,openapi-3.1,format:uint64=safe-number,strict-safe-integers,sorted-output
// Output: web/workspace/src/lib/generated/repository-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_repository_openapi_types -- --check
@@ -55,11 +55,21 @@ export type RepositorySshHostTrust = { created_at: string; current_revision: num
export type RepositorySummary = { default_selector?: string | null; diagnostics?: Array<RepositoryDiagnostic> | null; git?: GitRepositorySummary | null; kind: string; observed_at?: string | null; observed_status: RepositoryObservedStatus; provider: string; record_authority: string; repository_key: string; source: RepositorySource; source_fingerprint: string; source_revision: number; };
export type WorkerBusyState = { kind: "run"; state: WorkerRunState; } | { kind: "maintenance"; state: WorkerMaintenanceState; };
export type WorkerCapabilitySummary = { can_spawn_followup: boolean; can_stop: boolean; };
export type WorkerImplementationSummary = { display_hint: string; kind: string; };
export type WorkerSummary = { capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: unknown; workspace: WorkerWorkspaceSummary; };
export type WorkerMaintenanceState = "compacting";
export type WorkerRunState = "running" | "pausing" | "paused" | "cancelling";
export type WorkerState = { kind: "idle"; } | { kind: "busy"; state: WorkerBusyState; };
export type WorkerStateSnapshot = { last_command_id: number; state: WorkerState; };
export type WorkerSummary = { capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: WorkerStateSnapshot | null; workspace: WorkerWorkspaceSummary; };
export type WorkerWorkdirAttachmentSummary = { alias: string; working_directory: WorkingDirectorySummary; };
+14 -4
View File
@@ -1,6 +1,6 @@
// @generated by yoi-runtime-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:67e56d1ffd3b27bc8653ef791bd68b5150ac7d507ccbe4e65b2e00320834d718)
// Input contract: 0.1.0 (sha256:550383b600fe2a2e55630849c7de7a6a24463ad41d0c18dc5d254a3d14328f07)
// Options: runtime-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
// Output: web/workspace/src/lib/generated/runtime-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_runtime_api_types -- --check
@@ -105,11 +105,11 @@ export type RuntimeWorkerLifecycleResult = { diagnostics?: Array<Diagnostic>; ru
export type RuntimeWorkerListResponse = { diagnostics?: Array<Diagnostic>; items: Array<WorkerSummary>; limit: number; source: string; workspace_id: string; };
export type RuntimeWorkerShowResponse = { capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; updated_at: string; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: unknown; workspace: WorkerWorkspaceSummary; };
export type RuntimeWorkerShowResponse = { capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; updated_at: string; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: WorkerStateSnapshot | null; workspace: WorkerWorkspaceSummary; };
export type RuntimeWorkerSpawnAcceptanceEvidence = { detail: string; kind: string; };
export type RuntimeWorkerSpawnAcceptanceRequirement = "socket_ready" | { run_accepted: { expected_segments: number; }; };
export type RuntimeWorkerSpawnAcceptanceRequirement = { kind: "socket_ready"; } | { expected_segments: number; kind: "run_accepted"; };
export type RuntimeWorkerSpawnIntent = { kind: "workspace_companion"; } | { kind: "workspace_orchestrator"; } | { kind: "workspace_coding"; } | { kind: "ticket_role"; role: RuntimeTicketWorkerRole; ticket_id: string; };
@@ -127,12 +127,16 @@ export type RuntimeWorkerTicketAssignmentRequest = { operation_id: string; ticke
export type UpdateRemoteRuntimeRequest = { display_name?: string | null; endpoint: string; };
export type WorkerBusyState = { kind: "run"; state: WorkerRunState; } | { kind: "maintenance"; state: WorkerMaintenanceState; };
export type WorkerCapabilitySummary = { can_spawn_followup: boolean; can_stop: boolean; };
export type WorkerFileDeleteResponse = { deleted: boolean; };
export type WorkerImplementationSummary = { display_hint: string; kind: string; };
export type WorkerMaintenanceState = "compacting";
export type WorkerOperationState = "accepted" | "unsupported" | "rejected";
export type WorkerRestoreResponse = { result: WorkerRestoreResult; runtime_id: string; worker_id: string; workspace_id: string; };
@@ -143,7 +147,13 @@ export type WorkerRestoreState = "accepted" | "rejected" | "rolled_back" | "reco
export type WorkerRetentionResponse = { pinned: boolean; retention_state: string; runtime_id: string; worker_id: string; workspace_id: string; };
export type WorkerSummary = { capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: unknown; workspace: WorkerWorkspaceSummary; };
export type WorkerRunState = "running" | "pausing" | "paused" | "cancelling";
export type WorkerState = { kind: "idle"; } | { kind: "busy"; state: WorkerBusyState; };
export type WorkerStateSnapshot = { last_command_id: number; state: WorkerState; };
export type WorkerSummary = { capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: WorkerStateSnapshot | null; workspace: WorkerWorkspaceSummary; };
export type WorkerWorkdirAttachmentSummary = { alias: string; working_directory: WorkingDirectorySummary; };
@@ -1,6 +1,6 @@
// @generated by yoi-workdir-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:67e56d1ffd3b27bc8653ef791bd68b5150ac7d507ccbe4e65b2e00320834d718)
// Input contract: 0.1.0 (sha256:550383b600fe2a2e55630849c7de7a6a24463ad41d0c18dc5d254a3d14328f07)
// Options: workdir-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
// Output: web/workspace/src/lib/generated/workdir-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_workdir_api_types -- --check
@@ -1,68 +1,84 @@
// Generated from server-api. Do not edit by hand.
// Regenerate: cargo run -q -p server-api --features typescript --example generate_worker_launch_api_types > web/workspace/src/lib/generated/worker-launch-api.ts
// @generated by yoi-worker-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:550383b600fe2a2e55630849c7de7a6a24463ad41d0c18dc5d254a3d14328f07)
// Options: worker-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
// Output: web/workspace/src/lib/generated/worker-launch-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_worker_launch_api_types -- --check
import type { Segment } from "./protocol";
export type BrowserCreateWorkerResponse = { console_href: string; diagnostics: Array<Diagnostic>; runtime_id: string; worker: WorkerLaunchWorkerSummary; worker_id: string; workspace_id: string; };
export type BrowserWorkerWorkingDirectorySelection = { alias: string; relative_cwd?: string | null; working_directory_id: string; };
export type BrowserWorkspaceOrchestratorResponse = { diagnostics: Array<Diagnostic>; disposition: string; online: boolean; worker?: WorkerLaunchWorkerSummary | null; workspace_id: string; };
export type CreateWorkspaceWorkerRequest = { control_operation_id?: string | null; display_name: string; initial_submit?: Array<Segment>; profile?: string | null; runtime_id: string; ticket_assignment?: CreateWorkspaceWorkerTicketAssignmentRequest | null; workdir_attachments?: Array<BrowserWorkerWorkingDirectorySelection>; };
export type CreateWorkspaceWorkerTicketAssignmentRequest = { operation_id: string; ticket_id: string; };
export type Diagnostic = { code: string; message: string; severity: DiagnosticSeverity; };
export type DiagnosticSeverity = "info" | "warning" | "error";
export type Diagnostic = { code: string, severity: DiagnosticSeverity, message: string, };
export type PasteArtifactAvailability = "available" | "unavailable" | "integrity_failed";
export type PasteArtifactMediaType = "text_plain_utf8";
export type PasteArtifactRef = { artifact_id: string; availability: PasteArtifactAvailability; byte_len: number; char_count: number; created_at_ms: number; line_count: number; media_type: PasteArtifactMediaType; sha256: string; source_entry_id: string; };
export type RepositoryApiError = { diagnostics?: Array<Diagnostic>; error: string; message: string; };
export type RuntimeWorkerWorkdirAttachmentSummary = { alias: string; working_directory: RuntimeWorkingDirectorySummary; };
export type RuntimeWorkingDirectoryCleanupTarget = { kind: string; repository_id: string; working_directory_id: string; };
export type RuntimeWorkingDirectorySummary = { cleanliness?: string | null; cleanup_target?: RuntimeWorkingDirectoryCleanupTarget | null; creation_ref?: string | null; creation_selector?: string | null; creation_tree?: string | null; current_ref?: string | null; current_selector?: string | null; current_tree?: string | null; display_name?: string | null; materializer_kind: WorkingDirectoryMaterializerKind; observed_at_epoch_seconds?: number | null; occupied_by?: WorkingDirectoryOccupancy | null; repository_id: string; status: WorkingDirectoryStatusKind; working_directory_id: string; };
export type Segment = { content: string; kind: "text"; } | { chars: number; content: string; id: number; kind: "paste"; lines: number; } | { artifact: PasteArtifactRef; kind: "paste_artifact"; } | { file: UploadedFileRef; kind: "uploaded_file"; } | { kind: "file_ref"; path: string; } | { kind: "flow"; selector: string; } | { kind: "unknown"; };
export type UploadedFileAvailability = "available" | "unavailable" | "integrity_failed";
export type UploadedFileRef = { artifact_id: string; availability: UploadedFileAvailability; byte_len: number; created_at_ms: number; file_name: string; media_type: string; sha256: string; source_entry_id?: string | null; };
export type WorkerBusyState = { kind: "run"; state: WorkerRunState; } | { kind: "maintenance"; state: WorkerMaintenanceState; };
export type WorkerCapabilitySummary = { can_spawn_followup: boolean; can_stop: boolean; };
export type WorkerImplementationSummary = { display_hint: string; kind: string; };
export type WorkerLaunchOptionsResponse = { default_profile?: string | null; diagnostics: Array<Diagnostic>; profiles: Array<WorkerLaunchProfileCandidate>; repositories: Array<WorkingDirectoryRepositoryOption>; runtimes: Array<WorkerLaunchRuntimeOption>; working_directories: Array<WorkingDirectorySummary>; workspace_id: string; };
export type WorkerLaunchProfileCandidate = { description: string; id: string; label: string; };
export type WorkerLaunchRuntimeOption = { built_in: boolean; diagnostics: Array<Diagnostic>; display_name: string; runtime_id: string; status: string; worker_creation_available: boolean; working_directory_required: boolean; };
export type WorkerLaunchWorkerSummary = { capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned: boolean; profile?: string | null; retention_state: string; runtime_id: string; singleton_key?: string | null; state: string; tags: Array<string>; workdir_attachments?: Array<RuntimeWorkerWorkdirAttachmentSummary>; worker_id: string; workspace: WorkerWorkspaceSummary; };
export type WorkerListResponse = { diagnostics?: Array<Diagnostic>; items: Array<WorkerSummary>; limit: number; source: string; workspace_id: string; };
export type WorkerMaintenanceState = "compacting";
export type WorkerRunState = "running" | "pausing" | "paused" | "cancelling";
export type WorkerState = { kind: "idle"; } | { kind: "busy"; state: WorkerBusyState; };
export type WorkerStateSnapshot = { last_command_id: number; state: WorkerState; };
export type WorkerSummary = { capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: WorkerStateSnapshot | null; workspace: WorkerWorkspaceSummary; };
export type WorkerWorkdirAttachmentSummary = { alias: string; working_directory: WorkingDirectorySummary; };
export type WorkerWorkspaceSummary = { identity: string; visibility: string; workspace_id?: string | null; };
export type WorkingDirectoryCleanupTarget = { kind: string; repository_key: string; working_directory_id: string; };
export type WorkingDirectoryMaterializerKind = "runtime_git_clone" | "client_hosted_external";
export type WorkingDirectoryOccupancy = { display_name: string; linked_at: string; runtime_id: string; worker_id: string; };
export type WorkingDirectoryRepositoryOption = { default_selector?: string | null; repository_key: string; };
export type WorkingDirectorySource = { kind: "repository"; repository_key: string; } | { grant_id: string; kind: "external_grant"; };
export type WorkingDirectoryStatusKind = "active" | "cleanup_pending" | "corrupted" | "not_found" | "unknown";
export type WorkingDirectoryCleanupTarget = { kind: string, working_directory_id: string, repository_key: string, };
export type RuntimeWorkingDirectoryCleanupTarget = { kind: string, working_directory_id: string, repository_id: string, };
export type RuntimeWorkingDirectorySummary = { working_directory_id: string,
/**
* Optional human-facing label, never a routing key.
*/
display_name?: string | null, repository_id: string, creation_selector?: string | null, creation_ref?: string | null, creation_tree?: string | null, current_selector?: string | null, current_ref?: string | null, current_tree?: string | null, observed_at_epoch_seconds?: number | null, materializer_kind: WorkingDirectoryMaterializerKind, cleanup_target?: RuntimeWorkingDirectoryCleanupTarget | null, status: WorkingDirectoryStatusKind, cleanliness?: string | null, occupied_by?: WorkingDirectoryOccupancy | null, };
export type WorkingDirectoryOccupancy = { runtime_id: string, worker_id: string, display_name: string, linked_at: string, };
export type WorkingDirectorySource = { "kind": "repository", repository_key: string, } | { "kind": "external_grant", grant_id: string, };
export type WorkingDirectorySummary = { working_directory_id: string,
/**
* Optional human-facing label, never a routing key.
*/
display_name?: string | null, source: WorkingDirectorySource, creation_selector?: string | null, creation_ref?: string | null, creation_tree?: string | null, current_selector?: string | null, current_ref?: string | null, current_tree?: string | null, observed_at_epoch_seconds?: number | null, materializer_kind: WorkingDirectoryMaterializerKind, cleanup_target?: WorkingDirectoryCleanupTarget | null, status: WorkingDirectoryStatusKind, cleanliness?: string | null, occupied_by?: WorkingDirectoryOccupancy | null, };
export type WorkerWorkspaceSummary = { visibility: string, identity: string, workspace_id?: string | null, };
export type WorkerImplementationSummary = { kind: string, display_hint: string, };
export type WorkerCapabilitySummary = { can_stop: boolean, can_spawn_followup: boolean, };
export type RuntimeWorkerWorkdirAttachmentSummary = { alias: string, working_directory: RuntimeWorkingDirectorySummary, };
export type WorkerLaunchWorkerSummary = { runtime_id: string, worker_id: string, host_id: string, display_name: string, label: string, profile: string | null, singleton_key: string | null, tags: Array<string>, workspace: WorkerWorkspaceSummary, state: string, last_seen_at: string | null, pinned: boolean, retention_state: string, implementation: WorkerImplementationSummary, capabilities: WorkerCapabilitySummary, workdir_attachments?: Array<RuntimeWorkerWorkdirAttachmentSummary>, diagnostics: Array<Diagnostic>, };
export type WorkerLaunchRuntimeOption = { runtime_id: string, display_name: string, built_in: boolean, worker_creation_available: boolean, working_directory_required: boolean, status: string, diagnostics: Array<Diagnostic>, };
export type WorkerLaunchProfileCandidate = { id: string, label: string, description: string, };
export type WorkingDirectoryRepositoryOption = { repository_key: string, default_selector?: string | null, };
export type WorkerLaunchOptionsResponse = { workspace_id: string, runtimes: Array<WorkerLaunchRuntimeOption>, default_profile: string | null, profiles: Array<WorkerLaunchProfileCandidate>, repositories: Array<WorkingDirectoryRepositoryOption>, working_directories: Array<WorkingDirectorySummary>, diagnostics: Array<Diagnostic>, };
export type BrowserWorkerWorkingDirectorySelection = {
/**
* Stable Worker-local routing alias.
*/
alias: string, working_directory_id: string, relative_cwd: string | null, };
export type CreateWorkspaceWorkerTicketAssignmentRequest = { ticket_id: string, operation_id: string, };
export type CreateWorkspaceWorkerRequest = { runtime_id: string, display_name: string, profile: string | null, ticket_assignment: CreateWorkspaceWorkerTicketAssignmentRequest | null, initial_submit: Array<Segment>, workdir_attachments: Array<BrowserWorkerWorkingDirectorySelection>,
/**
* Backend idempotency key used only for authenticated Worker-owned spawn/control.
*/
control_operation_id: string | null, };
export type BrowserCreateWorkerResponse = { workspace_id: string, runtime_id: string, worker_id: string, console_href: string, worker: WorkerLaunchWorkerSummary, diagnostics: Array<Diagnostic>, };
export type BrowserWorkspaceOrchestratorResponse = { workspace_id: string, online: boolean, disposition: string, worker?: WorkerLaunchWorkerSummary | null, diagnostics: Array<Diagnostic>, };
export type WorkingDirectorySummary = { cleanliness?: string | null; cleanup_target?: WorkingDirectoryCleanupTarget | null; creation_ref?: string | null; creation_selector?: string | null; creation_tree?: string | null; current_ref?: string | null; current_selector?: string | null; current_tree?: string | null; display_name?: string | null; materializer_kind: WorkingDirectoryMaterializerKind; observed_at_epoch_seconds?: number | null; occupied_by?: WorkingDirectoryOccupancy | null; source: WorkingDirectorySource; status: WorkingDirectoryStatusKind; working_directory_id: string; };
+204 -3
View File
@@ -6,15 +6,20 @@ import type {
CreateWorkspaceWorkerTicketAssignmentRequest,
Diagnostic,
DiagnosticSeverity,
RepositoryApiError,
RuntimeWorkerWorkdirAttachmentSummary,
RuntimeWorkingDirectoryCleanupTarget,
RuntimeWorkingDirectorySummary,
RuntimeWorkerWorkdirAttachmentSummary,
WorkerCapabilitySummary,
WorkerImplementationSummary,
WorkerLaunchOptionsResponse,
WorkerLaunchProfileCandidate,
WorkerLaunchRuntimeOption,
WorkerLaunchWorkerSummary,
WorkerListResponse,
WorkerStateSnapshot,
WorkerSummary,
WorkerWorkdirAttachmentSummary,
WorkerWorkspaceSummary,
WorkingDirectoryRepositoryOption,
} from "$lib/generated/worker-launch-api";
@@ -45,8 +50,14 @@ function exact(
}
}
const MAX_STRING_LENGTH = 65_536;
const MAX_COLLECTION_LENGTH = 4_096;
function string(value: unknown, label: string): string {
if (typeof value !== "string") throw new Error(`${label} must be a string`);
if (value.length > MAX_STRING_LENGTH) {
throw new Error(`${label} exceeds its length limit`);
}
return value;
}
@@ -56,8 +67,8 @@ function boolean(value: unknown, label: string): boolean {
}
function number(value: unknown, label: string): number {
if (typeof value !== "number" || !Number.isFinite(value)) {
throw new Error(`${label} must be a finite number`);
if (typeof value !== "number" || !Number.isSafeInteger(value)) {
throw new Error(`${label} must be a safe integer`);
}
return value;
}
@@ -72,6 +83,9 @@ function array<T>(
parse: (item: unknown, label: string) => T,
): T[] {
if (!Array.isArray(value)) throw new Error(`${label} must be an array`);
if (value.length > MAX_COLLECTION_LENGTH) {
throw new Error(`${label} exceeds its item limit`);
}
return value.map((item, index) => parse(item, `${label}[${index}]`));
}
@@ -165,6 +179,18 @@ function repositoryOption(
};
}
export function parseWorkerApiError(value: unknown): RepositoryApiError {
const item = record(value, "Worker API error");
exact(item, ["error", "message", "diagnostics"], "Worker API error");
return {
error: string(item.error, "error"),
message: string(item.message, "message"),
diagnostics: item.diagnostics === undefined
? []
: array(item.diagnostics, "diagnostics", diagnostic),
};
}
export function parseWorkerLaunchOptionsResponse(
value: unknown,
): WorkerLaunchOptionsResponse {
@@ -237,6 +263,181 @@ function capabilitySummary(
};
}
function workerStateSnapshot(
value: unknown,
label: string,
): WorkerStateSnapshot {
const snapshot = record(value, label);
exact(snapshot, ["last_command_id", "state"], label);
const state = record(snapshot.state, `${label}.state`);
const kind = string(state.kind, `${label}.state.kind`);
if (kind === "idle") {
exact(state, ["kind"], `${label}.state`);
return {
last_command_id: unsignedInteger(
snapshot.last_command_id,
`${label}.last_command_id`,
),
state: { kind: "idle" },
};
}
if (kind !== "busy") throw new Error(`${label}.state.kind is invalid`);
exact(state, ["kind", "state"], `${label}.state`);
const busy = record(state.state, `${label}.state.state`);
exact(busy, ["kind", "state"], `${label}.state.state`);
const busyKind = string(busy.kind, `${label}.state.state.kind`);
const busyState = string(busy.state, `${label}.state.state.state`);
if (
(busyKind === "run" &&
["running", "pausing", "paused", "cancelling"].includes(busyState)) ||
(busyKind === "maintenance" && busyState === "compacting")
) {
return {
last_command_id: unsignedInteger(
snapshot.last_command_id,
`${label}.last_command_id`,
),
state: {
kind: "busy",
state: busyKind === "run"
? {
kind: "run",
state: busyState as "running" | "pausing" | "paused" | "cancelling",
}
: { kind: "maintenance", state: "compacting" },
},
};
}
throw new Error(`${label}.state.state is invalid`);
}
function workerWorkdirAttachment(
value: unknown,
label: string,
): WorkerWorkdirAttachmentSummary {
const item = record(value, label);
exact(item, ["alias", "working_directory"], label);
return {
alias: string(item.alias, `${label}.alias`),
working_directory: parseWorkingDirectorySummary(item.working_directory),
};
}
export type ParsedWorkerSummary =
& Omit<
WorkerSummary,
"display_name" | "tags" | "diagnostics"
>
& {
display_name: string;
tags: string[];
diagnostics: Diagnostic[];
};
export type ParsedWorkerListResponse = Omit<WorkerListResponse, "items"> & {
items: ParsedWorkerSummary[];
};
export function parseWorkerSummary(
value: unknown,
label = "Worker summary",
): ParsedWorkerSummary {
const item = record(value, label);
exact(
item,
[
"runtime_id",
"worker_id",
"resource_key",
"host_id",
"display_name",
"label",
"profile",
"singleton_key",
"tags",
"workspace",
"state",
"worker_state",
"last_seen_at",
"pinned",
"retention_state",
"implementation",
"capabilities",
"workdir_attachments",
"diagnostics",
],
label,
);
return {
runtime_id: string(item.runtime_id, `${label}.runtime_id`),
worker_id: string(item.worker_id, `${label}.worker_id`),
resource_key: string(item.resource_key, `${label}.resource_key`),
host_id: string(item.host_id, `${label}.host_id`),
display_name: item.display_name === undefined
? ""
: string(item.display_name, `${label}.display_name`),
label: string(item.label, `${label}.label`),
profile: optional(item.profile, `${label}.profile`, string),
singleton_key: optional(
item.singleton_key,
`${label}.singleton_key`,
string,
),
tags: item.tags === undefined
? []
: array(item.tags, `${label}.tags`, string),
workspace: workspaceSummary(item.workspace, `${label}.workspace`),
state: string(item.state, `${label}.state`),
worker_state: optional(
item.worker_state,
`${label}.worker_state`,
workerStateSnapshot,
),
last_seen_at: optional(item.last_seen_at, `${label}.last_seen_at`, string),
pinned: item.pinned === undefined
? false
: boolean(item.pinned, `${label}.pinned`),
retention_state: item.retention_state === undefined
? ""
: string(item.retention_state, `${label}.retention_state`),
implementation: implementationSummary(
item.implementation,
`${label}.implementation`,
),
capabilities: capabilitySummary(item.capabilities, `${label}.capabilities`),
workdir_attachments: item.workdir_attachments === undefined
? undefined
: array(
item.workdir_attachments,
`${label}.workdir_attachments`,
workerWorkdirAttachment,
),
diagnostics: item.diagnostics === undefined
? []
: array(item.diagnostics, `${label}.diagnostics`, diagnostic),
};
}
export function parseWorkerListResponse(
value: unknown,
): ParsedWorkerListResponse {
const item = record(value, "Worker list response");
exact(
item,
["workspace_id", "limit", "items", "source", "diagnostics"],
"Worker list response",
);
return {
workspace_id: string(item.workspace_id, "workspace_id"),
limit: unsignedInteger(item.limit, "limit"),
items: array(item.items, "items", parseWorkerSummary),
source: string(item.source, "source"),
diagnostics: item.diagnostics === undefined
? []
: array(item.diagnostics, "diagnostics", diagnostic),
};
}
function runtimeCleanupTarget(
value: unknown,
label: string,
@@ -9,10 +9,14 @@ import type {
BrowserCreateWorkerResponse as SharedBrowserCreateWorkerResponse,
BrowserWorkerWorkingDirectorySelection
as SharedBrowserWorkerWorkingDirectorySelection,
Diagnostic as SharedDiagnostic,
WorkerCapabilitySummary as SharedWorkerCapabilitySummary,
WorkerLaunchOptionsResponse as SharedWorkerLaunchOptionsResponse,
WorkerLaunchProfileCandidate as SharedWorkerLaunchProfileCandidate,
WorkerLaunchRuntimeOption as SharedWorkerLaunchRuntimeOption,
WorkerLaunchWorkerSummary as WorkerSummary,
WorkerLaunchWorkerSummary,
WorkerSummary as SharedWorkerSummary,
WorkerWorkdirAttachmentSummary as SharedWorkerWorkdirAttachmentSummary,
WorkingDirectoryRepositoryOption as SharedWorkingDirectoryRepositoryOption,
} from "$lib/generated/worker-launch-api";
import type {
@@ -53,11 +57,7 @@ export type {
};
export type WorkspaceResponse = SharedWorkspaceResponse;
export type Diagnostic = {
code: string;
severity: string;
message: string;
};
export type Diagnostic = SharedDiagnostic;
export type Runtime = {
runtime_id: string;
@@ -78,35 +78,17 @@ export type Runtime = {
};
};
export type WorkerCapabilities = {
can_stop: boolean;
can_spawn_followup: boolean;
};
export type WorkerCapabilities = SharedWorkerCapabilitySummary;
export type WorkerWorkdirAttachment = {
alias: string;
working_directory: WorkingDirectorySummary;
};
export type WorkerWorkdirAttachment = SharedWorkerWorkdirAttachmentSummary;
export type Worker = {
runtime_id: string;
worker_id: string;
resource_key: string;
host_id: string;
export type Worker = Omit<
SharedWorkerSummary,
"display_name" | "tags" | "worker_state" | "diagnostics"
> & {
display_name: string;
label: string;
profile?: string | null;
singleton_key?: string | null;
tags: string[];
workspace: { visibility: string; identity: string };
state: string;
worker_state?: WorkerStateSnapshot | null;
pinned?: boolean;
retention_state?: string;
last_seen_at?: string | null;
implementation: { kind: string; display_hint: string };
capabilities: WorkerCapabilities;
workdir_attachments?: WorkerWorkdirAttachment[];
diagnostics: Diagnostic[];
};
@@ -121,7 +103,7 @@ export type WorkerRestoreState =
export type WorkerRestoreResult = {
state: WorkerRestoreState;
worker?: WorkerSummary | null;
worker?: WorkerLaunchWorkerSummary | null;
diagnostics: Diagnostic[];
};
@@ -1,16 +1,18 @@
import { loadJson, workspaceApiPath } from "$lib/workspace/api/http";
import { parseWorkerListResponse } from "$lib/workspace/api/workers";
import { parseRuntimeCleanupPlan } from "$lib/workspace/api/runtime-workers";
import type {
ListResponse,
RuntimeCleanupPlanResponse,
Worker,
} from "$lib/workspace/sidebar/types";
import type { PageLoad } from "./$types";
export const load: PageLoad = async ({ fetch, params }) => {
const workers = await loadJson<ListResponse<Worker>>(
const workers = await loadJson(
fetch,
workspaceApiPath(params.workspaceId, "/workers"),
undefined,
parseWorkerListResponse,
{ diagnosticLabel: "Worker API", maxResponseBytes: 8 * 1024 * 1024 },
);
const runtimeIds = Array.from(
new Set(workers.data?.items.map((worker) => worker.runtime_id) ?? []),
@@ -1,20 +1,23 @@
import { redirect } from "@sveltejs/kit";
import { loadJson, workspaceApiPath } from "$lib/workspace/api/http";
import { parseWorkerSummary } from "$lib/workspace/api/workers";
import {
canonicalResourceReference,
resourceKey,
} from "$lib/workspace/resource-links";
import type { Worker } from "$lib/workspace/sidebar/types";
import type { PageLoad } from "./$types";
export const load = (async ({ fetch, params }) => {
const reference = resourceKey(params.workerRef);
const result = await loadJson<Worker>(
const result = await loadJson(
fetch,
workspaceApiPath(
params.workspaceId,
`/workers/${encodeURIComponent(reference)}`,
),
undefined,
parseWorkerSummary,
{ diagnosticLabel: "Worker API", maxResponseBytes: 8 * 1024 * 1024 },
);
if (result.data?.resource_key) {
const canonical = canonicalResourceReference(
@@ -1,20 +1,23 @@
import { redirect } from "@sveltejs/kit";
import { loadJson, workspaceApiPath } from "$lib/workspace/api/http";
import { parseWorkerSummary } from "$lib/workspace/api/workers";
import {
canonicalResourceReference,
resourceKey,
} from "$lib/workspace/resource-links";
import type { Worker } from "$lib/workspace/sidebar/types";
import type { PageLoad } from "./$types";
export const load = (async ({ fetch, params }) => {
const reference = resourceKey(params.workerRef);
const result = await loadJson<Worker>(
const result = await loadJson(
fetch,
workspaceApiPath(
params.workspaceId,
`/workers/${encodeURIComponent(reference)}`,
),
undefined,
parseWorkerSummary,
{ diagnosticLabel: "Worker API", maxResponseBytes: 8 * 1024 * 1024 },
);
if (result.data?.resource_key) {
const canonical = canonicalResourceReference(
@@ -1,13 +1,14 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { untrack } from 'svelte';
import { workspaceApiPath } from '$lib/workspace/api/http';
import { readBoundedJson, workspaceApiPath } from '$lib/workspace/api/http';
import {
parseWorkingDirectoryCreateResponse,
validateWorkingDirectoryCreateRequest,
} from '$lib/workspace/api/workdirs';
import {
parseBrowserCreateWorkerResponse,
parseWorkerApiError,
parseWorkerLaunchOptionsResponse,
} from '$lib/workspace/api/workers';
import { formatCurrentWorkdirRevision } from '$lib/workspace/settings/workdir-revision';
@@ -29,12 +30,6 @@
diagnostics: Diagnostic[];
};
type ErrorPayload = {
error?: { message?: string; code?: string } | string;
message?: string;
diagnostics?: Diagnostic[];
};
function workdirOptionLabel(directory: WorkingDirectorySummary): string {
const repositoryKey = directory.source.kind === 'repository'
? directory.source.repository_key
@@ -171,7 +166,9 @@
if (!response.ok) {
throw new Error(`worker launch options failed (${response.status})`);
}
const payload = parseWorkerLaunchOptionsResponse(await response.json());
const payload = parseWorkerLaunchOptionsResponse(
await readBoundedJson(response, 8 * 1024 * 1024),
);
options = payload;
const form = defaultWorkerLaunchForm(payload, {
runtime_id: runtimeId,
@@ -313,7 +310,9 @@
submitError = await responseDisplayError(response, 'worker create failed');
return;
}
const payload = parseBrowserCreateWorkerResponse(await response.json());
const payload = parseBrowserCreateWorkerResponse(
await readBoundedJson(response, 8 * 1024 * 1024),
);
await goto(payload.console_href);
} catch (err) {
submitError = exceptionDisplayError(err, 'worker create failed');
@@ -324,18 +323,13 @@
async function responseDisplayError(response: Response, fallback: string): Promise<DisplayError> {
try {
const payload = (await response.json()) as ErrorPayload;
const diagnostics = Array.isArray(payload.diagnostics) ? payload.diagnostics : [];
if (typeof payload.error === 'object' && payload.error?.message) {
return {
message: `${payload.error.code ?? 'request_failed'}: ${payload.error.message}`,
diagnostics,
};
}
if (payload.message) {
const code = typeof payload.error === 'string' ? payload.error : 'request_failed';
return { message: `${code}: ${payload.message}`, diagnostics };
}
const payload = parseWorkerApiError(
await readBoundedJson(response, 1024 * 1024),
);
return {
message: `${payload.error}: ${payload.message}`,
diagnostics: payload.diagnostics ?? [],
};
} catch {
// fall through
}