Files
kandev/apps/web/lib/api/domains/task-environment-api.ts
T
José Almeida f169d25b72 fix(executor-profile): live Configured badge + session/load resilience + live container status
Three independent fixes that all surface together while iterating on the
Docker executor flow:

- Remote Credentials card: the per-agent "Configured" / "Not Configured"
  badge was driven by useState that only seeded once on mount. Picking a
  secret in the dropdown updated the parent's `agentEnvVars` map but the
  local `choice` never moved to `"env"`, so the badge stayed grey until
  the page was reloaded. Derive `choice` straight from props every render
  so the badge tracks live state.

- ACP session/load: when the agent process restarted between turns
  (common with claude-agent-acp because its session map is in-memory),
  the host's session/load call failed with JSON-RPC -32002 "Resource not
  found" and the entire launch errored out. Treat that as the same kind
  of "session is gone" signal as -32601 / capability=false and fall back
  to session/new. Worst case the agent loses prior context; best case
  the user just keeps typing.

- Executor Settings popover: dropped Execution ID and Environment ID
  rows (debug-only noise users don't need), kept Container ID + the
  copyable `docker exec -it … bash` line, added a live status badge
  with tones for running / exited / paused / dead / error / missing,
  and a 3-second polling interval so the badge follows the real
  container state. New `GET /api/v1/tasks/:id/environment/live`
  endpoint plumbs Docker `inspect` data through the lifecycle manager
  → task service → handler. ContainerLiveStatus mirror type at the
  service layer keeps lifecycle types out of the public surface.
2026-05-04 21:08:51 +01:00

70 lines
1.7 KiB
TypeScript

import { fetchJson, type ApiRequestOptions } from "../client";
export type TaskEnvironment = {
id: string;
task_id: string;
repository_id: string;
executor_type: string;
executor_id: string;
executor_profile_id: string;
agent_execution_id: string;
control_port: number;
status: string;
worktree_id?: string;
worktree_path?: string;
worktree_branch?: string;
workspace_path?: string;
container_id?: string;
sandbox_id?: string;
created_at: string;
updated_at?: string;
};
export type ResetTaskEnvironmentPayload = {
push_branch?: boolean;
};
export type ContainerLiveStatus = {
container_id: string;
/** running, exited, paused, restarting, removing, dead, created, missing */
state: string;
/** Human-readable status, e.g. "Up 5 minutes". */
status: string;
started_at?: string;
finished_at?: string;
exit_code?: number;
health?: string;
missing?: boolean;
};
export type TaskEnvironmentLiveResponse = {
environment: TaskEnvironment;
container?: ContainerLiveStatus;
};
export async function fetchTaskEnvironment(taskId: string, options?: ApiRequestOptions) {
return fetchJson<TaskEnvironment>(`/api/v1/tasks/${taskId}/environment`, options);
}
export async function fetchTaskEnvironmentLive(taskId: string, options?: ApiRequestOptions) {
return fetchJson<TaskEnvironmentLiveResponse>(
`/api/v1/tasks/${taskId}/environment/live`,
options,
);
}
export async function resetTaskEnvironment(
taskId: string,
payload: ResetTaskEnvironmentPayload,
options?: ApiRequestOptions,
) {
return fetchJson<{ success: boolean }>(`/api/v1/tasks/${taskId}/environment/reset`, {
...options,
init: {
method: "POST",
body: JSON.stringify(payload),
...(options?.init ?? {}),
},
});
}