refactor: share Worker launch REST DTOs
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
"dev": "deno run -A npm:vite@7.2.7 dev",
|
||||
"dev:backend": "cd ../.. && cargo run -p yoi-workspace-server --bin yoi-server -- serve --listen 127.0.0.1:8787",
|
||||
"check": "deno run -A npm:@sveltejs/kit@2.49.4 sync && deno run -A npm:svelte-check@4.3.4 --tsconfig ./tsconfig.json",
|
||||
"test": "deno test --allow-read=src,test,tests --allow-env=LOG,VSCODE_TEXTMATE_DEBUG,NODE_ENV tests/workspace-model.test.ts tests/workspace-catalog.test.ts tests/profile-api.test.ts src/lib/workspace/auth/model.test.ts src/lib/workspace/api/http.test.ts src/lib/workspace/header/breadcrumb-model.test.ts src/lib/workspace/console/chat-submit.test.ts test/composer-history.test.ts tests/composer-paste.test.ts src/lib/workspace/console/composer-command.test.ts src/lib/workspace/console/composer-draft.test.ts src/lib/workspace/console/composer-completion.test.ts src/lib/workspace/console/markdown.test.ts test/console/ansi.test.ts src/lib/workspace/console/model.test.ts src/lib/workspace/companion/api.test.ts tests/workdir-api.test.ts src/lib/workspace/console/tasks.test.ts test/ticket-detail-route-reuse.test.ts test/repositories/ui.test.ts src/lib/workspace/console/worker-console.ui.test.ts src/lib/workspace/settings/model.test.ts src/lib/workspace/sidebar/override-stack.test.ts src/lib/workspace/sidebar/workers.test.ts src/lib/workspace/sidebar/workspace-switcher.test.ts src/lib/workspace/sidebar/worker-subscription.test.ts src/lib/workspace/sidebar/worker-launch.test.ts test/sidebar/worker-actions.test.ts src/lib/workspace/tickets/merge-request-resources.test.ts src/lib/workspace/tickets/ticket-panel.test.ts test/merge-request-status.test.ts test/config-source/decodal-grammar.test.ts test/config-source/editor-state.test.ts test/config-source/fixed-schema-wrapper.test.ts test/config-source/toolchain.test.ts test/config-source/wasm-parity.test.ts test/repository-access/api.test.ts test/repository-access/loader.test.ts test/repository-access/ui.test.ts",
|
||||
"test": "deno test --allow-read=src,test,tests --allow-env=LOG,VSCODE_TEXTMATE_DEBUG,NODE_ENV tests/workspace-model.test.ts tests/workspace-catalog.test.ts tests/profile-api.test.ts src/lib/workspace/auth/model.test.ts src/lib/workspace/api/http.test.ts src/lib/workspace/api/workers.test.ts src/lib/workspace/header/breadcrumb-model.test.ts src/lib/workspace/console/chat-submit.test.ts test/composer-history.test.ts tests/composer-paste.test.ts src/lib/workspace/console/composer-command.test.ts src/lib/workspace/console/composer-draft.test.ts src/lib/workspace/console/composer-completion.test.ts src/lib/workspace/console/markdown.test.ts test/console/ansi.test.ts src/lib/workspace/console/model.test.ts src/lib/workspace/companion/api.test.ts tests/workdir-api.test.ts src/lib/workspace/console/tasks.test.ts test/ticket-detail-route-reuse.test.ts test/repositories/ui.test.ts src/lib/workspace/console/worker-console.ui.test.ts src/lib/workspace/settings/model.test.ts src/lib/workspace/sidebar/override-stack.test.ts src/lib/workspace/sidebar/workers.test.ts src/lib/workspace/sidebar/workspace-switcher.test.ts src/lib/workspace/sidebar/worker-subscription.test.ts src/lib/workspace/sidebar/worker-launch.test.ts test/sidebar/worker-actions.test.ts src/lib/workspace/tickets/merge-request-resources.test.ts src/lib/workspace/tickets/ticket-panel.test.ts test/merge-request-status.test.ts test/config-source/decodal-grammar.test.ts test/config-source/editor-state.test.ts test/config-source/fixed-schema-wrapper.test.ts test/config-source/toolchain.test.ts test/config-source/wasm-parity.test.ts test/repository-access/api.test.ts test/repository-access/loader.test.ts test/repository-access/ui.test.ts",
|
||||
"build": "deno run -A npm:vite@7.2.7 build",
|
||||
"preview": "deno run -A npm:vite@7.2.7 preview"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
// Generated from workspace-api. Do not edit by hand.
|
||||
// Regenerate: cargo run -q -p workspace-api --features typescript --example generate_worker_launch_api_types > web/workspace/src/lib/generated/worker-launch-api.ts
|
||||
|
||||
import type { Segment } from "./protocol";
|
||||
|
||||
export type DiagnosticSeverity = "info" | "warning" | "error";
|
||||
|
||||
export type Diagnostic = {
|
||||
code: string;
|
||||
severity: DiagnosticSeverity;
|
||||
message: string;
|
||||
};
|
||||
|
||||
export type WorkingDirectoryMaterializerKind =
|
||||
| "runtime_git_cache"
|
||||
| "local_git_worktree";
|
||||
|
||||
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;
|
||||
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;
|
||||
primary_worker_id?: string | null;
|
||||
occupied_by?: WorkingDirectoryOccupancy | null;
|
||||
};
|
||||
|
||||
export type WorkingDirectoryOccupancy = {
|
||||
runtime_id: string;
|
||||
worker_id: string;
|
||||
display_name: string;
|
||||
linked_at: string;
|
||||
};
|
||||
|
||||
export type WorkingDirectorySummary = {
|
||||
working_directory_id: string;
|
||||
repository_key: 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?: WorkingDirectoryCleanupTarget | null;
|
||||
status: WorkingDirectoryStatusKind;
|
||||
cleanliness?: string | null;
|
||||
primary_worker_id?: 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 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;
|
||||
working_directory?: RuntimeWorkingDirectorySummary | null;
|
||||
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 = {
|
||||
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>;
|
||||
working_directory: BrowserWorkerWorkingDirectorySelection | null;
|
||||
/**
|
||||
* 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>;
|
||||
};
|
||||
@@ -55,7 +55,7 @@ export function parseWorkingDirectoryListResponse(
|
||||
);
|
||||
return {
|
||||
workspace_id: stringField(record, "workspace_id"),
|
||||
items: arrayField(record, "items").map(parseSummary),
|
||||
items: arrayField(record, "items").map(parseWorkingDirectorySummary),
|
||||
diagnostics: arrayField(record, "diagnostics").map(parseDiagnostic),
|
||||
};
|
||||
}
|
||||
@@ -101,12 +101,14 @@ function parseDetailLike(
|
||||
return {
|
||||
workspace_id: stringField(record, "workspace_id"),
|
||||
runtime_id: stringField(record, "runtime_id"),
|
||||
item: parseSummary(record.item),
|
||||
item: parseWorkingDirectorySummary(record.item),
|
||||
diagnostics: arrayField(record, "diagnostics").map(parseDiagnostic),
|
||||
};
|
||||
}
|
||||
|
||||
function parseSummary(value: unknown): WorkingDirectorySummary {
|
||||
export function parseWorkingDirectorySummary(
|
||||
value: unknown,
|
||||
): WorkingDirectorySummary {
|
||||
const record = exactRecord(value, SUMMARY_KEYS, "Workdir summary");
|
||||
const summary: WorkingDirectorySummary = {
|
||||
working_directory_id: stringField(record, "working_directory_id"),
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
declare const Deno: {
|
||||
test(name: string, fn: () => Promise<void> | void): void;
|
||||
};
|
||||
|
||||
function assertEquals(actual: unknown, expected: unknown): void {
|
||||
const actualJson = JSON.stringify(actual);
|
||||
const expectedJson = JSON.stringify(expected);
|
||||
if (actualJson !== expectedJson) {
|
||||
throw new Error(`Expected ${expectedJson}, received ${actualJson}`);
|
||||
}
|
||||
}
|
||||
|
||||
function assertThrows(
|
||||
operation: () => unknown,
|
||||
errorClass: typeof Error,
|
||||
message: string,
|
||||
): void {
|
||||
try {
|
||||
operation();
|
||||
} catch (error) {
|
||||
if (!(error instanceof errorClass) || !error.message.includes(message)) {
|
||||
throw error;
|
||||
}
|
||||
return;
|
||||
}
|
||||
throw new Error(`Expected operation to throw ${errorClass.name}: ${message}`);
|
||||
}
|
||||
|
||||
import {
|
||||
parseBrowserCreateWorkerResponse,
|
||||
parseBrowserWorkspaceOrchestratorResponse,
|
||||
parseCreateWorkspaceWorkerRequest,
|
||||
parseWorkerLaunchOptionsResponse,
|
||||
} from "./workers.ts";
|
||||
|
||||
const worker = {
|
||||
runtime_id: "runtime-a",
|
||||
worker_id: "worker-a",
|
||||
host_id: "host-a",
|
||||
display_name: "Worker A",
|
||||
label: "worker-a",
|
||||
profile: "builtin:coder",
|
||||
singleton_key: null,
|
||||
tags: [],
|
||||
workspace: {
|
||||
visibility: "workspace",
|
||||
identity: "workspace-a",
|
||||
workspace_id: "workspace-a",
|
||||
},
|
||||
state: "idle",
|
||||
last_seen_at: null,
|
||||
pinned: false,
|
||||
retention_state: "active",
|
||||
implementation: {
|
||||
kind: "runtime",
|
||||
display_hint: "Runtime Worker",
|
||||
},
|
||||
capabilities: {
|
||||
can_stop: true,
|
||||
can_spawn_followup: false,
|
||||
},
|
||||
diagnostics: [],
|
||||
};
|
||||
|
||||
Deno.test("Worker launch options parser accepts the generated wire shape", () => {
|
||||
const parsed = parseWorkerLaunchOptionsResponse({
|
||||
workspace_id: "workspace-a",
|
||||
runtimes: [{
|
||||
runtime_id: "runtime-a",
|
||||
display_name: "Runtime A",
|
||||
built_in: false,
|
||||
worker_creation_available: true,
|
||||
working_directory_required: true,
|
||||
status: "connected",
|
||||
diagnostics: [],
|
||||
}],
|
||||
default_profile: null,
|
||||
profiles: [{ id: "builtin:coder", label: "Coder", description: "Code" }],
|
||||
repositories: [{ repository_key: "main" }],
|
||||
working_directories: [],
|
||||
diagnostics: [],
|
||||
});
|
||||
|
||||
assertEquals(parsed.runtimes[0].runtime_id, "runtime-a");
|
||||
assertEquals(parsed.repositories[0].default_selector, undefined);
|
||||
});
|
||||
|
||||
Deno.test("Worker launch response parsers reject missing and unknown fields", () => {
|
||||
assertThrows(
|
||||
() =>
|
||||
parseWorkerLaunchOptionsResponse({
|
||||
workspace_id: "workspace-a",
|
||||
runtimes: [],
|
||||
profiles: [],
|
||||
repositories: [],
|
||||
working_directories: [],
|
||||
diagnostics: [],
|
||||
}),
|
||||
Error,
|
||||
"default_profile",
|
||||
);
|
||||
|
||||
assertThrows(
|
||||
() =>
|
||||
parseBrowserCreateWorkerResponse({
|
||||
workspace_id: "workspace-a",
|
||||
runtime_id: "runtime-a",
|
||||
worker_id: "worker-a",
|
||||
console_href: "/workers/worker-a",
|
||||
worker,
|
||||
diagnostics: [],
|
||||
unexpected: true,
|
||||
}),
|
||||
Error,
|
||||
"unknown field unexpected",
|
||||
);
|
||||
|
||||
assertThrows(
|
||||
() =>
|
||||
parseBrowserWorkspaceOrchestratorResponse({
|
||||
workspace_id: "workspace-a",
|
||||
online: false,
|
||||
disposition: "missing",
|
||||
diagnostics: [],
|
||||
extra: false,
|
||||
}),
|
||||
Error,
|
||||
"unknown field extra",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("Worker create request parser requires the complete shared request", () => {
|
||||
const request = {
|
||||
runtime_id: "runtime-a",
|
||||
display_name: "Worker A",
|
||||
profile: "builtin:coder",
|
||||
ticket_assignment: null,
|
||||
initial_submit: [{ kind: "text", content: "Implement T-565." }],
|
||||
working_directory: {
|
||||
working_directory_id: "workdir-a",
|
||||
relative_cwd: null,
|
||||
},
|
||||
control_operation_id: null,
|
||||
};
|
||||
|
||||
assertEquals(parseCreateWorkspaceWorkerRequest(request), request);
|
||||
assertThrows(
|
||||
() =>
|
||||
parseCreateWorkspaceWorkerRequest({
|
||||
...request,
|
||||
operation_id: "legacy-literal",
|
||||
}),
|
||||
Error,
|
||||
"unknown field operation_id",
|
||||
);
|
||||
const { initial_submit: _initialSubmit, ...missingInitialSubmit } = request;
|
||||
assertThrows(
|
||||
() => parseCreateWorkspaceWorkerRequest(missingInitialSubmit),
|
||||
Error,
|
||||
"initial_submit",
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,535 @@
|
||||
import type {
|
||||
BrowserCreateWorkerResponse,
|
||||
BrowserWorkerWorkingDirectorySelection,
|
||||
BrowserWorkspaceOrchestratorResponse,
|
||||
CreateWorkspaceWorkerRequest,
|
||||
CreateWorkspaceWorkerTicketAssignmentRequest,
|
||||
Diagnostic,
|
||||
DiagnosticSeverity,
|
||||
RuntimeWorkingDirectoryCleanupTarget,
|
||||
RuntimeWorkingDirectorySummary,
|
||||
WorkerCapabilitySummary,
|
||||
WorkerImplementationSummary,
|
||||
WorkerLaunchOptionsResponse,
|
||||
WorkerLaunchProfileCandidate,
|
||||
WorkerLaunchRuntimeOption,
|
||||
WorkerLaunchWorkerSummary,
|
||||
WorkerWorkspaceSummary,
|
||||
WorkingDirectoryRepositoryOption,
|
||||
} from "$lib/generated/worker-launch-api";
|
||||
import type { Segment } from "$lib/generated/protocol";
|
||||
import { parseWorkingDirectorySummary } from "$lib/workspace/api/workdirs";
|
||||
|
||||
const DIAGNOSTIC_SEVERITIES = new Set<DiagnosticSeverity>([
|
||||
"info",
|
||||
"warning",
|
||||
"error",
|
||||
]);
|
||||
|
||||
function record(value: unknown, label: string): Record<string, unknown> {
|
||||
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
||||
throw new Error(`${label} must be an object`);
|
||||
}
|
||||
return value as Record<string, unknown>;
|
||||
}
|
||||
|
||||
function exact(
|
||||
value: Record<string, unknown>,
|
||||
allowed: readonly string[],
|
||||
label: string,
|
||||
): void {
|
||||
const unexpected = Object.keys(value).filter((key) => !allowed.includes(key));
|
||||
if (unexpected.length > 0) {
|
||||
throw new Error(`${label} contains unknown field ${unexpected[0]}`);
|
||||
}
|
||||
}
|
||||
|
||||
function string(value: unknown, label: string): string {
|
||||
if (typeof value !== "string") throw new Error(`${label} must be a string`);
|
||||
return value;
|
||||
}
|
||||
|
||||
function boolean(value: unknown, label: string): boolean {
|
||||
if (typeof value !== "boolean") throw new Error(`${label} must be a boolean`);
|
||||
return value;
|
||||
}
|
||||
|
||||
function number(value: unknown, label: string): number {
|
||||
if (typeof value !== "number" || !Number.isFinite(value)) {
|
||||
throw new Error(`${label} must be a finite number`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function nullableString(value: unknown, label: string): string | null {
|
||||
return value === null ? null : string(value, label);
|
||||
}
|
||||
|
||||
function array<T>(
|
||||
value: unknown,
|
||||
label: string,
|
||||
parse: (item: unknown, label: string) => T,
|
||||
): T[] {
|
||||
if (!Array.isArray(value)) throw new Error(`${label} must be an array`);
|
||||
return value.map((item, index) => parse(item, `${label}[${index}]`));
|
||||
}
|
||||
|
||||
function optional<T>(
|
||||
value: unknown,
|
||||
label: string,
|
||||
parse: (item: unknown, label: string) => T,
|
||||
): T | null | undefined {
|
||||
return value === undefined
|
||||
? undefined
|
||||
: value === null
|
||||
? null
|
||||
: parse(value, label);
|
||||
}
|
||||
|
||||
function diagnostic(value: unknown, label: string): Diagnostic {
|
||||
const item = record(value, label);
|
||||
exact(item, ["code", "severity", "message"], label);
|
||||
const severity = string(item.severity, `${label}.severity`);
|
||||
if (!DIAGNOSTIC_SEVERITIES.has(severity as DiagnosticSeverity)) {
|
||||
throw new Error(`${label}.severity is invalid`);
|
||||
}
|
||||
return {
|
||||
code: string(item.code, `${label}.code`),
|
||||
severity: severity as DiagnosticSeverity,
|
||||
message: string(item.message, `${label}.message`),
|
||||
};
|
||||
}
|
||||
|
||||
function runtimeOption(
|
||||
value: unknown,
|
||||
label: string,
|
||||
): WorkerLaunchRuntimeOption {
|
||||
const item = record(value, label);
|
||||
exact(
|
||||
item,
|
||||
[
|
||||
"runtime_id",
|
||||
"display_name",
|
||||
"built_in",
|
||||
"worker_creation_available",
|
||||
"working_directory_required",
|
||||
"status",
|
||||
"diagnostics",
|
||||
],
|
||||
label,
|
||||
);
|
||||
return {
|
||||
runtime_id: string(item.runtime_id, `${label}.runtime_id`),
|
||||
display_name: string(item.display_name, `${label}.display_name`),
|
||||
built_in: boolean(item.built_in, `${label}.built_in`),
|
||||
worker_creation_available: boolean(
|
||||
item.worker_creation_available,
|
||||
`${label}.worker_creation_available`,
|
||||
),
|
||||
working_directory_required: boolean(
|
||||
item.working_directory_required,
|
||||
`${label}.working_directory_required`,
|
||||
),
|
||||
status: string(item.status, `${label}.status`),
|
||||
diagnostics: array(item.diagnostics, `${label}.diagnostics`, diagnostic),
|
||||
};
|
||||
}
|
||||
|
||||
function profileCandidate(
|
||||
value: unknown,
|
||||
label: string,
|
||||
): WorkerLaunchProfileCandidate {
|
||||
const item = record(value, label);
|
||||
exact(item, ["id", "label", "description"], label);
|
||||
return {
|
||||
id: string(item.id, `${label}.id`),
|
||||
label: string(item.label, `${label}.label`),
|
||||
description: string(item.description, `${label}.description`),
|
||||
};
|
||||
}
|
||||
|
||||
function repositoryOption(
|
||||
value: unknown,
|
||||
label: string,
|
||||
): WorkingDirectoryRepositoryOption {
|
||||
const item = record(value, label);
|
||||
exact(item, ["repository_key", "default_selector"], label);
|
||||
return {
|
||||
repository_key: string(item.repository_key, `${label}.repository_key`),
|
||||
default_selector: optional(
|
||||
item.default_selector,
|
||||
`${label}.default_selector`,
|
||||
string,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
export function parseWorkerLaunchOptionsResponse(
|
||||
value: unknown,
|
||||
): WorkerLaunchOptionsResponse {
|
||||
const item = record(value, "Worker launch options response");
|
||||
exact(
|
||||
item,
|
||||
[
|
||||
"workspace_id",
|
||||
"runtimes",
|
||||
"default_profile",
|
||||
"profiles",
|
||||
"repositories",
|
||||
"working_directories",
|
||||
"diagnostics",
|
||||
],
|
||||
"Worker launch options response",
|
||||
);
|
||||
return {
|
||||
workspace_id: string(item.workspace_id, "workspace_id"),
|
||||
runtimes: array(item.runtimes, "runtimes", runtimeOption),
|
||||
default_profile: nullableString(item.default_profile, "default_profile"),
|
||||
profiles: array(item.profiles, "profiles", profileCandidate),
|
||||
repositories: array(item.repositories, "repositories", repositoryOption),
|
||||
working_directories: array(
|
||||
item.working_directories,
|
||||
"working_directories",
|
||||
parseWorkingDirectorySummary,
|
||||
),
|
||||
diagnostics: array(item.diagnostics, "diagnostics", diagnostic),
|
||||
};
|
||||
}
|
||||
|
||||
function workspaceSummary(
|
||||
value: unknown,
|
||||
label: string,
|
||||
): WorkerWorkspaceSummary {
|
||||
const item = record(value, label);
|
||||
exact(item, ["visibility", "identity", "workspace_id"], label);
|
||||
return {
|
||||
visibility: string(item.visibility, `${label}.visibility`),
|
||||
identity: string(item.identity, `${label}.identity`),
|
||||
workspace_id: optional(item.workspace_id, `${label}.workspace_id`, string),
|
||||
};
|
||||
}
|
||||
|
||||
function implementationSummary(
|
||||
value: unknown,
|
||||
label: string,
|
||||
): WorkerImplementationSummary {
|
||||
const item = record(value, label);
|
||||
exact(item, ["kind", "display_hint"], label);
|
||||
return {
|
||||
kind: string(item.kind, `${label}.kind`),
|
||||
display_hint: string(item.display_hint, `${label}.display_hint`),
|
||||
};
|
||||
}
|
||||
|
||||
function capabilitySummary(
|
||||
value: unknown,
|
||||
label: string,
|
||||
): WorkerCapabilitySummary {
|
||||
const item = record(value, label);
|
||||
exact(item, ["can_stop", "can_spawn_followup"], label);
|
||||
return {
|
||||
can_stop: boolean(item.can_stop, `${label}.can_stop`),
|
||||
can_spawn_followup: boolean(
|
||||
item.can_spawn_followup,
|
||||
`${label}.can_spawn_followup`,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
function runtimeCleanupTarget(
|
||||
value: unknown,
|
||||
label: string,
|
||||
): RuntimeWorkingDirectoryCleanupTarget {
|
||||
const item = record(value, label);
|
||||
exact(item, ["kind", "working_directory_id", "repository_id"], label);
|
||||
return {
|
||||
kind: string(item.kind, `${label}.kind`),
|
||||
working_directory_id: string(
|
||||
item.working_directory_id,
|
||||
`${label}.working_directory_id`,
|
||||
),
|
||||
repository_id: string(item.repository_id, `${label}.repository_id`),
|
||||
};
|
||||
}
|
||||
|
||||
function runtimeWorkingDirectory(
|
||||
value: unknown,
|
||||
label: string,
|
||||
): RuntimeWorkingDirectorySummary {
|
||||
const item = record(value, label);
|
||||
exact(
|
||||
item,
|
||||
[
|
||||
"working_directory_id",
|
||||
"repository_id",
|
||||
"creation_selector",
|
||||
"creation_ref",
|
||||
"creation_tree",
|
||||
"current_selector",
|
||||
"current_ref",
|
||||
"current_tree",
|
||||
"observed_at_epoch_seconds",
|
||||
"materializer_kind",
|
||||
"cleanup_target",
|
||||
"status",
|
||||
"cleanliness",
|
||||
"primary_worker_id",
|
||||
"occupied_by",
|
||||
],
|
||||
label,
|
||||
);
|
||||
const materializerKind = string(
|
||||
item.materializer_kind,
|
||||
`${label}.materializer_kind`,
|
||||
);
|
||||
if (
|
||||
materializerKind !== "runtime_git_cache" &&
|
||||
materializerKind !== "local_git_worktree"
|
||||
) {
|
||||
throw new Error(`${label}.materializer_kind is invalid`);
|
||||
}
|
||||
const status = string(item.status, `${label}.status`);
|
||||
if (
|
||||
!["active", "cleanup_pending", "corrupted", "not_found", "unknown"]
|
||||
.includes(status)
|
||||
) {
|
||||
throw new Error(`${label}.status is invalid`);
|
||||
}
|
||||
const occupied = optional(
|
||||
item.occupied_by,
|
||||
`${label}.occupied_by`,
|
||||
(value, occupiedLabel) => {
|
||||
const occupancy = record(value, occupiedLabel);
|
||||
exact(
|
||||
occupancy,
|
||||
["runtime_id", "worker_id", "display_name", "linked_at"],
|
||||
occupiedLabel,
|
||||
);
|
||||
return {
|
||||
runtime_id: string(occupancy.runtime_id, `${occupiedLabel}.runtime_id`),
|
||||
worker_id: string(occupancy.worker_id, `${occupiedLabel}.worker_id`),
|
||||
display_name: string(
|
||||
occupancy.display_name,
|
||||
`${occupiedLabel}.display_name`,
|
||||
),
|
||||
linked_at: string(occupancy.linked_at, `${occupiedLabel}.linked_at`),
|
||||
};
|
||||
},
|
||||
);
|
||||
return {
|
||||
working_directory_id: string(
|
||||
item.working_directory_id,
|
||||
`${label}.working_directory_id`,
|
||||
),
|
||||
repository_id: string(item.repository_id, `${label}.repository_id`),
|
||||
creation_selector: optional(
|
||||
item.creation_selector,
|
||||
`${label}.creation_selector`,
|
||||
string,
|
||||
),
|
||||
creation_ref: optional(item.creation_ref, `${label}.creation_ref`, string),
|
||||
creation_tree: optional(
|
||||
item.creation_tree,
|
||||
`${label}.creation_tree`,
|
||||
string,
|
||||
),
|
||||
current_selector: optional(
|
||||
item.current_selector,
|
||||
`${label}.current_selector`,
|
||||
string,
|
||||
),
|
||||
current_ref: optional(item.current_ref, `${label}.current_ref`, string),
|
||||
current_tree: optional(item.current_tree, `${label}.current_tree`, string),
|
||||
observed_at_epoch_seconds: optional(
|
||||
item.observed_at_epoch_seconds,
|
||||
`${label}.observed_at_epoch_seconds`,
|
||||
number,
|
||||
),
|
||||
materializer_kind: materializerKind,
|
||||
cleanup_target: optional(
|
||||
item.cleanup_target,
|
||||
`${label}.cleanup_target`,
|
||||
runtimeCleanupTarget,
|
||||
),
|
||||
status: status as RuntimeWorkingDirectorySummary["status"],
|
||||
cleanliness: optional(item.cleanliness, `${label}.cleanliness`, string),
|
||||
primary_worker_id: optional(
|
||||
item.primary_worker_id,
|
||||
`${label}.primary_worker_id`,
|
||||
string,
|
||||
),
|
||||
occupied_by: occupied,
|
||||
};
|
||||
}
|
||||
|
||||
function workerSummary(
|
||||
value: unknown,
|
||||
label: string,
|
||||
): WorkerLaunchWorkerSummary {
|
||||
const item = record(value, label);
|
||||
exact(
|
||||
item,
|
||||
[
|
||||
"runtime_id",
|
||||
"worker_id",
|
||||
"host_id",
|
||||
"display_name",
|
||||
"label",
|
||||
"profile",
|
||||
"singleton_key",
|
||||
"tags",
|
||||
"workspace",
|
||||
"state",
|
||||
"last_seen_at",
|
||||
"pinned",
|
||||
"retention_state",
|
||||
"implementation",
|
||||
"capabilities",
|
||||
"working_directory",
|
||||
"diagnostics",
|
||||
],
|
||||
label,
|
||||
);
|
||||
return {
|
||||
runtime_id: string(item.runtime_id, `${label}.runtime_id`),
|
||||
worker_id: string(item.worker_id, `${label}.worker_id`),
|
||||
host_id: string(item.host_id, `${label}.host_id`),
|
||||
display_name: string(item.display_name, `${label}.display_name`),
|
||||
label: string(item.label, `${label}.label`),
|
||||
profile: nullableString(item.profile, `${label}.profile`),
|
||||
singleton_key: nullableString(item.singleton_key, `${label}.singleton_key`),
|
||||
tags: array(item.tags, `${label}.tags`, string),
|
||||
workspace: workspaceSummary(item.workspace, `${label}.workspace`),
|
||||
state: string(item.state, `${label}.state`),
|
||||
last_seen_at: nullableString(item.last_seen_at, `${label}.last_seen_at`),
|
||||
pinned: boolean(item.pinned, `${label}.pinned`),
|
||||
retention_state: string(item.retention_state, `${label}.retention_state`),
|
||||
implementation: implementationSummary(
|
||||
item.implementation,
|
||||
`${label}.implementation`,
|
||||
),
|
||||
capabilities: capabilitySummary(item.capabilities, `${label}.capabilities`),
|
||||
working_directory: optional(
|
||||
item.working_directory,
|
||||
`${label}.working_directory`,
|
||||
runtimeWorkingDirectory,
|
||||
),
|
||||
diagnostics: array(item.diagnostics, `${label}.diagnostics`, diagnostic),
|
||||
};
|
||||
}
|
||||
|
||||
export function parseBrowserCreateWorkerResponse(
|
||||
value: unknown,
|
||||
): BrowserCreateWorkerResponse {
|
||||
const item = record(value, "Worker create response");
|
||||
exact(
|
||||
item,
|
||||
[
|
||||
"workspace_id",
|
||||
"runtime_id",
|
||||
"worker_id",
|
||||
"console_href",
|
||||
"worker",
|
||||
"diagnostics",
|
||||
],
|
||||
"Worker create response",
|
||||
);
|
||||
return {
|
||||
workspace_id: string(item.workspace_id, "workspace_id"),
|
||||
runtime_id: string(item.runtime_id, "runtime_id"),
|
||||
worker_id: string(item.worker_id, "worker_id"),
|
||||
console_href: string(item.console_href, "console_href"),
|
||||
worker: workerSummary(item.worker, "worker"),
|
||||
diagnostics: array(item.diagnostics, "diagnostics", diagnostic),
|
||||
};
|
||||
}
|
||||
|
||||
export function parseBrowserWorkspaceOrchestratorResponse(
|
||||
value: unknown,
|
||||
): BrowserWorkspaceOrchestratorResponse {
|
||||
const item = record(value, "Workspace Orchestrator response");
|
||||
exact(
|
||||
item,
|
||||
["workspace_id", "online", "disposition", "worker", "diagnostics"],
|
||||
"Workspace Orchestrator response",
|
||||
);
|
||||
return {
|
||||
workspace_id: string(item.workspace_id, "workspace_id"),
|
||||
online: boolean(item.online, "online"),
|
||||
disposition: string(item.disposition, "disposition"),
|
||||
worker: optional(item.worker, "worker", workerSummary),
|
||||
diagnostics: array(item.diagnostics, "diagnostics", diagnostic),
|
||||
};
|
||||
}
|
||||
|
||||
function workingDirectorySelection(
|
||||
value: unknown,
|
||||
label: string,
|
||||
): BrowserWorkerWorkingDirectorySelection {
|
||||
const item = record(value, label);
|
||||
exact(item, ["working_directory_id", "relative_cwd"], label);
|
||||
return {
|
||||
working_directory_id: string(
|
||||
item.working_directory_id,
|
||||
`${label}.working_directory_id`,
|
||||
),
|
||||
relative_cwd: nullableString(item.relative_cwd, `${label}.relative_cwd`),
|
||||
};
|
||||
}
|
||||
|
||||
function ticketAssignment(
|
||||
value: unknown,
|
||||
label: string,
|
||||
): CreateWorkspaceWorkerTicketAssignmentRequest {
|
||||
const item = record(value, label);
|
||||
exact(item, ["ticket_id", "operation_id"], label);
|
||||
return {
|
||||
ticket_id: string(item.ticket_id, `${label}.ticket_id`),
|
||||
operation_id: string(item.operation_id, `${label}.operation_id`),
|
||||
};
|
||||
}
|
||||
|
||||
function segment(value: unknown, label: string): Segment {
|
||||
const item = record(value, label);
|
||||
const kind = string(item.kind, `${label}.kind`);
|
||||
if (kind === "text") {
|
||||
exact(item, ["kind", "content"], label);
|
||||
return { kind, content: string(item.content, `${label}.content`) };
|
||||
}
|
||||
throw new Error(`${label}.kind is not supported by Worker creation`);
|
||||
}
|
||||
|
||||
export function parseCreateWorkspaceWorkerRequest(
|
||||
value: unknown,
|
||||
): CreateWorkspaceWorkerRequest {
|
||||
const item = record(value, "Worker create request");
|
||||
exact(
|
||||
item,
|
||||
[
|
||||
"runtime_id",
|
||||
"display_name",
|
||||
"profile",
|
||||
"ticket_assignment",
|
||||
"initial_submit",
|
||||
"working_directory",
|
||||
"control_operation_id",
|
||||
],
|
||||
"Worker create request",
|
||||
);
|
||||
return {
|
||||
runtime_id: string(item.runtime_id, "runtime_id"),
|
||||
display_name: string(item.display_name, "display_name"),
|
||||
profile: nullableString(item.profile, "profile"),
|
||||
ticket_assignment: item.ticket_assignment === null
|
||||
? null
|
||||
: ticketAssignment(item.ticket_assignment, "ticket_assignment"),
|
||||
initial_submit: array(item.initial_submit, "initial_submit", segment),
|
||||
working_directory: item.working_directory === null
|
||||
? null
|
||||
: workingDirectorySelection(item.working_directory, "working_directory"),
|
||||
control_operation_id: nullableString(
|
||||
item.control_operation_id,
|
||||
"control_operation_id",
|
||||
),
|
||||
};
|
||||
}
|
||||
@@ -1,3 +1,12 @@
|
||||
import type {
|
||||
BrowserCreateWorkerResponse as SharedBrowserCreateWorkerResponse,
|
||||
BrowserWorkerWorkingDirectorySelection
|
||||
as SharedBrowserWorkerWorkingDirectorySelection,
|
||||
WorkerLaunchOptionsResponse as SharedWorkerLaunchOptionsResponse,
|
||||
WorkerLaunchProfileCandidate as SharedWorkerLaunchProfileCandidate,
|
||||
WorkerLaunchRuntimeOption as SharedWorkerLaunchRuntimeOption,
|
||||
WorkingDirectoryRepositoryOption as SharedWorkingDirectoryRepositoryOption,
|
||||
} from "$lib/generated/worker-launch-api";
|
||||
import type {
|
||||
WorkingDirectoryCreateRequest,
|
||||
WorkingDirectoryCreateResponse,
|
||||
@@ -101,26 +110,10 @@ export type Worker = {
|
||||
|
||||
export type WorkerOperationState = "accepted" | "unsupported" | "rejected";
|
||||
|
||||
export type WorkerLaunchRuntimeOption = {
|
||||
runtime_id: string;
|
||||
display_name: string;
|
||||
built_in: boolean;
|
||||
worker_creation_available: boolean;
|
||||
working_directory_required: boolean;
|
||||
status: string;
|
||||
diagnostics: Diagnostic[];
|
||||
};
|
||||
|
||||
export type WorkerLaunchProfileCandidate = {
|
||||
id: string;
|
||||
label: string;
|
||||
description: string;
|
||||
};
|
||||
|
||||
export type WorkingDirectoryRepositoryOption = {
|
||||
repository_key: string;
|
||||
default_selector?: string | null;
|
||||
};
|
||||
export type WorkerLaunchRuntimeOption = SharedWorkerLaunchRuntimeOption;
|
||||
export type WorkerLaunchProfileCandidate = SharedWorkerLaunchProfileCandidate;
|
||||
export type WorkingDirectoryRepositoryOption =
|
||||
SharedWorkingDirectoryRepositoryOption;
|
||||
|
||||
export type CleanupTargetKind =
|
||||
| "worker_delete"
|
||||
@@ -185,29 +178,10 @@ export type RuntimeCleanupExecutionResponse = {
|
||||
diagnostics: Diagnostic[];
|
||||
};
|
||||
|
||||
export type BrowserWorkerWorkingDirectorySelection = {
|
||||
working_directory_id: string;
|
||||
relative_cwd?: string | null;
|
||||
};
|
||||
|
||||
export type WorkerLaunchOptionsResponse = {
|
||||
workspace_id: string;
|
||||
runtimes: WorkerLaunchRuntimeOption[];
|
||||
default_profile?: string | null;
|
||||
profiles: WorkerLaunchProfileCandidate[];
|
||||
repositories: WorkingDirectoryRepositoryOption[];
|
||||
working_directories: WorkingDirectorySummary[];
|
||||
diagnostics: Diagnostic[];
|
||||
};
|
||||
|
||||
export type BrowserCreateWorkerResponse = {
|
||||
workspace_id: string;
|
||||
runtime_id: string;
|
||||
worker_id: string;
|
||||
console_href: string;
|
||||
worker: Worker;
|
||||
diagnostics: Diagnostic[];
|
||||
};
|
||||
export type BrowserWorkerWorkingDirectorySelection =
|
||||
SharedBrowserWorkerWorkingDirectorySelection;
|
||||
export type WorkerLaunchOptionsResponse = SharedWorkerLaunchOptionsResponse;
|
||||
export type BrowserCreateWorkerResponse = SharedBrowserCreateWorkerResponse;
|
||||
|
||||
export type WorkerInputResult = {
|
||||
state: WorkerOperationState;
|
||||
|
||||
@@ -196,11 +196,13 @@ Deno.test("buildCreateWorkspaceWorkerRequest sends working_directory id and rela
|
||||
runtime_id: "embedded",
|
||||
display_name: "Worker",
|
||||
profile: "builtin:coder",
|
||||
ticket_assignment: null,
|
||||
initial_submit: [{ kind: "text", content: "go" }],
|
||||
working_directory: {
|
||||
working_directory_id: "wd-1-repo",
|
||||
relative_cwd: "crates/yoi",
|
||||
},
|
||||
control_operation_id: null,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -219,7 +221,7 @@ Deno.test("buildCreateWorkspaceWorkerRequest sends no initial segments for an em
|
||||
assertEquals(request.initial_submit, []);
|
||||
});
|
||||
|
||||
Deno.test("buildCreateWorkspaceWorkerRequest omits working_directory for embedded no-workdir launches", () => {
|
||||
Deno.test("buildCreateWorkspaceWorkerRequest emits null for embedded no-workdir launches", () => {
|
||||
const request = buildCreateWorkspaceWorkerRequest({
|
||||
runtime_id: "embedded",
|
||||
display_name: "Worker",
|
||||
@@ -235,6 +237,9 @@ Deno.test("buildCreateWorkspaceWorkerRequest omits working_directory for embedde
|
||||
runtime_id: "embedded",
|
||||
display_name: "Worker",
|
||||
profile: "builtin:companion",
|
||||
ticket_assignment: null,
|
||||
initial_submit: [{ kind: "text", content: "chat" }],
|
||||
working_directory: null,
|
||||
control_operation_id: null,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import type { Segment } from "$lib/generated/protocol";
|
||||
import type { CreateWorkspaceWorkerRequest } from "$lib/generated/worker-launch-api";
|
||||
import { parseCreateWorkspaceWorkerRequest } from "$lib/workspace/api/workers";
|
||||
|
||||
import type {
|
||||
BrowserWorkerWorkingDirectorySelection,
|
||||
WorkerLaunchOptionsResponse,
|
||||
} from "./types";
|
||||
import type { WorkerLaunchOptionsResponse } from "./types";
|
||||
|
||||
export type WorkerLaunchFormState = {
|
||||
runtime_id: string;
|
||||
@@ -16,14 +14,6 @@ export type WorkerLaunchFormState = {
|
||||
relative_cwd: string;
|
||||
};
|
||||
|
||||
export type CreateWorkspaceWorkerRequest = {
|
||||
runtime_id: string;
|
||||
display_name: string;
|
||||
profile: string;
|
||||
initial_submit: Segment[];
|
||||
working_directory?: BrowserWorkerWorkingDirectorySelection;
|
||||
};
|
||||
|
||||
export function defaultWorkerLaunchForm(
|
||||
options: WorkerLaunchOptionsResponse | null,
|
||||
current: WorkerLaunchFormState,
|
||||
@@ -86,7 +76,8 @@ export function defaultWorkerLaunchForm(
|
||||
)
|
||||
? current.working_directory_id
|
||||
: preferredWorkingDirectory?.working_directory_id || "",
|
||||
working_directory_repository_key: current.working_directory_repository_key ||
|
||||
working_directory_repository_key:
|
||||
current.working_directory_repository_key ||
|
||||
preferredRepository?.repository_key || "",
|
||||
working_directory_selector: current.working_directory_selector ||
|
||||
preferredRepository?.default_selector || "HEAD",
|
||||
@@ -97,22 +88,21 @@ export function defaultWorkerLaunchForm(
|
||||
export function buildCreateWorkspaceWorkerRequest(
|
||||
form: WorkerLaunchFormState,
|
||||
): CreateWorkspaceWorkerRequest {
|
||||
const request: CreateWorkspaceWorkerRequest = {
|
||||
runtime_id: form.runtime_id,
|
||||
display_name: form.display_name,
|
||||
profile: form.profile,
|
||||
initial_submit: form.initial_text.trim()
|
||||
const initialMessage = form.initial_text.trim();
|
||||
return parseCreateWorkspaceWorkerRequest({
|
||||
runtime_id: form.runtime_id.trim(),
|
||||
display_name: form.display_name.trim(),
|
||||
profile: form.profile.trim() || null,
|
||||
ticket_assignment: null,
|
||||
initial_submit: initialMessage
|
||||
? [{ kind: "text", content: form.initial_text }]
|
||||
: [],
|
||||
};
|
||||
if (form.working_directory_id) {
|
||||
request.working_directory = {
|
||||
working_directory_id: form.working_directory_id,
|
||||
};
|
||||
const relativeCwd = form.relative_cwd.trim();
|
||||
if (relativeCwd) {
|
||||
request.working_directory.relative_cwd = relativeCwd;
|
||||
}
|
||||
}
|
||||
return request;
|
||||
working_directory: form.working_directory_id
|
||||
? {
|
||||
working_directory_id: form.working_directory_id,
|
||||
relative_cwd: form.relative_cwd.trim() || null,
|
||||
}
|
||||
: null,
|
||||
control_operation_id: null,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { BrowserWorkspaceOrchestratorResponse } from "$lib/generated/worker-launch-api";
|
||||
import type { TicketDetail, TicketSummary } from "$lib/generated/ticket-api";
|
||||
|
||||
export const TICKET_STATES = [
|
||||
@@ -12,22 +13,7 @@ export const TICKET_STATES = [
|
||||
export type TicketState = (typeof TICKET_STATES)[number];
|
||||
export type TicketWorkerRole = "coder" | "reviewer";
|
||||
|
||||
export type WorkspaceOrchestratorStatus = {
|
||||
workspace_id: string;
|
||||
online: boolean;
|
||||
disposition: string;
|
||||
worker?: {
|
||||
runtime_id: string;
|
||||
worker_id: string;
|
||||
state: string;
|
||||
display_name: string;
|
||||
} | null;
|
||||
diagnostics: Array<{
|
||||
code: string;
|
||||
severity: string;
|
||||
message: string;
|
||||
}>;
|
||||
};
|
||||
export type WorkspaceOrchestratorStatus = BrowserWorkspaceOrchestratorResponse;
|
||||
|
||||
const LANE_DEFINITIONS = [
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { untrack } from "svelte";
|
||||
import type { ApiResult } from "$lib/workspace/api/http";
|
||||
import { loadJson, workspaceApiPath } from "$lib/workspace/api/http";
|
||||
import { parseBrowserWorkspaceOrchestratorResponse } from "$lib/workspace/api/workers";
|
||||
import type {
|
||||
QueryPage,
|
||||
TicketListResponse,
|
||||
@@ -99,6 +100,7 @@
|
||||
fetch,
|
||||
workspaceApiPath(data.workspaceId, "/orchestrator"),
|
||||
{ method: "POST" },
|
||||
parseBrowserWorkspaceOrchestratorResponse,
|
||||
);
|
||||
orchestratorStarting = false;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { parseBrowserWorkspaceOrchestratorResponse } from "$lib/workspace/api/workers";
|
||||
import { loadJson, workspaceApiPath } from "$lib/workspace/api/http";
|
||||
import type { TicketListResponse } from "$lib/generated/ticket-api";
|
||||
import type { WorkspaceOrchestratorStatus } from "$lib/workspace/tickets/ticket-panel";
|
||||
@@ -42,6 +43,8 @@ export const load: PageLoad = async ({ fetch, params }) => {
|
||||
loadJson<WorkspaceOrchestratorStatus>(
|
||||
fetch,
|
||||
workspaceApiPath(workspaceId, "/orchestrator"),
|
||||
undefined,
|
||||
parseBrowserWorkspaceOrchestratorResponse,
|
||||
),
|
||||
]);
|
||||
|
||||
|
||||
@@ -6,10 +6,13 @@
|
||||
parseWorkingDirectoryCreateResponse,
|
||||
validateWorkingDirectoryCreateRequest,
|
||||
} from '$lib/workspace/api/workdirs';
|
||||
import {
|
||||
parseBrowserCreateWorkerResponse,
|
||||
parseWorkerLaunchOptionsResponse,
|
||||
} from '$lib/workspace/api/workers';
|
||||
import { formatCurrentWorkdirRevision } from '$lib/workspace/settings/workdir-revision';
|
||||
import { buildCreateWorkspaceWorkerRequest, defaultWorkerLaunchForm } from '$lib/workspace/sidebar/worker-launch';
|
||||
import type {
|
||||
BrowserCreateWorkerResponse,
|
||||
Diagnostic,
|
||||
WorkerLaunchOptionsResponse,
|
||||
WorkingDirectorySummary,
|
||||
@@ -115,7 +118,7 @@
|
||||
if (!response.ok) {
|
||||
throw new Error(`worker launch options failed (${response.status})`);
|
||||
}
|
||||
const payload = (await response.json()) as WorkerLaunchOptionsResponse;
|
||||
const payload = parseWorkerLaunchOptionsResponse(await response.json());
|
||||
options = payload;
|
||||
const form = defaultWorkerLaunchForm(payload, {
|
||||
runtime_id: runtimeId,
|
||||
@@ -229,7 +232,7 @@
|
||||
submitError = await responseDisplayError(response, 'worker create failed');
|
||||
return;
|
||||
}
|
||||
const payload = (await response.json()) as BrowserCreateWorkerResponse;
|
||||
const payload = parseBrowserCreateWorkerResponse(await response.json());
|
||||
await goto(payload.console_href);
|
||||
} catch (err) {
|
||||
submitError = exceptionDisplayError(err, 'worker create failed');
|
||||
|
||||
Reference in New Issue
Block a user