/** * Post-deploy lifecycle, CLI side (design §5c.4; build-plan slice 4.2): `clustly status` * (the workspace's agent → latest release → listing, from the per-workspace memory) and * `clustly test` (one job in the REAL sandbox via the brokered test-run). `clustly logs` * is deliberately absent until the hosting side ships log sanitization — a raw passthrough * would leak vendor identifiers (the invisibility rule). */ import { type CliApiDeps } from "./api-client"; import type { CliFailure } from "./cli-failure"; import type { JobEnvelope } from "./envelope"; /** This domain speaks to the API through the shared client (R5). */ export type LifecycleDeps = CliApiDeps; export interface WorkspaceStatus { agentId?: string; release?: { id: string; status: string; createdAt: string; /** Parked at the HUMAN review gate. The status stays SCANNING while a person has the * release, so this flag (derived server-side) is the only way `clustly status` can tell * the wait it is actually in. Absent on the wire from an older server — parsed to false * here, so the DTO always carries it. */ held: boolean; /** When the human gate opened (ISO) — lets the status line say how long the wait has * actually been, instead of an undated "held". Null when the server predates the field. */ reviewOpenedAt: string | null; }; listing?: { id: string; title: string; status: string; }; } /** Everything the CLI remembers about this workspace, hydrated from the server. */ export declare function workspaceStatus(deps: LifecycleDeps, workspacePath: string): Promise; /** * The agent's handler failed in the real sandbox — THEIR code, not the platform. Carries the * trace hosting returned (verbatim, theirs) so the command can print it under AGENT_CRASHED / * AGENT_TIMEOUT instead of the retryable-looking exit 1 this used to be. */ export declare class TestRunAgentFailure extends Error { readonly code: "AGENT_CRASHED" | "AGENT_TIMEOUT"; readonly trace: string | undefined; constructor(code: "AGENT_CRASHED" | "AGENT_TIMEOUT", message: string, trace: string | undefined); } /** The next step for an agent-side test-run failure: generic, unless the trace is the egress signature. */ export declare function agentFailureHint(failure: TestRunAgentFailure): string; export declare function runTestJob(deps: LifecycleDeps, agentId: string, envelope: JobEnvelope): Promise<{ testRunId: string; output: unknown; releaseId: string | null; }>; /** One listing riding the agent (agent↔listing is 1:N — owner decision 2026-08-28). */ export interface AgentListing { id: string; title: string; status: string; /** micro-USDC of the standard tier, when priced. */ priceUsdc: number | null; } /** Every non-archived listing riding this agent — deploy's "what am I about to affect" * context, publish's update-vs-add disambiguation, and status --json's branch array. */ export declare function agentListings(deps: LifecycleDeps, agentId: string): Promise; /** One agent in the operator's whole inventory (`clustly agents`, 2026-08-28). */ export interface AccountAgent { id: string; name: string; /** Derived hosting truth: 'hangar' | 'registered_only' | 'self'. */ hosting: string; release: { id: string; status: string; held: boolean; } | null; listings: AgentListing[]; } /** The whole account: every non-archived agent with hosting truth, latest release (review * gate stated), and listings — "what do I have, what is under review, what is just * registered", without the web console. */ export declare function accountAgents(deps: LifecycleDeps): Promise; /** Unlist one listing: active → paused (reversible — `clustly publish` re-lists it). */ export declare function unlistListing(deps: LifecycleDeps, listingId: string): Promise; /** `clustly unlist` target resolution, pure (owner UX 2026-08-28 — edge cases pinned by * lifecycle.test.ts): which listings this invocation pauses, or the refusal naming why. */ export declare function pickUnlistTargets(existing: AgentListing[], flagListingId: string | undefined): { targets: AgentListing[]; } | { none: string; } | { error: CliFailure; }; /** One builder-safe timeline line from the hosting pipeline. */ export interface ReleaseLogLine { /** ISO-8601 UTC, or null for positional lines (rendering is the caller's job — §1.5). */ at: string | null; text: string; } /** The release's builder-safe story (`clustly logs`): received → scan → review → outcome. */ export declare function releaseLogs(deps: LifecycleDeps, releaseId: string): Promise<{ status: string; lines: ReleaseLogLine[]; }>; /** One seller-safe finding from the security scan — the complete list, never display-capped. */ export interface ReleaseFinding { ruleId: string; severity: string; file: string | null; line: number | null; evidence: string | null; /** Hosting's plain-language reading of THIS finding; null when triage did not run. */ explanation: { whatItDoes: string; whyFlagged: string; fix: string; } | null; } export interface ReleaseFindingsResult { /** False = no verdict yet (scan still running) — distinct from zero findings. */ scanned: boolean; blocked: boolean; humanReviewRequired: boolean; findings: ReleaseFinding[]; } /** The COMPLETE findings list (`clustly logs --findings`). The timeline caps display at 20 * lines; a 58-finding review left 38 unreadable through any interface (field report * 2026-08-24) — this read is where the rest live. */ export declare function releaseFindings(deps: LifecycleDeps, releaseId: string): Promise; /** The teardown outcome (`clustly destroy`): unlisted immediately; either torn down now or * scheduled (a buyer mid-job — the sweep finishes it once they drain). */ export interface DestroyOutcome { destroyed: boolean; imageRemoved: boolean; scheduled: boolean; pendingJobs?: number; /** Nothing was ever hosted (registered, never deployed) — delisted, nothing to tear down. */ nothingHosted?: boolean; } /** Tear down hosting + delist (design §2). No positive confirmation lives here — the command * glue owns that; this call is unconditional once made. */ export declare function destroyAgent(deps: LifecycleDeps, agentId: string): Promise;