From 9bf520ca78130e56fd5d397fced9f403fa1101c3 Mon Sep 17 00:00:00 2001 From: John Fawcett Date: Thu, 12 Mar 2026 16:55:46 -0500 Subject: [PATCH 1/9] feat(gastown): add staged convoys for plan-review-iterate workflow Adds staged mode to convoys so users can plan work before executing. gt_sling_batch gains a staged param that creates convoy + beads without hooking agents. New gt_convoy_start tool transitions staged convoys to open, triggering agent dispatch. Dashboard shows staged convoys with draft visual state and a Start button. Mayor prompt updated with staged convoy instructions. Closes #1006 --- cloudflare-gastown/container/plugin/client.ts | 9 ++ .../container/plugin/mayor-tools.test.ts | 69 ++++++++++ .../container/plugin/mayor-tools.ts | 35 ++++- cloudflare-gastown/container/plugin/types.ts | 9 +- .../src/db/tables/convoy-metadata.table.ts | 8 +- cloudflare-gastown/src/dos/Town.do.ts | 127 +++++++++++++++--- cloudflare-gastown/src/gastown.worker.ts | 4 + .../src/handlers/mayor-tools.handler.ts | 33 +++++ .../src/prompts/mayor-system.prompt.ts | 26 +++- cloudflare-gastown/src/ui/dashboard.ui.ts | 93 +++++++++++++ 10 files changed, 385 insertions(+), 28 deletions(-) diff --git a/cloudflare-gastown/container/plugin/client.ts b/cloudflare-gastown/container/plugin/client.ts index 02710ae382..7023a7edca 100644 --- a/cloudflare-gastown/container/plugin/client.ts +++ b/cloudflare-gastown/container/plugin/client.ts @@ -7,6 +7,7 @@ import type { BeadType, Convoy, ConvoyDetail, + ConvoyStartResult, GastownEnv, Mail, MayorGastownEnv, @@ -334,6 +335,7 @@ export class MayorGastownClient { tasks: Array<{ title: string; body?: string; depends_on?: number[] }>; merge_mode?: 'review-then-land' | 'review-and-merge'; parallel?: boolean; + staged?: boolean; }): Promise { return this.request(this.mayorPath('/sling-batch'), { method: 'POST', @@ -341,6 +343,13 @@ export class MayorGastownClient { }); } + async startConvoy(convoyId: string): Promise { + return this.request(this.mayorPath(`/convoys/${convoyId}/start`), { + method: 'POST', + body: JSON.stringify({}), + }); + } + async listConvoys(): Promise { return this.request(this.mayorPath('/convoys')); } diff --git a/cloudflare-gastown/container/plugin/mayor-tools.test.ts b/cloudflare-gastown/container/plugin/mayor-tools.test.ts index aa6daba7c7..e1bd7a35df 100644 --- a/cloudflare-gastown/container/plugin/mayor-tools.test.ts +++ b/cloudflare-gastown/container/plugin/mayor-tools.test.ts @@ -5,6 +5,7 @@ import type { Bead, Convoy, ConvoyDetail, + ConvoyStartResult, Rig, SlingBatchResult, SlingResult, @@ -60,6 +61,7 @@ const FAKE_CONVOY: Convoy = { id: 'convoy-1', title: 'JWT Authentication', status: 'active', + staged: false, total_beads: 3, closed_beads: 1, created_by: null, @@ -67,6 +69,18 @@ const FAKE_CONVOY: Convoy = { landed_at: null, }; +const FAKE_STAGED_CONVOY: Convoy = { + id: 'convoy-staged-1', + title: 'Big Refactor', + status: 'staged', + staged: true, + total_beads: 2, + closed_beads: 0, + created_by: null, + created_at: '2026-03-05T00:00:00Z', + landed_at: null, +}; + function makeFakeMayorClient(overrides: Partial = {}): MayorGastownClient { return { sling: vi.fn<() => Promise>().mockResolvedValue({ @@ -95,8 +109,22 @@ function makeFakeMayorClient(overrides: Partial = {}): Mayor ], }), listConvoys: vi.fn<() => Promise>().mockResolvedValue([FAKE_CONVOY]), + startConvoy: vi.fn<() => Promise>().mockResolvedValue({ + convoy: { ...FAKE_STAGED_CONVOY, status: 'active', staged: false }, + beads: [ + { + bead: { ...FAKE_BEAD, bead_id: 'bead-1', title: 'Task 1' }, + agent: { ...FAKE_AGENT, id: 'agent-1', name: 'Toast' }, + }, + { + bead: { ...FAKE_BEAD, bead_id: 'bead-2', title: 'Task 2' }, + agent: { ...FAKE_AGENT, id: 'agent-2', name: 'Muffin' }, + }, + ], + }), getConvoyStatus: vi.fn<() => Promise>().mockResolvedValue({ ...FAKE_CONVOY, + staged: false, beads: [ { bead_id: 'bead-1', @@ -339,4 +367,45 @@ describe('mayor tools', () => { expect(client.acknowledgeEscalation).toHaveBeenCalledWith('esc-1'); }); }); + + describe('gt_sling_batch staged', () => { + it('passes staged=true to client and reports convoy as staged', async () => { + client = makeFakeMayorClient({ + slingBatch: vi.fn<() => Promise>().mockResolvedValue({ + convoy: FAKE_STAGED_CONVOY, + beads: [ + { + bead: { ...FAKE_BEAD, bead_id: 'bead-1', title: 'Task 1' }, + agent: { ...FAKE_AGENT, id: 'agent-1', name: 'Toast' }, + }, + { + bead: { ...FAKE_BEAD, bead_id: 'bead-2', title: 'Task 2' }, + agent: { ...FAKE_AGENT, id: 'agent-2', name: 'Muffin' }, + }, + ], + }), + }); + tools = createMayorTools(client); + + const tasks = [{ title: 'Task 1' }, { title: 'Task 2', depends_on: [0] }]; + const result = await tools.gt_sling_batch.execute( + { rig_id: 'rig-1', convoy_title: 'Big Refactor', tasks, staged: true }, + CTX + ); + + expect(result).toContain('Convoy staged:'); + expect(result).toContain('convoy-staged-1'); + expect(result).toContain('gt_convoy_start'); + expect(client.slingBatch).toHaveBeenCalledWith(expect.objectContaining({ staged: true })); + }); + }); + + describe('gt_convoy_start', () => { + it('starts a staged convoy and reports bead count', async () => { + const result = await tools.gt_convoy_start.execute({ convoy_id: 'convoy-staged-1' }, CTX); + expect(result).toContain('Convoy started'); + expect(result).toContain('2 bead(s)'); + expect(client.startConvoy).toHaveBeenCalledWith('convoy-staged-1'); + }); + }); }); diff --git a/cloudflare-gastown/container/plugin/mayor-tools.ts b/cloudflare-gastown/container/plugin/mayor-tools.ts index 7d6ecb04e6..80b07c35d4 100644 --- a/cloudflare-gastown/container/plugin/mayor-tools.ts +++ b/cloudflare-gastown/container/plugin/mayor-tools.ts @@ -169,6 +169,14 @@ export function createMayorTools(client: MayorGastownClient) { 'that need ordering, which causes merge conflicts and failures.' ) .optional(), + staged: tool.schema + .boolean() + .describe( + 'If true, creates the convoy plan without dispatching agents. ' + + 'The user can review and edit before calling gt_convoy_start to begin execution. ' + + 'Default: false (dispatch immediately).' + ) + .optional(), }, async execute(args) { const result = await client.slingBatch({ @@ -177,6 +185,7 @@ export function createMayorTools(client: MayorGastownClient) { tasks: args.tasks, merge_mode: args.merge_mode, parallel: args.parallel, + staged: args.staged, }); const beadLines = result.beads.map( @@ -184,14 +193,17 @@ export function createMayorTools(client: MayorGastownClient) { ` ${i + 1}. "${b.bead.title}" → ${b.agent.name} (${b.agent.id})` ); const mode = args.merge_mode ?? 'review-then-land'; + const staged = args.staged === true; return [ - `Convoy created: "${result.convoy.title}" (${result.convoy.id})`, + `Convoy ${staged ? 'staged' : 'created'}: "${result.convoy.title}" (${result.convoy.id})`, `Merge mode: ${mode}`, `Tracking ${result.convoy.total_beads} beads:`, ...beadLines, - mode === 'review-then-land' - ? `Beads will be reviewed and merged into the convoy feature branch. A final PR/merge to main occurs when all beads are done.` - : `Each bead will go through the full review + merge/PR cycle independently.`, + staged + ? `Convoy is staged — agents have NOT been dispatched. Call gt_convoy_start with convoy_id "${result.convoy.id}" when ready to begin execution.` + : mode === 'review-then-land' + ? `Beads will be reviewed and merged into the convoy feature branch. A final PR/merge to main occurs when all beads are done.` + : `Each bead will go through the full review + merge/PR cycle independently.`, ].join('\n'); }, }), @@ -223,6 +235,21 @@ export function createMayorTools(client: MayorGastownClient) { }, }), + gt_convoy_start: tool({ + description: + 'Start a staged convoy. Transitions the convoy from staged (planned but not executing) ' + + 'to active: hooks agents to all tracked beads and begins dispatch. ' + + 'Call this when the user approves a staged plan and says to start it.', + args: { + convoy_id: tool.schema.string().describe('The UUID of the staged convoy to start'), + }, + async execute(args) { + const result = await client.startConvoy(args.convoy_id); + const beadCount = result.beads?.length ?? 0; + return `Convoy started. ${beadCount} bead(s) dispatched to agents.`; + }, + }), + gt_mail_send: tool({ description: 'Send a mail message to an agent in any rig. ' + diff --git a/cloudflare-gastown/container/plugin/types.ts b/cloudflare-gastown/container/plugin/types.ts index 0fb1998ec3..ef40798c1d 100644 --- a/cloudflare-gastown/container/plugin/types.ts +++ b/cloudflare-gastown/container/plugin/types.ts @@ -97,7 +97,8 @@ export type SlingBatchResult = { export type Convoy = { id: string; title: string; - status: 'active' | 'landed'; + status: 'active' | 'staged' | 'landed'; + staged: boolean; total_beads: number; closed_beads: number; created_by: string | null; @@ -105,6 +106,12 @@ export type Convoy = { landed_at: string | null; }; +// Result returned by POST /convoys/:id/start +export type ConvoyStartResult = { + convoy: Convoy; + beads: Array<{ bead: Bead; agent: Agent }>; +}; + // Detailed convoy status with per-bead breakdown export type ConvoyDetail = Convoy & { beads: Array<{ diff --git a/cloudflare-gastown/src/db/tables/convoy-metadata.table.ts b/cloudflare-gastown/src/db/tables/convoy-metadata.table.ts index 5ef4d8ea11..063bd1fe60 100644 --- a/cloudflare-gastown/src/db/tables/convoy-metadata.table.ts +++ b/cloudflare-gastown/src/db/tables/convoy-metadata.table.ts @@ -19,6 +19,8 @@ export const ConvoyMetadataRecord = z.object({ * individually, like standalone beads. */ merge_mode: ConvoyMergeMode.nullable(), + /** 1 = staged (planned, agents not dispatched), 0 = active (SQLite boolean) */ + staged: z.number().int().default(0), }); export type ConvoyMetadataRecord = z.output; @@ -32,7 +34,8 @@ export function createTableConvoyMetadata(): string { closed_beads: `integer not null default 0`, landed_at: `text`, feature_branch: `text`, - merge_mode: `text`, + merge_mode: `text check(merge_mode in ('review-then-land', 'review-and-merge'))`, + staged: `integer not null default 0`, }); } @@ -40,6 +43,7 @@ export function createTableConvoyMetadata(): string { export function migrateConvoyMetadata(): string[] { return [ `ALTER TABLE convoy_metadata ADD COLUMN feature_branch text`, - `ALTER TABLE convoy_metadata ADD COLUMN merge_mode text`, + `ALTER TABLE convoy_metadata ADD COLUMN merge_mode text check(merge_mode in ('review-then-land', 'review-and-merge'))`, + `ALTER TABLE convoy_metadata ADD COLUMN staged integer not null default 0`, ]; } diff --git a/cloudflare-gastown/src/dos/Town.do.ts b/cloudflare-gastown/src/dos/Town.do.ts index 2fabe00121..ef48fb3f11 100644 --- a/cloudflare-gastown/src/dos/Town.do.ts +++ b/cloudflare-gastown/src/dos/Town.do.ts @@ -171,6 +171,7 @@ type ConvoyEntry = { id: string; title: string; status: 'active' | 'landed'; + staged: boolean; total_beads: number; closed_beads: number; created_by: string | null; @@ -185,6 +186,7 @@ function toConvoy(row: ConvoyBeadRecord): ConvoyEntry { id: row.bead_id, title: row.title, status: row.status === 'closed' ? 'landed' : 'active', + staged: row.staged === 1, total_beads: row.total_beads, closed_beads: row.closed_beads, created_by: row.created_by, @@ -199,7 +201,7 @@ const CONVOY_JOIN = /* sql */ ` SELECT ${beads}.*, ${convoy_metadata.total_beads}, ${convoy_metadata.closed_beads}, ${convoy_metadata.landed_at}, ${convoy_metadata.feature_branch}, - ${convoy_metadata.merge_mode} + ${convoy_metadata.merge_mode}, ${convoy_metadata.staged} FROM ${beads} INNER JOIN ${convoy_metadata} ON ${beads.bead_id} = ${convoy_metadata.bead_id} `; @@ -1849,7 +1851,8 @@ export class TownDO extends DurableObject { convoyTitle: string; tasks: Array<{ title: string; body?: string; depends_on?: number[] }>; merge_mode?: 'review-then-land' | 'review-and-merge'; - }): Promise<{ convoy: ConvoyEntry; beads: Array<{ bead: Bead; agent: Agent }> }> { + staged?: boolean; + }): Promise<{ convoy: ConvoyEntry; beads: Array<{ bead: Bead; agent: Agent | null }> }> { await this.ensureInitialized(); const convoyId = generateId(); @@ -1941,21 +1944,24 @@ export class TownDO extends DurableObject { const mergeMode = input.merge_mode ?? 'review-then-land'; + const stagedValue = input.staged ? 1 : 0; + query( this.sql, /* sql */ ` INSERT INTO ${convoy_metadata} ( ${convoy_metadata.columns.bead_id}, ${convoy_metadata.columns.total_beads}, ${convoy_metadata.columns.closed_beads}, ${convoy_metadata.columns.landed_at}, - ${convoy_metadata.columns.feature_branch}, ${convoy_metadata.columns.merge_mode} - ) VALUES (?, ?, ?, ?, ?, ?) + ${convoy_metadata.columns.feature_branch}, ${convoy_metadata.columns.merge_mode}, + ${convoy_metadata.columns.staged} + ) VALUES (?, ?, ?, ?, ?, ?, ?) `, - [convoyId, input.tasks.length, 0, null, featureBranch, mergeMode] + [convoyId, input.tasks.length, 0, null, featureBranch, mergeMode, stagedValue] ); // 2. Create all beads and track their IDs (needed for depends_on resolution) const beadIds: string[] = []; - const results: Array<{ bead: Bead; agent: Agent }> = []; + const results: Array<{ bead: Bead; agent: Agent | null }> = []; for (const task of input.tasks) { const createdBead = beadOps.createBead(this.sql, { @@ -2002,24 +2008,109 @@ export class TownDO extends DurableObject { } } - // 4. For each bead: assign a polecat, but only dispatch if unblocked - for (let i = 0; i < beadIds.length; i++) { - const beadId = beadIds[i]; - const agent = agents.getOrCreateAgent(this.sql, 'polecat', input.rigId, this.townId); - agents.hookBead(this.sql, agent.id, beadId); + if (input.staged) { + // Staged mode: collect beads without hooking agents or dispatching. + for (const beadId of beadIds) { + const bead = beadOps.getBead(this.sql, beadId); + if (!bead) continue; + results.push({ bead, agent: null }); + } + } else { + // 4. For each bead: assign a polecat, but only dispatch if unblocked + for (let i = 0; i < beadIds.length; i++) { + const beadId = beadIds[i]; + const agent = agents.getOrCreateAgent(this.sql, 'polecat', input.rigId, this.townId); + agents.hookBead(this.sql, agent.id, beadId); + + const bead = beadOps.getBead(this.sql, beadId); + const hookedAgent = agents.getAgent(this.sql, agent.id) ?? agent; + if (!bead) continue; + + // Only dispatch beads with no unresolved blockers + if (!beadOps.hasUnresolvedBlockers(this.sql, beadId)) { + this.dispatchAgent(hookedAgent, bead).catch(err => + console.error(`${TOWN_LOG} slingConvoy: fire-and-forget dispatchAgent failed:`, err) + ); + } else { + console.log( + `${TOWN_LOG} slingConvoy: bead=${beadId} blocked, deferring dispatch until deps close` + ); + } + + results.push({ bead, agent: hookedAgent }); + } + + await this.armAlarmIfNeeded(); + } + + const convoy = this.getConvoy(convoyId); + if (!convoy) throw new Error('Failed to create convoy'); + return { convoy, beads: results }; + } + + /** + * Transition a staged convoy to active: hook agents and begin dispatch. + */ + async startConvoy( + convoyId: string + ): Promise<{ convoy: ConvoyEntry; beads: Array<{ bead: Bead; agent: Agent }> }> { + await this.ensureInitialized(); + + const convoy = this.getConvoy(convoyId); + if (!convoy) throw new Error(`Convoy not found: ${convoyId}`); + if (!convoy.staged) throw new Error(`Convoy is not staged: ${convoyId}`); + + // Mark convoy as active + query( + this.sql, + /* sql */ ` + UPDATE ${convoy_metadata} + SET ${convoy_metadata.columns.staged} = 0 + WHERE ${convoy_metadata.bead_id} = ? + `, + [convoyId] + ); + // Find all beads tracked by this convoy + const trackedRows = [ + ...query( + this.sql, + /* sql */ ` + SELECT ${bead_dependencies.bead_id} + FROM ${bead_dependencies} + WHERE ${bead_dependencies.depends_on_bead_id} = ? + AND ${bead_dependencies.dependency_type} = 'tracks' + `, + [convoyId] + ), + ]; + + const BeadIdRow = z.object({ bead_id: z.string() }); + const trackedBeadIds = BeadIdRow.array() + .parse(trackedRows) + .map(r => r.bead_id); + + const results: Array<{ bead: Bead; agent: Agent }> = []; + + for (const beadId of trackedBeadIds) { const bead = beadOps.getBead(this.sql, beadId); - const hookedAgent = agents.getAgent(this.sql, agent.id) ?? agent; if (!bead) continue; - // Only dispatch beads with no unresolved blockers + const rigId = bead.rig_id; + if (!rigId) continue; + + const agent = agents.getOrCreateAgent(this.sql, 'polecat', rigId, this.townId); + agents.hookBead(this.sql, agent.id, beadId); + + const hookedAgent = agents.getAgent(this.sql, agent.id) ?? agent; + if (!beadOps.hasUnresolvedBlockers(this.sql, beadId)) { this.dispatchAgent(hookedAgent, bead).catch(err => - console.error(`${TOWN_LOG} slingConvoy: fire-and-forget dispatchAgent failed:`, err) + console.error(`${TOWN_LOG} startConvoy: fire-and-forget dispatchAgent failed:`, err) ); } else { console.log( - `${TOWN_LOG} slingConvoy: bead=${beadId} blocked, deferring dispatch until deps close` + `${TOWN_LOG} startConvoy: bead=${beadId} blocked, deferring dispatch until deps close` ); } @@ -2028,14 +2119,14 @@ export class TownDO extends DurableObject { await this.armAlarmIfNeeded(); - const convoy = this.getConvoy(convoyId); - if (!convoy) throw new Error('Failed to create convoy'); + const updatedConvoy = this.getConvoy(convoyId); + if (!updatedConvoy) throw new Error(`Failed to re-fetch convoy after start: ${convoyId}`); this.emitEvent({ event: 'convoy.created', townId: this.townId, convoyId, }); - return { convoy, beads: results }; + return { convoy: updatedConvoy, beads: results }; } /** diff --git a/cloudflare-gastown/src/gastown.worker.ts b/cloudflare-gastown/src/gastown.worker.ts index 09c72f98ec..343aaea4f2 100644 --- a/cloudflare-gastown/src/gastown.worker.ts +++ b/cloudflare-gastown/src/gastown.worker.ts @@ -95,6 +95,7 @@ import { handleMayorConvoyUpdate, handleMayorBeadDelete, handleMayorEscalationAcknowledge, + handleMayorConvoyStart, } from './handlers/mayor-tools.handler'; import { mayorAuthMiddleware } from './middleware/mayor-auth.middleware'; import { timingMiddleware, instrumented } from './middleware/analytics.middleware'; @@ -656,6 +657,9 @@ app.post('/api/mayor/:townId/tools/escalations/:escalationId/acknowledge', c => handleMayorEscalationAcknowledge(c, c.req.param()) ) ); +app.post('/api/mayor/:townId/tools/convoys/:convoyId/start', c => + handleMayorConvoyStart(c, c.req.param()) +); // ── tRPC ──────────────────────────────────────────────────────────────── // Serve the gastown tRPC router directly. The frontend tRPC client diff --git a/cloudflare-gastown/src/handlers/mayor-tools.handler.ts b/cloudflare-gastown/src/handlers/mayor-tools.handler.ts index 208cc80482..76128b879e 100644 --- a/cloudflare-gastown/src/handlers/mayor-tools.handler.ts +++ b/cloudflare-gastown/src/handlers/mayor-tools.handler.ts @@ -35,6 +35,7 @@ const MayorSlingBatchBody = z merge_mode: z.enum(['review-then-land', 'review-and-merge']).optional(), /** Set to true only when ALL tasks are genuinely independent (no shared files, no shared state). */ parallel: z.boolean().optional(), + staged: z.boolean().optional(), }) .superRefine((data, ctx) => { // Require dependency graph unless explicitly opted out with parallel: true. @@ -288,6 +289,7 @@ export async function handleMayorSlingBatch(c: Context, params: { to convoyTitle: parsed.data.convoy_title, tasks: parsed.data.tasks, merge_mode: parsed.data.merge_mode, + staged: parsed.data.staged, }); console.log( @@ -602,3 +604,34 @@ export async function handleMayorEscalationAcknowledge( if (!escalation) return c.json(resError('Escalation not found'), 404); return c.json(resSuccess(escalation)); } + +/** + * POST /api/mayor/:townId/tools/convoys/:convoyId/start + * Transition a staged convoy to active: hook agents and begin dispatch. + */ +export async function handleMayorConvoyStart( + c: Context, + params: { townId: string; convoyId: string } +) { + console.log( + `${HANDLER_LOG} handleMayorConvoyStart: townId=${params.townId} convoyId=${params.convoyId}` + ); + + const town = getTownDOStub(c.env, params.townId); + let result: Awaited>; + try { + result = await town.startConvoy(params.convoyId); + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + if (message.includes('not found') || message.includes('not staged')) { + return c.json(resError('Convoy not found or not staged'), 404); + } + throw err; + } + + console.log( + `${HANDLER_LOG} handleMayorConvoyStart: completed, convoy=${result.convoy.id} beads=${result.beads.length}` + ); + + return c.json(resSuccess(result)); +} diff --git a/cloudflare-gastown/src/prompts/mayor-system.prompt.ts b/cloudflare-gastown/src/prompts/mayor-system.prompt.ts index 9def1750ed..714278c4ad 100644 --- a/cloudflare-gastown/src/prompts/mayor-system.prompt.ts +++ b/cloudflare-gastown/src/prompts/mayor-system.prompt.ts @@ -26,9 +26,11 @@ Your #1 purpose is to turn user requests into actionable work items. Every time You have these tools for cross-rig coordination: - **gt_sling** — Delegate a single task to a polecat in a specific rig. Use for one-off tasks. -- **gt_sling_batch** — YOUR MOST IMPORTANT TOOL. Sling multiple beads as a tracked convoy. Use this when breaking work into parallel sub-tasks. Creates all beads at once, groups them into a convoy for progress tracking, and dispatches polecats automatically. Accepts an optional \`merge_mode\`: + - **gt_sling_batch** — YOUR MOST IMPORTANT TOOL. Sling multiple beads as a tracked convoy. Use this when breaking work into parallel sub-tasks. Creates all beads at once, groups them into a convoy for progress tracking, and dispatches polecats automatically. Accepts an optional \`merge_mode\`: - **"review-then-land"** (default): Each bead is reviewed by the refinery and merged into the convoy's feature branch. Only at the very end does a PR or merge to main occur. Best for tightly coupled tasks that build on each other. - **"review-and-merge"**: Each bead goes through the full review + merge/PR cycle independently. Best for loosely coupled tasks where each can land on its own. + - Accepts an optional \`staged\` boolean. When \`staged: true\`, creates the convoy and beads without dispatching agents — a plan for review. See the Staged Convoys section below. +- **gt_convoy_start** — Start a staged convoy. Transitions it from staged (planned, no agents) to active: hooks agents to all tracked beads and begins dispatch. Call this when the user approves a staged plan. - **gt_list_rigs** — List all rigs in your town. Returns rig ID, name, git URL, and default branch. Call this first when you need to know what repositories are available. - **gt_list_beads** — List beads (work items) in a rig. Filter by status or type. Use this to check progress, find open work, or review completed tasks. - **gt_list_agents** — List agents in a rig. Shows who is working, idle, or stuck. Use this to understand workforce capacity. @@ -221,6 +223,24 @@ Use these tools when the user reports stuck state, when you detect problems duri - You maintain context across messages. This is a continuous conversation. - Never fabricate rig IDs or agent IDs. Always use gt_list_rigs to discover real IDs. - If no rigs exist, tell the user they need to create one first. -- If a task spans multiple rigs, create separate slings for each rig. -- ALWAYS sling when the user requests work. Describing what you would do without actually slinging is a failure mode. Prefer gt_sling_batch for multi-task requests.`; + - If a task spans multiple rigs, create separate slings for each rig. + - ALWAYS sling when the user requests work. Describing what you would do without actually slinging is a failure mode. Prefer gt_sling_batch for multi-task requests. + +## Staged Convoys + +When the user asks you to plan or prepare work (but not start it immediately), +use gt_sling_batch with staged=true. This creates the convoy and beads without +dispatching agents — it's a plan for review. + +After creating a staged convoy, tell the user: +- The convoy title and number of beads +- A brief description of the plan +- That they can review the beads and say "start it" or "go" when ready + +When the user says "go", "start it", "kick it off", or similar for a staged +convoy, call gt_convoy_start with the convoy_id. + +For large convoys (>5 beads) where the decomposition is non-obvious, consider +using staged=true by default to give the user a chance to review before agents +start spending compute.`; } diff --git a/cloudflare-gastown/src/ui/dashboard.ui.ts b/cloudflare-gastown/src/ui/dashboard.ui.ts index b45f5c432c..145caf62ec 100644 --- a/cloudflare-gastown/src/ui/dashboard.ui.ts +++ b/cloudflare-gastown/src/ui/dashboard.ui.ts @@ -58,6 +58,7 @@ export function dashboardHtml(): string { padding: 4px 8px; border-radius: 4px; font-family: inherit; font-size: 12px; width: 100%; min-height: 80px; resize: vertical; } textarea.body-edit:focus { border-color: #58a6ff; outline: none; } + .badge.staged { background: #21262d; color: #8b949e; border: 1px dashed #30363d; } .empty { color: #484f58; font-style: italic; } #toast { position: fixed; bottom: 16px; right: 16px; background: #1f6feb; color: #fff; padding: 8px 16px; border-radius: 6px; font-size: 12px; @@ -363,6 +364,19 @@ export function dashboardHtml(): string {
+ +
+

Convoys

+
+ + + + + +
+
+
+

API Log

@@ -1058,6 +1072,85 @@ async function containerSendMessage() { if (r.ok) { el('cMessage').value = ''; toast('Message sent'); } } +// ── Convoys ────────────────────────────────────────────────────────── + +async function loadConvoys() { + const convoyTownId = el('convoyTownId').value.trim(); + if (!convoyTownId) { toast('Set a Town ID first', true); return; } + const mayorToken = el('mayorToken').value.trim(); + const log = el('apiLog'); + const path = '/api/mayor/' + convoyTownId + '/tools/convoys'; + log.innerHTML += 'GET ' + esc(path) + '\\n'; + try { + const res = await fetch(path, { + headers: { 'Authorization': 'Bearer ' + mayorToken, 'Content-Type': 'application/json' }, + }); + const data = await res.json(); + const cls = res.ok ? 'ok' : 'err'; + log.innerHTML += '' + res.status + ' ' + + esc(JSON.stringify(data, null, 2)) + '\\n\\n'; + log.scrollTop = log.scrollHeight; + if (!res.ok) { toast(data.error || res.status, true); return; } + renderConvoys(data.data || [], convoyTownId); + } catch (e) { + log.innerHTML += 'FETCH ERROR: ' + esc(e.message) + '\\n\\n'; + toast(e.message, true); + } +} + +function renderConvoys(convoys, convoyTownId) { + if (!convoys.length) { el('convoysList').innerHTML = '

No convoys

'; return; } + let h = ''; + for (const c of convoys) { + const isStaged = c.staged === true; + const statusBadge = isStaged + ? 'STAGED' + : '' + (c.status || 'open') + ''; + const progress = (c.closed_beads != null && c.total_beads != null) + ? c.closed_beads + '/' + c.total_beads + : '—'; + h += '' + + '' + + '' + + '' + + '' + + '' + + ''; + } + h += '
IDTitleStatusBeads
' + short(c.convoy_id) + '' + esc(c.title || '—') + '' + statusBadge + '' + progress + '' + + (isStaged ? '' : '') + + '
'; + el('convoysList').innerHTML = h; +} + +async function startConvoy(convoyId, convoyTownId) { + const mayorToken = el('mayorToken').value.trim(); + const log = el('apiLog'); + const path = '/api/mayor/' + convoyTownId + '/tools/convoys/' + convoyId + '/start'; + log.innerHTML += 'POST ' + esc(path) + '\\n'; + try { + const res = await fetch(path, { + method: 'POST', + headers: { 'Authorization': 'Bearer ' + mayorToken, 'Content-Type': 'application/json' }, + body: '{}', + }); + const data = await res.json(); + const cls = res.ok ? 'ok' : 'err'; + log.innerHTML += '' + res.status + ' ' + + esc(JSON.stringify(data, null, 2)) + '\\n\\n'; + log.scrollTop = log.scrollHeight; + if (data.success) { + toast('Convoy ' + convoyId.slice(0, 8) + ' started'); + loadConvoys(); + } else { + toast('Error: ' + (data.error || 'unknown'), true); + } + } catch (e) { + log.innerHTML += 'FETCH ERROR: ' + esc(e.message) + '\\n\\n'; + toast(e.message, true); + } +} + // ── Helpers ───────────────────────────────────────────────────────── function copyId(id) { From c57b9a294cf149c48cd1aef5292fce31ab95f84c Mon Sep 17 00:00:00 2001 From: John Fawcett Date: Sat, 14 Mar 2026 14:57:02 -0500 Subject: [PATCH 2/9] fix(gastown): resolve TS2589 deep type instantiation in handleMayorConvoyStart --- cloudflare-gastown/src/handlers/mayor-tools.handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudflare-gastown/src/handlers/mayor-tools.handler.ts b/cloudflare-gastown/src/handlers/mayor-tools.handler.ts index 76128b879e..bbeb882d5d 100644 --- a/cloudflare-gastown/src/handlers/mayor-tools.handler.ts +++ b/cloudflare-gastown/src/handlers/mayor-tools.handler.ts @@ -618,7 +618,7 @@ export async function handleMayorConvoyStart( ); const town = getTownDOStub(c.env, params.townId); - let result: Awaited>; + let result: { convoy: { id: string }; beads: unknown[] }; try { result = await town.startConvoy(params.convoyId); } catch (err) { From 074734eca887fccd8dcabb9d8b1d57d7f2776310 Mon Sep 17 00:00:00 2001 From: John Fawcett Date: Sat, 14 Mar 2026 17:55:45 -0500 Subject: [PATCH 3/9] fix(gastown): handle null agents in staged convoys and exclude staged convoys from deacon patrol SlingBatchResult.agent is null for staged convoys since agents aren't assigned until gt_convoy_start. The gt_sling_batch tool now handles this gracefully instead of crashing on b.agent.name. feedStrandedConvoys now joins convoy_metadata and filters on staged=0 so the deacon patrol doesn't auto-assign agents to staged convoy beads. --- cloudflare-gastown/container/plugin/mayor-tools.test.ts | 5 +++-- cloudflare-gastown/container/plugin/mayor-tools.ts | 9 +++++++-- cloudflare-gastown/container/plugin/types.ts | 3 ++- cloudflare-gastown/src/dos/town/patrol.ts | 9 +++++++-- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/cloudflare-gastown/container/plugin/mayor-tools.test.ts b/cloudflare-gastown/container/plugin/mayor-tools.test.ts index e1bd7a35df..0116b135e8 100644 --- a/cloudflare-gastown/container/plugin/mayor-tools.test.ts +++ b/cloudflare-gastown/container/plugin/mayor-tools.test.ts @@ -376,11 +376,11 @@ describe('mayor tools', () => { beads: [ { bead: { ...FAKE_BEAD, bead_id: 'bead-1', title: 'Task 1' }, - agent: { ...FAKE_AGENT, id: 'agent-1', name: 'Toast' }, + agent: null, }, { bead: { ...FAKE_BEAD, bead_id: 'bead-2', title: 'Task 2' }, - agent: { ...FAKE_AGENT, id: 'agent-2', name: 'Muffin' }, + agent: null, }, ], }), @@ -396,6 +396,7 @@ describe('mayor tools', () => { expect(result).toContain('Convoy staged:'); expect(result).toContain('convoy-staged-1'); expect(result).toContain('gt_convoy_start'); + expect(result).toContain('unassigned, pending gt_convoy_start'); expect(client.slingBatch).toHaveBeenCalledWith(expect.objectContaining({ staged: true })); }); }); diff --git a/cloudflare-gastown/container/plugin/mayor-tools.ts b/cloudflare-gastown/container/plugin/mayor-tools.ts index 80b07c35d4..2c1a82b5ad 100644 --- a/cloudflare-gastown/container/plugin/mayor-tools.ts +++ b/cloudflare-gastown/container/plugin/mayor-tools.ts @@ -189,8 +189,13 @@ export function createMayorTools(client: MayorGastownClient) { }); const beadLines = result.beads.map( - (b: { bead: { title: string }; agent: { name: string; id: string } }, i: number) => - ` ${i + 1}. "${b.bead.title}" → ${b.agent.name} (${b.agent.id})` + ( + b: { bead: { title: string }; agent: { name: string; id: string } | null }, + i: number + ) => + b.agent + ? ` ${i + 1}. "${b.bead.title}" → ${b.agent.name} (${b.agent.id})` + : ` ${i + 1}. "${b.bead.title}" (unassigned, pending gt_convoy_start)` ); const mode = args.merge_mode ?? 'review-then-land'; const staged = args.staged === true; diff --git a/cloudflare-gastown/container/plugin/types.ts b/cloudflare-gastown/container/plugin/types.ts index ef40798c1d..892d4bd56c 100644 --- a/cloudflare-gastown/container/plugin/types.ts +++ b/cloudflare-gastown/container/plugin/types.ts @@ -88,9 +88,10 @@ export type SlingResult = { }; // Sling batch result (convoy + beads + agents) +// agent is null for staged convoys (agents aren't assigned until gt_convoy_start) export type SlingBatchResult = { convoy: Convoy; - beads: Array<{ bead: Bead; agent: Agent }>; + beads: Array<{ bead: Bead; agent: Agent | null }>; }; // Convoy summary (returned by list and status endpoints) diff --git a/cloudflare-gastown/src/dos/town/patrol.ts b/cloudflare-gastown/src/dos/town/patrol.ts index b7e6298a4a..f434a9a815 100644 --- a/cloudflare-gastown/src/dos/town/patrol.ts +++ b/cloudflare-gastown/src/dos/town/patrol.ts @@ -12,6 +12,7 @@ import { z } from 'zod'; import { beads, BeadRecord as BeadRecordSchema } from '../../db/tables/beads.table'; import { agent_metadata, AgentMetadataRecord } from '../../db/tables/agent-metadata.table'; import { bead_dependencies } from '../../db/tables/bead-dependencies.table'; +import { convoy_metadata } from '../../db/tables/convoy-metadata.table'; import { query } from '../../util/query.util'; import { sendMail } from './mail'; import { deleteAgent, getOrCreateAgent, hookBead, unhookBead } from './agents'; @@ -501,8 +502,10 @@ export function detectStaleHooks(sql: SqlStorage): void { } /** - * Feed stranded convoys: find active convoys that have open beads with - * no assigned agent. Auto-sling by assigning idle polecats. + * Feed stranded convoys: find active (non-staged) convoys that have open + * beads with no assigned agent. Auto-sling by assigning idle polecats. + * Staged convoys are excluded — their beads remain unassigned until + * the convoy is explicitly started via startConvoy(). */ export function feedStrandedConvoys(sql: SqlStorage, townId: string): void { // Find open issue beads that: @@ -524,9 +527,11 @@ export function feedStrandedConvoys(sql: SqlStorage, townId: string): void { FROM ${bead_dependencies} INNER JOIN ${beads} ON ${bead_dependencies.bead_id} = ${beads.bead_id} INNER JOIN ${beads} AS convoy ON ${bead_dependencies.depends_on_bead_id} = convoy.${beads.columns.bead_id} + INNER JOIN ${convoy_metadata} ON ${convoy_metadata.bead_id} = convoy.${beads.columns.bead_id} WHERE ${bead_dependencies.dependency_type} = 'tracks' AND convoy.${beads.columns.type} = 'convoy' AND convoy.${beads.columns.status} = 'open' + AND ${convoy_metadata.staged} = 0 AND ${beads.status} = 'open' AND ${beads.type} = 'issue' AND ${beads.assignee_agent_bead_id} IS NULL From 518e3f6c937d6581ee7c9eff2ddae9a7da98bed4 Mon Sep 17 00:00:00 2001 From: John Fawcett Date: Sat, 14 Mar 2026 18:08:23 -0500 Subject: [PATCH 4/9] feat(gastown): add convoy drawer UI with staged indicator and start button - Add staged field to ConvoyOutput tRPC schema - Add startConvoy tRPC mutation - Add convoy ResourceRef type to DrawerStack - Create ConvoyPanel drawer with DAG wave layout, metadata, and start button - Update ConvoyTimeline with staged badge, clickable title to open drawer, and inline start button for staged convoys - Wire startConvoy mutation in TownOverviewPageClient and RigDetailPageClient - Fix convoy_id -> id field in dashboard.ui.ts (PR review comment) - Regenerate gastown tRPC type declarations --- cloudflare-gastown/src/trpc/router.ts | 16 + cloudflare-gastown/src/trpc/schemas.ts | 1 + cloudflare-gastown/src/ui/dashboard.ui.ts | 4 +- .../[townId]/TownOverviewPageClient.tsx | 13 + .../rigs/[rigId]/RigDetailPageClient.tsx | 13 + src/components/gastown/ConvoyTimeline.tsx | 40 +- src/components/gastown/DrawerStack.tsx | 3 +- src/components/gastown/DrawerStackContent.tsx | 5 + .../gastown/drawer-panels/ConvoyPanel.tsx | 356 +++ src/lib/gastown/types/router.d.ts | 2665 ++++++++--------- src/lib/gastown/types/schemas.d.ts | 1274 ++++---- 11 files changed, 2229 insertions(+), 2161 deletions(-) create mode 100644 src/components/gastown/drawer-panels/ConvoyPanel.tsx diff --git a/cloudflare-gastown/src/trpc/router.ts b/cloudflare-gastown/src/trpc/router.ts index 2a0dbc954b..abfd81f2a3 100644 --- a/cloudflare-gastown/src/trpc/router.ts +++ b/cloudflare-gastown/src/trpc/router.ts @@ -645,6 +645,22 @@ export const gastownRouter = router({ return status ?? { ...convoy, beads: [] }; }), + startConvoy: gastownProcedure + .input( + z.object({ + townId: z.string().uuid(), + convoyId: z.string().uuid(), + }) + ) + .output(RpcConvoyDetailOutput.nullable()) + .mutation(async ({ ctx, input }) => { + await verifyTownOwnership(ctx.env, ctx.userId, input.townId); + const townStub = getTownDOStub(ctx.env, input.townId); + await townStub.startConvoy(input.convoyId); + const status = await townStub.getConvoyStatus(input.convoyId); + return status ?? null; + }), + // ── Admin-only routes (bypass ownership checks) ────────────────────── adminListBeads: adminProcedure diff --git a/cloudflare-gastown/src/trpc/schemas.ts b/cloudflare-gastown/src/trpc/schemas.ts index 584d54817d..a71c07ffe5 100644 --- a/cloudflare-gastown/src/trpc/schemas.ts +++ b/cloudflare-gastown/src/trpc/schemas.ts @@ -118,6 +118,7 @@ export const ConvoyOutput = z.object({ id: z.string(), title: z.string(), status: z.enum(['active', 'landed']), + staged: z.boolean(), total_beads: z.number(), closed_beads: z.number(), created_by: z.string().nullable(), diff --git a/cloudflare-gastown/src/ui/dashboard.ui.ts b/cloudflare-gastown/src/ui/dashboard.ui.ts index 145caf62ec..74d5298f59 100644 --- a/cloudflare-gastown/src/ui/dashboard.ui.ts +++ b/cloudflare-gastown/src/ui/dashboard.ui.ts @@ -1110,12 +1110,12 @@ function renderConvoys(convoys, convoyTownId) { ? c.closed_beads + '/' + c.total_beads : '—'; h += '' - + '' + short(c.convoy_id) + '' + + '' + short(c.id) + '' + '' + esc(c.title || '—') + '' + '' + statusBadge + '' + '' + progress + '' + '' - + (isStaged ? '' : '') + + (isStaged ? '' : '') + '' + ''; } diff --git a/src/app/(app)/gastown/[townId]/TownOverviewPageClient.tsx b/src/app/(app)/gastown/[townId]/TownOverviewPageClient.tsx index 1699e351e4..40c5fcfdcf 100644 --- a/src/app/(app)/gastown/[townId]/TownOverviewPageClient.tsx +++ b/src/app/(app)/gastown/[townId]/TownOverviewPageClient.tsx @@ -108,6 +108,17 @@ export function TownOverviewPageClient({ townId }: TownOverviewPageClientProps) onError: err => toast.error(err.message), }) ); + const startConvoyMutation = useMutation( + trpc.gastown.startConvoy.mutationOptions({ + onSuccess: () => { + void queryClient.invalidateQueries({ + queryKey: trpc.gastown.listConvoys.queryKey({ townId }), + }); + toast.success('Convoy started'); + }, + onError: err => toast.error(err.message), + }) + ); const rigs = rigsQuery.data ?? []; const events = townEventsQuery.data ?? []; @@ -335,7 +346,9 @@ export function TownOverviewPageClient({ townId }: TownOverviewPageClientProps) onSelectBead={(beadId, rigId) => { if (rigId) openDrawer({ type: 'bead', beadId, rigId }); }} + onSelectConvoy={convoyId => openDrawer({ type: 'convoy', convoyId, townId })} onCloseConvoy={convoyId => closeConvoyMutation.mutate({ townId, convoyId })} + onStartConvoy={convoyId => startConvoyMutation.mutate({ townId, convoyId })} />
diff --git a/src/app/(app)/gastown/[townId]/rigs/[rigId]/RigDetailPageClient.tsx b/src/app/(app)/gastown/[townId]/rigs/[rigId]/RigDetailPageClient.tsx index fd9b81e282..649e36418d 100644 --- a/src/app/(app)/gastown/[townId]/rigs/[rigId]/RigDetailPageClient.tsx +++ b/src/app/(app)/gastown/[townId]/rigs/[rigId]/RigDetailPageClient.tsx @@ -77,6 +77,17 @@ export function RigDetailPageClient({ townId, rigId }: RigDetailPageClientProps) onError: err => toast.error(err.message), }) ); + const startConvoyMutation = useMutation( + trpc.gastown.startConvoy.mutationOptions({ + onSuccess: () => { + void queryClient.invalidateQueries({ + queryKey: trpc.gastown.listConvoys.queryKey({ townId }), + }); + toast.success('Convoy started'); + }, + onError: err => toast.error(err.message), + }) + ); const beads = beadsQuery.data ?? []; const agents = agentsQuery.data ?? []; @@ -160,7 +171,9 @@ export function RigDetailPageClient({ townId, rigId }: RigDetailPageClientProps) onSelectBead={(beadId, beadRigId) => openDrawer({ type: 'bead', beadId, rigId: beadRigId ?? rigId }) } + onSelectConvoy={convoyId => openDrawer({ type: 'convoy', convoyId, townId })} onCloseConvoy={convoyId => closeConvoyMutation.mutate({ townId, convoyId })} + onStartConvoy={convoyId => startConvoyMutation.mutate({ townId, convoyId })} /> diff --git a/src/components/gastown/ConvoyTimeline.tsx b/src/components/gastown/ConvoyTimeline.tsx index 840c178438..184e0e2350 100644 --- a/src/components/gastown/ConvoyTimeline.tsx +++ b/src/components/gastown/ConvoyTimeline.tsx @@ -2,7 +2,7 @@ import { useState, useMemo } from 'react'; import type { GastownOutputs } from '@/lib/gastown/trpc'; -import { CheckCircle, GitBranch, Loader2, X, ArrowRight } from 'lucide-react'; +import { CheckCircle, GitBranch, Loader2, X, ArrowRight, Play } from 'lucide-react'; import { motion, AnimatePresence } from 'motion/react'; type ConvoyDetail = GastownOutputs['gastown']['listConvoys'][number]; @@ -13,7 +13,9 @@ export type ConvoyTimelineProps = { convoys: ConvoyDetail[]; collapsed?: boolean; onSelectBead?: (beadId: string, rigId: string | null) => void; + onSelectConvoy?: (convoyId: string) => void; onCloseConvoy?: (convoyId: string) => void; + onStartConvoy?: (convoyId: string) => void; }; const STATUS_COLORS: Record = { @@ -105,7 +107,9 @@ export function ConvoyTimeline({ convoys, collapsed = false, onSelectBead, + onSelectConvoy, onCloseConvoy, + onStartConvoy, }: ConvoyTimelineProps) { if (convoys.length === 0) { return null; @@ -125,7 +129,9 @@ export function ConvoyTimeline({ key={convoy.id} convoy={convoy} onSelectBead={onSelectBead} + onSelectConvoy={onSelectConvoy ? () => onSelectConvoy(convoy.id) : undefined} onClose={onCloseConvoy ? () => onCloseConvoy(convoy.id) : undefined} + onStart={convoy.staged && onStartConvoy ? () => onStartConvoy(convoy.id) : undefined} /> ))} @@ -137,13 +143,18 @@ export function ConvoyTimeline({ function ConvoyCard({ convoy, onSelectBead, + onSelectConvoy, onClose, + onStart, }: { convoy: ConvoyDetail; onSelectBead?: (beadId: string, rigId: string | null) => void; + onSelectConvoy?: () => void; onClose?: () => void; + onStart?: () => void; }) { const [confirming, setConfirming] = useState(false); + const isStaged = 'staged' in convoy && convoy.staged === true; const progress = convoy.total_beads > 0 ? convoy.closed_beads / convoy.total_beads : 0; const waves = useMemo( @@ -154,19 +165,24 @@ function ConvoyCard({ const hasDag = (convoy.dependency_edges ?? []).length > 0; return ( -
+
{/* Convoy header */}
- - CONVOY - + {isStaged ? 'STAGED' : 'CONVOY'} + + {convoy.feature_branch && (
+ {onStart && ( + + )} {convoy.closed_beads}/{convoy.total_beads} diff --git a/src/components/gastown/DrawerStack.tsx b/src/components/gastown/DrawerStack.tsx index e84776804e..e97ddbf120 100644 --- a/src/components/gastown/DrawerStack.tsx +++ b/src/components/gastown/DrawerStack.tsx @@ -10,7 +10,8 @@ import type { TownEvent } from './ActivityFeed'; export type ResourceRef = | { type: 'bead'; beadId: string; rigId: string } | { type: 'agent'; agentId: string; rigId: string; townId?: string } - | { type: 'event'; event: TownEvent }; + | { type: 'event'; event: TownEvent } + | { type: 'convoy'; convoyId: string; townId: string }; type DrawerStackEntry = { key: string; diff --git a/src/components/gastown/DrawerStackContent.tsx b/src/components/gastown/DrawerStackContent.tsx index 876b6f0fd8..5e21f3b70d 100644 --- a/src/components/gastown/DrawerStackContent.tsx +++ b/src/components/gastown/DrawerStackContent.tsx @@ -5,6 +5,7 @@ import type { ResourceRef } from './DrawerStack'; import { BeadPanel } from './drawer-panels/BeadPanel'; import { AgentPanel } from './drawer-panels/AgentPanel'; import { EventPanel } from './drawer-panels/EventPanel'; +import { ConvoyPanel } from './drawer-panels/ConvoyPanel'; /** * Dispatch function that maps a ResourceRef to the right panel component. @@ -29,5 +30,9 @@ export function renderDrawerContent( ); case 'event': return ; + case 'convoy': + return ( + + ); } } diff --git a/src/components/gastown/drawer-panels/ConvoyPanel.tsx b/src/components/gastown/drawer-panels/ConvoyPanel.tsx new file mode 100644 index 0000000000..6c30e9157a --- /dev/null +++ b/src/components/gastown/drawer-panels/ConvoyPanel.tsx @@ -0,0 +1,356 @@ +'use client'; + +import { useMemo } from 'react'; +import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; +import { useGastownTRPC } from '@/lib/gastown/trpc'; +import { Badge } from '@/components/ui/badge'; +import { Button } from '@/components/ui/button'; +import type { ResourceRef } from '@/components/gastown/DrawerStack'; + +import { format } from 'date-fns'; +import { + Layers, + GitBranch, + Clock, + Play, + CheckCircle, + Loader2, + ArrowRight, + Hexagon, + Hash, +} from 'lucide-react'; +import { toast } from 'sonner'; + +type ConvoyBead = { + bead_id: string; + title: string; + status: string; + rig_id: string | null; + assignee_agent_name: string | null; +}; + +type DependencyEdge = { + bead_id: string; + depends_on_bead_id: string; +}; + +const STATUS_STYLES: Record = { + open: 'border-sky-500/30 bg-sky-500/10 text-sky-300', + in_progress: 'border-amber-500/30 bg-amber-500/10 text-amber-300', + closed: 'border-emerald-500/30 bg-emerald-500/10 text-emerald-300', + failed: 'border-red-500/30 bg-red-500/10 text-red-300', +}; + +const STATUS_DOT_COLORS: Record = { + open: 'bg-sky-400', + in_progress: 'bg-amber-400', + closed: 'bg-emerald-400', + failed: 'bg-red-400', +}; + +/** + * Topological wave grouping via Kahn's algorithm. + * Wave 0 = no incoming edges, Wave N = all blockers in prior waves. + */ +function computeWaves(beadList: ConvoyBead[], edges: DependencyEdge[]): ConvoyBead[][] { + const beadIds = new Set(beadList.map(b => b.bead_id)); + const inDegree = new Map(); + const blockedBy = new Map(); + for (const b of beadList) { + inDegree.set(b.bead_id, 0); + blockedBy.set(b.bead_id, []); + } + for (const edge of edges) { + if (!beadIds.has(edge.bead_id) || !beadIds.has(edge.depends_on_bead_id)) continue; + inDegree.set(edge.bead_id, (inDegree.get(edge.bead_id) ?? 0) + 1); + blockedBy.get(edge.bead_id)?.push(edge.depends_on_bead_id); + } + + const beadById = new Map(beadList.map(b => [b.bead_id, b])); + const waves: ConvoyBead[][] = []; + const remaining = new Set(beadIds); + + while (remaining.size > 0) { + const wave: ConvoyBead[] = []; + for (const id of remaining) { + if ((inDegree.get(id) ?? 0) === 0) { + const bead = beadById.get(id); + if (bead) wave.push(bead); + } + } + if (wave.length === 0) { + const rest: ConvoyBead[] = []; + for (const id of remaining) { + const bead = beadById.get(id); + if (bead) rest.push(bead); + } + waves.push(rest); + break; + } + waves.push(wave); + for (const bead of wave) remaining.delete(bead.bead_id); + for (const id of remaining) { + const blockers = blockedBy.get(id) ?? []; + let newDeg = 0; + for (const dep of blockers) { + if (remaining.has(dep)) newDeg++; + } + inDegree.set(id, newDeg); + } + } + return waves; +} + +export function ConvoyPanel({ + convoyId, + townId, + push, +}: { + convoyId: string; + townId: string; + push: (ref: ResourceRef) => void; +}) { + const trpc = useGastownTRPC(); + const queryClient = useQueryClient(); + + const convoysQuery = useQuery({ + ...trpc.gastown.listConvoys.queryOptions({ townId }), + refetchInterval: 5_000, + }); + + const convoy = (convoysQuery.data ?? []).find(c => c.id === convoyId); + + const startConvoyMutation = useMutation( + trpc.gastown.startConvoy.mutationOptions({ + onSuccess: () => { + void queryClient.invalidateQueries({ + queryKey: trpc.gastown.listConvoys.queryKey({ townId }), + }); + toast.success('Convoy started'); + }, + onError: err => toast.error(err.message), + }) + ); + + const waves = useMemo( + () => computeWaves(convoy?.beads ?? [], convoy?.dependency_edges ?? []), + [convoy?.beads, convoy?.dependency_edges] + ); + + if (convoysQuery.isLoading) { + return ( +
+ +
+ ); + } + + if (!convoy) { + return
Convoy not found
; + } + + const progress = convoy.total_beads > 0 ? convoy.closed_beads / convoy.total_beads : 0; + const hasDag = (convoy.dependency_edges ?? []).length > 0; + + return ( +
+ {/* Header */} +
+
+ + Convoy + {convoy.staged && ( + + STAGED + + )} + {!convoy.staged && convoy.status === 'active' && ( + + ACTIVE + + )} + {convoy.status === 'landed' && ( + + LANDED + + )} +
+

{convoy.title}

+
+ + {/* Staged banner + start button */} + {convoy.staged && ( +
+
+ This convoy is staged — agents have not been dispatched yet. Start the convoy when + you're ready to begin execution. +
+ +
+ )} + + {/* Progress */} +
+
+ Progress + + {convoy.closed_beads}/{convoy.total_beads} + +
+
+
+
+
+ + {/* Metadata grid */} +
+ } + label="ID" + value={convoy.id.slice(0, 8)} + mono + /> + } + label="Created" + value={format(new Date(convoy.created_at), 'MMM d, HH:mm')} + /> + {convoy.feature_branch && ( + } + label="Branch" + value={convoy.feature_branch} + mono + colSpan2 + /> + )} + {convoy.merge_mode && ( + } + label="Merge Mode" + value={convoy.merge_mode} + colSpan2 + /> + )} +
+ + {/* DAG: Bead list with wave structure */} +
+
+ + + Beads ({convoy.beads.length}) + +
+ + {hasDag ? ( +
+ {waves.map((wave, waveIdx) => ( +
+ {waveIdx > 0 && ( +
+ + wave {waveIdx + 1} +
+
+ )} +
+ {wave.map(bead => ( + + ))} +
+
+ ))} +
+ ) : ( +
+ {convoy.beads.map(bead => ( + + ))} +
+ )} +
+
+ ); +} + +function BeadRow({ bead, push }: { bead: ConvoyBead; push: (ref: ResourceRef) => void }) { + return ( + + ); +} + +function MetaCell({ + icon, + label, + value, + mono, + colSpan2, +}: { + icon: React.ReactNode; + label: string; + value: string; + mono?: boolean; + colSpan2?: boolean; +}) { + return ( +
+ {icon} +
+
{label}
+
+ {value} +
+
+
+ ); +} diff --git a/src/lib/gastown/types/router.d.ts b/src/lib/gastown/types/router.d.ts index 5f4eef29e5..e27e331588 100644 --- a/src/lib/gastown/types/router.d.ts +++ b/src/lib/gastown/types/router.d.ts @@ -1,932 +1,63 @@ import type { TRPCContext } from './init'; -export declare const gastownRouter: import('@trpc/server').TRPCBuiltRouter< - { +export declare const gastownRouter: import("@trpc/server").TRPCBuiltRouter<{ ctx: TRPCContext; meta: object; - errorShape: import('@trpc/server').TRPCDefaultErrorShape; + errorShape: import("@trpc/server").TRPCDefaultErrorShape; transformer: false; - }, - import('@trpc/server').TRPCDecorateCreateRouterOptions<{ - createTown: import('@trpc/server').TRPCMutationProcedure<{ - input: { - name: string; - }; - output: { - id: string; - name: string; - owner_user_id: string; - created_at: string; - updated_at: string; - }; - meta: object; - }>; - listTowns: import('@trpc/server').TRPCQueryProcedure<{ - input: void; - output: { - id: string; - name: string; - owner_user_id: string; - created_at: string; - updated_at: string; - }[]; - meta: object; - }>; - getTown: import('@trpc/server').TRPCQueryProcedure<{ - input: { - townId: string; - }; - output: { - id: string; - name: string; - owner_user_id: string; - created_at: string; - updated_at: string; - }; - meta: object; - }>; - deleteTown: import('@trpc/server').TRPCMutationProcedure<{ - input: { - townId: string; - }; - output: void; - meta: object; - }>; - createRig: import('@trpc/server').TRPCMutationProcedure<{ - input: { - townId: string; - name: string; - gitUrl: string; - defaultBranch?: string | undefined; - platformIntegrationId?: string | undefined; - }; - output: { - id: string; - town_id: string; - name: string; - git_url: string; - default_branch: string; - platform_integration_id: string | null; - created_at: string; - updated_at: string; - }; - meta: object; - }>; - listRigs: import('@trpc/server').TRPCQueryProcedure<{ - input: { - townId: string; - }; - output: { - id: string; - town_id: string; - name: string; - git_url: string; - default_branch: string; - platform_integration_id: string | null; - created_at: string; - updated_at: string; - }[]; - meta: object; - }>; - getRig: import('@trpc/server').TRPCQueryProcedure<{ - input: { - rigId: string; - }; - output: { - id: string; - town_id: string; - name: string; - git_url: string; - default_branch: string; - platform_integration_id: string | null; - created_at: string; - updated_at: string; - agents: { - id: string; - rig_id: string | null; - role: string; - name: string; - identity: string; - status: string; - current_hook_bead_id: string | null; - dispatch_attempts: number; - last_activity_at: string | null; - checkpoint?: unknown; - created_at: string; - agent_status_message: string | null; - agent_status_updated_at: string | null; - }[]; - beads: { - bead_id: string; - type: - | 'agent' - | 'convoy' - | 'escalation' - | 'issue' - | 'merge_request' - | 'message' - | 'molecule'; - status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; - title: string; - body: string | null; - rig_id: string | null; - parent_bead_id: string | null; - assignee_agent_bead_id: string | null; - priority: 'critical' | 'high' | 'low' | 'medium'; - labels: string[]; - metadata: Record; - created_by: string | null; - created_at: string; - updated_at: string; - closed_at: string | null; - }[]; - }; - meta: object; - }>; - deleteRig: import('@trpc/server').TRPCMutationProcedure<{ - input: { - rigId: string; - }; - output: void; - meta: object; - }>; - listBeads: import('@trpc/server').TRPCQueryProcedure<{ - input: { - rigId: string; - status?: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open' | undefined; - }; - output: { - bead_id: string; - type: - | 'agent' - | 'convoy' - | 'escalation' - | 'issue' - | 'merge_request' - | 'message' - | 'molecule'; - status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; - title: string; - body: string | null; - rig_id: string | null; - parent_bead_id: string | null; - assignee_agent_bead_id: string | null; - priority: 'critical' | 'high' | 'low' | 'medium'; - labels: string[]; - metadata: Record; - created_by: string | null; - created_at: string; - updated_at: string; - closed_at: string | null; - }[]; - meta: object; - }>; - deleteBead: import('@trpc/server').TRPCMutationProcedure<{ - input: { - rigId: string; - beadId: string; - }; - output: void; - meta: object; - }>; - updateBead: import('@trpc/server').TRPCMutationProcedure<{ - input: { - rigId: string; - beadId: string; - title?: string | undefined; - body?: string | null | undefined; - status?: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open' | undefined; - priority?: 'critical' | 'high' | 'low' | 'medium' | undefined; - labels?: string[] | undefined; - metadata?: Record | undefined; - rig_id?: string | null | undefined; - parent_bead_id?: string | null | undefined; - }; - output: { - bead_id: string; - type: - | 'agent' - | 'convoy' - | 'escalation' - | 'issue' - | 'merge_request' - | 'message' - | 'molecule'; - status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; - title: string; - body: string | null; - rig_id: string | null; - parent_bead_id: string | null; - assignee_agent_bead_id: string | null; - priority: 'critical' | 'high' | 'low' | 'medium'; - labels: string[]; - metadata: Record; - created_by: string | null; - created_at: string; - updated_at: string; - closed_at: string | null; - }; - meta: object; - }>; - listAgents: import('@trpc/server').TRPCQueryProcedure<{ - input: { - rigId: string; - }; - output: { - id: string; - rig_id: string | null; - role: string; - name: string; - identity: string; - status: string; - current_hook_bead_id: string | null; - dispatch_attempts: number; - last_activity_at: string | null; - checkpoint?: unknown; - created_at: string; - agent_status_message: string | null; - agent_status_updated_at: string | null; - }[]; - meta: object; - }>; - deleteAgent: import('@trpc/server').TRPCMutationProcedure<{ - input: { - rigId: string; - agentId: string; - }; - output: void; - meta: object; - }>; - sling: import('@trpc/server').TRPCMutationProcedure<{ - input: { - rigId: string; - title: string; - body?: string | undefined; - model?: string | undefined; - }; - output: { - bead: { - bead_id: string; - type: - | 'agent' - | 'convoy' - | 'escalation' - | 'issue' - | 'merge_request' - | 'message' - | 'molecule'; - status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; - title: string; - body: string | null; - rig_id: string | null; - parent_bead_id: string | null; - assignee_agent_bead_id: string | null; - priority: 'critical' | 'high' | 'low' | 'medium'; - labels: string[]; - metadata: Record; - created_by: string | null; - created_at: string; - updated_at: string; - closed_at: string | null; - }; - agent: { - id: string; - rig_id: string | null; - role: string; - name: string; - identity: string; - status: string; - current_hook_bead_id: string | null; - dispatch_attempts: number; - last_activity_at: string | null; - checkpoint?: unknown; - created_at: string; - agent_status_message: string | null; - agent_status_updated_at: string | null; - }; - }; - meta: object; - }>; - sendMessage: import('@trpc/server').TRPCMutationProcedure<{ - input: { - townId: string; - message: string; - model?: string | undefined; - rigId?: string | undefined; - }; - output: { - agentId: string; - sessionStatus: 'active' | 'idle' | 'starting'; - }; - meta: object; - }>; - getMayorStatus: import('@trpc/server').TRPCQueryProcedure<{ - input: { - townId: string; - }; - output: { - configured: boolean; - townId: string | null; - session: { - agentId: string; - sessionId: string; - status: 'active' | 'idle' | 'starting'; - lastActivityAt: string; - } | null; - }; - meta: object; - }>; - getAlarmStatus: import('@trpc/server').TRPCQueryProcedure<{ - input: { - townId: string; - }; - output: { - alarm: { - nextFireAt: string | null; - intervalMs: number; - intervalLabel: string; - }; - agents: { - working: number; - idle: number; - stalled: number; - dead: number; - total: number; - }; - beads: { - open: number; - inProgress: number; - inReview: number; - failed: number; - triageRequests: number; - }; - patrol: { - guppWarnings: number; - guppEscalations: number; - stalledAgents: number; - orphanedHooks: number; - }; - recentEvents: { - time: string; - type: string; - message: string; - }[]; - }; - meta: object; - }>; - ensureMayor: import('@trpc/server').TRPCMutationProcedure<{ - input: { - townId: string; - }; - output: { - agentId: string; - sessionStatus: 'active' | 'idle' | 'starting'; - }; - meta: object; - }>; - getAgentStreamUrl: import('@trpc/server').TRPCQueryProcedure<{ - input: { - agentId: string; - townId: string; - }; - output: { - url: string; - ticket: string; - }; - meta: object; - }>; - createPtySession: import('@trpc/server').TRPCMutationProcedure<{ - input: { - townId: string; - agentId: string; - }; - output: { - pty: { - [x: string]: unknown; - id: string; - }; - wsUrl: string; - }; - meta: object; - }>; - resizePtySession: import('@trpc/server').TRPCMutationProcedure<{ - input: { - townId: string; - agentId: string; - ptyId: string; - cols: number; - rows: number; - }; - output: void; - meta: object; - }>; - getTownConfig: import('@trpc/server').TRPCQueryProcedure<{ - input: { - townId: string; - }; - output: { - env_vars: Record; - git_auth: { - github_token?: string | undefined; - gitlab_token?: string | undefined; - gitlab_instance_url?: string | undefined; - platform_integration_id?: string | undefined; - }; - owner_user_id?: string | undefined; - kilocode_token?: string | undefined; - default_model?: string | undefined; - small_model?: string | undefined; - max_polecats_per_rig?: number | undefined; - merge_strategy: 'direct' | 'pr'; - refinery?: - | { - gates: string[]; - auto_merge: boolean; - require_clean_merge: boolean; - } - | undefined; - alarm_interval_active?: number | undefined; - alarm_interval_idle?: number | undefined; - container?: - | { - sleep_after_minutes?: number | undefined; - } - | undefined; - }; - meta: object; - }>; - updateTownConfig: import('@trpc/server').TRPCMutationProcedure<{ - input: { - townId: string; - config: { - env_vars?: Record | undefined; - git_auth?: - | { - github_token?: string | undefined; - gitlab_token?: string | undefined; - gitlab_instance_url?: string | undefined; - platform_integration_id?: string | undefined; - } - | undefined; - owner_user_id?: string | undefined; - kilocode_token?: string | undefined; - default_model?: string | undefined; - small_model?: string | undefined; - max_polecats_per_rig?: number | undefined; - merge_strategy?: 'direct' | 'pr' | undefined; - refinery?: - | { - gates?: string[] | undefined; - auto_merge?: boolean | undefined; - require_clean_merge?: boolean | undefined; - } - | undefined; - alarm_interval_active?: number | undefined; - alarm_interval_idle?: number | undefined; - container?: - | { - sleep_after_minutes?: number | undefined; - } - | undefined; - }; - }; - output: { - env_vars: Record; - git_auth: { - github_token?: string | undefined; - gitlab_token?: string | undefined; - gitlab_instance_url?: string | undefined; - platform_integration_id?: string | undefined; - }; - owner_user_id?: string | undefined; - kilocode_token?: string | undefined; - default_model?: string | undefined; - small_model?: string | undefined; - max_polecats_per_rig?: number | undefined; - merge_strategy: 'direct' | 'pr'; - refinery?: - | { - gates: string[]; - auto_merge: boolean; - require_clean_merge: boolean; - } - | undefined; - alarm_interval_active?: number | undefined; - alarm_interval_idle?: number | undefined; - container?: - | { - sleep_after_minutes?: number | undefined; - } - | undefined; - }; - meta: object; - }>; - getBeadEvents: import('@trpc/server').TRPCQueryProcedure<{ - input: { - rigId: string; - beadId?: string | undefined; - since?: string | undefined; - limit?: number | undefined; - }; - output: { - bead_event_id: string; - bead_id: string; - agent_id: string | null; - event_type: string; - old_value: string | null; - new_value: string | null; - metadata: Record; - created_at: string; - rig_id?: string | undefined; - rig_name?: string | undefined; - }[]; - meta: object; - }>; - getTownEvents: import('@trpc/server').TRPCQueryProcedure<{ - input: { - townId: string; - since?: string | undefined; - limit?: number | undefined; - }; - output: { - bead_event_id: string; - bead_id: string; - agent_id: string | null; - event_type: string; - old_value: string | null; - new_value: string | null; - metadata: Record; - created_at: string; - rig_id?: string | undefined; - rig_name?: string | undefined; - }[]; - meta: object; - }>; - listConvoys: import('@trpc/server').TRPCQueryProcedure<{ - input: { - townId: string; - }; - output: { - id: string; - title: string; - status: 'active' | 'landed'; - total_beads: number; - closed_beads: number; - created_by: string | null; - created_at: string; - landed_at: string | null; - feature_branch: string | null; - merge_mode: string | null; - beads: { - bead_id: string; - title: string; - status: string; - rig_id: string | null; - assignee_agent_name: string | null; - }[]; - dependency_edges: { - bead_id: string; - depends_on_bead_id: string; - }[]; - }[]; - meta: object; - }>; - closeConvoy: import('@trpc/server').TRPCMutationProcedure<{ - input: { - townId: string; - convoyId: string; - }; - output: { - id: string; - title: string; - status: 'active' | 'landed'; - total_beads: number; - closed_beads: number; - created_by: string | null; - created_at: string; - landed_at: string | null; - feature_branch: string | null; - merge_mode: string | null; - beads: { - bead_id: string; - title: string; - status: string; - rig_id: string | null; - assignee_agent_name: string | null; - }[]; - dependency_edges: { - bead_id: string; - depends_on_bead_id: string; - }[]; - } | null; - meta: object; - }>; - adminListBeads: import('@trpc/server').TRPCQueryProcedure<{ - input: { - townId: string; - status?: 'closed' | 'failed' | 'in_progress' | 'open' | undefined; - type?: - | 'agent' - | 'convoy' - | 'escalation' - | 'issue' - | 'merge_request' - | 'message' - | 'molecule' - | undefined; - limit?: number | undefined; - }; - output: { - bead_id: string; - type: - | 'agent' - | 'convoy' - | 'escalation' - | 'issue' - | 'merge_request' - | 'message' - | 'molecule'; - status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; - title: string; - body: string | null; - rig_id: string | null; - parent_bead_id: string | null; - assignee_agent_bead_id: string | null; - priority: 'critical' | 'high' | 'low' | 'medium'; - labels: string[]; - metadata: Record; - created_by: string | null; - created_at: string; - updated_at: string; - closed_at: string | null; - }[]; - meta: object; - }>; - adminListAgents: import('@trpc/server').TRPCQueryProcedure<{ - input: { - townId: string; - }; - output: { - id: string; - rig_id: string | null; - role: string; - name: string; - identity: string; - status: string; - current_hook_bead_id: string | null; - dispatch_attempts: number; - last_activity_at: string | null; - checkpoint?: unknown; - created_at: string; - agent_status_message: string | null; - agent_status_updated_at: string | null; - }[]; - meta: object; - }>; - adminForceRestartContainer: import('@trpc/server').TRPCMutationProcedure<{ - input: { - townId: string; - }; - output: void; - meta: object; - }>; - adminForceResetAgent: import('@trpc/server').TRPCMutationProcedure<{ - input: { - townId: string; - agentId: string; - }; - output: void; - meta: object; - }>; - adminForceCloseBead: import('@trpc/server').TRPCMutationProcedure<{ - input: { - townId: string; - beadId: string; - }; - output: { - bead_id: string; - type: - | 'agent' - | 'convoy' - | 'escalation' - | 'issue' - | 'merge_request' - | 'message' - | 'molecule'; - status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; - title: string; - body: string | null; - rig_id: string | null; - parent_bead_id: string | null; - assignee_agent_bead_id: string | null; - priority: 'critical' | 'high' | 'low' | 'medium'; - labels: string[]; - metadata: Record; - created_by: string | null; - created_at: string; - updated_at: string; - closed_at: string | null; - }; - meta: object; - }>; - adminForceFailBead: import('@trpc/server').TRPCMutationProcedure<{ - input: { - townId: string; - beadId: string; - }; - output: { - bead_id: string; - type: - | 'agent' - | 'convoy' - | 'escalation' - | 'issue' - | 'merge_request' - | 'message' - | 'molecule'; - status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; - title: string; - body: string | null; - rig_id: string | null; - parent_bead_id: string | null; - assignee_agent_bead_id: string | null; - priority: 'critical' | 'high' | 'low' | 'medium'; - labels: string[]; - metadata: Record; - created_by: string | null; - created_at: string; - updated_at: string; - closed_at: string | null; - }; - meta: object; - }>; - adminGetAlarmStatus: import('@trpc/server').TRPCQueryProcedure<{ - input: { - townId: string; - }; - output: { - alarm: { - nextFireAt: string | null; - intervalMs: number; - intervalLabel: string; - }; - agents: { - working: number; - idle: number; - stalled: number; - dead: number; - total: number; - }; - beads: { - open: number; - inProgress: number; - inReview: number; - failed: number; - triageRequests: number; - }; - patrol: { - guppWarnings: number; - guppEscalations: number; - stalledAgents: number; - orphanedHooks: number; - }; - recentEvents: { - time: string; - type: string; - message: string; - }[]; - }; - meta: object; - }>; - adminGetTownEvents: import('@trpc/server').TRPCQueryProcedure<{ - input: { - townId: string; - beadId?: string | undefined; - since?: string | undefined; - limit?: number | undefined; - }; - output: { - bead_event_id: string; - bead_id: string; - agent_id: string | null; - event_type: string; - old_value: string | null; - new_value: string | null; - metadata: Record; - created_at: string; - rig_id?: string | undefined; - rig_name?: string | undefined; - }[]; - meta: object; - }>; - adminGetBead: import('@trpc/server').TRPCQueryProcedure<{ - input: { - townId: string; - beadId: string; - }; - output: { - bead_id: string; - type: - | 'agent' - | 'convoy' - | 'escalation' - | 'issue' - | 'merge_request' - | 'message' - | 'molecule'; - status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; - title: string; - body: string | null; - rig_id: string | null; - parent_bead_id: string | null; - assignee_agent_bead_id: string | null; - priority: 'critical' | 'high' | 'low' | 'medium'; - labels: string[]; - metadata: Record; - created_by: string | null; - created_at: string; - updated_at: string; - closed_at: string | null; - } | null; - meta: object; - }>; - }> ->; -export type GastownRouter = typeof gastownRouter; -/** - * Wrapped router that nests gastownRouter under a `gastown` key. - * This preserves the `trpc.gastown.X` call pattern on the frontend, - * matching the existing RootRouter shape so components don't need - * to change their procedure paths. - */ -export declare const wrappedGastownRouter: import('@trpc/server').TRPCBuiltRouter< - { - ctx: TRPCContext; - meta: object; - errorShape: import('@trpc/server').TRPCDefaultErrorShape; - transformer: false; - }, - import('@trpc/server').TRPCDecorateCreateRouterOptions<{ - gastown: import('@trpc/server').TRPCBuiltRouter< - { - ctx: TRPCContext; - meta: object; - errorShape: import('@trpc/server').TRPCDefaultErrorShape; - transformer: false; - }, - import('@trpc/server').TRPCDecorateCreateRouterOptions<{ - createTown: import('@trpc/server').TRPCMutationProcedure<{ - input: { +}, import("@trpc/server").TRPCDecorateCreateRouterOptions<{ + createTown: import("@trpc/server").TRPCMutationProcedure<{ + input: { name: string; - }; - output: { + }; + output: { id: string; name: string; owner_user_id: string; created_at: string; updated_at: string; - }; - meta: object; - }>; - listTowns: import('@trpc/server').TRPCQueryProcedure<{ - input: void; - output: { + }; + meta: object; + }>; + listTowns: import("@trpc/server").TRPCQueryProcedure<{ + input: void; + output: { id: string; name: string; owner_user_id: string; created_at: string; updated_at: string; - }[]; - meta: object; - }>; - getTown: import('@trpc/server').TRPCQueryProcedure<{ - input: { + }[]; + meta: object; + }>; + getTown: import("@trpc/server").TRPCQueryProcedure<{ + input: { townId: string; - }; - output: { + }; + output: { id: string; name: string; owner_user_id: string; created_at: string; updated_at: string; - }; - meta: object; - }>; - deleteTown: import('@trpc/server').TRPCMutationProcedure<{ - input: { + }; + meta: object; + }>; + deleteTown: import("@trpc/server").TRPCMutationProcedure<{ + input: { townId: string; - }; - output: void; - meta: object; - }>; - createRig: import('@trpc/server').TRPCMutationProcedure<{ - input: { + }; + output: void; + meta: object; + }>; + createRig: import("@trpc/server").TRPCMutationProcedure<{ + input: { townId: string; name: string; gitUrl: string; defaultBranch?: string | undefined; platformIntegrationId?: string | undefined; - }; - output: { + }; + output: { id: string; town_id: string; name: string; @@ -935,14 +66,14 @@ export declare const wrappedGastownRouter: import('@trpc/server').TRPCBuiltRoute platform_integration_id: string | null; created_at: string; updated_at: string; - }; - meta: object; - }>; - listRigs: import('@trpc/server').TRPCQueryProcedure<{ - input: { + }; + meta: object; + }>; + listRigs: import("@trpc/server").TRPCQueryProcedure<{ + input: { townId: string; - }; - output: { + }; + output: { id: string; town_id: string; name: string; @@ -951,14 +82,14 @@ export declare const wrappedGastownRouter: import('@trpc/server').TRPCBuiltRoute platform_integration_id: string | null; created_at: string; updated_at: string; - }[]; - meta: object; - }>; - getRig: import('@trpc/server').TRPCQueryProcedure<{ - input: { + }[]; + meta: object; + }>; + getRig: import("@trpc/server").TRPCQueryProcedure<{ + input: { rigId: string; - }; - output: { + }; + output: { id: string; town_id: string; name: string; @@ -968,137 +99,116 @@ export declare const wrappedGastownRouter: import('@trpc/server').TRPCBuiltRoute created_at: string; updated_at: string; agents: { - id: string; - rig_id: string | null; - role: string; - name: string; - identity: string; - status: string; - current_hook_bead_id: string | null; - dispatch_attempts: number; - last_activity_at: string | null; - checkpoint?: unknown; - created_at: string; - agent_status_message: string | null; - agent_status_updated_at: string | null; + id: string; + rig_id: string | null; + role: string; + name: string; + identity: string; + status: string; + current_hook_bead_id: string | null; + dispatch_attempts: number; + last_activity_at: string | null; + checkpoint?: unknown; + created_at: string; + agent_status_message: string | null; + agent_status_updated_at: string | null; }[]; beads: { - bead_id: string; - type: - | 'agent' - | 'convoy' - | 'escalation' - | 'issue' - | 'merge_request' - | 'message' - | 'molecule'; - status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; - title: string; - body: string | null; - rig_id: string | null; - parent_bead_id: string | null; - assignee_agent_bead_id: string | null; - priority: 'critical' | 'high' | 'low' | 'medium'; - labels: string[]; - metadata: Record; - created_by: string | null; - created_at: string; - updated_at: string; - closed_at: string | null; + bead_id: string; + type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; + status: "closed" | "failed" | "in_progress" | "in_review" | "open"; + title: string; + body: string | null; + rig_id: string | null; + parent_bead_id: string | null; + assignee_agent_bead_id: string | null; + priority: "critical" | "high" | "low" | "medium"; + labels: string[]; + metadata: Record; + created_by: string | null; + created_at: string; + updated_at: string; + closed_at: string | null; }[]; - }; - meta: object; - }>; - deleteRig: import('@trpc/server').TRPCMutationProcedure<{ - input: { + }; + meta: object; + }>; + deleteRig: import("@trpc/server").TRPCMutationProcedure<{ + input: { rigId: string; - }; - output: void; - meta: object; - }>; - listBeads: import('@trpc/server').TRPCQueryProcedure<{ - input: { + }; + output: void; + meta: object; + }>; + listBeads: import("@trpc/server").TRPCQueryProcedure<{ + input: { rigId: string; - status?: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open' | undefined; - }; - output: { + status?: "closed" | "failed" | "in_progress" | "in_review" | "open" | undefined; + }; + output: { bead_id: string; - type: - | 'agent' - | 'convoy' - | 'escalation' - | 'issue' - | 'merge_request' - | 'message' - | 'molecule'; - status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; + type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; + status: "closed" | "failed" | "in_progress" | "in_review" | "open"; title: string; body: string | null; rig_id: string | null; parent_bead_id: string | null; assignee_agent_bead_id: string | null; - priority: 'critical' | 'high' | 'low' | 'medium'; + priority: "critical" | "high" | "low" | "medium"; labels: string[]; metadata: Record; created_by: string | null; created_at: string; updated_at: string; closed_at: string | null; - }[]; - meta: object; - }>; - deleteBead: import('@trpc/server').TRPCMutationProcedure<{ - input: { + }[]; + meta: object; + }>; + deleteBead: import("@trpc/server").TRPCMutationProcedure<{ + input: { rigId: string; beadId: string; - }; - output: void; - meta: object; - }>; - updateBead: import('@trpc/server').TRPCMutationProcedure<{ - input: { + }; + output: void; + meta: object; + }>; + updateBead: import("@trpc/server").TRPCMutationProcedure<{ + input: { rigId: string; beadId: string; title?: string | undefined; body?: string | null | undefined; - status?: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open' | undefined; - priority?: 'critical' | 'high' | 'low' | 'medium' | undefined; + status?: "closed" | "failed" | "in_progress" | "in_review" | "open" | undefined; + priority?: "critical" | "high" | "low" | "medium" | undefined; labels?: string[] | undefined; metadata?: Record | undefined; rig_id?: string | null | undefined; parent_bead_id?: string | null | undefined; - }; - output: { + }; + output: { bead_id: string; - type: - | 'agent' - | 'convoy' - | 'escalation' - | 'issue' - | 'merge_request' - | 'message' - | 'molecule'; - status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; + type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; + status: "closed" | "failed" | "in_progress" | "in_review" | "open"; title: string; body: string | null; rig_id: string | null; parent_bead_id: string | null; assignee_agent_bead_id: string | null; - priority: 'critical' | 'high' | 'low' | 'medium'; + priority: "critical" | "high" | "low" | "medium"; labels: string[]; metadata: Record; created_by: string | null; created_at: string; updated_at: string; closed_at: string | null; - }; - meta: object; - }>; - listAgents: import('@trpc/server').TRPCQueryProcedure<{ - input: { + }; + meta: object; + }>; + listAgents: import("@trpc/server").TRPCQueryProcedure<{ + input: { rigId: string; - }; - output: { + }; + output: { id: string; rig_id: string | null; role: string; @@ -1112,289 +222,268 @@ export declare const wrappedGastownRouter: import('@trpc/server').TRPCBuiltRoute created_at: string; agent_status_message: string | null; agent_status_updated_at: string | null; - }[]; - meta: object; - }>; - deleteAgent: import('@trpc/server').TRPCMutationProcedure<{ - input: { + }[]; + meta: object; + }>; + deleteAgent: import("@trpc/server").TRPCMutationProcedure<{ + input: { rigId: string; agentId: string; - }; - output: void; - meta: object; - }>; - sling: import('@trpc/server').TRPCMutationProcedure<{ - input: { + }; + output: void; + meta: object; + }>; + sling: import("@trpc/server").TRPCMutationProcedure<{ + input: { rigId: string; title: string; body?: string | undefined; model?: string | undefined; - }; - output: { + }; + output: { bead: { - bead_id: string; - type: - | 'agent' - | 'convoy' - | 'escalation' - | 'issue' - | 'merge_request' - | 'message' - | 'molecule'; - status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; - title: string; - body: string | null; - rig_id: string | null; - parent_bead_id: string | null; - assignee_agent_bead_id: string | null; - priority: 'critical' | 'high' | 'low' | 'medium'; - labels: string[]; - metadata: Record; - created_by: string | null; - created_at: string; - updated_at: string; - closed_at: string | null; + bead_id: string; + type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; + status: "closed" | "failed" | "in_progress" | "in_review" | "open"; + title: string; + body: string | null; + rig_id: string | null; + parent_bead_id: string | null; + assignee_agent_bead_id: string | null; + priority: "critical" | "high" | "low" | "medium"; + labels: string[]; + metadata: Record; + created_by: string | null; + created_at: string; + updated_at: string; + closed_at: string | null; }; agent: { - id: string; - rig_id: string | null; - role: string; - name: string; - identity: string; - status: string; - current_hook_bead_id: string | null; - dispatch_attempts: number; - last_activity_at: string | null; - checkpoint?: unknown; - created_at: string; - agent_status_message: string | null; - agent_status_updated_at: string | null; - }; - }; - meta: object; - }>; - sendMessage: import('@trpc/server').TRPCMutationProcedure<{ - input: { + id: string; + rig_id: string | null; + role: string; + name: string; + identity: string; + status: string; + current_hook_bead_id: string | null; + dispatch_attempts: number; + last_activity_at: string | null; + checkpoint?: unknown; + created_at: string; + agent_status_message: string | null; + agent_status_updated_at: string | null; + }; + }; + meta: object; + }>; + sendMessage: import("@trpc/server").TRPCMutationProcedure<{ + input: { townId: string; message: string; model?: string | undefined; rigId?: string | undefined; - }; - output: { + }; + output: { agentId: string; - sessionStatus: 'active' | 'idle' | 'starting'; - }; - meta: object; - }>; - getMayorStatus: import('@trpc/server').TRPCQueryProcedure<{ - input: { + sessionStatus: "active" | "idle" | "starting"; + }; + meta: object; + }>; + getMayorStatus: import("@trpc/server").TRPCQueryProcedure<{ + input: { townId: string; - }; - output: { + }; + output: { configured: boolean; townId: string | null; session: { - agentId: string; - sessionId: string; - status: 'active' | 'idle' | 'starting'; - lastActivityAt: string; + agentId: string; + sessionId: string; + status: "active" | "idle" | "starting"; + lastActivityAt: string; } | null; - }; - meta: object; - }>; - getAlarmStatus: import('@trpc/server').TRPCQueryProcedure<{ - input: { + }; + meta: object; + }>; + getAlarmStatus: import("@trpc/server").TRPCQueryProcedure<{ + input: { townId: string; - }; - output: { + }; + output: { alarm: { - nextFireAt: string | null; - intervalMs: number; - intervalLabel: string; + nextFireAt: string | null; + intervalMs: number; + intervalLabel: string; }; agents: { - working: number; - idle: number; - stalled: number; - dead: number; - total: number; + working: number; + idle: number; + stalled: number; + dead: number; + total: number; }; beads: { - open: number; - inProgress: number; - inReview: number; - failed: number; - triageRequests: number; + open: number; + inProgress: number; + inReview: number; + failed: number; + triageRequests: number; }; patrol: { - guppWarnings: number; - guppEscalations: number; - stalledAgents: number; - orphanedHooks: number; + guppWarnings: number; + guppEscalations: number; + stalledAgents: number; + orphanedHooks: number; }; recentEvents: { - time: string; - type: string; - message: string; + time: string; + type: string; + message: string; }[]; - }; - meta: object; - }>; - ensureMayor: import('@trpc/server').TRPCMutationProcedure<{ - input: { + }; + meta: object; + }>; + ensureMayor: import("@trpc/server").TRPCMutationProcedure<{ + input: { townId: string; - }; - output: { + }; + output: { agentId: string; - sessionStatus: 'active' | 'idle' | 'starting'; - }; - meta: object; - }>; - getAgentStreamUrl: import('@trpc/server').TRPCQueryProcedure<{ - input: { + sessionStatus: "active" | "idle" | "starting"; + }; + meta: object; + }>; + getAgentStreamUrl: import("@trpc/server").TRPCQueryProcedure<{ + input: { agentId: string; townId: string; - }; - output: { + }; + output: { url: string; ticket: string; - }; - meta: object; - }>; - createPtySession: import('@trpc/server').TRPCMutationProcedure<{ - input: { + }; + meta: object; + }>; + createPtySession: import("@trpc/server").TRPCMutationProcedure<{ + input: { townId: string; agentId: string; - }; - output: { + }; + output: { pty: { - [x: string]: unknown; - id: string; + [x: string]: unknown; + id: string; }; wsUrl: string; - }; - meta: object; - }>; - resizePtySession: import('@trpc/server').TRPCMutationProcedure<{ - input: { + }; + meta: object; + }>; + resizePtySession: import("@trpc/server").TRPCMutationProcedure<{ + input: { townId: string; agentId: string; ptyId: string; cols: number; rows: number; - }; - output: void; - meta: object; - }>; - getTownConfig: import('@trpc/server').TRPCQueryProcedure<{ - input: { + }; + output: void; + meta: object; + }>; + getTownConfig: import("@trpc/server").TRPCQueryProcedure<{ + input: { townId: string; - }; - output: { + }; + output: { env_vars: Record; git_auth: { - github_token?: string | undefined; - gitlab_token?: string | undefined; - gitlab_instance_url?: string | undefined; - platform_integration_id?: string | undefined; + github_token?: string | undefined; + gitlab_token?: string | undefined; + gitlab_instance_url?: string | undefined; + platform_integration_id?: string | undefined; }; owner_user_id?: string | undefined; kilocode_token?: string | undefined; default_model?: string | undefined; small_model?: string | undefined; max_polecats_per_rig?: number | undefined; - merge_strategy: 'direct' | 'pr'; - refinery?: - | { - gates: string[]; - auto_merge: boolean; - require_clean_merge: boolean; - } - | undefined; + merge_strategy: "direct" | "pr"; + refinery?: { + gates: string[]; + auto_merge: boolean; + require_clean_merge: boolean; + } | undefined; alarm_interval_active?: number | undefined; alarm_interval_idle?: number | undefined; - container?: - | { - sleep_after_minutes?: number | undefined; - } - | undefined; - }; - meta: object; - }>; - updateTownConfig: import('@trpc/server').TRPCMutationProcedure<{ - input: { + container?: { + sleep_after_minutes?: number | undefined; + } | undefined; + }; + meta: object; + }>; + updateTownConfig: import("@trpc/server").TRPCMutationProcedure<{ + input: { townId: string; config: { - env_vars?: Record | undefined; - git_auth?: - | { + env_vars?: Record | undefined; + git_auth?: { github_token?: string | undefined; gitlab_token?: string | undefined; gitlab_instance_url?: string | undefined; platform_integration_id?: string | undefined; - } - | undefined; - owner_user_id?: string | undefined; - kilocode_token?: string | undefined; - default_model?: string | undefined; - small_model?: string | undefined; - max_polecats_per_rig?: number | undefined; - merge_strategy?: 'direct' | 'pr' | undefined; - refinery?: - | { + } | undefined; + owner_user_id?: string | undefined; + kilocode_token?: string | undefined; + default_model?: string | undefined; + small_model?: string | undefined; + max_polecats_per_rig?: number | undefined; + merge_strategy?: "direct" | "pr" | undefined; + refinery?: { gates?: string[] | undefined; auto_merge?: boolean | undefined; require_clean_merge?: boolean | undefined; - } - | undefined; - alarm_interval_active?: number | undefined; - alarm_interval_idle?: number | undefined; - container?: - | { + } | undefined; + alarm_interval_active?: number | undefined; + alarm_interval_idle?: number | undefined; + container?: { sleep_after_minutes?: number | undefined; - } - | undefined; + } | undefined; }; - }; - output: { + }; + output: { env_vars: Record; git_auth: { - github_token?: string | undefined; - gitlab_token?: string | undefined; - gitlab_instance_url?: string | undefined; - platform_integration_id?: string | undefined; + github_token?: string | undefined; + gitlab_token?: string | undefined; + gitlab_instance_url?: string | undefined; + platform_integration_id?: string | undefined; }; owner_user_id?: string | undefined; kilocode_token?: string | undefined; default_model?: string | undefined; small_model?: string | undefined; max_polecats_per_rig?: number | undefined; - merge_strategy: 'direct' | 'pr'; - refinery?: - | { - gates: string[]; - auto_merge: boolean; - require_clean_merge: boolean; - } - | undefined; + merge_strategy: "direct" | "pr"; + refinery?: { + gates: string[]; + auto_merge: boolean; + require_clean_merge: boolean; + } | undefined; alarm_interval_active?: number | undefined; alarm_interval_idle?: number | undefined; - container?: - | { - sleep_after_minutes?: number | undefined; - } - | undefined; - }; - meta: object; - }>; - getBeadEvents: import('@trpc/server').TRPCQueryProcedure<{ - input: { + container?: { + sleep_after_minutes?: number | undefined; + } | undefined; + }; + meta: object; + }>; + getBeadEvents: import("@trpc/server").TRPCQueryProcedure<{ + input: { rigId: string; beadId?: string | undefined; since?: string | undefined; limit?: number | undefined; - }; - output: { + }; + output: { bead_event_id: string; bead_id: string; agent_id: string | null; @@ -1405,16 +494,16 @@ export declare const wrappedGastownRouter: import('@trpc/server').TRPCBuiltRoute created_at: string; rig_id?: string | undefined; rig_name?: string | undefined; - }[]; - meta: object; - }>; - getTownEvents: import('@trpc/server').TRPCQueryProcedure<{ - input: { + }[]; + meta: object; + }>; + getTownEvents: import("@trpc/server").TRPCQueryProcedure<{ + input: { townId: string; since?: string | undefined; limit?: number | undefined; - }; - output: { + }; + output: { bead_event_id: string; bead_id: string; agent_id: string | null; @@ -1425,17 +514,18 @@ export declare const wrappedGastownRouter: import('@trpc/server').TRPCBuiltRoute created_at: string; rig_id?: string | undefined; rig_name?: string | undefined; - }[]; - meta: object; - }>; - listConvoys: import('@trpc/server').TRPCQueryProcedure<{ - input: { + }[]; + meta: object; + }>; + listConvoys: import("@trpc/server").TRPCQueryProcedure<{ + input: { townId: string; - }; - output: { + }; + output: { id: string; title: string; - status: 'active' | 'landed'; + status: "active" | "landed"; + staged: boolean; total_beads: number; closed_beads: number; created_by: string | null; @@ -1444,28 +534,29 @@ export declare const wrappedGastownRouter: import('@trpc/server').TRPCBuiltRoute feature_branch: string | null; merge_mode: string | null; beads: { - bead_id: string; - title: string; - status: string; - rig_id: string | null; - assignee_agent_name: string | null; + bead_id: string; + title: string; + status: string; + rig_id: string | null; + assignee_agent_name: string | null; }[]; dependency_edges: { - bead_id: string; - depends_on_bead_id: string; + bead_id: string; + depends_on_bead_id: string; }[]; - }[]; - meta: object; - }>; - closeConvoy: import('@trpc/server').TRPCMutationProcedure<{ - input: { + }[]; + meta: object; + }>; + closeConvoy: import("@trpc/server").TRPCMutationProcedure<{ + input: { townId: string; convoyId: string; - }; - output: { + }; + output: { id: string; title: string; - status: 'active' | 'landed'; + status: "active" | "landed"; + staged: boolean; total_beads: number; closed_beads: number; created_by: string | null; @@ -1474,65 +565,81 @@ export declare const wrappedGastownRouter: import('@trpc/server').TRPCBuiltRoute feature_branch: string | null; merge_mode: string | null; beads: { - bead_id: string; - title: string; - status: string; - rig_id: string | null; - assignee_agent_name: string | null; + bead_id: string; + title: string; + status: string; + rig_id: string | null; + assignee_agent_name: string | null; }[]; dependency_edges: { - bead_id: string; - depends_on_bead_id: string; + bead_id: string; + depends_on_bead_id: string; }[]; - } | null; - meta: object; - }>; - adminListBeads: import('@trpc/server').TRPCQueryProcedure<{ - input: { + } | null; + meta: object; + }>; + startConvoy: import("@trpc/server").TRPCMutationProcedure<{ + input: { townId: string; - status?: 'closed' | 'failed' | 'in_progress' | 'open' | undefined; - type?: - | 'agent' - | 'convoy' - | 'escalation' - | 'issue' - | 'merge_request' - | 'message' - | 'molecule' - | undefined; + convoyId: string; + }; + output: { + id: string; + title: string; + status: "active" | "landed"; + staged: boolean; + total_beads: number; + closed_beads: number; + created_by: string | null; + created_at: string; + landed_at: string | null; + feature_branch: string | null; + merge_mode: string | null; + beads: { + bead_id: string; + title: string; + status: string; + rig_id: string | null; + assignee_agent_name: string | null; + }[]; + dependency_edges: { + bead_id: string; + depends_on_bead_id: string; + }[]; + } | null; + meta: object; + }>; + adminListBeads: import("@trpc/server").TRPCQueryProcedure<{ + input: { + townId: string; + status?: "closed" | "failed" | "in_progress" | "open" | undefined; + type?: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule" | undefined; limit?: number | undefined; - }; - output: { + }; + output: { bead_id: string; - type: - | 'agent' - | 'convoy' - | 'escalation' - | 'issue' - | 'merge_request' - | 'message' - | 'molecule'; - status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; + type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; + status: "closed" | "failed" | "in_progress" | "in_review" | "open"; title: string; body: string | null; rig_id: string | null; parent_bead_id: string | null; assignee_agent_bead_id: string | null; - priority: 'critical' | 'high' | 'low' | 'medium'; + priority: "critical" | "high" | "low" | "medium"; labels: string[]; metadata: Record; created_by: string | null; created_at: string; updated_at: string; closed_at: string | null; - }[]; - meta: object; - }>; - adminListAgents: import('@trpc/server').TRPCQueryProcedure<{ - input: { + }[]; + meta: object; + }>; + adminListAgents: import("@trpc/server").TRPCQueryProcedure<{ + input: { townId: string; - }; - output: { + }; + output: { id: string; rig_id: string | null; role: string; @@ -1546,132 +653,118 @@ export declare const wrappedGastownRouter: import('@trpc/server').TRPCBuiltRoute created_at: string; agent_status_message: string | null; agent_status_updated_at: string | null; - }[]; - meta: object; - }>; - adminForceRestartContainer: import('@trpc/server').TRPCMutationProcedure<{ - input: { + }[]; + meta: object; + }>; + adminForceRestartContainer: import("@trpc/server").TRPCMutationProcedure<{ + input: { townId: string; - }; - output: void; - meta: object; - }>; - adminForceResetAgent: import('@trpc/server').TRPCMutationProcedure<{ - input: { + }; + output: void; + meta: object; + }>; + adminForceResetAgent: import("@trpc/server").TRPCMutationProcedure<{ + input: { townId: string; agentId: string; - }; - output: void; - meta: object; - }>; - adminForceCloseBead: import('@trpc/server').TRPCMutationProcedure<{ - input: { + }; + output: void; + meta: object; + }>; + adminForceCloseBead: import("@trpc/server").TRPCMutationProcedure<{ + input: { townId: string; beadId: string; - }; - output: { + }; + output: { bead_id: string; - type: - | 'agent' - | 'convoy' - | 'escalation' - | 'issue' - | 'merge_request' - | 'message' - | 'molecule'; - status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; + type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; + status: "closed" | "failed" | "in_progress" | "in_review" | "open"; title: string; body: string | null; rig_id: string | null; parent_bead_id: string | null; assignee_agent_bead_id: string | null; - priority: 'critical' | 'high' | 'low' | 'medium'; + priority: "critical" | "high" | "low" | "medium"; labels: string[]; metadata: Record; created_by: string | null; created_at: string; updated_at: string; closed_at: string | null; - }; - meta: object; - }>; - adminForceFailBead: import('@trpc/server').TRPCMutationProcedure<{ - input: { + }; + meta: object; + }>; + adminForceFailBead: import("@trpc/server").TRPCMutationProcedure<{ + input: { townId: string; beadId: string; - }; - output: { + }; + output: { bead_id: string; - type: - | 'agent' - | 'convoy' - | 'escalation' - | 'issue' - | 'merge_request' - | 'message' - | 'molecule'; - status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; + type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; + status: "closed" | "failed" | "in_progress" | "in_review" | "open"; title: string; body: string | null; rig_id: string | null; parent_bead_id: string | null; assignee_agent_bead_id: string | null; - priority: 'critical' | 'high' | 'low' | 'medium'; + priority: "critical" | "high" | "low" | "medium"; labels: string[]; metadata: Record; created_by: string | null; created_at: string; updated_at: string; closed_at: string | null; - }; - meta: object; - }>; - adminGetAlarmStatus: import('@trpc/server').TRPCQueryProcedure<{ - input: { + }; + meta: object; + }>; + adminGetAlarmStatus: import("@trpc/server").TRPCQueryProcedure<{ + input: { townId: string; - }; - output: { + }; + output: { alarm: { - nextFireAt: string | null; - intervalMs: number; - intervalLabel: string; + nextFireAt: string | null; + intervalMs: number; + intervalLabel: string; }; agents: { - working: number; - idle: number; - stalled: number; - dead: number; - total: number; + working: number; + idle: number; + stalled: number; + dead: number; + total: number; }; beads: { - open: number; - inProgress: number; - inReview: number; - failed: number; - triageRequests: number; + open: number; + inProgress: number; + inReview: number; + failed: number; + triageRequests: number; }; patrol: { - guppWarnings: number; - guppEscalations: number; - stalledAgents: number; - orphanedHooks: number; + guppWarnings: number; + guppEscalations: number; + stalledAgents: number; + orphanedHooks: number; }; recentEvents: { - time: string; - type: string; - message: string; + time: string; + type: string; + message: string; }[]; - }; - meta: object; - }>; - adminGetTownEvents: import('@trpc/server').TRPCQueryProcedure<{ - input: { + }; + meta: object; + }>; + adminGetTownEvents: import("@trpc/server").TRPCQueryProcedure<{ + input: { townId: string; beadId?: string | undefined; since?: string | undefined; limit?: number | undefined; - }; - output: { + }; + output: { bead_event_id: string; bead_id: string; agent_id: string | null; @@ -1682,42 +775,850 @@ export declare const wrappedGastownRouter: import('@trpc/server').TRPCBuiltRoute created_at: string; rig_id?: string | undefined; rig_name?: string | undefined; - }[]; - meta: object; - }>; - adminGetBead: import('@trpc/server').TRPCQueryProcedure<{ - input: { + }[]; + meta: object; + }>; + adminGetBead: import("@trpc/server").TRPCQueryProcedure<{ + input: { townId: string; beadId: string; - }; - output: { + }; + output: { bead_id: string; - type: - | 'agent' - | 'convoy' - | 'escalation' - | 'issue' - | 'merge_request' - | 'message' - | 'molecule'; - status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; + type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; + status: "closed" | "failed" | "in_progress" | "in_review" | "open"; title: string; body: string | null; rig_id: string | null; parent_bead_id: string | null; assignee_agent_bead_id: string | null; - priority: 'critical' | 'high' | 'low' | 'medium'; + priority: "critical" | "high" | "low" | "medium"; labels: string[]; metadata: Record; created_by: string | null; created_at: string; updated_at: string; closed_at: string | null; - } | null; - meta: object; + } | null; + meta: object; + }>; +}>>; +export type GastownRouter = typeof gastownRouter; +/** + * Wrapped router that nests gastownRouter under a `gastown` key. + * This preserves the `trpc.gastown.X` call pattern on the frontend, + * matching the existing RootRouter shape so components don't need + * to change their procedure paths. + */ +export declare const wrappedGastownRouter: import("@trpc/server").TRPCBuiltRouter<{ + ctx: TRPCContext; + meta: object; + errorShape: import("@trpc/server").TRPCDefaultErrorShape; + transformer: false; +}, import("@trpc/server").TRPCDecorateCreateRouterOptions<{ + gastown: import("@trpc/server").TRPCBuiltRouter<{ + ctx: TRPCContext; + meta: object; + errorShape: import("@trpc/server").TRPCDefaultErrorShape; + transformer: false; + }, import("@trpc/server").TRPCDecorateCreateRouterOptions<{ + createTown: import("@trpc/server").TRPCMutationProcedure<{ + input: { + name: string; + }; + output: { + id: string; + name: string; + owner_user_id: string; + created_at: string; + updated_at: string; + }; + meta: object; + }>; + listTowns: import("@trpc/server").TRPCQueryProcedure<{ + input: void; + output: { + id: string; + name: string; + owner_user_id: string; + created_at: string; + updated_at: string; + }[]; + meta: object; + }>; + getTown: import("@trpc/server").TRPCQueryProcedure<{ + input: { + townId: string; + }; + output: { + id: string; + name: string; + owner_user_id: string; + created_at: string; + updated_at: string; + }; + meta: object; + }>; + deleteTown: import("@trpc/server").TRPCMutationProcedure<{ + input: { + townId: string; + }; + output: void; + meta: object; + }>; + createRig: import("@trpc/server").TRPCMutationProcedure<{ + input: { + townId: string; + name: string; + gitUrl: string; + defaultBranch?: string | undefined; + platformIntegrationId?: string | undefined; + }; + output: { + id: string; + town_id: string; + name: string; + git_url: string; + default_branch: string; + platform_integration_id: string | null; + created_at: string; + updated_at: string; + }; + meta: object; + }>; + listRigs: import("@trpc/server").TRPCQueryProcedure<{ + input: { + townId: string; + }; + output: { + id: string; + town_id: string; + name: string; + git_url: string; + default_branch: string; + platform_integration_id: string | null; + created_at: string; + updated_at: string; + }[]; + meta: object; + }>; + getRig: import("@trpc/server").TRPCQueryProcedure<{ + input: { + rigId: string; + }; + output: { + id: string; + town_id: string; + name: string; + git_url: string; + default_branch: string; + platform_integration_id: string | null; + created_at: string; + updated_at: string; + agents: { + id: string; + rig_id: string | null; + role: string; + name: string; + identity: string; + status: string; + current_hook_bead_id: string | null; + dispatch_attempts: number; + last_activity_at: string | null; + checkpoint?: unknown; + created_at: string; + agent_status_message: string | null; + agent_status_updated_at: string | null; + }[]; + beads: { + bead_id: string; + type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; + status: "closed" | "failed" | "in_progress" | "in_review" | "open"; + title: string; + body: string | null; + rig_id: string | null; + parent_bead_id: string | null; + assignee_agent_bead_id: string | null; + priority: "critical" | "high" | "low" | "medium"; + labels: string[]; + metadata: Record; + created_by: string | null; + created_at: string; + updated_at: string; + closed_at: string | null; + }[]; + }; + meta: object; + }>; + deleteRig: import("@trpc/server").TRPCMutationProcedure<{ + input: { + rigId: string; + }; + output: void; + meta: object; + }>; + listBeads: import("@trpc/server").TRPCQueryProcedure<{ + input: { + rigId: string; + status?: "closed" | "failed" | "in_progress" | "in_review" | "open" | undefined; + }; + output: { + bead_id: string; + type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; + status: "closed" | "failed" | "in_progress" | "in_review" | "open"; + title: string; + body: string | null; + rig_id: string | null; + parent_bead_id: string | null; + assignee_agent_bead_id: string | null; + priority: "critical" | "high" | "low" | "medium"; + labels: string[]; + metadata: Record; + created_by: string | null; + created_at: string; + updated_at: string; + closed_at: string | null; + }[]; + meta: object; + }>; + deleteBead: import("@trpc/server").TRPCMutationProcedure<{ + input: { + rigId: string; + beadId: string; + }; + output: void; + meta: object; + }>; + updateBead: import("@trpc/server").TRPCMutationProcedure<{ + input: { + rigId: string; + beadId: string; + title?: string | undefined; + body?: string | null | undefined; + status?: "closed" | "failed" | "in_progress" | "in_review" | "open" | undefined; + priority?: "critical" | "high" | "low" | "medium" | undefined; + labels?: string[] | undefined; + metadata?: Record | undefined; + rig_id?: string | null | undefined; + parent_bead_id?: string | null | undefined; + }; + output: { + bead_id: string; + type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; + status: "closed" | "failed" | "in_progress" | "in_review" | "open"; + title: string; + body: string | null; + rig_id: string | null; + parent_bead_id: string | null; + assignee_agent_bead_id: string | null; + priority: "critical" | "high" | "low" | "medium"; + labels: string[]; + metadata: Record; + created_by: string | null; + created_at: string; + updated_at: string; + closed_at: string | null; + }; + meta: object; + }>; + listAgents: import("@trpc/server").TRPCQueryProcedure<{ + input: { + rigId: string; + }; + output: { + id: string; + rig_id: string | null; + role: string; + name: string; + identity: string; + status: string; + current_hook_bead_id: string | null; + dispatch_attempts: number; + last_activity_at: string | null; + checkpoint?: unknown; + created_at: string; + agent_status_message: string | null; + agent_status_updated_at: string | null; + }[]; + meta: object; + }>; + deleteAgent: import("@trpc/server").TRPCMutationProcedure<{ + input: { + rigId: string; + agentId: string; + }; + output: void; + meta: object; + }>; + sling: import("@trpc/server").TRPCMutationProcedure<{ + input: { + rigId: string; + title: string; + body?: string | undefined; + model?: string | undefined; + }; + output: { + bead: { + bead_id: string; + type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; + status: "closed" | "failed" | "in_progress" | "in_review" | "open"; + title: string; + body: string | null; + rig_id: string | null; + parent_bead_id: string | null; + assignee_agent_bead_id: string | null; + priority: "critical" | "high" | "low" | "medium"; + labels: string[]; + metadata: Record; + created_by: string | null; + created_at: string; + updated_at: string; + closed_at: string | null; + }; + agent: { + id: string; + rig_id: string | null; + role: string; + name: string; + identity: string; + status: string; + current_hook_bead_id: string | null; + dispatch_attempts: number; + last_activity_at: string | null; + checkpoint?: unknown; + created_at: string; + agent_status_message: string | null; + agent_status_updated_at: string | null; + }; + }; + meta: object; + }>; + sendMessage: import("@trpc/server").TRPCMutationProcedure<{ + input: { + townId: string; + message: string; + model?: string | undefined; + rigId?: string | undefined; + }; + output: { + agentId: string; + sessionStatus: "active" | "idle" | "starting"; + }; + meta: object; + }>; + getMayorStatus: import("@trpc/server").TRPCQueryProcedure<{ + input: { + townId: string; + }; + output: { + configured: boolean; + townId: string | null; + session: { + agentId: string; + sessionId: string; + status: "active" | "idle" | "starting"; + lastActivityAt: string; + } | null; + }; + meta: object; + }>; + getAlarmStatus: import("@trpc/server").TRPCQueryProcedure<{ + input: { + townId: string; + }; + output: { + alarm: { + nextFireAt: string | null; + intervalMs: number; + intervalLabel: string; + }; + agents: { + working: number; + idle: number; + stalled: number; + dead: number; + total: number; + }; + beads: { + open: number; + inProgress: number; + inReview: number; + failed: number; + triageRequests: number; + }; + patrol: { + guppWarnings: number; + guppEscalations: number; + stalledAgents: number; + orphanedHooks: number; + }; + recentEvents: { + time: string; + type: string; + message: string; + }[]; + }; + meta: object; + }>; + ensureMayor: import("@trpc/server").TRPCMutationProcedure<{ + input: { + townId: string; + }; + output: { + agentId: string; + sessionStatus: "active" | "idle" | "starting"; + }; + meta: object; + }>; + getAgentStreamUrl: import("@trpc/server").TRPCQueryProcedure<{ + input: { + agentId: string; + townId: string; + }; + output: { + url: string; + ticket: string; + }; + meta: object; + }>; + createPtySession: import("@trpc/server").TRPCMutationProcedure<{ + input: { + townId: string; + agentId: string; + }; + output: { + pty: { + [x: string]: unknown; + id: string; + }; + wsUrl: string; + }; + meta: object; + }>; + resizePtySession: import("@trpc/server").TRPCMutationProcedure<{ + input: { + townId: string; + agentId: string; + ptyId: string; + cols: number; + rows: number; + }; + output: void; + meta: object; + }>; + getTownConfig: import("@trpc/server").TRPCQueryProcedure<{ + input: { + townId: string; + }; + output: { + env_vars: Record; + git_auth: { + github_token?: string | undefined; + gitlab_token?: string | undefined; + gitlab_instance_url?: string | undefined; + platform_integration_id?: string | undefined; + }; + owner_user_id?: string | undefined; + kilocode_token?: string | undefined; + default_model?: string | undefined; + small_model?: string | undefined; + max_polecats_per_rig?: number | undefined; + merge_strategy: "direct" | "pr"; + refinery?: { + gates: string[]; + auto_merge: boolean; + require_clean_merge: boolean; + } | undefined; + alarm_interval_active?: number | undefined; + alarm_interval_idle?: number | undefined; + container?: { + sleep_after_minutes?: number | undefined; + } | undefined; + }; + meta: object; + }>; + updateTownConfig: import("@trpc/server").TRPCMutationProcedure<{ + input: { + townId: string; + config: { + env_vars?: Record | undefined; + git_auth?: { + github_token?: string | undefined; + gitlab_token?: string | undefined; + gitlab_instance_url?: string | undefined; + platform_integration_id?: string | undefined; + } | undefined; + owner_user_id?: string | undefined; + kilocode_token?: string | undefined; + default_model?: string | undefined; + small_model?: string | undefined; + max_polecats_per_rig?: number | undefined; + merge_strategy?: "direct" | "pr" | undefined; + refinery?: { + gates?: string[] | undefined; + auto_merge?: boolean | undefined; + require_clean_merge?: boolean | undefined; + } | undefined; + alarm_interval_active?: number | undefined; + alarm_interval_idle?: number | undefined; + container?: { + sleep_after_minutes?: number | undefined; + } | undefined; + }; + }; + output: { + env_vars: Record; + git_auth: { + github_token?: string | undefined; + gitlab_token?: string | undefined; + gitlab_instance_url?: string | undefined; + platform_integration_id?: string | undefined; + }; + owner_user_id?: string | undefined; + kilocode_token?: string | undefined; + default_model?: string | undefined; + small_model?: string | undefined; + max_polecats_per_rig?: number | undefined; + merge_strategy: "direct" | "pr"; + refinery?: { + gates: string[]; + auto_merge: boolean; + require_clean_merge: boolean; + } | undefined; + alarm_interval_active?: number | undefined; + alarm_interval_idle?: number | undefined; + container?: { + sleep_after_minutes?: number | undefined; + } | undefined; + }; + meta: object; + }>; + getBeadEvents: import("@trpc/server").TRPCQueryProcedure<{ + input: { + rigId: string; + beadId?: string | undefined; + since?: string | undefined; + limit?: number | undefined; + }; + output: { + bead_event_id: string; + bead_id: string; + agent_id: string | null; + event_type: string; + old_value: string | null; + new_value: string | null; + metadata: Record; + created_at: string; + rig_id?: string | undefined; + rig_name?: string | undefined; + }[]; + meta: object; + }>; + getTownEvents: import("@trpc/server").TRPCQueryProcedure<{ + input: { + townId: string; + since?: string | undefined; + limit?: number | undefined; + }; + output: { + bead_event_id: string; + bead_id: string; + agent_id: string | null; + event_type: string; + old_value: string | null; + new_value: string | null; + metadata: Record; + created_at: string; + rig_id?: string | undefined; + rig_name?: string | undefined; + }[]; + meta: object; + }>; + listConvoys: import("@trpc/server").TRPCQueryProcedure<{ + input: { + townId: string; + }; + output: { + id: string; + title: string; + status: "active" | "landed"; + staged: boolean; + total_beads: number; + closed_beads: number; + created_by: string | null; + created_at: string; + landed_at: string | null; + feature_branch: string | null; + merge_mode: string | null; + beads: { + bead_id: string; + title: string; + status: string; + rig_id: string | null; + assignee_agent_name: string | null; + }[]; + dependency_edges: { + bead_id: string; + depends_on_bead_id: string; + }[]; + }[]; + meta: object; + }>; + closeConvoy: import("@trpc/server").TRPCMutationProcedure<{ + input: { + townId: string; + convoyId: string; + }; + output: { + id: string; + title: string; + status: "active" | "landed"; + staged: boolean; + total_beads: number; + closed_beads: number; + created_by: string | null; + created_at: string; + landed_at: string | null; + feature_branch: string | null; + merge_mode: string | null; + beads: { + bead_id: string; + title: string; + status: string; + rig_id: string | null; + assignee_agent_name: string | null; + }[]; + dependency_edges: { + bead_id: string; + depends_on_bead_id: string; + }[]; + } | null; + meta: object; + }>; + startConvoy: import("@trpc/server").TRPCMutationProcedure<{ + input: { + townId: string; + convoyId: string; + }; + output: { + id: string; + title: string; + status: "active" | "landed"; + staged: boolean; + total_beads: number; + closed_beads: number; + created_by: string | null; + created_at: string; + landed_at: string | null; + feature_branch: string | null; + merge_mode: string | null; + beads: { + bead_id: string; + title: string; + status: string; + rig_id: string | null; + assignee_agent_name: string | null; + }[]; + dependency_edges: { + bead_id: string; + depends_on_bead_id: string; + }[]; + } | null; + meta: object; + }>; + adminListBeads: import("@trpc/server").TRPCQueryProcedure<{ + input: { + townId: string; + status?: "closed" | "failed" | "in_progress" | "open" | undefined; + type?: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule" | undefined; + limit?: number | undefined; + }; + output: { + bead_id: string; + type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; + status: "closed" | "failed" | "in_progress" | "in_review" | "open"; + title: string; + body: string | null; + rig_id: string | null; + parent_bead_id: string | null; + assignee_agent_bead_id: string | null; + priority: "critical" | "high" | "low" | "medium"; + labels: string[]; + metadata: Record; + created_by: string | null; + created_at: string; + updated_at: string; + closed_at: string | null; + }[]; + meta: object; + }>; + adminListAgents: import("@trpc/server").TRPCQueryProcedure<{ + input: { + townId: string; + }; + output: { + id: string; + rig_id: string | null; + role: string; + name: string; + identity: string; + status: string; + current_hook_bead_id: string | null; + dispatch_attempts: number; + last_activity_at: string | null; + checkpoint?: unknown; + created_at: string; + agent_status_message: string | null; + agent_status_updated_at: string | null; + }[]; + meta: object; + }>; + adminForceRestartContainer: import("@trpc/server").TRPCMutationProcedure<{ + input: { + townId: string; + }; + output: void; + meta: object; + }>; + adminForceResetAgent: import("@trpc/server").TRPCMutationProcedure<{ + input: { + townId: string; + agentId: string; + }; + output: void; + meta: object; + }>; + adminForceCloseBead: import("@trpc/server").TRPCMutationProcedure<{ + input: { + townId: string; + beadId: string; + }; + output: { + bead_id: string; + type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; + status: "closed" | "failed" | "in_progress" | "in_review" | "open"; + title: string; + body: string | null; + rig_id: string | null; + parent_bead_id: string | null; + assignee_agent_bead_id: string | null; + priority: "critical" | "high" | "low" | "medium"; + labels: string[]; + metadata: Record; + created_by: string | null; + created_at: string; + updated_at: string; + closed_at: string | null; + }; + meta: object; + }>; + adminForceFailBead: import("@trpc/server").TRPCMutationProcedure<{ + input: { + townId: string; + beadId: string; + }; + output: { + bead_id: string; + type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; + status: "closed" | "failed" | "in_progress" | "in_review" | "open"; + title: string; + body: string | null; + rig_id: string | null; + parent_bead_id: string | null; + assignee_agent_bead_id: string | null; + priority: "critical" | "high" | "low" | "medium"; + labels: string[]; + metadata: Record; + created_by: string | null; + created_at: string; + updated_at: string; + closed_at: string | null; + }; + meta: object; + }>; + adminGetAlarmStatus: import("@trpc/server").TRPCQueryProcedure<{ + input: { + townId: string; + }; + output: { + alarm: { + nextFireAt: string | null; + intervalMs: number; + intervalLabel: string; + }; + agents: { + working: number; + idle: number; + stalled: number; + dead: number; + total: number; + }; + beads: { + open: number; + inProgress: number; + inReview: number; + failed: number; + triageRequests: number; + }; + patrol: { + guppWarnings: number; + guppEscalations: number; + stalledAgents: number; + orphanedHooks: number; + }; + recentEvents: { + time: string; + type: string; + message: string; + }[]; + }; + meta: object; + }>; + adminGetTownEvents: import("@trpc/server").TRPCQueryProcedure<{ + input: { + townId: string; + beadId?: string | undefined; + since?: string | undefined; + limit?: number | undefined; + }; + output: { + bead_event_id: string; + bead_id: string; + agent_id: string | null; + event_type: string; + old_value: string | null; + new_value: string | null; + metadata: Record; + created_at: string; + rig_id?: string | undefined; + rig_name?: string | undefined; + }[]; + meta: object; + }>; + adminGetBead: import("@trpc/server").TRPCQueryProcedure<{ + input: { + townId: string; + beadId: string; + }; + output: { + bead_id: string; + type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; + status: "closed" | "failed" | "in_progress" | "in_review" | "open"; + title: string; + body: string | null; + rig_id: string | null; + parent_bead_id: string | null; + assignee_agent_bead_id: string | null; + priority: "critical" | "high" | "low" | "medium"; + labels: string[]; + metadata: Record; + created_by: string | null; + created_at: string; + updated_at: string; + closed_at: string | null; + } | null; + meta: object; }>; - }> - >; - }> ->; + }>>; +}>>; export type WrappedGastownRouter = typeof wrappedGastownRouter; diff --git a/src/lib/gastown/types/schemas.d.ts b/src/lib/gastown/types/schemas.d.ts index 88c60ecfd2..af0294e888 100644 --- a/src/lib/gastown/types/schemas.d.ts +++ b/src/lib/gastown/types/schemas.d.ts @@ -1,16 +1,12 @@ -import { z } from 'zod'; -export declare const TownOutput: z.ZodObject< - { +import type { z } from 'zod'; +export declare const TownOutput: z.ZodObject<{ id: z.ZodString; name: z.ZodString; owner_user_id: z.ZodString; created_at: z.ZodString; updated_at: z.ZodString; - }, - z.core.$strip ->; -export declare const RigOutput: z.ZodObject< - { +}, z.core.$strip>; +export declare const RigOutput: z.ZodObject<{ id: z.ZodString; town_id: z.ZodString; name: z.ZodString; @@ -19,27 +15,24 @@ export declare const RigOutput: z.ZodObject< platform_integration_id: z.ZodDefault>>; created_at: z.ZodString; updated_at: z.ZodString; - }, - z.core.$strip ->; -export declare const BeadOutput: z.ZodObject< - { +}, z.core.$strip>; +export declare const BeadOutput: z.ZodObject<{ bead_id: z.ZodString; type: z.ZodEnum<{ - agent: 'agent'; - convoy: 'convoy'; - escalation: 'escalation'; - issue: 'issue'; - merge_request: 'merge_request'; - message: 'message'; - molecule: 'molecule'; + agent: "agent"; + convoy: "convoy"; + escalation: "escalation"; + issue: "issue"; + merge_request: "merge_request"; + message: "message"; + molecule: "molecule"; }>; status: z.ZodEnum<{ - closed: 'closed'; - failed: 'failed'; - in_progress: 'in_progress'; - in_review: 'in_review'; - open: 'open'; + closed: "closed"; + failed: "failed"; + in_progress: "in_progress"; + in_review: "in_review"; + open: "open"; }>; title: z.ZodString; body: z.ZodNullable; @@ -47,10 +40,10 @@ export declare const BeadOutput: z.ZodObject< parent_bead_id: z.ZodNullable; assignee_agent_bead_id: z.ZodNullable; priority: z.ZodEnum<{ - critical: 'critical'; - high: 'high'; - low: 'low'; - medium: 'medium'; + critical: "critical"; + high: "high"; + low: "low"; + medium: "medium"; }>; labels: z.ZodArray; metadata: z.ZodRecord; @@ -58,36 +51,23 @@ export declare const BeadOutput: z.ZodObject< created_at: z.ZodString; updated_at: z.ZodString; closed_at: z.ZodNullable; - }, - z.core.$strip ->; -export declare const AgentOutput: z.ZodObject< - { +}, z.core.$strip>; +export declare const AgentOutput: z.ZodObject<{ id: z.ZodString; rig_id: z.ZodNullable; - role: z.ZodUnion< - [ - z.ZodEnum<{ - mayor: 'mayor'; - polecat: 'polecat'; - refinery: 'refinery'; - }>, - z.ZodString, - ] - >; + role: z.ZodUnion<[z.ZodEnum<{ + mayor: "mayor"; + polecat: "polecat"; + refinery: "refinery"; + }>, z.ZodString]>; name: z.ZodString; identity: z.ZodString; - status: z.ZodUnion< - [ - z.ZodEnum<{ - dead: 'dead'; - idle: 'idle'; - stalled: 'stalled'; - working: 'working'; - }>, - z.ZodString, - ] - >; + status: z.ZodUnion<[z.ZodEnum<{ + dead: "dead"; + idle: "idle"; + stalled: "stalled"; + working: "working"; + }>, z.ZodString]>; current_hook_bead_id: z.ZodNullable; dispatch_attempts: z.ZodDefault; last_activity_at: z.ZodNullable; @@ -95,11 +75,8 @@ export declare const AgentOutput: z.ZodObject< created_at: z.ZodString; agent_status_message: z.ZodDefault>>; agent_status_updated_at: z.ZodDefault>>; - }, - z.core.$strip ->; -export declare const BeadEventOutput: z.ZodObject< - { +}, z.core.$strip>; +export declare const BeadEventOutput: z.ZodObject<{ bead_event_id: z.ZodString; bead_id: z.ZodString; agent_id: z.ZodNullable; @@ -110,69 +87,343 @@ export declare const BeadEventOutput: z.ZodObject< created_at: z.ZodString; rig_id: z.ZodOptional; rig_name: z.ZodOptional; - }, - z.core.$strip ->; -export declare const MayorSendResultOutput: z.ZodObject< - { +}, z.core.$strip>; +export declare const MayorSendResultOutput: z.ZodObject<{ agentId: z.ZodString; sessionStatus: z.ZodEnum<{ - active: 'active'; - idle: 'idle'; - starting: 'starting'; + active: "active"; + idle: "idle"; + starting: "starting"; }>; - }, - z.core.$strip ->; -export declare const MayorStatusOutput: z.ZodObject< - { +}, z.core.$strip>; +export declare const MayorStatusOutput: z.ZodObject<{ configured: z.ZodBoolean; townId: z.ZodNullable; - session: z.ZodNullable< - z.ZodObject< - { - agentId: z.ZodString; - sessionId: z.ZodString; - status: z.ZodEnum<{ - active: 'active'; - idle: 'idle'; - starting: 'starting'; - }>; - lastActivityAt: z.ZodString; - }, - z.core.$strip - > - >; - }, - z.core.$strip ->; -export declare const StreamTicketOutput: z.ZodObject< - { + session: z.ZodNullable; + lastActivityAt: z.ZodString; + }, z.core.$strip>>; +}, z.core.$strip>; +export declare const StreamTicketOutput: z.ZodObject<{ + url: z.ZodString; + ticket: z.ZodString; +}, z.core.$strip>; +export declare const PtySessionOutput: z.ZodObject<{ + pty: z.ZodObject<{ + id: z.ZodString; + }, z.core.$loose>; + wsUrl: z.ZodString; +}, z.core.$strip>; +export declare const ConvoyOutput: z.ZodObject<{ + id: z.ZodString; + title: z.ZodString; + status: z.ZodEnum<{ + active: "active"; + landed: "landed"; + }>; + staged: z.ZodBoolean; + total_beads: z.ZodNumber; + closed_beads: z.ZodNumber; + created_by: z.ZodNullable; + created_at: z.ZodString; + landed_at: z.ZodNullable; + feature_branch: z.ZodNullable; + merge_mode: z.ZodNullable; +}, z.core.$strip>; +export declare const ConvoyDetailOutput: z.ZodObject<{ + id: z.ZodString; + title: z.ZodString; + status: z.ZodEnum<{ + active: "active"; + landed: "landed"; + }>; + staged: z.ZodBoolean; + total_beads: z.ZodNumber; + closed_beads: z.ZodNumber; + created_by: z.ZodNullable; + created_at: z.ZodString; + landed_at: z.ZodNullable; + feature_branch: z.ZodNullable; + merge_mode: z.ZodNullable; + beads: z.ZodArray; + assignee_agent_name: z.ZodNullable; + }, z.core.$strip>>; + dependency_edges: z.ZodArray>; +}, z.core.$strip>; +export declare const SlingResultOutput: z.ZodObject<{ + bead: z.ZodObject<{ + bead_id: z.ZodString; + type: z.ZodEnum<{ + agent: "agent"; + convoy: "convoy"; + escalation: "escalation"; + issue: "issue"; + merge_request: "merge_request"; + message: "message"; + molecule: "molecule"; + }>; + status: z.ZodEnum<{ + closed: "closed"; + failed: "failed"; + in_progress: "in_progress"; + in_review: "in_review"; + open: "open"; + }>; + title: z.ZodString; + body: z.ZodNullable; + rig_id: z.ZodNullable; + parent_bead_id: z.ZodNullable; + assignee_agent_bead_id: z.ZodNullable; + priority: z.ZodEnum<{ + critical: "critical"; + high: "high"; + low: "low"; + medium: "medium"; + }>; + labels: z.ZodArray; + metadata: z.ZodRecord; + created_by: z.ZodNullable; + created_at: z.ZodString; + updated_at: z.ZodString; + closed_at: z.ZodNullable; + }, z.core.$strip>; + agent: z.ZodObject<{ + id: z.ZodString; + rig_id: z.ZodNullable; + role: z.ZodUnion<[z.ZodEnum<{ + mayor: "mayor"; + polecat: "polecat"; + refinery: "refinery"; + }>, z.ZodString]>; + name: z.ZodString; + identity: z.ZodString; + status: z.ZodUnion<[z.ZodEnum<{ + dead: "dead"; + idle: "idle"; + stalled: "stalled"; + working: "working"; + }>, z.ZodString]>; + current_hook_bead_id: z.ZodNullable; + dispatch_attempts: z.ZodDefault; + last_activity_at: z.ZodNullable; + checkpoint: z.ZodOptional; + created_at: z.ZodString; + agent_status_message: z.ZodDefault>>; + agent_status_updated_at: z.ZodDefault>>; + }, z.core.$strip>; +}, z.core.$strip>; +export declare const RigDetailOutput: z.ZodObject<{ + id: z.ZodString; + town_id: z.ZodString; + name: z.ZodString; + git_url: z.ZodString; + default_branch: z.ZodString; + platform_integration_id: z.ZodDefault>>; + created_at: z.ZodString; + updated_at: z.ZodString; + agents: z.ZodArray; + role: z.ZodUnion<[z.ZodEnum<{ + mayor: "mayor"; + polecat: "polecat"; + refinery: "refinery"; + }>, z.ZodString]>; + name: z.ZodString; + identity: z.ZodString; + status: z.ZodUnion<[z.ZodEnum<{ + dead: "dead"; + idle: "idle"; + stalled: "stalled"; + working: "working"; + }>, z.ZodString]>; + current_hook_bead_id: z.ZodNullable; + dispatch_attempts: z.ZodDefault; + last_activity_at: z.ZodNullable; + checkpoint: z.ZodOptional; + created_at: z.ZodString; + agent_status_message: z.ZodDefault>>; + agent_status_updated_at: z.ZodDefault>>; + }, z.core.$strip>>; + beads: z.ZodArray; + status: z.ZodEnum<{ + closed: "closed"; + failed: "failed"; + in_progress: "in_progress"; + in_review: "in_review"; + open: "open"; + }>; + title: z.ZodString; + body: z.ZodNullable; + rig_id: z.ZodNullable; + parent_bead_id: z.ZodNullable; + assignee_agent_bead_id: z.ZodNullable; + priority: z.ZodEnum<{ + critical: "critical"; + high: "high"; + low: "low"; + medium: "medium"; + }>; + labels: z.ZodArray; + metadata: z.ZodRecord; + created_by: z.ZodNullable; + created_at: z.ZodString; + updated_at: z.ZodString; + closed_at: z.ZodNullable; + }, z.core.$strip>>; +}, z.core.$strip>; +export declare const RpcTownOutput: z.ZodPipe>; +export declare const RpcRigOutput: z.ZodPipe>>; + created_at: z.ZodString; + updated_at: z.ZodString; +}, z.core.$strip>>; +export declare const RpcBeadOutput: z.ZodPipe; + status: z.ZodEnum<{ + closed: "closed"; + failed: "failed"; + in_progress: "in_progress"; + in_review: "in_review"; + open: "open"; + }>; + title: z.ZodString; + body: z.ZodNullable; + rig_id: z.ZodNullable; + parent_bead_id: z.ZodNullable; + assignee_agent_bead_id: z.ZodNullable; + priority: z.ZodEnum<{ + critical: "critical"; + high: "high"; + low: "low"; + medium: "medium"; + }>; + labels: z.ZodArray; + metadata: z.ZodRecord; + created_by: z.ZodNullable; + created_at: z.ZodString; + updated_at: z.ZodString; + closed_at: z.ZodNullable; +}, z.core.$strip>>; +export declare const RpcAgentOutput: z.ZodPipe; + role: z.ZodUnion<[z.ZodEnum<{ + mayor: "mayor"; + polecat: "polecat"; + refinery: "refinery"; + }>, z.ZodString]>; + name: z.ZodString; + identity: z.ZodString; + status: z.ZodUnion<[z.ZodEnum<{ + dead: "dead"; + idle: "idle"; + stalled: "stalled"; + working: "working"; + }>, z.ZodString]>; + current_hook_bead_id: z.ZodNullable; + dispatch_attempts: z.ZodDefault; + last_activity_at: z.ZodNullable; + checkpoint: z.ZodOptional; + created_at: z.ZodString; + agent_status_message: z.ZodDefault>>; + agent_status_updated_at: z.ZodDefault>>; +}, z.core.$strip>>; +export declare const RpcBeadEventOutput: z.ZodPipe; + event_type: z.ZodString; + old_value: z.ZodNullable; + new_value: z.ZodNullable; + metadata: z.ZodRecord; + created_at: z.ZodString; + rig_id: z.ZodOptional; + rig_name: z.ZodOptional; +}, z.core.$strip>>; +export declare const RpcMayorSendResultOutput: z.ZodPipe; +}, z.core.$strip>>; +export declare const RpcMayorStatusOutput: z.ZodPipe; + session: z.ZodNullable; + lastActivityAt: z.ZodString; + }, z.core.$strip>>; +}, z.core.$strip>>; +export declare const RpcStreamTicketOutput: z.ZodPipe; -export declare const PtySessionOutput: z.ZodObject< - { - pty: z.ZodObject< - { +}, z.core.$strip>>; +export declare const RpcPtySessionOutput: z.ZodPipe; + }, z.core.$loose>; wsUrl: z.ZodString; - }, - z.core.$strip ->; -export declare const ConvoyOutput: z.ZodObject< - { +}, z.core.$strip>>; +export declare const RpcConvoyOutput: z.ZodPipe; + staged: z.ZodBoolean; total_beads: z.ZodNumber; closed_beads: z.ZodNumber; created_by: z.ZodNullable; @@ -180,17 +431,15 @@ export declare const ConvoyOutput: z.ZodObject< landed_at: z.ZodNullable; feature_branch: z.ZodNullable; merge_mode: z.ZodNullable; - }, - z.core.$strip ->; -export declare const ConvoyDetailOutput: z.ZodObject< - { +}, z.core.$strip>>; +export declare const RpcConvoyDetailOutput: z.ZodPipe; + staged: z.ZodBoolean; total_beads: z.ZodNumber; closed_beads: z.ZodNumber; created_by: z.ZodNullable; @@ -198,50 +447,36 @@ export declare const ConvoyDetailOutput: z.ZodObject< landed_at: z.ZodNullable; feature_branch: z.ZodNullable; merge_mode: z.ZodNullable; - beads: z.ZodArray< - z.ZodObject< - { - bead_id: z.ZodString; - title: z.ZodString; - status: z.ZodString; - rig_id: z.ZodNullable; - assignee_agent_name: z.ZodNullable; - }, - z.core.$strip - > - >; - dependency_edges: z.ZodArray< - z.ZodObject< - { - bead_id: z.ZodString; - depends_on_bead_id: z.ZodString; - }, - z.core.$strip - > - >; - }, - z.core.$strip ->; -export declare const SlingResultOutput: z.ZodObject< - { - bead: z.ZodObject< - { + beads: z.ZodArray; + assignee_agent_name: z.ZodNullable; + }, z.core.$strip>>; + dependency_edges: z.ZodArray>; +}, z.core.$strip>>; +export declare const RpcSlingResultOutput: z.ZodPipe; status: z.ZodEnum<{ - closed: 'closed'; - failed: 'failed'; - in_progress: 'in_progress'; - in_review: 'in_review'; - open: 'open'; + closed: "closed"; + failed: "failed"; + in_progress: "in_progress"; + in_review: "in_review"; + open: "open"; }>; title: z.ZodString; body: z.ZodNullable; @@ -249,10 +484,10 @@ export declare const SlingResultOutput: z.ZodObject< parent_bead_id: z.ZodNullable; assignee_agent_bead_id: z.ZodNullable; priority: z.ZodEnum<{ - critical: 'critical'; - high: 'high'; - low: 'low'; - medium: 'medium'; + critical: "critical"; + high: "high"; + low: "low"; + medium: "medium"; }>; labels: z.ZodArray; metadata: z.ZodRecord; @@ -260,36 +495,23 @@ export declare const SlingResultOutput: z.ZodObject< created_at: z.ZodString; updated_at: z.ZodString; closed_at: z.ZodNullable; - }, - z.core.$strip - >; - agent: z.ZodObject< - { + }, z.core.$strip>; + agent: z.ZodObject<{ id: z.ZodString; rig_id: z.ZodNullable; - role: z.ZodUnion< - [ - z.ZodEnum<{ - mayor: 'mayor'; - polecat: 'polecat'; - refinery: 'refinery'; - }>, - z.ZodString, - ] - >; + role: z.ZodUnion<[z.ZodEnum<{ + mayor: "mayor"; + polecat: "polecat"; + refinery: "refinery"; + }>, z.ZodString]>; name: z.ZodString; identity: z.ZodString; - status: z.ZodUnion< - [ - z.ZodEnum<{ - dead: 'dead'; - idle: 'idle'; - stalled: 'stalled'; - working: 'working'; - }>, - z.ZodString, - ] - >; + status: z.ZodUnion<[z.ZodEnum<{ + dead: "dead"; + idle: "idle"; + stalled: "stalled"; + working: "working"; + }>, z.ZodString]>; current_hook_bead_id: z.ZodNullable; dispatch_attempts: z.ZodDefault; last_activity_at: z.ZodNullable; @@ -297,14 +519,41 @@ export declare const SlingResultOutput: z.ZodObject< created_at: z.ZodString; agent_status_message: z.ZodDefault>>; agent_status_updated_at: z.ZodDefault>>; - }, - z.core.$strip - >; - }, - z.core.$strip ->; -export declare const RigDetailOutput: z.ZodObject< - { + }, z.core.$strip>; +}, z.core.$strip>>; +export declare const RpcAlarmStatusOutput: z.ZodPipe; + intervalMs: z.ZodNumber; + intervalLabel: z.ZodString; + }, z.core.$strip>; + agents: z.ZodObject<{ + working: z.ZodNumber; + idle: z.ZodNumber; + stalled: z.ZodNumber; + dead: z.ZodNumber; + total: z.ZodNumber; + }, z.core.$strip>; + beads: z.ZodObject<{ + open: z.ZodNumber; + inProgress: z.ZodNumber; + inReview: z.ZodNumber; + failed: z.ZodNumber; + triageRequests: z.ZodNumber; + }, z.core.$strip>; + patrol: z.ZodObject<{ + guppWarnings: z.ZodNumber; + guppEscalations: z.ZodNumber; + stalledAgents: z.ZodNumber; + orphanedHooks: z.ZodNumber; + }, z.core.$strip>; + recentEvents: z.ZodArray>; +}, z.core.$strip>>; +export declare const RpcRigDetailOutput: z.ZodPipe>>; created_at: z.ZodString; updated_at: z.ZodString; - agents: z.ZodArray< - z.ZodObject< - { - id: z.ZodString; - rig_id: z.ZodNullable; - role: z.ZodUnion< - [ - z.ZodEnum<{ - mayor: 'mayor'; - polecat: 'polecat'; - refinery: 'refinery'; - }>, - z.ZodString, - ] - >; - name: z.ZodString; - identity: z.ZodString; - status: z.ZodUnion< - [ - z.ZodEnum<{ - dead: 'dead'; - idle: 'idle'; - stalled: 'stalled'; - working: 'working'; - }>, - z.ZodString, - ] - >; - current_hook_bead_id: z.ZodNullable; - dispatch_attempts: z.ZodDefault; - last_activity_at: z.ZodNullable; - checkpoint: z.ZodOptional; - created_at: z.ZodString; - agent_status_message: z.ZodDefault>>; - agent_status_updated_at: z.ZodDefault>>; - }, - z.core.$strip - > - >; - beads: z.ZodArray< - z.ZodObject< - { - bead_id: z.ZodString; - type: z.ZodEnum<{ - agent: 'agent'; - convoy: 'convoy'; - escalation: 'escalation'; - issue: 'issue'; - merge_request: 'merge_request'; - message: 'message'; - molecule: 'molecule'; - }>; - status: z.ZodEnum<{ - closed: 'closed'; - failed: 'failed'; - in_progress: 'in_progress'; - in_review: 'in_review'; - open: 'open'; - }>; - title: z.ZodString; - body: z.ZodNullable; - rig_id: z.ZodNullable; - parent_bead_id: z.ZodNullable; - assignee_agent_bead_id: z.ZodNullable; - priority: z.ZodEnum<{ - critical: 'critical'; - high: 'high'; - low: 'low'; - medium: 'medium'; - }>; - labels: z.ZodArray; - metadata: z.ZodRecord; - created_by: z.ZodNullable; - created_at: z.ZodString; - updated_at: z.ZodString; - closed_at: z.ZodNullable; - }, - z.core.$strip - > - >; - }, - z.core.$strip ->; -export declare const RpcTownOutput: z.ZodPipe< - z.ZodAny, - z.ZodObject< - { - id: z.ZodString; - name: z.ZodString; - owner_user_id: z.ZodString; - created_at: z.ZodString; - updated_at: z.ZodString; - }, - z.core.$strip - > ->; -export declare const RpcRigOutput: z.ZodPipe< - z.ZodAny, - z.ZodObject< - { - id: z.ZodString; - town_id: z.ZodString; - name: z.ZodString; - git_url: z.ZodString; - default_branch: z.ZodString; - platform_integration_id: z.ZodDefault>>; - created_at: z.ZodString; - updated_at: z.ZodString; - }, - z.core.$strip - > ->; -export declare const RpcBeadOutput: z.ZodPipe< - z.ZodAny, - z.ZodObject< - { - bead_id: z.ZodString; - type: z.ZodEnum<{ - agent: 'agent'; - convoy: 'convoy'; - escalation: 'escalation'; - issue: 'issue'; - merge_request: 'merge_request'; - message: 'message'; - molecule: 'molecule'; - }>; - status: z.ZodEnum<{ - closed: 'closed'; - failed: 'failed'; - in_progress: 'in_progress'; - in_review: 'in_review'; - open: 'open'; - }>; - title: z.ZodString; - body: z.ZodNullable; - rig_id: z.ZodNullable; - parent_bead_id: z.ZodNullable; - assignee_agent_bead_id: z.ZodNullable; - priority: z.ZodEnum<{ - critical: 'critical'; - high: 'high'; - low: 'low'; - medium: 'medium'; - }>; - labels: z.ZodArray; - metadata: z.ZodRecord; - created_by: z.ZodNullable; - created_at: z.ZodString; - updated_at: z.ZodString; - closed_at: z.ZodNullable; - }, - z.core.$strip - > ->; -export declare const RpcAgentOutput: z.ZodPipe< - z.ZodAny, - z.ZodObject< - { - id: z.ZodString; - rig_id: z.ZodNullable; - role: z.ZodUnion< - [ - z.ZodEnum<{ - mayor: 'mayor'; - polecat: 'polecat'; - refinery: 'refinery'; - }>, - z.ZodString, - ] - >; - name: z.ZodString; - identity: z.ZodString; - status: z.ZodUnion< - [ - z.ZodEnum<{ - dead: 'dead'; - idle: 'idle'; - stalled: 'stalled'; - working: 'working'; - }>, - z.ZodString, - ] - >; - current_hook_bead_id: z.ZodNullable; - dispatch_attempts: z.ZodDefault; - last_activity_at: z.ZodNullable; - checkpoint: z.ZodOptional; - created_at: z.ZodString; - agent_status_message: z.ZodDefault>>; - agent_status_updated_at: z.ZodDefault>>; - }, - z.core.$strip - > ->; -export declare const RpcBeadEventOutput: z.ZodPipe< - z.ZodAny, - z.ZodObject< - { - bead_event_id: z.ZodString; - bead_id: z.ZodString; - agent_id: z.ZodNullable; - event_type: z.ZodString; - old_value: z.ZodNullable; - new_value: z.ZodNullable; - metadata: z.ZodRecord; - created_at: z.ZodString; - rig_id: z.ZodOptional; - rig_name: z.ZodOptional; - }, - z.core.$strip - > ->; -export declare const RpcMayorSendResultOutput: z.ZodPipe< - z.ZodAny, - z.ZodObject< - { - agentId: z.ZodString; - sessionStatus: z.ZodEnum<{ - active: 'active'; - idle: 'idle'; - starting: 'starting'; - }>; - }, - z.core.$strip - > ->; -export declare const RpcMayorStatusOutput: z.ZodPipe< - z.ZodAny, - z.ZodObject< - { - configured: z.ZodBoolean; - townId: z.ZodNullable; - session: z.ZodNullable< - z.ZodObject< - { - agentId: z.ZodString; - sessionId: z.ZodString; - status: z.ZodEnum<{ - active: 'active'; - idle: 'idle'; - starting: 'starting'; - }>; - lastActivityAt: z.ZodString; - }, - z.core.$strip - > - >; - }, - z.core.$strip - > ->; -export declare const RpcStreamTicketOutput: z.ZodPipe< - z.ZodAny, - z.ZodObject< - { - url: z.ZodString; - ticket: z.ZodString; - }, - z.core.$strip - > ->; -export declare const RpcPtySessionOutput: z.ZodPipe< - z.ZodAny, - z.ZodObject< - { - pty: z.ZodObject< - { - id: z.ZodString; - }, - z.core.$loose - >; - wsUrl: z.ZodString; - }, - z.core.$strip - > ->; -export declare const RpcConvoyOutput: z.ZodPipe< - z.ZodAny, - z.ZodObject< - { - id: z.ZodString; - title: z.ZodString; - status: z.ZodEnum<{ - active: 'active'; - landed: 'landed'; - }>; - total_beads: z.ZodNumber; - closed_beads: z.ZodNumber; - created_by: z.ZodNullable; - created_at: z.ZodString; - landed_at: z.ZodNullable; - feature_branch: z.ZodNullable; - merge_mode: z.ZodNullable; - }, - z.core.$strip - > ->; -export declare const RpcConvoyDetailOutput: z.ZodPipe< - z.ZodAny, - z.ZodObject< - { - id: z.ZodString; - title: z.ZodString; - status: z.ZodEnum<{ - active: 'active'; - landed: 'landed'; - }>; - total_beads: z.ZodNumber; - closed_beads: z.ZodNumber; - created_by: z.ZodNullable; - created_at: z.ZodString; - landed_at: z.ZodNullable; - feature_branch: z.ZodNullable; - merge_mode: z.ZodNullable; - beads: z.ZodArray< - z.ZodObject< - { - bead_id: z.ZodString; - title: z.ZodString; - status: z.ZodString; - rig_id: z.ZodNullable; - assignee_agent_name: z.ZodNullable; - }, - z.core.$strip - > - >; - dependency_edges: z.ZodArray< - z.ZodObject< - { - bead_id: z.ZodString; - depends_on_bead_id: z.ZodString; - }, - z.core.$strip - > - >; - }, - z.core.$strip - > ->; -export declare const RpcSlingResultOutput: z.ZodPipe< - z.ZodAny, - z.ZodObject< - { - bead: z.ZodObject< - { - bead_id: z.ZodString; - type: z.ZodEnum<{ - agent: 'agent'; - convoy: 'convoy'; - escalation: 'escalation'; - issue: 'issue'; - merge_request: 'merge_request'; - message: 'message'; - molecule: 'molecule'; - }>; - status: z.ZodEnum<{ - closed: 'closed'; - failed: 'failed'; - in_progress: 'in_progress'; - in_review: 'in_review'; - open: 'open'; - }>; - title: z.ZodString; - body: z.ZodNullable; - rig_id: z.ZodNullable; - parent_bead_id: z.ZodNullable; - assignee_agent_bead_id: z.ZodNullable; - priority: z.ZodEnum<{ - critical: 'critical'; - high: 'high'; - low: 'low'; - medium: 'medium'; - }>; - labels: z.ZodArray; - metadata: z.ZodRecord; - created_by: z.ZodNullable; - created_at: z.ZodString; - updated_at: z.ZodString; - closed_at: z.ZodNullable; - }, - z.core.$strip - >; - agent: z.ZodObject< - { - id: z.ZodString; - rig_id: z.ZodNullable; - role: z.ZodUnion< - [ - z.ZodEnum<{ - mayor: 'mayor'; - polecat: 'polecat'; - refinery: 'refinery'; - }>, - z.ZodString, - ] - >; - name: z.ZodString; - identity: z.ZodString; - status: z.ZodUnion< - [ - z.ZodEnum<{ - dead: 'dead'; - idle: 'idle'; - stalled: 'stalled'; - working: 'working'; - }>, - z.ZodString, - ] - >; - current_hook_bead_id: z.ZodNullable; - dispatch_attempts: z.ZodDefault; - last_activity_at: z.ZodNullable; - checkpoint: z.ZodOptional; - created_at: z.ZodString; - agent_status_message: z.ZodDefault>>; - agent_status_updated_at: z.ZodDefault>>; - }, - z.core.$strip - >; - }, - z.core.$strip - > ->; -export declare const RpcAlarmStatusOutput: z.ZodPipe< - z.ZodAny, - z.ZodObject< - { - alarm: z.ZodObject< - { - nextFireAt: z.ZodNullable; - intervalMs: z.ZodNumber; - intervalLabel: z.ZodString; - }, - z.core.$strip - >; - agents: z.ZodObject< - { - working: z.ZodNumber; - idle: z.ZodNumber; - stalled: z.ZodNumber; - dead: z.ZodNumber; - total: z.ZodNumber; - }, - z.core.$strip - >; - beads: z.ZodObject< - { - open: z.ZodNumber; - inProgress: z.ZodNumber; - inReview: z.ZodNumber; - failed: z.ZodNumber; - triageRequests: z.ZodNumber; - }, - z.core.$strip - >; - patrol: z.ZodObject< - { - guppWarnings: z.ZodNumber; - guppEscalations: z.ZodNumber; - stalledAgents: z.ZodNumber; - orphanedHooks: z.ZodNumber; - }, - z.core.$strip - >; - recentEvents: z.ZodArray< - z.ZodObject< - { - time: z.ZodString; - type: z.ZodString; - message: z.ZodString; - }, - z.core.$strip - > - >; - }, - z.core.$strip - > ->; -export declare const RpcRigDetailOutput: z.ZodPipe< - z.ZodAny, - z.ZodObject< - { - id: z.ZodString; - town_id: z.ZodString; - name: z.ZodString; - git_url: z.ZodString; - default_branch: z.ZodString; - platform_integration_id: z.ZodDefault>>; - created_at: z.ZodString; - updated_at: z.ZodString; - agents: z.ZodArray< - z.ZodObject< - { - id: z.ZodString; - rig_id: z.ZodNullable; - role: z.ZodUnion< - [ - z.ZodEnum<{ - mayor: 'mayor'; - polecat: 'polecat'; - refinery: 'refinery'; - }>, - z.ZodString, - ] - >; - name: z.ZodString; - identity: z.ZodString; - status: z.ZodUnion< - [ - z.ZodEnum<{ - dead: 'dead'; - idle: 'idle'; - stalled: 'stalled'; - working: 'working'; - }>, - z.ZodString, - ] - >; - current_hook_bead_id: z.ZodNullable; - dispatch_attempts: z.ZodDefault; - last_activity_at: z.ZodNullable; - checkpoint: z.ZodOptional; - created_at: z.ZodString; - agent_status_message: z.ZodDefault>>; - agent_status_updated_at: z.ZodDefault>>; - }, - z.core.$strip - > - >; - beads: z.ZodArray< - z.ZodObject< - { - bead_id: z.ZodString; - type: z.ZodEnum<{ - agent: 'agent'; - convoy: 'convoy'; - escalation: 'escalation'; - issue: 'issue'; - merge_request: 'merge_request'; - message: 'message'; - molecule: 'molecule'; - }>; - status: z.ZodEnum<{ - closed: 'closed'; - failed: 'failed'; - in_progress: 'in_progress'; - in_review: 'in_review'; - open: 'open'; - }>; - title: z.ZodString; - body: z.ZodNullable; - rig_id: z.ZodNullable; - parent_bead_id: z.ZodNullable; - assignee_agent_bead_id: z.ZodNullable; - priority: z.ZodEnum<{ - critical: 'critical'; - high: 'high'; - low: 'low'; - medium: 'medium'; - }>; - labels: z.ZodArray; - metadata: z.ZodRecord; - created_by: z.ZodNullable; - created_at: z.ZodString; - updated_at: z.ZodString; - closed_at: z.ZodNullable; - }, - z.core.$strip - > - >; - }, - z.core.$strip - > ->; + agents: z.ZodArray; + role: z.ZodUnion<[z.ZodEnum<{ + mayor: "mayor"; + polecat: "polecat"; + refinery: "refinery"; + }>, z.ZodString]>; + name: z.ZodString; + identity: z.ZodString; + status: z.ZodUnion<[z.ZodEnum<{ + dead: "dead"; + idle: "idle"; + stalled: "stalled"; + working: "working"; + }>, z.ZodString]>; + current_hook_bead_id: z.ZodNullable; + dispatch_attempts: z.ZodDefault; + last_activity_at: z.ZodNullable; + checkpoint: z.ZodOptional; + created_at: z.ZodString; + agent_status_message: z.ZodDefault>>; + agent_status_updated_at: z.ZodDefault>>; + }, z.core.$strip>>; + beads: z.ZodArray; + status: z.ZodEnum<{ + closed: "closed"; + failed: "failed"; + in_progress: "in_progress"; + in_review: "in_review"; + open: "open"; + }>; + title: z.ZodString; + body: z.ZodNullable; + rig_id: z.ZodNullable; + parent_bead_id: z.ZodNullable; + assignee_agent_bead_id: z.ZodNullable; + priority: z.ZodEnum<{ + critical: "critical"; + high: "high"; + low: "low"; + medium: "medium"; + }>; + labels: z.ZodArray; + metadata: z.ZodRecord; + created_by: z.ZodNullable; + created_at: z.ZodString; + updated_at: z.ZodString; + closed_at: z.ZodNullable; + }, z.core.$strip>>; +}, z.core.$strip>>; From c60e67430effd12728660ecb4db2950f8da44c59 Mon Sep 17 00:00:00 2001 From: John Fawcett Date: Sat, 14 Mar 2026 19:06:39 -0500 Subject: [PATCH 5/9] feat(gastown): add staged_convoys_default town setting Adds a town-level config toggle that forces all convoys to be created in staged mode by default. When enabled, the mayor must explicitly start each convoy before agents are dispatched. - Add staged_convoys_default to TownConfigSchema (default: false) - slingConvoy resolves staged as input.staged ?? config.staged_convoys_default - Add Switch toggle in town settings UI under new Convoys section - Add field to admin router TownConfigRecord --- cloudflare-gastown/src/dos/Town.do.ts | 8 +++-- cloudflare-gastown/src/types.ts | 4 +++ .../settings/TownSettingsPageClient.tsx | 33 +++++++++++++++++-- src/lib/gastown/types/router.d.ts | 6 ++++ src/routers/admin/gastown-router.ts | 1 + 5 files changed, 48 insertions(+), 4 deletions(-) diff --git a/cloudflare-gastown/src/dos/Town.do.ts b/cloudflare-gastown/src/dos/Town.do.ts index ef48fb3f11..e3d7c62b5e 100644 --- a/cloudflare-gastown/src/dos/Town.do.ts +++ b/cloudflare-gastown/src/dos/Town.do.ts @@ -1855,6 +1855,10 @@ export class TownDO extends DurableObject { }): Promise<{ convoy: ConvoyEntry; beads: Array<{ bead: Bead; agent: Agent | null }> }> { await this.ensureInitialized(); + // Resolve staged: explicit request wins, otherwise fall back to town config default. + const townConfig = await this.getTownConfig(); + const isStaged = input.staged ?? townConfig.staged_convoys_default; + const convoyId = generateId(); const timestamp = now(); @@ -1944,7 +1948,7 @@ export class TownDO extends DurableObject { const mergeMode = input.merge_mode ?? 'review-then-land'; - const stagedValue = input.staged ? 1 : 0; + const stagedValue = isStaged ? 1 : 0; query( this.sql, @@ -2008,7 +2012,7 @@ export class TownDO extends DurableObject { } } - if (input.staged) { + if (isStaged) { // Staged mode: collect beads without hooking agents or dispatching. for (const beadId of beadIds) { const bead = beadOps.getBead(this.sql, beadId); diff --git a/cloudflare-gastown/src/types.ts b/cloudflare-gastown/src/types.ts index f721a9463b..870f6ac02b 100644 --- a/cloudflare-gastown/src/types.ts +++ b/cloudflare-gastown/src/types.ts @@ -245,6 +245,9 @@ export const TownConfigSchema = z.object({ sleep_after_minutes: z.number().int().min(5).max(120).optional(), }) .optional(), + + /** When true, all convoys are created as staged by default (agents not dispatched until started). */ + staged_convoys_default: z.boolean().default(false), }); export type TownConfig = z.infer; @@ -285,6 +288,7 @@ export const TownConfigUpdateSchema = z.object({ sleep_after_minutes: z.number().int().min(5).max(120).optional(), }) .optional(), + staged_convoys_default: z.boolean().optional(), }); export type TownConfigUpdate = z.infer; diff --git a/src/app/(app)/gastown/[townId]/settings/TownSettingsPageClient.tsx b/src/app/(app)/gastown/[townId]/settings/TownSettingsPageClient.tsx index c48b7d0596..9d563b28d9 100644 --- a/src/app/(app)/gastown/[townId]/settings/TownSettingsPageClient.tsx +++ b/src/app/(app)/gastown/[townId]/settings/TownSettingsPageClient.tsx @@ -21,6 +21,7 @@ import { Bot, Shield, Variable, + Layers, } from 'lucide-react'; import { motion } from 'motion/react'; @@ -33,6 +34,7 @@ const SECTIONS = [ { id: 'git-auth', label: 'Git Authentication', icon: GitBranch }, { id: 'env-vars', label: 'Environment Variables', icon: Variable }, { id: 'agent-defaults', label: 'Agent Defaults', icon: Bot }, + { id: 'convoys', label: 'Convoys', icon: Layers }, { id: 'merge-strategy', label: 'Merge Strategy', icon: GitPullRequest }, { id: 'refinery', label: 'Refinery', icon: Shield }, ] as const; @@ -101,6 +103,7 @@ export function TownSettingsPageClient({ townId }: Props) { const [refineryGates, setRefineryGates] = useState([]); const [autoMerge, setAutoMerge] = useState(true); const [mergeStrategy, setMergeStrategy] = useState<'direct' | 'pr'>('direct'); + const [stagedConvoysDefault, setStagedConvoysDefault] = useState(false); const [initialized, setInitialized] = useState(false); const [showTokens, setShowTokens] = useState(false); @@ -116,6 +119,7 @@ export function TownSettingsPageClient({ townId }: Props) { setRefineryGates(cfg.refinery?.gates ?? []); setAutoMerge(cfg.refinery?.auto_merge ?? true); setMergeStrategy(cfg.merge_strategy === 'pr' ? 'pr' : 'direct'); + setStagedConvoysDefault(cfg.staged_convoys_default ?? false); setInitialized(true); } @@ -141,6 +145,7 @@ export function TownSettingsPageClient({ townId }: Props) { ...(defaultModel ? { default_model: defaultModel } : {}), ...(maxPolecats ? { max_polecats_per_rig: maxPolecats } : {}), merge_strategy: mergeStrategy, + staged_convoys_default: stagedConvoysDefault, refinery: { gates: refineryGates.filter(g => g.trim()), auto_merge: autoMerge, @@ -360,13 +365,37 @@ export function TownSettingsPageClient({ townId }: Props) {
+ {/* ── Convoys ──────────────────────────────────────── */} + +
+ +
+ +

+ When enabled, new convoys are created in staged mode — agents are not + dispatched until the convoy is explicitly started. This gives the mayor a + chance to review and adjust the plan before execution begins. +

+
+
+
+ {/* ── Merge Strategy ──────────────────────────────────── */}
; @@ -447,6 +448,7 @@ export declare const gastownRouter: import("@trpc/server").TRPCBuiltRouter<{ container?: { sleep_after_minutes?: number | undefined; } | undefined; + staged_convoys_default?: boolean | undefined; }; }; output: { @@ -473,6 +475,7 @@ export declare const gastownRouter: import("@trpc/server").TRPCBuiltRouter<{ container?: { sleep_after_minutes?: number | undefined; } | undefined; + staged_convoys_default: boolean; }; meta: object; }>; @@ -1234,6 +1237,7 @@ export declare const wrappedGastownRouter: import("@trpc/server").TRPCBuiltRoute container?: { sleep_after_minutes?: number | undefined; } | undefined; + staged_convoys_default: boolean; }; meta: object; }>; @@ -1264,6 +1268,7 @@ export declare const wrappedGastownRouter: import("@trpc/server").TRPCBuiltRoute container?: { sleep_after_minutes?: number | undefined; } | undefined; + staged_convoys_default?: boolean | undefined; }; }; output: { @@ -1290,6 +1295,7 @@ export declare const wrappedGastownRouter: import("@trpc/server").TRPCBuiltRoute container?: { sleep_after_minutes?: number | undefined; } | undefined; + staged_convoys_default: boolean; }; meta: object; }>; diff --git a/src/routers/admin/gastown-router.ts b/src/routers/admin/gastown-router.ts index 0e51132b8d..021ae2b8c6 100644 --- a/src/routers/admin/gastown-router.ts +++ b/src/routers/admin/gastown-router.ts @@ -135,6 +135,7 @@ const TownConfigRecord = z.object({ alarm_interval_active: z.number().optional(), alarm_interval_idle: z.number().optional(), container: z.object({ sleep_after_minutes: z.number().optional() }).optional(), + staged_convoys_default: z.boolean().optional(), }); const ConvoyDetailRecord = z.object({ From 86ed65cf0a3f8a5ee270452accbfddbd8df0ade6 Mon Sep 17 00:00:00 2001 From: John Fawcett Date: Sat, 14 Mar 2026 19:53:01 -0500 Subject: [PATCH 6/9] fix(gastown): address PR review feedback on staged convoys - Fix duplicate mayorToken DOM id in dashboard convoy panel (use convoyMayorToken) - Remove 'staged' from Convoy status enum in container plugin types (staging is tracked by the boolean field, not status) - Re-read bead after hookBead in startConvoy so assignee is up to date - Change convoy.created to convoy.started event in startConvoy --- .../container/plugin/mayor-tools.test.ts | 2 +- cloudflare-gastown/container/plugin/types.ts | 4 +++- cloudflare-gastown/src/dos/Town.do.ts | 8 +++++--- cloudflare-gastown/src/ui/dashboard.ui.ts | 10 +++++----- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/cloudflare-gastown/container/plugin/mayor-tools.test.ts b/cloudflare-gastown/container/plugin/mayor-tools.test.ts index 0116b135e8..fe21e25673 100644 --- a/cloudflare-gastown/container/plugin/mayor-tools.test.ts +++ b/cloudflare-gastown/container/plugin/mayor-tools.test.ts @@ -72,7 +72,7 @@ const FAKE_CONVOY: Convoy = { const FAKE_STAGED_CONVOY: Convoy = { id: 'convoy-staged-1', title: 'Big Refactor', - status: 'staged', + status: 'active', staged: true, total_beads: 2, closed_beads: 0, diff --git a/cloudflare-gastown/container/plugin/types.ts b/cloudflare-gastown/container/plugin/types.ts index 892d4bd56c..1bc956b5d8 100644 --- a/cloudflare-gastown/container/plugin/types.ts +++ b/cloudflare-gastown/container/plugin/types.ts @@ -95,10 +95,12 @@ export type SlingBatchResult = { }; // Convoy summary (returned by list and status endpoints) +// Staging is tracked by the `staged` boolean, not the status field. +// status tracks the convoy lifecycle: active (in progress) or landed (complete). export type Convoy = { id: string; title: string; - status: 'active' | 'staged' | 'landed'; + status: 'active' | 'landed'; staged: boolean; total_beads: number; closed_beads: number; diff --git a/cloudflare-gastown/src/dos/Town.do.ts b/cloudflare-gastown/src/dos/Town.do.ts index e3d7c62b5e..08eb61a226 100644 --- a/cloudflare-gastown/src/dos/Town.do.ts +++ b/cloudflare-gastown/src/dos/Town.do.ts @@ -2107,9 +2107,11 @@ export class TownDO extends DurableObject { agents.hookBead(this.sql, agent.id, beadId); const hookedAgent = agents.getAgent(this.sql, agent.id) ?? agent; + // Re-read bead after hookBead so assignee_agent_bead_id is up to date + const updatedBead = beadOps.getBead(this.sql, beadId) ?? bead; if (!beadOps.hasUnresolvedBlockers(this.sql, beadId)) { - this.dispatchAgent(hookedAgent, bead).catch(err => + this.dispatchAgent(hookedAgent, updatedBead).catch(err => console.error(`${TOWN_LOG} startConvoy: fire-and-forget dispatchAgent failed:`, err) ); } else { @@ -2118,7 +2120,7 @@ export class TownDO extends DurableObject { ); } - results.push({ bead, agent: hookedAgent }); + results.push({ bead: updatedBead, agent: hookedAgent }); } await this.armAlarmIfNeeded(); @@ -2126,7 +2128,7 @@ export class TownDO extends DurableObject { const updatedConvoy = this.getConvoy(convoyId); if (!updatedConvoy) throw new Error(`Failed to re-fetch convoy after start: ${convoyId}`); this.emitEvent({ - event: 'convoy.created', + event: 'convoy.started', townId: this.townId, convoyId, }); diff --git a/cloudflare-gastown/src/ui/dashboard.ui.ts b/cloudflare-gastown/src/ui/dashboard.ui.ts index 74d5298f59..adc783ce90 100644 --- a/cloudflare-gastown/src/ui/dashboard.ui.ts +++ b/cloudflare-gastown/src/ui/dashboard.ui.ts @@ -371,7 +371,7 @@ export function dashboardHtml(): string { - +
@@ -1077,13 +1077,13 @@ async function containerSendMessage() { async function loadConvoys() { const convoyTownId = el('convoyTownId').value.trim(); if (!convoyTownId) { toast('Set a Town ID first', true); return; } - const mayorToken = el('mayorToken').value.trim(); + const token = el('convoyMayorToken').value.trim(); const log = el('apiLog'); const path = '/api/mayor/' + convoyTownId + '/tools/convoys'; log.innerHTML += 'GET ' + esc(path) + '\\n'; try { const res = await fetch(path, { - headers: { 'Authorization': 'Bearer ' + mayorToken, 'Content-Type': 'application/json' }, + headers: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' }, }); const data = await res.json(); const cls = res.ok ? 'ok' : 'err'; @@ -1124,14 +1124,14 @@ function renderConvoys(convoys, convoyTownId) { } async function startConvoy(convoyId, convoyTownId) { - const mayorToken = el('mayorToken').value.trim(); + const token = el('convoyMayorToken').value.trim(); const log = el('apiLog'); const path = '/api/mayor/' + convoyTownId + '/tools/convoys/' + convoyId + '/start'; log.innerHTML += 'POST ' + esc(path) + '\\n'; try { const res = await fetch(path, { method: 'POST', - headers: { 'Authorization': 'Bearer ' + mayorToken, 'Content-Type': 'application/json' }, + headers: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' }, body: '{}', }); const data = await res.json(); From 701b967aeb3164a4d7977aeadb5a486ecdbad5e5 Mon Sep 17 00:00:00 2001 From: John Fawcett Date: Sat, 14 Mar 2026 20:09:09 -0500 Subject: [PATCH 7/9] fix(gastown): address PR review feedback round 3 - Use result.convoy.staged instead of args.staged in gt_sling_batch so tool output reflects actual server state (respects town config default) - Add getConvoy tRPC query so ConvoyPanel uses a by-id query instead of filtering listConvoys (drawer no longer breaks when convoy lands) - Emit convoy.created event in slingConvoy so batch-created convoys appear in the activity feed/analytics - Fix prettier formatting on generated .d.ts files --- .../container/plugin/mayor-tools.ts | 2 +- cloudflare-gastown/src/dos/Town.do.ts | 5 + cloudflare-gastown/src/trpc/router.ts | 14 + .../gastown/drawer-panels/ConvoyPanel.tsx | 11 +- src/lib/gastown/types/router.d.ts | 2765 +++++++++-------- src/lib/gastown/types/schemas.d.ts | 1272 +++++--- 6 files changed, 2293 insertions(+), 1776 deletions(-) diff --git a/cloudflare-gastown/container/plugin/mayor-tools.ts b/cloudflare-gastown/container/plugin/mayor-tools.ts index 2c1a82b5ad..92d29482fe 100644 --- a/cloudflare-gastown/container/plugin/mayor-tools.ts +++ b/cloudflare-gastown/container/plugin/mayor-tools.ts @@ -198,7 +198,7 @@ export function createMayorTools(client: MayorGastownClient) { : ` ${i + 1}. "${b.bead.title}" (unassigned, pending gt_convoy_start)` ); const mode = args.merge_mode ?? 'review-then-land'; - const staged = args.staged === true; + const staged = result.convoy.staged; return [ `Convoy ${staged ? 'staged' : 'created'}: "${result.convoy.title}" (${result.convoy.id})`, `Merge mode: ${mode}`, diff --git a/cloudflare-gastown/src/dos/Town.do.ts b/cloudflare-gastown/src/dos/Town.do.ts index 08eb61a226..3060e84ca2 100644 --- a/cloudflare-gastown/src/dos/Town.do.ts +++ b/cloudflare-gastown/src/dos/Town.do.ts @@ -2049,6 +2049,11 @@ export class TownDO extends DurableObject { const convoy = this.getConvoy(convoyId); if (!convoy) throw new Error('Failed to create convoy'); + this.emitEvent({ + event: 'convoy.created', + townId: this.townId, + convoyId, + }); return { convoy, beads: results }; } diff --git a/cloudflare-gastown/src/trpc/router.ts b/cloudflare-gastown/src/trpc/router.ts index abfd81f2a3..2f9df5046a 100644 --- a/cloudflare-gastown/src/trpc/router.ts +++ b/cloudflare-gastown/src/trpc/router.ts @@ -628,6 +628,20 @@ export const gastownRouter = router({ return townStub.listConvoysDetailed(); }), + getConvoy: gastownProcedure + .input( + z.object({ + townId: z.string().uuid(), + convoyId: z.string().uuid(), + }) + ) + .output(RpcConvoyDetailOutput.nullable()) + .query(async ({ ctx, input }) => { + await verifyTownOwnership(ctx.env, ctx.userId, input.townId); + const townStub = getTownDOStub(ctx.env, input.townId); + return townStub.getConvoyStatus(input.convoyId); + }), + closeConvoy: gastownProcedure .input( z.object({ diff --git a/src/components/gastown/drawer-panels/ConvoyPanel.tsx b/src/components/gastown/drawer-panels/ConvoyPanel.tsx index 6c30e9157a..4c2cc7342a 100644 --- a/src/components/gastown/drawer-panels/ConvoyPanel.tsx +++ b/src/components/gastown/drawer-panels/ConvoyPanel.tsx @@ -113,16 +113,19 @@ export function ConvoyPanel({ const trpc = useGastownTRPC(); const queryClient = useQueryClient(); - const convoysQuery = useQuery({ - ...trpc.gastown.listConvoys.queryOptions({ townId }), + const convoyQuery = useQuery({ + ...trpc.gastown.getConvoy.queryOptions({ townId, convoyId }), refetchInterval: 5_000, }); - const convoy = (convoysQuery.data ?? []).find(c => c.id === convoyId); + const convoy = convoyQuery.data ?? null; const startConvoyMutation = useMutation( trpc.gastown.startConvoy.mutationOptions({ onSuccess: () => { + void queryClient.invalidateQueries({ + queryKey: trpc.gastown.getConvoy.queryKey({ townId, convoyId }), + }); void queryClient.invalidateQueries({ queryKey: trpc.gastown.listConvoys.queryKey({ townId }), }); @@ -137,7 +140,7 @@ export function ConvoyPanel({ [convoy?.beads, convoy?.dependency_edges] ); - if (convoysQuery.isLoading) { + if (convoyQuery.isLoading) { return (
diff --git a/src/lib/gastown/types/router.d.ts b/src/lib/gastown/types/router.d.ts index 647e5ffaa1..4927c0d778 100644 --- a/src/lib/gastown/types/router.d.ts +++ b/src/lib/gastown/types/router.d.ts @@ -1,63 +1,999 @@ import type { TRPCContext } from './init'; -export declare const gastownRouter: import("@trpc/server").TRPCBuiltRouter<{ +export declare const gastownRouter: import('@trpc/server').TRPCBuiltRouter< + { ctx: TRPCContext; meta: object; - errorShape: import("@trpc/server").TRPCDefaultErrorShape; + errorShape: import('@trpc/server').TRPCDefaultErrorShape; transformer: false; -}, import("@trpc/server").TRPCDecorateCreateRouterOptions<{ - createTown: import("@trpc/server").TRPCMutationProcedure<{ - input: { - name: string; + }, + import('@trpc/server').TRPCDecorateCreateRouterOptions<{ + createTown: import('@trpc/server').TRPCMutationProcedure<{ + input: { + name: string; + }; + output: { + id: string; + name: string; + owner_user_id: string; + created_at: string; + updated_at: string; + }; + meta: object; + }>; + listTowns: import('@trpc/server').TRPCQueryProcedure<{ + input: void; + output: { + id: string; + name: string; + owner_user_id: string; + created_at: string; + updated_at: string; + }[]; + meta: object; + }>; + getTown: import('@trpc/server').TRPCQueryProcedure<{ + input: { + townId: string; + }; + output: { + id: string; + name: string; + owner_user_id: string; + created_at: string; + updated_at: string; + }; + meta: object; + }>; + deleteTown: import('@trpc/server').TRPCMutationProcedure<{ + input: { + townId: string; + }; + output: void; + meta: object; + }>; + createRig: import('@trpc/server').TRPCMutationProcedure<{ + input: { + townId: string; + name: string; + gitUrl: string; + defaultBranch?: string | undefined; + platformIntegrationId?: string | undefined; + }; + output: { + id: string; + town_id: string; + name: string; + git_url: string; + default_branch: string; + platform_integration_id: string | null; + created_at: string; + updated_at: string; + }; + meta: object; + }>; + listRigs: import('@trpc/server').TRPCQueryProcedure<{ + input: { + townId: string; + }; + output: { + id: string; + town_id: string; + name: string; + git_url: string; + default_branch: string; + platform_integration_id: string | null; + created_at: string; + updated_at: string; + }[]; + meta: object; + }>; + getRig: import('@trpc/server').TRPCQueryProcedure<{ + input: { + rigId: string; + }; + output: { + id: string; + town_id: string; + name: string; + git_url: string; + default_branch: string; + platform_integration_id: string | null; + created_at: string; + updated_at: string; + agents: { + id: string; + rig_id: string | null; + role: string; + name: string; + identity: string; + status: string; + current_hook_bead_id: string | null; + dispatch_attempts: number; + last_activity_at: string | null; + checkpoint?: unknown; + created_at: string; + agent_status_message: string | null; + agent_status_updated_at: string | null; + }[]; + beads: { + bead_id: string; + type: + | 'agent' + | 'convoy' + | 'escalation' + | 'issue' + | 'merge_request' + | 'message' + | 'molecule'; + status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; + title: string; + body: string | null; + rig_id: string | null; + parent_bead_id: string | null; + assignee_agent_bead_id: string | null; + priority: 'critical' | 'high' | 'low' | 'medium'; + labels: string[]; + metadata: Record; + created_by: string | null; + created_at: string; + updated_at: string; + closed_at: string | null; + }[]; + }; + meta: object; + }>; + deleteRig: import('@trpc/server').TRPCMutationProcedure<{ + input: { + rigId: string; + }; + output: void; + meta: object; + }>; + listBeads: import('@trpc/server').TRPCQueryProcedure<{ + input: { + rigId: string; + status?: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open' | undefined; + }; + output: { + bead_id: string; + type: + | 'agent' + | 'convoy' + | 'escalation' + | 'issue' + | 'merge_request' + | 'message' + | 'molecule'; + status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; + title: string; + body: string | null; + rig_id: string | null; + parent_bead_id: string | null; + assignee_agent_bead_id: string | null; + priority: 'critical' | 'high' | 'low' | 'medium'; + labels: string[]; + metadata: Record; + created_by: string | null; + created_at: string; + updated_at: string; + closed_at: string | null; + }[]; + meta: object; + }>; + deleteBead: import('@trpc/server').TRPCMutationProcedure<{ + input: { + rigId: string; + beadId: string; + }; + output: void; + meta: object; + }>; + updateBead: import('@trpc/server').TRPCMutationProcedure<{ + input: { + rigId: string; + beadId: string; + title?: string | undefined; + body?: string | null | undefined; + status?: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open' | undefined; + priority?: 'critical' | 'high' | 'low' | 'medium' | undefined; + labels?: string[] | undefined; + metadata?: Record | undefined; + rig_id?: string | null | undefined; + parent_bead_id?: string | null | undefined; + }; + output: { + bead_id: string; + type: + | 'agent' + | 'convoy' + | 'escalation' + | 'issue' + | 'merge_request' + | 'message' + | 'molecule'; + status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; + title: string; + body: string | null; + rig_id: string | null; + parent_bead_id: string | null; + assignee_agent_bead_id: string | null; + priority: 'critical' | 'high' | 'low' | 'medium'; + labels: string[]; + metadata: Record; + created_by: string | null; + created_at: string; + updated_at: string; + closed_at: string | null; + }; + meta: object; + }>; + listAgents: import('@trpc/server').TRPCQueryProcedure<{ + input: { + rigId: string; + }; + output: { + id: string; + rig_id: string | null; + role: string; + name: string; + identity: string; + status: string; + current_hook_bead_id: string | null; + dispatch_attempts: number; + last_activity_at: string | null; + checkpoint?: unknown; + created_at: string; + agent_status_message: string | null; + agent_status_updated_at: string | null; + }[]; + meta: object; + }>; + deleteAgent: import('@trpc/server').TRPCMutationProcedure<{ + input: { + rigId: string; + agentId: string; + }; + output: void; + meta: object; + }>; + sling: import('@trpc/server').TRPCMutationProcedure<{ + input: { + rigId: string; + title: string; + body?: string | undefined; + model?: string | undefined; + }; + output: { + bead: { + bead_id: string; + type: + | 'agent' + | 'convoy' + | 'escalation' + | 'issue' + | 'merge_request' + | 'message' + | 'molecule'; + status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; + title: string; + body: string | null; + rig_id: string | null; + parent_bead_id: string | null; + assignee_agent_bead_id: string | null; + priority: 'critical' | 'high' | 'low' | 'medium'; + labels: string[]; + metadata: Record; + created_by: string | null; + created_at: string; + updated_at: string; + closed_at: string | null; + }; + agent: { + id: string; + rig_id: string | null; + role: string; + name: string; + identity: string; + status: string; + current_hook_bead_id: string | null; + dispatch_attempts: number; + last_activity_at: string | null; + checkpoint?: unknown; + created_at: string; + agent_status_message: string | null; + agent_status_updated_at: string | null; + }; + }; + meta: object; + }>; + sendMessage: import('@trpc/server').TRPCMutationProcedure<{ + input: { + townId: string; + message: string; + model?: string | undefined; + rigId?: string | undefined; + }; + output: { + agentId: string; + sessionStatus: 'active' | 'idle' | 'starting'; + }; + meta: object; + }>; + getMayorStatus: import('@trpc/server').TRPCQueryProcedure<{ + input: { + townId: string; + }; + output: { + configured: boolean; + townId: string | null; + session: { + agentId: string; + sessionId: string; + status: 'active' | 'idle' | 'starting'; + lastActivityAt: string; + } | null; + }; + meta: object; + }>; + getAlarmStatus: import('@trpc/server').TRPCQueryProcedure<{ + input: { + townId: string; + }; + output: { + alarm: { + nextFireAt: string | null; + intervalMs: number; + intervalLabel: string; + }; + agents: { + working: number; + idle: number; + stalled: number; + dead: number; + total: number; + }; + beads: { + open: number; + inProgress: number; + inReview: number; + failed: number; + triageRequests: number; + }; + patrol: { + guppWarnings: number; + guppEscalations: number; + stalledAgents: number; + orphanedHooks: number; + }; + recentEvents: { + time: string; + type: string; + message: string; + }[]; + }; + meta: object; + }>; + ensureMayor: import('@trpc/server').TRPCMutationProcedure<{ + input: { + townId: string; + }; + output: { + agentId: string; + sessionStatus: 'active' | 'idle' | 'starting'; + }; + meta: object; + }>; + getAgentStreamUrl: import('@trpc/server').TRPCQueryProcedure<{ + input: { + agentId: string; + townId: string; + }; + output: { + url: string; + ticket: string; + }; + meta: object; + }>; + createPtySession: import('@trpc/server').TRPCMutationProcedure<{ + input: { + townId: string; + agentId: string; + }; + output: { + pty: { + [x: string]: unknown; + id: string; + }; + wsUrl: string; + }; + meta: object; + }>; + resizePtySession: import('@trpc/server').TRPCMutationProcedure<{ + input: { + townId: string; + agentId: string; + ptyId: string; + cols: number; + rows: number; + }; + output: void; + meta: object; + }>; + getTownConfig: import('@trpc/server').TRPCQueryProcedure<{ + input: { + townId: string; + }; + output: { + env_vars: Record; + git_auth: { + github_token?: string | undefined; + gitlab_token?: string | undefined; + gitlab_instance_url?: string | undefined; + platform_integration_id?: string | undefined; + }; + owner_user_id?: string | undefined; + kilocode_token?: string | undefined; + default_model?: string | undefined; + small_model?: string | undefined; + max_polecats_per_rig?: number | undefined; + merge_strategy: 'direct' | 'pr'; + refinery?: + | { + gates: string[]; + auto_merge: boolean; + require_clean_merge: boolean; + } + | undefined; + alarm_interval_active?: number | undefined; + alarm_interval_idle?: number | undefined; + container?: + | { + sleep_after_minutes?: number | undefined; + } + | undefined; + staged_convoys_default: boolean; + }; + meta: object; + }>; + updateTownConfig: import('@trpc/server').TRPCMutationProcedure<{ + input: { + townId: string; + config: { + env_vars?: Record | undefined; + git_auth?: + | { + github_token?: string | undefined; + gitlab_token?: string | undefined; + gitlab_instance_url?: string | undefined; + platform_integration_id?: string | undefined; + } + | undefined; + owner_user_id?: string | undefined; + kilocode_token?: string | undefined; + default_model?: string | undefined; + small_model?: string | undefined; + max_polecats_per_rig?: number | undefined; + merge_strategy?: 'direct' | 'pr' | undefined; + refinery?: + | { + gates?: string[] | undefined; + auto_merge?: boolean | undefined; + require_clean_merge?: boolean | undefined; + } + | undefined; + alarm_interval_active?: number | undefined; + alarm_interval_idle?: number | undefined; + container?: + | { + sleep_after_minutes?: number | undefined; + } + | undefined; + staged_convoys_default?: boolean | undefined; + }; + }; + output: { + env_vars: Record; + git_auth: { + github_token?: string | undefined; + gitlab_token?: string | undefined; + gitlab_instance_url?: string | undefined; + platform_integration_id?: string | undefined; }; - output: { + owner_user_id?: string | undefined; + kilocode_token?: string | undefined; + default_model?: string | undefined; + small_model?: string | undefined; + max_polecats_per_rig?: number | undefined; + merge_strategy: 'direct' | 'pr'; + refinery?: + | { + gates: string[]; + auto_merge: boolean; + require_clean_merge: boolean; + } + | undefined; + alarm_interval_active?: number | undefined; + alarm_interval_idle?: number | undefined; + container?: + | { + sleep_after_minutes?: number | undefined; + } + | undefined; + staged_convoys_default: boolean; + }; + meta: object; + }>; + getBeadEvents: import('@trpc/server').TRPCQueryProcedure<{ + input: { + rigId: string; + beadId?: string | undefined; + since?: string | undefined; + limit?: number | undefined; + }; + output: { + bead_event_id: string; + bead_id: string; + agent_id: string | null; + event_type: string; + old_value: string | null; + new_value: string | null; + metadata: Record; + created_at: string; + rig_id?: string | undefined; + rig_name?: string | undefined; + }[]; + meta: object; + }>; + getTownEvents: import('@trpc/server').TRPCQueryProcedure<{ + input: { + townId: string; + since?: string | undefined; + limit?: number | undefined; + }; + output: { + bead_event_id: string; + bead_id: string; + agent_id: string | null; + event_type: string; + old_value: string | null; + new_value: string | null; + metadata: Record; + created_at: string; + rig_id?: string | undefined; + rig_name?: string | undefined; + }[]; + meta: object; + }>; + listConvoys: import('@trpc/server').TRPCQueryProcedure<{ + input: { + townId: string; + }; + output: { + id: string; + title: string; + status: 'active' | 'landed'; + staged: boolean; + total_beads: number; + closed_beads: number; + created_by: string | null; + created_at: string; + landed_at: string | null; + feature_branch: string | null; + merge_mode: string | null; + beads: { + bead_id: string; + title: string; + status: string; + rig_id: string | null; + assignee_agent_name: string | null; + }[]; + dependency_edges: { + bead_id: string; + depends_on_bead_id: string; + }[]; + }[]; + meta: object; + }>; + getConvoy: import('@trpc/server').TRPCQueryProcedure<{ + input: { + townId: string; + convoyId: string; + }; + output: { + id: string; + title: string; + status: 'active' | 'landed'; + staged: boolean; + total_beads: number; + closed_beads: number; + created_by: string | null; + created_at: string; + landed_at: string | null; + feature_branch: string | null; + merge_mode: string | null; + beads: { + bead_id: string; + title: string; + status: string; + rig_id: string | null; + assignee_agent_name: string | null; + }[]; + dependency_edges: { + bead_id: string; + depends_on_bead_id: string; + }[]; + } | null; + meta: object; + }>; + closeConvoy: import('@trpc/server').TRPCMutationProcedure<{ + input: { + townId: string; + convoyId: string; + }; + output: { + id: string; + title: string; + status: 'active' | 'landed'; + staged: boolean; + total_beads: number; + closed_beads: number; + created_by: string | null; + created_at: string; + landed_at: string | null; + feature_branch: string | null; + merge_mode: string | null; + beads: { + bead_id: string; + title: string; + status: string; + rig_id: string | null; + assignee_agent_name: string | null; + }[]; + dependency_edges: { + bead_id: string; + depends_on_bead_id: string; + }[]; + } | null; + meta: object; + }>; + startConvoy: import('@trpc/server').TRPCMutationProcedure<{ + input: { + townId: string; + convoyId: string; + }; + output: { + id: string; + title: string; + status: 'active' | 'landed'; + staged: boolean; + total_beads: number; + closed_beads: number; + created_by: string | null; + created_at: string; + landed_at: string | null; + feature_branch: string | null; + merge_mode: string | null; + beads: { + bead_id: string; + title: string; + status: string; + rig_id: string | null; + assignee_agent_name: string | null; + }[]; + dependency_edges: { + bead_id: string; + depends_on_bead_id: string; + }[]; + } | null; + meta: object; + }>; + adminListBeads: import('@trpc/server').TRPCQueryProcedure<{ + input: { + townId: string; + status?: 'closed' | 'failed' | 'in_progress' | 'open' | undefined; + type?: + | 'agent' + | 'convoy' + | 'escalation' + | 'issue' + | 'merge_request' + | 'message' + | 'molecule' + | undefined; + limit?: number | undefined; + }; + output: { + bead_id: string; + type: + | 'agent' + | 'convoy' + | 'escalation' + | 'issue' + | 'merge_request' + | 'message' + | 'molecule'; + status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; + title: string; + body: string | null; + rig_id: string | null; + parent_bead_id: string | null; + assignee_agent_bead_id: string | null; + priority: 'critical' | 'high' | 'low' | 'medium'; + labels: string[]; + metadata: Record; + created_by: string | null; + created_at: string; + updated_at: string; + closed_at: string | null; + }[]; + meta: object; + }>; + adminListAgents: import('@trpc/server').TRPCQueryProcedure<{ + input: { + townId: string; + }; + output: { + id: string; + rig_id: string | null; + role: string; + name: string; + identity: string; + status: string; + current_hook_bead_id: string | null; + dispatch_attempts: number; + last_activity_at: string | null; + checkpoint?: unknown; + created_at: string; + agent_status_message: string | null; + agent_status_updated_at: string | null; + }[]; + meta: object; + }>; + adminForceRestartContainer: import('@trpc/server').TRPCMutationProcedure<{ + input: { + townId: string; + }; + output: void; + meta: object; + }>; + adminForceResetAgent: import('@trpc/server').TRPCMutationProcedure<{ + input: { + townId: string; + agentId: string; + }; + output: void; + meta: object; + }>; + adminForceCloseBead: import('@trpc/server').TRPCMutationProcedure<{ + input: { + townId: string; + beadId: string; + }; + output: { + bead_id: string; + type: + | 'agent' + | 'convoy' + | 'escalation' + | 'issue' + | 'merge_request' + | 'message' + | 'molecule'; + status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; + title: string; + body: string | null; + rig_id: string | null; + parent_bead_id: string | null; + assignee_agent_bead_id: string | null; + priority: 'critical' | 'high' | 'low' | 'medium'; + labels: string[]; + metadata: Record; + created_by: string | null; + created_at: string; + updated_at: string; + closed_at: string | null; + }; + meta: object; + }>; + adminForceFailBead: import('@trpc/server').TRPCMutationProcedure<{ + input: { + townId: string; + beadId: string; + }; + output: { + bead_id: string; + type: + | 'agent' + | 'convoy' + | 'escalation' + | 'issue' + | 'merge_request' + | 'message' + | 'molecule'; + status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; + title: string; + body: string | null; + rig_id: string | null; + parent_bead_id: string | null; + assignee_agent_bead_id: string | null; + priority: 'critical' | 'high' | 'low' | 'medium'; + labels: string[]; + metadata: Record; + created_by: string | null; + created_at: string; + updated_at: string; + closed_at: string | null; + }; + meta: object; + }>; + adminGetAlarmStatus: import('@trpc/server').TRPCQueryProcedure<{ + input: { + townId: string; + }; + output: { + alarm: { + nextFireAt: string | null; + intervalMs: number; + intervalLabel: string; + }; + agents: { + working: number; + idle: number; + stalled: number; + dead: number; + total: number; + }; + beads: { + open: number; + inProgress: number; + inReview: number; + failed: number; + triageRequests: number; + }; + patrol: { + guppWarnings: number; + guppEscalations: number; + stalledAgents: number; + orphanedHooks: number; + }; + recentEvents: { + time: string; + type: string; + message: string; + }[]; + }; + meta: object; + }>; + adminGetTownEvents: import('@trpc/server').TRPCQueryProcedure<{ + input: { + townId: string; + beadId?: string | undefined; + since?: string | undefined; + limit?: number | undefined; + }; + output: { + bead_event_id: string; + bead_id: string; + agent_id: string | null; + event_type: string; + old_value: string | null; + new_value: string | null; + metadata: Record; + created_at: string; + rig_id?: string | undefined; + rig_name?: string | undefined; + }[]; + meta: object; + }>; + adminGetBead: import('@trpc/server').TRPCQueryProcedure<{ + input: { + townId: string; + beadId: string; + }; + output: { + bead_id: string; + type: + | 'agent' + | 'convoy' + | 'escalation' + | 'issue' + | 'merge_request' + | 'message' + | 'molecule'; + status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; + title: string; + body: string | null; + rig_id: string | null; + parent_bead_id: string | null; + assignee_agent_bead_id: string | null; + priority: 'critical' | 'high' | 'low' | 'medium'; + labels: string[]; + metadata: Record; + created_by: string | null; + created_at: string; + updated_at: string; + closed_at: string | null; + } | null; + meta: object; + }>; + }> +>; +export type GastownRouter = typeof gastownRouter; +/** + * Wrapped router that nests gastownRouter under a `gastown` key. + * This preserves the `trpc.gastown.X` call pattern on the frontend, + * matching the existing RootRouter shape so components don't need + * to change their procedure paths. + */ +export declare const wrappedGastownRouter: import('@trpc/server').TRPCBuiltRouter< + { + ctx: TRPCContext; + meta: object; + errorShape: import('@trpc/server').TRPCDefaultErrorShape; + transformer: false; + }, + import('@trpc/server').TRPCDecorateCreateRouterOptions<{ + gastown: import('@trpc/server').TRPCBuiltRouter< + { + ctx: TRPCContext; + meta: object; + errorShape: import('@trpc/server').TRPCDefaultErrorShape; + transformer: false; + }, + import('@trpc/server').TRPCDecorateCreateRouterOptions<{ + createTown: import('@trpc/server').TRPCMutationProcedure<{ + input: { + name: string; + }; + output: { id: string; name: string; owner_user_id: string; created_at: string; updated_at: string; - }; - meta: object; - }>; - listTowns: import("@trpc/server").TRPCQueryProcedure<{ - input: void; - output: { + }; + meta: object; + }>; + listTowns: import('@trpc/server').TRPCQueryProcedure<{ + input: void; + output: { id: string; name: string; owner_user_id: string; created_at: string; updated_at: string; - }[]; - meta: object; - }>; - getTown: import("@trpc/server").TRPCQueryProcedure<{ - input: { + }[]; + meta: object; + }>; + getTown: import('@trpc/server').TRPCQueryProcedure<{ + input: { townId: string; - }; - output: { + }; + output: { id: string; name: string; owner_user_id: string; created_at: string; updated_at: string; - }; - meta: object; - }>; - deleteTown: import("@trpc/server").TRPCMutationProcedure<{ - input: { + }; + meta: object; + }>; + deleteTown: import('@trpc/server').TRPCMutationProcedure<{ + input: { townId: string; - }; - output: void; - meta: object; - }>; - createRig: import("@trpc/server").TRPCMutationProcedure<{ - input: { + }; + output: void; + meta: object; + }>; + createRig: import('@trpc/server').TRPCMutationProcedure<{ + input: { townId: string; name: string; gitUrl: string; defaultBranch?: string | undefined; platformIntegrationId?: string | undefined; - }; - output: { + }; + output: { id: string; town_id: string; name: string; @@ -66,14 +1002,14 @@ export declare const gastownRouter: import("@trpc/server").TRPCBuiltRouter<{ platform_integration_id: string | null; created_at: string; updated_at: string; - }; - meta: object; - }>; - listRigs: import("@trpc/server").TRPCQueryProcedure<{ - input: { + }; + meta: object; + }>; + listRigs: import('@trpc/server').TRPCQueryProcedure<{ + input: { townId: string; - }; - output: { + }; + output: { id: string; town_id: string; name: string; @@ -82,14 +1018,14 @@ export declare const gastownRouter: import("@trpc/server").TRPCBuiltRouter<{ platform_integration_id: string | null; created_at: string; updated_at: string; - }[]; - meta: object; - }>; - getRig: import("@trpc/server").TRPCQueryProcedure<{ - input: { + }[]; + meta: object; + }>; + getRig: import('@trpc/server').TRPCQueryProcedure<{ + input: { rigId: string; - }; - output: { + }; + output: { id: string; town_id: string; name: string; @@ -99,116 +1035,137 @@ export declare const gastownRouter: import("@trpc/server").TRPCBuiltRouter<{ created_at: string; updated_at: string; agents: { - id: string; - rig_id: string | null; - role: string; - name: string; - identity: string; - status: string; - current_hook_bead_id: string | null; - dispatch_attempts: number; - last_activity_at: string | null; - checkpoint?: unknown; - created_at: string; - agent_status_message: string | null; - agent_status_updated_at: string | null; + id: string; + rig_id: string | null; + role: string; + name: string; + identity: string; + status: string; + current_hook_bead_id: string | null; + dispatch_attempts: number; + last_activity_at: string | null; + checkpoint?: unknown; + created_at: string; + agent_status_message: string | null; + agent_status_updated_at: string | null; }[]; beads: { - bead_id: string; - type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; - status: "closed" | "failed" | "in_progress" | "in_review" | "open"; - title: string; - body: string | null; - rig_id: string | null; - parent_bead_id: string | null; - assignee_agent_bead_id: string | null; - priority: "critical" | "high" | "low" | "medium"; - labels: string[]; - metadata: Record; - created_by: string | null; - created_at: string; - updated_at: string; - closed_at: string | null; + bead_id: string; + type: + | 'agent' + | 'convoy' + | 'escalation' + | 'issue' + | 'merge_request' + | 'message' + | 'molecule'; + status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; + title: string; + body: string | null; + rig_id: string | null; + parent_bead_id: string | null; + assignee_agent_bead_id: string | null; + priority: 'critical' | 'high' | 'low' | 'medium'; + labels: string[]; + metadata: Record; + created_by: string | null; + created_at: string; + updated_at: string; + closed_at: string | null; }[]; - }; - meta: object; - }>; - deleteRig: import("@trpc/server").TRPCMutationProcedure<{ - input: { + }; + meta: object; + }>; + deleteRig: import('@trpc/server').TRPCMutationProcedure<{ + input: { rigId: string; - }; - output: void; - meta: object; - }>; - listBeads: import("@trpc/server").TRPCQueryProcedure<{ - input: { + }; + output: void; + meta: object; + }>; + listBeads: import('@trpc/server').TRPCQueryProcedure<{ + input: { rigId: string; - status?: "closed" | "failed" | "in_progress" | "in_review" | "open" | undefined; - }; - output: { + status?: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open' | undefined; + }; + output: { bead_id: string; - type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; - status: "closed" | "failed" | "in_progress" | "in_review" | "open"; + type: + | 'agent' + | 'convoy' + | 'escalation' + | 'issue' + | 'merge_request' + | 'message' + | 'molecule'; + status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; title: string; body: string | null; rig_id: string | null; parent_bead_id: string | null; assignee_agent_bead_id: string | null; - priority: "critical" | "high" | "low" | "medium"; + priority: 'critical' | 'high' | 'low' | 'medium'; labels: string[]; metadata: Record; created_by: string | null; created_at: string; updated_at: string; closed_at: string | null; - }[]; - meta: object; - }>; - deleteBead: import("@trpc/server").TRPCMutationProcedure<{ - input: { + }[]; + meta: object; + }>; + deleteBead: import('@trpc/server').TRPCMutationProcedure<{ + input: { rigId: string; beadId: string; - }; - output: void; - meta: object; - }>; - updateBead: import("@trpc/server").TRPCMutationProcedure<{ - input: { + }; + output: void; + meta: object; + }>; + updateBead: import('@trpc/server').TRPCMutationProcedure<{ + input: { rigId: string; beadId: string; title?: string | undefined; body?: string | null | undefined; - status?: "closed" | "failed" | "in_progress" | "in_review" | "open" | undefined; - priority?: "critical" | "high" | "low" | "medium" | undefined; + status?: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open' | undefined; + priority?: 'critical' | 'high' | 'low' | 'medium' | undefined; labels?: string[] | undefined; metadata?: Record | undefined; rig_id?: string | null | undefined; parent_bead_id?: string | null | undefined; - }; - output: { + }; + output: { bead_id: string; - type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; - status: "closed" | "failed" | "in_progress" | "in_review" | "open"; + type: + | 'agent' + | 'convoy' + | 'escalation' + | 'issue' + | 'merge_request' + | 'message' + | 'molecule'; + status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; title: string; body: string | null; rig_id: string | null; parent_bead_id: string | null; assignee_agent_bead_id: string | null; - priority: "critical" | "high" | "low" | "medium"; + priority: 'critical' | 'high' | 'low' | 'medium'; labels: string[]; metadata: Record; created_by: string | null; created_at: string; updated_at: string; closed_at: string | null; - }; - meta: object; - }>; - listAgents: import("@trpc/server").TRPCQueryProcedure<{ - input: { + }; + meta: object; + }>; + listAgents: import('@trpc/server').TRPCQueryProcedure<{ + input: { rigId: string; - }; - output: { + }; + output: { id: string; rig_id: string | null; role: string; @@ -222,271 +1179,292 @@ export declare const gastownRouter: import("@trpc/server").TRPCBuiltRouter<{ created_at: string; agent_status_message: string | null; agent_status_updated_at: string | null; - }[]; - meta: object; - }>; - deleteAgent: import("@trpc/server").TRPCMutationProcedure<{ - input: { + }[]; + meta: object; + }>; + deleteAgent: import('@trpc/server').TRPCMutationProcedure<{ + input: { rigId: string; agentId: string; - }; - output: void; - meta: object; - }>; - sling: import("@trpc/server").TRPCMutationProcedure<{ - input: { + }; + output: void; + meta: object; + }>; + sling: import('@trpc/server').TRPCMutationProcedure<{ + input: { rigId: string; title: string; body?: string | undefined; model?: string | undefined; - }; - output: { + }; + output: { bead: { - bead_id: string; - type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; - status: "closed" | "failed" | "in_progress" | "in_review" | "open"; - title: string; - body: string | null; - rig_id: string | null; - parent_bead_id: string | null; - assignee_agent_bead_id: string | null; - priority: "critical" | "high" | "low" | "medium"; - labels: string[]; - metadata: Record; - created_by: string | null; - created_at: string; - updated_at: string; - closed_at: string | null; + bead_id: string; + type: + | 'agent' + | 'convoy' + | 'escalation' + | 'issue' + | 'merge_request' + | 'message' + | 'molecule'; + status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; + title: string; + body: string | null; + rig_id: string | null; + parent_bead_id: string | null; + assignee_agent_bead_id: string | null; + priority: 'critical' | 'high' | 'low' | 'medium'; + labels: string[]; + metadata: Record; + created_by: string | null; + created_at: string; + updated_at: string; + closed_at: string | null; }; agent: { - id: string; - rig_id: string | null; - role: string; - name: string; - identity: string; - status: string; - current_hook_bead_id: string | null; - dispatch_attempts: number; - last_activity_at: string | null; - checkpoint?: unknown; - created_at: string; - agent_status_message: string | null; - agent_status_updated_at: string | null; - }; - }; - meta: object; - }>; - sendMessage: import("@trpc/server").TRPCMutationProcedure<{ - input: { + id: string; + rig_id: string | null; + role: string; + name: string; + identity: string; + status: string; + current_hook_bead_id: string | null; + dispatch_attempts: number; + last_activity_at: string | null; + checkpoint?: unknown; + created_at: string; + agent_status_message: string | null; + agent_status_updated_at: string | null; + }; + }; + meta: object; + }>; + sendMessage: import('@trpc/server').TRPCMutationProcedure<{ + input: { townId: string; message: string; model?: string | undefined; rigId?: string | undefined; - }; - output: { + }; + output: { agentId: string; - sessionStatus: "active" | "idle" | "starting"; - }; - meta: object; - }>; - getMayorStatus: import("@trpc/server").TRPCQueryProcedure<{ - input: { + sessionStatus: 'active' | 'idle' | 'starting'; + }; + meta: object; + }>; + getMayorStatus: import('@trpc/server').TRPCQueryProcedure<{ + input: { townId: string; - }; - output: { + }; + output: { configured: boolean; townId: string | null; session: { - agentId: string; - sessionId: string; - status: "active" | "idle" | "starting"; - lastActivityAt: string; + agentId: string; + sessionId: string; + status: 'active' | 'idle' | 'starting'; + lastActivityAt: string; } | null; - }; - meta: object; - }>; - getAlarmStatus: import("@trpc/server").TRPCQueryProcedure<{ - input: { + }; + meta: object; + }>; + getAlarmStatus: import('@trpc/server').TRPCQueryProcedure<{ + input: { townId: string; - }; - output: { + }; + output: { alarm: { - nextFireAt: string | null; - intervalMs: number; - intervalLabel: string; + nextFireAt: string | null; + intervalMs: number; + intervalLabel: string; }; agents: { - working: number; - idle: number; - stalled: number; - dead: number; - total: number; + working: number; + idle: number; + stalled: number; + dead: number; + total: number; }; beads: { - open: number; - inProgress: number; - inReview: number; - failed: number; - triageRequests: number; + open: number; + inProgress: number; + inReview: number; + failed: number; + triageRequests: number; }; patrol: { - guppWarnings: number; - guppEscalations: number; - stalledAgents: number; - orphanedHooks: number; + guppWarnings: number; + guppEscalations: number; + stalledAgents: number; + orphanedHooks: number; }; recentEvents: { - time: string; - type: string; - message: string; + time: string; + type: string; + message: string; }[]; - }; - meta: object; - }>; - ensureMayor: import("@trpc/server").TRPCMutationProcedure<{ - input: { + }; + meta: object; + }>; + ensureMayor: import('@trpc/server').TRPCMutationProcedure<{ + input: { townId: string; - }; - output: { + }; + output: { agentId: string; - sessionStatus: "active" | "idle" | "starting"; - }; - meta: object; - }>; - getAgentStreamUrl: import("@trpc/server").TRPCQueryProcedure<{ - input: { + sessionStatus: 'active' | 'idle' | 'starting'; + }; + meta: object; + }>; + getAgentStreamUrl: import('@trpc/server').TRPCQueryProcedure<{ + input: { agentId: string; townId: string; - }; - output: { + }; + output: { url: string; ticket: string; - }; - meta: object; - }>; - createPtySession: import("@trpc/server").TRPCMutationProcedure<{ - input: { + }; + meta: object; + }>; + createPtySession: import('@trpc/server').TRPCMutationProcedure<{ + input: { townId: string; agentId: string; - }; - output: { + }; + output: { pty: { - [x: string]: unknown; - id: string; + [x: string]: unknown; + id: string; }; wsUrl: string; - }; - meta: object; - }>; - resizePtySession: import("@trpc/server").TRPCMutationProcedure<{ - input: { + }; + meta: object; + }>; + resizePtySession: import('@trpc/server').TRPCMutationProcedure<{ + input: { townId: string; agentId: string; ptyId: string; cols: number; rows: number; - }; - output: void; - meta: object; - }>; - getTownConfig: import("@trpc/server").TRPCQueryProcedure<{ - input: { + }; + output: void; + meta: object; + }>; + getTownConfig: import('@trpc/server').TRPCQueryProcedure<{ + input: { townId: string; - }; - output: { + }; + output: { env_vars: Record; git_auth: { - github_token?: string | undefined; - gitlab_token?: string | undefined; - gitlab_instance_url?: string | undefined; - platform_integration_id?: string | undefined; + github_token?: string | undefined; + gitlab_token?: string | undefined; + gitlab_instance_url?: string | undefined; + platform_integration_id?: string | undefined; }; owner_user_id?: string | undefined; kilocode_token?: string | undefined; default_model?: string | undefined; small_model?: string | undefined; max_polecats_per_rig?: number | undefined; - merge_strategy: "direct" | "pr"; - refinery?: { - gates: string[]; - auto_merge: boolean; - require_clean_merge: boolean; - } | undefined; + merge_strategy: 'direct' | 'pr'; + refinery?: + | { + gates: string[]; + auto_merge: boolean; + require_clean_merge: boolean; + } + | undefined; alarm_interval_active?: number | undefined; alarm_interval_idle?: number | undefined; - container?: { - sleep_after_minutes?: number | undefined; - } | undefined; + container?: + | { + sleep_after_minutes?: number | undefined; + } + | undefined; staged_convoys_default: boolean; - }; - meta: object; - }>; - updateTownConfig: import("@trpc/server").TRPCMutationProcedure<{ - input: { + }; + meta: object; + }>; + updateTownConfig: import('@trpc/server').TRPCMutationProcedure<{ + input: { townId: string; config: { - env_vars?: Record | undefined; - git_auth?: { + env_vars?: Record | undefined; + git_auth?: + | { github_token?: string | undefined; gitlab_token?: string | undefined; gitlab_instance_url?: string | undefined; platform_integration_id?: string | undefined; - } | undefined; - owner_user_id?: string | undefined; - kilocode_token?: string | undefined; - default_model?: string | undefined; - small_model?: string | undefined; - max_polecats_per_rig?: number | undefined; - merge_strategy?: "direct" | "pr" | undefined; - refinery?: { + } + | undefined; + owner_user_id?: string | undefined; + kilocode_token?: string | undefined; + default_model?: string | undefined; + small_model?: string | undefined; + max_polecats_per_rig?: number | undefined; + merge_strategy?: 'direct' | 'pr' | undefined; + refinery?: + | { gates?: string[] | undefined; auto_merge?: boolean | undefined; require_clean_merge?: boolean | undefined; - } | undefined; - alarm_interval_active?: number | undefined; - alarm_interval_idle?: number | undefined; - container?: { + } + | undefined; + alarm_interval_active?: number | undefined; + alarm_interval_idle?: number | undefined; + container?: + | { sleep_after_minutes?: number | undefined; - } | undefined; - staged_convoys_default?: boolean | undefined; + } + | undefined; + staged_convoys_default?: boolean | undefined; }; - }; - output: { + }; + output: { env_vars: Record; git_auth: { - github_token?: string | undefined; - gitlab_token?: string | undefined; - gitlab_instance_url?: string | undefined; - platform_integration_id?: string | undefined; + github_token?: string | undefined; + gitlab_token?: string | undefined; + gitlab_instance_url?: string | undefined; + platform_integration_id?: string | undefined; }; owner_user_id?: string | undefined; kilocode_token?: string | undefined; default_model?: string | undefined; small_model?: string | undefined; max_polecats_per_rig?: number | undefined; - merge_strategy: "direct" | "pr"; - refinery?: { - gates: string[]; - auto_merge: boolean; - require_clean_merge: boolean; - } | undefined; + merge_strategy: 'direct' | 'pr'; + refinery?: + | { + gates: string[]; + auto_merge: boolean; + require_clean_merge: boolean; + } + | undefined; alarm_interval_active?: number | undefined; alarm_interval_idle?: number | undefined; - container?: { - sleep_after_minutes?: number | undefined; - } | undefined; + container?: + | { + sleep_after_minutes?: number | undefined; + } + | undefined; staged_convoys_default: boolean; - }; - meta: object; - }>; - getBeadEvents: import("@trpc/server").TRPCQueryProcedure<{ - input: { + }; + meta: object; + }>; + getBeadEvents: import('@trpc/server').TRPCQueryProcedure<{ + input: { rigId: string; beadId?: string | undefined; since?: string | undefined; limit?: number | undefined; - }; - output: { + }; + output: { bead_event_id: string; bead_id: string; agent_id: string | null; @@ -497,16 +1475,16 @@ export declare const gastownRouter: import("@trpc/server").TRPCBuiltRouter<{ created_at: string; rig_id?: string | undefined; rig_name?: string | undefined; - }[]; - meta: object; - }>; - getTownEvents: import("@trpc/server").TRPCQueryProcedure<{ - input: { + }[]; + meta: object; + }>; + getTownEvents: import('@trpc/server').TRPCQueryProcedure<{ + input: { townId: string; since?: string | undefined; limit?: number | undefined; - }; - output: { + }; + output: { bead_event_id: string; bead_id: string; agent_id: string | null; @@ -517,17 +1495,17 @@ export declare const gastownRouter: import("@trpc/server").TRPCBuiltRouter<{ created_at: string; rig_id?: string | undefined; rig_name?: string | undefined; - }[]; - meta: object; - }>; - listConvoys: import("@trpc/server").TRPCQueryProcedure<{ - input: { + }[]; + meta: object; + }>; + listConvoys: import('@trpc/server').TRPCQueryProcedure<{ + input: { townId: string; - }; - output: { + }; + output: { id: string; title: string; - status: "active" | "landed"; + status: 'active' | 'landed'; staged: boolean; total_beads: number; closed_beads: number; @@ -537,28 +1515,28 @@ export declare const gastownRouter: import("@trpc/server").TRPCBuiltRouter<{ feature_branch: string | null; merge_mode: string | null; beads: { - bead_id: string; - title: string; - status: string; - rig_id: string | null; - assignee_agent_name: string | null; + bead_id: string; + title: string; + status: string; + rig_id: string | null; + assignee_agent_name: string | null; }[]; dependency_edges: { - bead_id: string; - depends_on_bead_id: string; + bead_id: string; + depends_on_bead_id: string; }[]; - }[]; - meta: object; - }>; - closeConvoy: import("@trpc/server").TRPCMutationProcedure<{ - input: { + }[]; + meta: object; + }>; + getConvoy: import('@trpc/server').TRPCQueryProcedure<{ + input: { townId: string; convoyId: string; - }; - output: { + }; + output: { id: string; title: string; - status: "active" | "landed"; + status: 'active' | 'landed'; staged: boolean; total_beads: number; closed_beads: number; @@ -568,28 +1546,28 @@ export declare const gastownRouter: import("@trpc/server").TRPCBuiltRouter<{ feature_branch: string | null; merge_mode: string | null; beads: { - bead_id: string; - title: string; - status: string; - rig_id: string | null; - assignee_agent_name: string | null; + bead_id: string; + title: string; + status: string; + rig_id: string | null; + assignee_agent_name: string | null; }[]; dependency_edges: { - bead_id: string; - depends_on_bead_id: string; + bead_id: string; + depends_on_bead_id: string; }[]; - } | null; - meta: object; - }>; - startConvoy: import("@trpc/server").TRPCMutationProcedure<{ - input: { + } | null; + meta: object; + }>; + closeConvoy: import('@trpc/server').TRPCMutationProcedure<{ + input: { townId: string; convoyId: string; - }; - output: { + }; + output: { id: string; title: string; - status: "active" | "landed"; + status: 'active' | 'landed'; staged: boolean; total_beads: number; closed_beads: number; @@ -599,50 +1577,96 @@ export declare const gastownRouter: import("@trpc/server").TRPCBuiltRouter<{ feature_branch: string | null; merge_mode: string | null; beads: { - bead_id: string; - title: string; - status: string; - rig_id: string | null; - assignee_agent_name: string | null; + bead_id: string; + title: string; + status: string; + rig_id: string | null; + assignee_agent_name: string | null; }[]; dependency_edges: { - bead_id: string; - depends_on_bead_id: string; + bead_id: string; + depends_on_bead_id: string; }[]; - } | null; - meta: object; - }>; - adminListBeads: import("@trpc/server").TRPCQueryProcedure<{ - input: { + } | null; + meta: object; + }>; + startConvoy: import('@trpc/server').TRPCMutationProcedure<{ + input: { + townId: string; + convoyId: string; + }; + output: { + id: string; + title: string; + status: 'active' | 'landed'; + staged: boolean; + total_beads: number; + closed_beads: number; + created_by: string | null; + created_at: string; + landed_at: string | null; + feature_branch: string | null; + merge_mode: string | null; + beads: { + bead_id: string; + title: string; + status: string; + rig_id: string | null; + assignee_agent_name: string | null; + }[]; + dependency_edges: { + bead_id: string; + depends_on_bead_id: string; + }[]; + } | null; + meta: object; + }>; + adminListBeads: import('@trpc/server').TRPCQueryProcedure<{ + input: { townId: string; - status?: "closed" | "failed" | "in_progress" | "open" | undefined; - type?: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule" | undefined; + status?: 'closed' | 'failed' | 'in_progress' | 'open' | undefined; + type?: + | 'agent' + | 'convoy' + | 'escalation' + | 'issue' + | 'merge_request' + | 'message' + | 'molecule' + | undefined; limit?: number | undefined; - }; - output: { + }; + output: { bead_id: string; - type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; - status: "closed" | "failed" | "in_progress" | "in_review" | "open"; + type: + | 'agent' + | 'convoy' + | 'escalation' + | 'issue' + | 'merge_request' + | 'message' + | 'molecule'; + status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; title: string; body: string | null; rig_id: string | null; parent_bead_id: string | null; assignee_agent_bead_id: string | null; - priority: "critical" | "high" | "low" | "medium"; + priority: 'critical' | 'high' | 'low' | 'medium'; labels: string[]; metadata: Record; created_by: string | null; created_at: string; updated_at: string; closed_at: string | null; - }[]; - meta: object; - }>; - adminListAgents: import("@trpc/server").TRPCQueryProcedure<{ - input: { + }[]; + meta: object; + }>; + adminListAgents: import('@trpc/server').TRPCQueryProcedure<{ + input: { townId: string; - }; - output: { + }; + output: { id: string; rig_id: string | null; role: string; @@ -656,118 +1680,132 @@ export declare const gastownRouter: import("@trpc/server").TRPCBuiltRouter<{ created_at: string; agent_status_message: string | null; agent_status_updated_at: string | null; - }[]; - meta: object; - }>; - adminForceRestartContainer: import("@trpc/server").TRPCMutationProcedure<{ - input: { + }[]; + meta: object; + }>; + adminForceRestartContainer: import('@trpc/server').TRPCMutationProcedure<{ + input: { townId: string; - }; - output: void; - meta: object; - }>; - adminForceResetAgent: import("@trpc/server").TRPCMutationProcedure<{ - input: { + }; + output: void; + meta: object; + }>; + adminForceResetAgent: import('@trpc/server').TRPCMutationProcedure<{ + input: { townId: string; agentId: string; - }; - output: void; - meta: object; - }>; - adminForceCloseBead: import("@trpc/server").TRPCMutationProcedure<{ - input: { + }; + output: void; + meta: object; + }>; + adminForceCloseBead: import('@trpc/server').TRPCMutationProcedure<{ + input: { townId: string; beadId: string; - }; - output: { + }; + output: { bead_id: string; - type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; - status: "closed" | "failed" | "in_progress" | "in_review" | "open"; + type: + | 'agent' + | 'convoy' + | 'escalation' + | 'issue' + | 'merge_request' + | 'message' + | 'molecule'; + status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; title: string; body: string | null; rig_id: string | null; parent_bead_id: string | null; assignee_agent_bead_id: string | null; - priority: "critical" | "high" | "low" | "medium"; + priority: 'critical' | 'high' | 'low' | 'medium'; labels: string[]; metadata: Record; created_by: string | null; created_at: string; updated_at: string; closed_at: string | null; - }; - meta: object; - }>; - adminForceFailBead: import("@trpc/server").TRPCMutationProcedure<{ - input: { + }; + meta: object; + }>; + adminForceFailBead: import('@trpc/server').TRPCMutationProcedure<{ + input: { townId: string; beadId: string; - }; - output: { + }; + output: { bead_id: string; - type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; - status: "closed" | "failed" | "in_progress" | "in_review" | "open"; + type: + | 'agent' + | 'convoy' + | 'escalation' + | 'issue' + | 'merge_request' + | 'message' + | 'molecule'; + status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; title: string; body: string | null; rig_id: string | null; parent_bead_id: string | null; assignee_agent_bead_id: string | null; - priority: "critical" | "high" | "low" | "medium"; + priority: 'critical' | 'high' | 'low' | 'medium'; labels: string[]; metadata: Record; created_by: string | null; created_at: string; updated_at: string; closed_at: string | null; - }; - meta: object; - }>; - adminGetAlarmStatus: import("@trpc/server").TRPCQueryProcedure<{ - input: { + }; + meta: object; + }>; + adminGetAlarmStatus: import('@trpc/server').TRPCQueryProcedure<{ + input: { townId: string; - }; - output: { + }; + output: { alarm: { - nextFireAt: string | null; - intervalMs: number; - intervalLabel: string; + nextFireAt: string | null; + intervalMs: number; + intervalLabel: string; }; agents: { - working: number; - idle: number; - stalled: number; - dead: number; - total: number; + working: number; + idle: number; + stalled: number; + dead: number; + total: number; }; beads: { - open: number; - inProgress: number; - inReview: number; - failed: number; - triageRequests: number; + open: number; + inProgress: number; + inReview: number; + failed: number; + triageRequests: number; }; patrol: { - guppWarnings: number; - guppEscalations: number; - stalledAgents: number; - orphanedHooks: number; + guppWarnings: number; + guppEscalations: number; + stalledAgents: number; + orphanedHooks: number; }; recentEvents: { - time: string; - type: string; - message: string; + time: string; + type: string; + message: string; }[]; - }; - meta: object; - }>; - adminGetTownEvents: import("@trpc/server").TRPCQueryProcedure<{ - input: { + }; + meta: object; + }>; + adminGetTownEvents: import('@trpc/server').TRPCQueryProcedure<{ + input: { townId: string; beadId?: string | undefined; since?: string | undefined; limit?: number | undefined; - }; - output: { + }; + output: { bead_event_id: string; bead_id: string; agent_id: string | null; @@ -778,853 +1816,42 @@ export declare const gastownRouter: import("@trpc/server").TRPCBuiltRouter<{ created_at: string; rig_id?: string | undefined; rig_name?: string | undefined; - }[]; - meta: object; - }>; - adminGetBead: import("@trpc/server").TRPCQueryProcedure<{ - input: { + }[]; + meta: object; + }>; + adminGetBead: import('@trpc/server').TRPCQueryProcedure<{ + input: { townId: string; beadId: string; - }; - output: { + }; + output: { bead_id: string; - type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; - status: "closed" | "failed" | "in_progress" | "in_review" | "open"; + type: + | 'agent' + | 'convoy' + | 'escalation' + | 'issue' + | 'merge_request' + | 'message' + | 'molecule'; + status: 'closed' | 'failed' | 'in_progress' | 'in_review' | 'open'; title: string; body: string | null; rig_id: string | null; parent_bead_id: string | null; assignee_agent_bead_id: string | null; - priority: "critical" | "high" | "low" | "medium"; + priority: 'critical' | 'high' | 'low' | 'medium'; labels: string[]; metadata: Record; created_by: string | null; created_at: string; updated_at: string; closed_at: string | null; - } | null; - meta: object; - }>; -}>>; -export type GastownRouter = typeof gastownRouter; -/** - * Wrapped router that nests gastownRouter under a `gastown` key. - * This preserves the `trpc.gastown.X` call pattern on the frontend, - * matching the existing RootRouter shape so components don't need - * to change their procedure paths. - */ -export declare const wrappedGastownRouter: import("@trpc/server").TRPCBuiltRouter<{ - ctx: TRPCContext; - meta: object; - errorShape: import("@trpc/server").TRPCDefaultErrorShape; - transformer: false; -}, import("@trpc/server").TRPCDecorateCreateRouterOptions<{ - gastown: import("@trpc/server").TRPCBuiltRouter<{ - ctx: TRPCContext; - meta: object; - errorShape: import("@trpc/server").TRPCDefaultErrorShape; - transformer: false; - }, import("@trpc/server").TRPCDecorateCreateRouterOptions<{ - createTown: import("@trpc/server").TRPCMutationProcedure<{ - input: { - name: string; - }; - output: { - id: string; - name: string; - owner_user_id: string; - created_at: string; - updated_at: string; - }; - meta: object; - }>; - listTowns: import("@trpc/server").TRPCQueryProcedure<{ - input: void; - output: { - id: string; - name: string; - owner_user_id: string; - created_at: string; - updated_at: string; - }[]; - meta: object; - }>; - getTown: import("@trpc/server").TRPCQueryProcedure<{ - input: { - townId: string; - }; - output: { - id: string; - name: string; - owner_user_id: string; - created_at: string; - updated_at: string; - }; - meta: object; - }>; - deleteTown: import("@trpc/server").TRPCMutationProcedure<{ - input: { - townId: string; - }; - output: void; - meta: object; - }>; - createRig: import("@trpc/server").TRPCMutationProcedure<{ - input: { - townId: string; - name: string; - gitUrl: string; - defaultBranch?: string | undefined; - platformIntegrationId?: string | undefined; - }; - output: { - id: string; - town_id: string; - name: string; - git_url: string; - default_branch: string; - platform_integration_id: string | null; - created_at: string; - updated_at: string; - }; - meta: object; - }>; - listRigs: import("@trpc/server").TRPCQueryProcedure<{ - input: { - townId: string; - }; - output: { - id: string; - town_id: string; - name: string; - git_url: string; - default_branch: string; - platform_integration_id: string | null; - created_at: string; - updated_at: string; - }[]; - meta: object; - }>; - getRig: import("@trpc/server").TRPCQueryProcedure<{ - input: { - rigId: string; - }; - output: { - id: string; - town_id: string; - name: string; - git_url: string; - default_branch: string; - platform_integration_id: string | null; - created_at: string; - updated_at: string; - agents: { - id: string; - rig_id: string | null; - role: string; - name: string; - identity: string; - status: string; - current_hook_bead_id: string | null; - dispatch_attempts: number; - last_activity_at: string | null; - checkpoint?: unknown; - created_at: string; - agent_status_message: string | null; - agent_status_updated_at: string | null; - }[]; - beads: { - bead_id: string; - type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; - status: "closed" | "failed" | "in_progress" | "in_review" | "open"; - title: string; - body: string | null; - rig_id: string | null; - parent_bead_id: string | null; - assignee_agent_bead_id: string | null; - priority: "critical" | "high" | "low" | "medium"; - labels: string[]; - metadata: Record; - created_by: string | null; - created_at: string; - updated_at: string; - closed_at: string | null; - }[]; - }; - meta: object; - }>; - deleteRig: import("@trpc/server").TRPCMutationProcedure<{ - input: { - rigId: string; - }; - output: void; - meta: object; - }>; - listBeads: import("@trpc/server").TRPCQueryProcedure<{ - input: { - rigId: string; - status?: "closed" | "failed" | "in_progress" | "in_review" | "open" | undefined; - }; - output: { - bead_id: string; - type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; - status: "closed" | "failed" | "in_progress" | "in_review" | "open"; - title: string; - body: string | null; - rig_id: string | null; - parent_bead_id: string | null; - assignee_agent_bead_id: string | null; - priority: "critical" | "high" | "low" | "medium"; - labels: string[]; - metadata: Record; - created_by: string | null; - created_at: string; - updated_at: string; - closed_at: string | null; - }[]; - meta: object; - }>; - deleteBead: import("@trpc/server").TRPCMutationProcedure<{ - input: { - rigId: string; - beadId: string; - }; - output: void; - meta: object; - }>; - updateBead: import("@trpc/server").TRPCMutationProcedure<{ - input: { - rigId: string; - beadId: string; - title?: string | undefined; - body?: string | null | undefined; - status?: "closed" | "failed" | "in_progress" | "in_review" | "open" | undefined; - priority?: "critical" | "high" | "low" | "medium" | undefined; - labels?: string[] | undefined; - metadata?: Record | undefined; - rig_id?: string | null | undefined; - parent_bead_id?: string | null | undefined; - }; - output: { - bead_id: string; - type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; - status: "closed" | "failed" | "in_progress" | "in_review" | "open"; - title: string; - body: string | null; - rig_id: string | null; - parent_bead_id: string | null; - assignee_agent_bead_id: string | null; - priority: "critical" | "high" | "low" | "medium"; - labels: string[]; - metadata: Record; - created_by: string | null; - created_at: string; - updated_at: string; - closed_at: string | null; - }; - meta: object; - }>; - listAgents: import("@trpc/server").TRPCQueryProcedure<{ - input: { - rigId: string; - }; - output: { - id: string; - rig_id: string | null; - role: string; - name: string; - identity: string; - status: string; - current_hook_bead_id: string | null; - dispatch_attempts: number; - last_activity_at: string | null; - checkpoint?: unknown; - created_at: string; - agent_status_message: string | null; - agent_status_updated_at: string | null; - }[]; - meta: object; - }>; - deleteAgent: import("@trpc/server").TRPCMutationProcedure<{ - input: { - rigId: string; - agentId: string; - }; - output: void; - meta: object; - }>; - sling: import("@trpc/server").TRPCMutationProcedure<{ - input: { - rigId: string; - title: string; - body?: string | undefined; - model?: string | undefined; - }; - output: { - bead: { - bead_id: string; - type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; - status: "closed" | "failed" | "in_progress" | "in_review" | "open"; - title: string; - body: string | null; - rig_id: string | null; - parent_bead_id: string | null; - assignee_agent_bead_id: string | null; - priority: "critical" | "high" | "low" | "medium"; - labels: string[]; - metadata: Record; - created_by: string | null; - created_at: string; - updated_at: string; - closed_at: string | null; - }; - agent: { - id: string; - rig_id: string | null; - role: string; - name: string; - identity: string; - status: string; - current_hook_bead_id: string | null; - dispatch_attempts: number; - last_activity_at: string | null; - checkpoint?: unknown; - created_at: string; - agent_status_message: string | null; - agent_status_updated_at: string | null; - }; - }; - meta: object; - }>; - sendMessage: import("@trpc/server").TRPCMutationProcedure<{ - input: { - townId: string; - message: string; - model?: string | undefined; - rigId?: string | undefined; - }; - output: { - agentId: string; - sessionStatus: "active" | "idle" | "starting"; - }; - meta: object; - }>; - getMayorStatus: import("@trpc/server").TRPCQueryProcedure<{ - input: { - townId: string; - }; - output: { - configured: boolean; - townId: string | null; - session: { - agentId: string; - sessionId: string; - status: "active" | "idle" | "starting"; - lastActivityAt: string; - } | null; - }; - meta: object; - }>; - getAlarmStatus: import("@trpc/server").TRPCQueryProcedure<{ - input: { - townId: string; - }; - output: { - alarm: { - nextFireAt: string | null; - intervalMs: number; - intervalLabel: string; - }; - agents: { - working: number; - idle: number; - stalled: number; - dead: number; - total: number; - }; - beads: { - open: number; - inProgress: number; - inReview: number; - failed: number; - triageRequests: number; - }; - patrol: { - guppWarnings: number; - guppEscalations: number; - stalledAgents: number; - orphanedHooks: number; - }; - recentEvents: { - time: string; - type: string; - message: string; - }[]; - }; - meta: object; - }>; - ensureMayor: import("@trpc/server").TRPCMutationProcedure<{ - input: { - townId: string; - }; - output: { - agentId: string; - sessionStatus: "active" | "idle" | "starting"; - }; - meta: object; - }>; - getAgentStreamUrl: import("@trpc/server").TRPCQueryProcedure<{ - input: { - agentId: string; - townId: string; - }; - output: { - url: string; - ticket: string; - }; - meta: object; - }>; - createPtySession: import("@trpc/server").TRPCMutationProcedure<{ - input: { - townId: string; - agentId: string; - }; - output: { - pty: { - [x: string]: unknown; - id: string; - }; - wsUrl: string; - }; - meta: object; - }>; - resizePtySession: import("@trpc/server").TRPCMutationProcedure<{ - input: { - townId: string; - agentId: string; - ptyId: string; - cols: number; - rows: number; - }; - output: void; - meta: object; - }>; - getTownConfig: import("@trpc/server").TRPCQueryProcedure<{ - input: { - townId: string; - }; - output: { - env_vars: Record; - git_auth: { - github_token?: string | undefined; - gitlab_token?: string | undefined; - gitlab_instance_url?: string | undefined; - platform_integration_id?: string | undefined; - }; - owner_user_id?: string | undefined; - kilocode_token?: string | undefined; - default_model?: string | undefined; - small_model?: string | undefined; - max_polecats_per_rig?: number | undefined; - merge_strategy: "direct" | "pr"; - refinery?: { - gates: string[]; - auto_merge: boolean; - require_clean_merge: boolean; - } | undefined; - alarm_interval_active?: number | undefined; - alarm_interval_idle?: number | undefined; - container?: { - sleep_after_minutes?: number | undefined; - } | undefined; - staged_convoys_default: boolean; - }; - meta: object; - }>; - updateTownConfig: import("@trpc/server").TRPCMutationProcedure<{ - input: { - townId: string; - config: { - env_vars?: Record | undefined; - git_auth?: { - github_token?: string | undefined; - gitlab_token?: string | undefined; - gitlab_instance_url?: string | undefined; - platform_integration_id?: string | undefined; - } | undefined; - owner_user_id?: string | undefined; - kilocode_token?: string | undefined; - default_model?: string | undefined; - small_model?: string | undefined; - max_polecats_per_rig?: number | undefined; - merge_strategy?: "direct" | "pr" | undefined; - refinery?: { - gates?: string[] | undefined; - auto_merge?: boolean | undefined; - require_clean_merge?: boolean | undefined; - } | undefined; - alarm_interval_active?: number | undefined; - alarm_interval_idle?: number | undefined; - container?: { - sleep_after_minutes?: number | undefined; - } | undefined; - staged_convoys_default?: boolean | undefined; - }; - }; - output: { - env_vars: Record; - git_auth: { - github_token?: string | undefined; - gitlab_token?: string | undefined; - gitlab_instance_url?: string | undefined; - platform_integration_id?: string | undefined; - }; - owner_user_id?: string | undefined; - kilocode_token?: string | undefined; - default_model?: string | undefined; - small_model?: string | undefined; - max_polecats_per_rig?: number | undefined; - merge_strategy: "direct" | "pr"; - refinery?: { - gates: string[]; - auto_merge: boolean; - require_clean_merge: boolean; - } | undefined; - alarm_interval_active?: number | undefined; - alarm_interval_idle?: number | undefined; - container?: { - sleep_after_minutes?: number | undefined; - } | undefined; - staged_convoys_default: boolean; - }; - meta: object; - }>; - getBeadEvents: import("@trpc/server").TRPCQueryProcedure<{ - input: { - rigId: string; - beadId?: string | undefined; - since?: string | undefined; - limit?: number | undefined; - }; - output: { - bead_event_id: string; - bead_id: string; - agent_id: string | null; - event_type: string; - old_value: string | null; - new_value: string | null; - metadata: Record; - created_at: string; - rig_id?: string | undefined; - rig_name?: string | undefined; - }[]; - meta: object; - }>; - getTownEvents: import("@trpc/server").TRPCQueryProcedure<{ - input: { - townId: string; - since?: string | undefined; - limit?: number | undefined; - }; - output: { - bead_event_id: string; - bead_id: string; - agent_id: string | null; - event_type: string; - old_value: string | null; - new_value: string | null; - metadata: Record; - created_at: string; - rig_id?: string | undefined; - rig_name?: string | undefined; - }[]; - meta: object; - }>; - listConvoys: import("@trpc/server").TRPCQueryProcedure<{ - input: { - townId: string; - }; - output: { - id: string; - title: string; - status: "active" | "landed"; - staged: boolean; - total_beads: number; - closed_beads: number; - created_by: string | null; - created_at: string; - landed_at: string | null; - feature_branch: string | null; - merge_mode: string | null; - beads: { - bead_id: string; - title: string; - status: string; - rig_id: string | null; - assignee_agent_name: string | null; - }[]; - dependency_edges: { - bead_id: string; - depends_on_bead_id: string; - }[]; - }[]; - meta: object; - }>; - closeConvoy: import("@trpc/server").TRPCMutationProcedure<{ - input: { - townId: string; - convoyId: string; - }; - output: { - id: string; - title: string; - status: "active" | "landed"; - staged: boolean; - total_beads: number; - closed_beads: number; - created_by: string | null; - created_at: string; - landed_at: string | null; - feature_branch: string | null; - merge_mode: string | null; - beads: { - bead_id: string; - title: string; - status: string; - rig_id: string | null; - assignee_agent_name: string | null; - }[]; - dependency_edges: { - bead_id: string; - depends_on_bead_id: string; - }[]; - } | null; - meta: object; - }>; - startConvoy: import("@trpc/server").TRPCMutationProcedure<{ - input: { - townId: string; - convoyId: string; - }; - output: { - id: string; - title: string; - status: "active" | "landed"; - staged: boolean; - total_beads: number; - closed_beads: number; - created_by: string | null; - created_at: string; - landed_at: string | null; - feature_branch: string | null; - merge_mode: string | null; - beads: { - bead_id: string; - title: string; - status: string; - rig_id: string | null; - assignee_agent_name: string | null; - }[]; - dependency_edges: { - bead_id: string; - depends_on_bead_id: string; - }[]; - } | null; - meta: object; - }>; - adminListBeads: import("@trpc/server").TRPCQueryProcedure<{ - input: { - townId: string; - status?: "closed" | "failed" | "in_progress" | "open" | undefined; - type?: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule" | undefined; - limit?: number | undefined; - }; - output: { - bead_id: string; - type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; - status: "closed" | "failed" | "in_progress" | "in_review" | "open"; - title: string; - body: string | null; - rig_id: string | null; - parent_bead_id: string | null; - assignee_agent_bead_id: string | null; - priority: "critical" | "high" | "low" | "medium"; - labels: string[]; - metadata: Record; - created_by: string | null; - created_at: string; - updated_at: string; - closed_at: string | null; - }[]; - meta: object; - }>; - adminListAgents: import("@trpc/server").TRPCQueryProcedure<{ - input: { - townId: string; - }; - output: { - id: string; - rig_id: string | null; - role: string; - name: string; - identity: string; - status: string; - current_hook_bead_id: string | null; - dispatch_attempts: number; - last_activity_at: string | null; - checkpoint?: unknown; - created_at: string; - agent_status_message: string | null; - agent_status_updated_at: string | null; - }[]; - meta: object; - }>; - adminForceRestartContainer: import("@trpc/server").TRPCMutationProcedure<{ - input: { - townId: string; - }; - output: void; - meta: object; - }>; - adminForceResetAgent: import("@trpc/server").TRPCMutationProcedure<{ - input: { - townId: string; - agentId: string; - }; - output: void; - meta: object; - }>; - adminForceCloseBead: import("@trpc/server").TRPCMutationProcedure<{ - input: { - townId: string; - beadId: string; - }; - output: { - bead_id: string; - type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; - status: "closed" | "failed" | "in_progress" | "in_review" | "open"; - title: string; - body: string | null; - rig_id: string | null; - parent_bead_id: string | null; - assignee_agent_bead_id: string | null; - priority: "critical" | "high" | "low" | "medium"; - labels: string[]; - metadata: Record; - created_by: string | null; - created_at: string; - updated_at: string; - closed_at: string | null; - }; - meta: object; - }>; - adminForceFailBead: import("@trpc/server").TRPCMutationProcedure<{ - input: { - townId: string; - beadId: string; - }; - output: { - bead_id: string; - type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; - status: "closed" | "failed" | "in_progress" | "in_review" | "open"; - title: string; - body: string | null; - rig_id: string | null; - parent_bead_id: string | null; - assignee_agent_bead_id: string | null; - priority: "critical" | "high" | "low" | "medium"; - labels: string[]; - metadata: Record; - created_by: string | null; - created_at: string; - updated_at: string; - closed_at: string | null; - }; - meta: object; - }>; - adminGetAlarmStatus: import("@trpc/server").TRPCQueryProcedure<{ - input: { - townId: string; - }; - output: { - alarm: { - nextFireAt: string | null; - intervalMs: number; - intervalLabel: string; - }; - agents: { - working: number; - idle: number; - stalled: number; - dead: number; - total: number; - }; - beads: { - open: number; - inProgress: number; - inReview: number; - failed: number; - triageRequests: number; - }; - patrol: { - guppWarnings: number; - guppEscalations: number; - stalledAgents: number; - orphanedHooks: number; - }; - recentEvents: { - time: string; - type: string; - message: string; - }[]; - }; - meta: object; - }>; - adminGetTownEvents: import("@trpc/server").TRPCQueryProcedure<{ - input: { - townId: string; - beadId?: string | undefined; - since?: string | undefined; - limit?: number | undefined; - }; - output: { - bead_event_id: string; - bead_id: string; - agent_id: string | null; - event_type: string; - old_value: string | null; - new_value: string | null; - metadata: Record; - created_at: string; - rig_id?: string | undefined; - rig_name?: string | undefined; - }[]; - meta: object; - }>; - adminGetBead: import("@trpc/server").TRPCQueryProcedure<{ - input: { - townId: string; - beadId: string; - }; - output: { - bead_id: string; - type: "agent" | "convoy" | "escalation" | "issue" | "merge_request" | "message" | "molecule"; - status: "closed" | "failed" | "in_progress" | "in_review" | "open"; - title: string; - body: string | null; - rig_id: string | null; - parent_bead_id: string | null; - assignee_agent_bead_id: string | null; - priority: "critical" | "high" | "low" | "medium"; - labels: string[]; - metadata: Record; - created_by: string | null; - created_at: string; - updated_at: string; - closed_at: string | null; - } | null; - meta: object; + } | null; + meta: object; }>; - }>>; -}>>; + }> + >; + }> +>; export type WrappedGastownRouter = typeof wrappedGastownRouter; diff --git a/src/lib/gastown/types/schemas.d.ts b/src/lib/gastown/types/schemas.d.ts index af0294e888..98f3440b29 100644 --- a/src/lib/gastown/types/schemas.d.ts +++ b/src/lib/gastown/types/schemas.d.ts @@ -1,12 +1,16 @@ import type { z } from 'zod'; -export declare const TownOutput: z.ZodObject<{ +export declare const TownOutput: z.ZodObject< + { id: z.ZodString; name: z.ZodString; owner_user_id: z.ZodString; created_at: z.ZodString; updated_at: z.ZodString; -}, z.core.$strip>; -export declare const RigOutput: z.ZodObject<{ + }, + z.core.$strip +>; +export declare const RigOutput: z.ZodObject< + { id: z.ZodString; town_id: z.ZodString; name: z.ZodString; @@ -15,24 +19,27 @@ export declare const RigOutput: z.ZodObject<{ platform_integration_id: z.ZodDefault>>; created_at: z.ZodString; updated_at: z.ZodString; -}, z.core.$strip>; -export declare const BeadOutput: z.ZodObject<{ + }, + z.core.$strip +>; +export declare const BeadOutput: z.ZodObject< + { bead_id: z.ZodString; type: z.ZodEnum<{ - agent: "agent"; - convoy: "convoy"; - escalation: "escalation"; - issue: "issue"; - merge_request: "merge_request"; - message: "message"; - molecule: "molecule"; + agent: 'agent'; + convoy: 'convoy'; + escalation: 'escalation'; + issue: 'issue'; + merge_request: 'merge_request'; + message: 'message'; + molecule: 'molecule'; }>; status: z.ZodEnum<{ - closed: "closed"; - failed: "failed"; - in_progress: "in_progress"; - in_review: "in_review"; - open: "open"; + closed: 'closed'; + failed: 'failed'; + in_progress: 'in_progress'; + in_review: 'in_review'; + open: 'open'; }>; title: z.ZodString; body: z.ZodNullable; @@ -40,10 +47,10 @@ export declare const BeadOutput: z.ZodObject<{ parent_bead_id: z.ZodNullable; assignee_agent_bead_id: z.ZodNullable; priority: z.ZodEnum<{ - critical: "critical"; - high: "high"; - low: "low"; - medium: "medium"; + critical: 'critical'; + high: 'high'; + low: 'low'; + medium: 'medium'; }>; labels: z.ZodArray; metadata: z.ZodRecord; @@ -51,23 +58,36 @@ export declare const BeadOutput: z.ZodObject<{ created_at: z.ZodString; updated_at: z.ZodString; closed_at: z.ZodNullable; -}, z.core.$strip>; -export declare const AgentOutput: z.ZodObject<{ + }, + z.core.$strip +>; +export declare const AgentOutput: z.ZodObject< + { id: z.ZodString; rig_id: z.ZodNullable; - role: z.ZodUnion<[z.ZodEnum<{ - mayor: "mayor"; - polecat: "polecat"; - refinery: "refinery"; - }>, z.ZodString]>; + role: z.ZodUnion< + [ + z.ZodEnum<{ + mayor: 'mayor'; + polecat: 'polecat'; + refinery: 'refinery'; + }>, + z.ZodString, + ] + >; name: z.ZodString; identity: z.ZodString; - status: z.ZodUnion<[z.ZodEnum<{ - dead: "dead"; - idle: "idle"; - stalled: "stalled"; - working: "working"; - }>, z.ZodString]>; + status: z.ZodUnion< + [ + z.ZodEnum<{ + dead: 'dead'; + idle: 'idle'; + stalled: 'stalled'; + working: 'working'; + }>, + z.ZodString, + ] + >; current_hook_bead_id: z.ZodNullable; dispatch_attempts: z.ZodDefault; last_activity_at: z.ZodNullable; @@ -75,8 +95,11 @@ export declare const AgentOutput: z.ZodObject<{ created_at: z.ZodString; agent_status_message: z.ZodDefault>>; agent_status_updated_at: z.ZodDefault>>; -}, z.core.$strip>; -export declare const BeadEventOutput: z.ZodObject<{ + }, + z.core.$strip +>; +export declare const BeadEventOutput: z.ZodObject< + { bead_event_id: z.ZodString; bead_id: z.ZodString; agent_id: z.ZodNullable; @@ -87,341 +110,68 @@ export declare const BeadEventOutput: z.ZodObject<{ created_at: z.ZodString; rig_id: z.ZodOptional; rig_name: z.ZodOptional; -}, z.core.$strip>; -export declare const MayorSendResultOutput: z.ZodObject<{ + }, + z.core.$strip +>; +export declare const MayorSendResultOutput: z.ZodObject< + { agentId: z.ZodString; sessionStatus: z.ZodEnum<{ - active: "active"; - idle: "idle"; - starting: "starting"; + active: 'active'; + idle: 'idle'; + starting: 'starting'; }>; -}, z.core.$strip>; -export declare const MayorStatusOutput: z.ZodObject<{ + }, + z.core.$strip +>; +export declare const MayorStatusOutput: z.ZodObject< + { configured: z.ZodBoolean; townId: z.ZodNullable; - session: z.ZodNullable; - lastActivityAt: z.ZodString; - }, z.core.$strip>>; -}, z.core.$strip>; -export declare const StreamTicketOutput: z.ZodObject<{ - url: z.ZodString; - ticket: z.ZodString; -}, z.core.$strip>; -export declare const PtySessionOutput: z.ZodObject<{ - pty: z.ZodObject<{ - id: z.ZodString; - }, z.core.$loose>; - wsUrl: z.ZodString; -}, z.core.$strip>; -export declare const ConvoyOutput: z.ZodObject<{ - id: z.ZodString; - title: z.ZodString; - status: z.ZodEnum<{ - active: "active"; - landed: "landed"; - }>; - staged: z.ZodBoolean; - total_beads: z.ZodNumber; - closed_beads: z.ZodNumber; - created_by: z.ZodNullable; - created_at: z.ZodString; - landed_at: z.ZodNullable; - feature_branch: z.ZodNullable; - merge_mode: z.ZodNullable; -}, z.core.$strip>; -export declare const ConvoyDetailOutput: z.ZodObject<{ - id: z.ZodString; - title: z.ZodString; - status: z.ZodEnum<{ - active: "active"; - landed: "landed"; - }>; - staged: z.ZodBoolean; - total_beads: z.ZodNumber; - closed_beads: z.ZodNumber; - created_by: z.ZodNullable; - created_at: z.ZodString; - landed_at: z.ZodNullable; - feature_branch: z.ZodNullable; - merge_mode: z.ZodNullable; - beads: z.ZodArray; - assignee_agent_name: z.ZodNullable; - }, z.core.$strip>>; - dependency_edges: z.ZodArray>; -}, z.core.$strip>; -export declare const SlingResultOutput: z.ZodObject<{ - bead: z.ZodObject<{ - bead_id: z.ZodString; - type: z.ZodEnum<{ - agent: "agent"; - convoy: "convoy"; - escalation: "escalation"; - issue: "issue"; - merge_request: "merge_request"; - message: "message"; - molecule: "molecule"; - }>; - status: z.ZodEnum<{ - closed: "closed"; - failed: "failed"; - in_progress: "in_progress"; - in_review: "in_review"; - open: "open"; - }>; - title: z.ZodString; - body: z.ZodNullable; - rig_id: z.ZodNullable; - parent_bead_id: z.ZodNullable; - assignee_agent_bead_id: z.ZodNullable; - priority: z.ZodEnum<{ - critical: "critical"; - high: "high"; - low: "low"; - medium: "medium"; - }>; - labels: z.ZodArray; - metadata: z.ZodRecord; - created_by: z.ZodNullable; - created_at: z.ZodString; - updated_at: z.ZodString; - closed_at: z.ZodNullable; - }, z.core.$strip>; - agent: z.ZodObject<{ - id: z.ZodString; - rig_id: z.ZodNullable; - role: z.ZodUnion<[z.ZodEnum<{ - mayor: "mayor"; - polecat: "polecat"; - refinery: "refinery"; - }>, z.ZodString]>; - name: z.ZodString; - identity: z.ZodString; - status: z.ZodUnion<[z.ZodEnum<{ - dead: "dead"; - idle: "idle"; - stalled: "stalled"; - working: "working"; - }>, z.ZodString]>; - current_hook_bead_id: z.ZodNullable; - dispatch_attempts: z.ZodDefault; - last_activity_at: z.ZodNullable; - checkpoint: z.ZodOptional; - created_at: z.ZodString; - agent_status_message: z.ZodDefault>>; - agent_status_updated_at: z.ZodDefault>>; - }, z.core.$strip>; -}, z.core.$strip>; -export declare const RigDetailOutput: z.ZodObject<{ - id: z.ZodString; - town_id: z.ZodString; - name: z.ZodString; - git_url: z.ZodString; - default_branch: z.ZodString; - platform_integration_id: z.ZodDefault>>; - created_at: z.ZodString; - updated_at: z.ZodString; - agents: z.ZodArray; - role: z.ZodUnion<[z.ZodEnum<{ - mayor: "mayor"; - polecat: "polecat"; - refinery: "refinery"; - }>, z.ZodString]>; - name: z.ZodString; - identity: z.ZodString; - status: z.ZodUnion<[z.ZodEnum<{ - dead: "dead"; - idle: "idle"; - stalled: "stalled"; - working: "working"; - }>, z.ZodString]>; - current_hook_bead_id: z.ZodNullable; - dispatch_attempts: z.ZodDefault; - last_activity_at: z.ZodNullable; - checkpoint: z.ZodOptional; - created_at: z.ZodString; - agent_status_message: z.ZodDefault>>; - agent_status_updated_at: z.ZodDefault>>; - }, z.core.$strip>>; - beads: z.ZodArray; - status: z.ZodEnum<{ - closed: "closed"; - failed: "failed"; - in_progress: "in_progress"; - in_review: "in_review"; - open: "open"; - }>; - title: z.ZodString; - body: z.ZodNullable; - rig_id: z.ZodNullable; - parent_bead_id: z.ZodNullable; - assignee_agent_bead_id: z.ZodNullable; - priority: z.ZodEnum<{ - critical: "critical"; - high: "high"; - low: "low"; - medium: "medium"; - }>; - labels: z.ZodArray; - metadata: z.ZodRecord; - created_by: z.ZodNullable; - created_at: z.ZodString; - updated_at: z.ZodString; - closed_at: z.ZodNullable; - }, z.core.$strip>>; -}, z.core.$strip>; -export declare const RpcTownOutput: z.ZodPipe>; -export declare const RpcRigOutput: z.ZodPipe>>; - created_at: z.ZodString; - updated_at: z.ZodString; -}, z.core.$strip>>; -export declare const RpcBeadOutput: z.ZodPipe; - status: z.ZodEnum<{ - closed: "closed"; - failed: "failed"; - in_progress: "in_progress"; - in_review: "in_review"; - open: "open"; - }>; - title: z.ZodString; - body: z.ZodNullable; - rig_id: z.ZodNullable; - parent_bead_id: z.ZodNullable; - assignee_agent_bead_id: z.ZodNullable; - priority: z.ZodEnum<{ - critical: "critical"; - high: "high"; - low: "low"; - medium: "medium"; - }>; - labels: z.ZodArray; - metadata: z.ZodRecord; - created_by: z.ZodNullable; - created_at: z.ZodString; - updated_at: z.ZodString; - closed_at: z.ZodNullable; -}, z.core.$strip>>; -export declare const RpcAgentOutput: z.ZodPipe; - role: z.ZodUnion<[z.ZodEnum<{ - mayor: "mayor"; - polecat: "polecat"; - refinery: "refinery"; - }>, z.ZodString]>; - name: z.ZodString; - identity: z.ZodString; - status: z.ZodUnion<[z.ZodEnum<{ - dead: "dead"; - idle: "idle"; - stalled: "stalled"; - working: "working"; - }>, z.ZodString]>; - current_hook_bead_id: z.ZodNullable; - dispatch_attempts: z.ZodDefault; - last_activity_at: z.ZodNullable; - checkpoint: z.ZodOptional; - created_at: z.ZodString; - agent_status_message: z.ZodDefault>>; - agent_status_updated_at: z.ZodDefault>>; -}, z.core.$strip>>; -export declare const RpcBeadEventOutput: z.ZodPipe; - event_type: z.ZodString; - old_value: z.ZodNullable; - new_value: z.ZodNullable; - metadata: z.ZodRecord; - created_at: z.ZodString; - rig_id: z.ZodOptional; - rig_name: z.ZodOptional; -}, z.core.$strip>>; -export declare const RpcMayorSendResultOutput: z.ZodPipe; -}, z.core.$strip>>; -export declare const RpcMayorStatusOutput: z.ZodPipe; - session: z.ZodNullable; - lastActivityAt: z.ZodString; - }, z.core.$strip>>; -}, z.core.$strip>>; -export declare const RpcStreamTicketOutput: z.ZodPipe; + lastActivityAt: z.ZodString; + }, + z.core.$strip + > + >; + }, + z.core.$strip +>; +export declare const StreamTicketOutput: z.ZodObject< + { url: z.ZodString; ticket: z.ZodString; -}, z.core.$strip>>; -export declare const RpcPtySessionOutput: z.ZodPipe; +export declare const PtySessionOutput: z.ZodObject< + { + pty: z.ZodObject< + { id: z.ZodString; - }, z.core.$loose>; + }, + z.core.$loose + >; wsUrl: z.ZodString; -}, z.core.$strip>>; -export declare const RpcConvoyOutput: z.ZodPipe; +export declare const ConvoyOutput: z.ZodObject< + { id: z.ZodString; title: z.ZodString; status: z.ZodEnum<{ - active: "active"; - landed: "landed"; + active: 'active'; + landed: 'landed'; }>; staged: z.ZodBoolean; total_beads: z.ZodNumber; @@ -431,13 +181,16 @@ export declare const RpcConvoyOutput: z.ZodPipe; feature_branch: z.ZodNullable; merge_mode: z.ZodNullable; -}, z.core.$strip>>; -export declare const RpcConvoyDetailOutput: z.ZodPipe; +export declare const ConvoyDetailOutput: z.ZodObject< + { id: z.ZodString; title: z.ZodString; status: z.ZodEnum<{ - active: "active"; - landed: "landed"; + active: 'active'; + landed: 'landed'; }>; staged: z.ZodBoolean; total_beads: z.ZodNumber; @@ -447,36 +200,50 @@ export declare const RpcConvoyDetailOutput: z.ZodPipe; feature_branch: z.ZodNullable; merge_mode: z.ZodNullable; - beads: z.ZodArray; - assignee_agent_name: z.ZodNullable; - }, z.core.$strip>>; - dependency_edges: z.ZodArray>; -}, z.core.$strip>>; -export declare const RpcSlingResultOutput: z.ZodPipe; + assignee_agent_name: z.ZodNullable; + }, + z.core.$strip + > + >; + dependency_edges: z.ZodArray< + z.ZodObject< + { + bead_id: z.ZodString; + depends_on_bead_id: z.ZodString; + }, + z.core.$strip + > + >; + }, + z.core.$strip +>; +export declare const SlingResultOutput: z.ZodObject< + { + bead: z.ZodObject< + { bead_id: z.ZodString; type: z.ZodEnum<{ - agent: "agent"; - convoy: "convoy"; - escalation: "escalation"; - issue: "issue"; - merge_request: "merge_request"; - message: "message"; - molecule: "molecule"; + agent: 'agent'; + convoy: 'convoy'; + escalation: 'escalation'; + issue: 'issue'; + merge_request: 'merge_request'; + message: 'message'; + molecule: 'molecule'; }>; status: z.ZodEnum<{ - closed: "closed"; - failed: "failed"; - in_progress: "in_progress"; - in_review: "in_review"; - open: "open"; + closed: 'closed'; + failed: 'failed'; + in_progress: 'in_progress'; + in_review: 'in_review'; + open: 'open'; }>; title: z.ZodString; body: z.ZodNullable; @@ -484,10 +251,10 @@ export declare const RpcSlingResultOutput: z.ZodPipe; assignee_agent_bead_id: z.ZodNullable; priority: z.ZodEnum<{ - critical: "critical"; - high: "high"; - low: "low"; - medium: "medium"; + critical: 'critical'; + high: 'high'; + low: 'low'; + medium: 'medium'; }>; labels: z.ZodArray; metadata: z.ZodRecord; @@ -495,23 +262,36 @@ export declare const RpcSlingResultOutput: z.ZodPipe; - }, z.core.$strip>; - agent: z.ZodObject<{ + }, + z.core.$strip + >; + agent: z.ZodObject< + { id: z.ZodString; rig_id: z.ZodNullable; - role: z.ZodUnion<[z.ZodEnum<{ - mayor: "mayor"; - polecat: "polecat"; - refinery: "refinery"; - }>, z.ZodString]>; + role: z.ZodUnion< + [ + z.ZodEnum<{ + mayor: 'mayor'; + polecat: 'polecat'; + refinery: 'refinery'; + }>, + z.ZodString, + ] + >; name: z.ZodString; identity: z.ZodString; - status: z.ZodUnion<[z.ZodEnum<{ - dead: "dead"; - idle: "idle"; - stalled: "stalled"; - working: "working"; - }>, z.ZodString]>; + status: z.ZodUnion< + [ + z.ZodEnum<{ + dead: 'dead'; + idle: 'idle'; + stalled: 'stalled'; + working: 'working'; + }>, + z.ZodString, + ] + >; current_hook_bead_id: z.ZodNullable; dispatch_attempts: z.ZodDefault; last_activity_at: z.ZodNullable; @@ -519,41 +299,14 @@ export declare const RpcSlingResultOutput: z.ZodPipe>>; agent_status_updated_at: z.ZodDefault>>; - }, z.core.$strip>; -}, z.core.$strip>>; -export declare const RpcAlarmStatusOutput: z.ZodPipe; - intervalMs: z.ZodNumber; - intervalLabel: z.ZodString; - }, z.core.$strip>; - agents: z.ZodObject<{ - working: z.ZodNumber; - idle: z.ZodNumber; - stalled: z.ZodNumber; - dead: z.ZodNumber; - total: z.ZodNumber; - }, z.core.$strip>; - beads: z.ZodObject<{ - open: z.ZodNumber; - inProgress: z.ZodNumber; - inReview: z.ZodNumber; - failed: z.ZodNumber; - triageRequests: z.ZodNumber; - }, z.core.$strip>; - patrol: z.ZodObject<{ - guppWarnings: z.ZodNumber; - guppEscalations: z.ZodNumber; - stalledAgents: z.ZodNumber; - orphanedHooks: z.ZodNumber; - }, z.core.$strip>; - recentEvents: z.ZodArray>; -}, z.core.$strip>>; -export declare const RpcRigDetailOutput: z.ZodPipe; + }, + z.core.$strip +>; +export declare const RigDetailOutput: z.ZodObject< + { id: z.ZodString; town_id: z.ZodString; name: z.ZodString; @@ -562,64 +315,579 @@ export declare const RpcRigDetailOutput: z.ZodPipe>>; created_at: z.ZodString; updated_at: z.ZodString; - agents: z.ZodArray; - role: z.ZodUnion<[z.ZodEnum<{ - mayor: "mayor"; - polecat: "polecat"; - refinery: "refinery"; - }>, z.ZodString]>; - name: z.ZodString; - identity: z.ZodString; - status: z.ZodUnion<[z.ZodEnum<{ - dead: "dead"; - idle: "idle"; - stalled: "stalled"; - working: "working"; - }>, z.ZodString]>; - current_hook_bead_id: z.ZodNullable; - dispatch_attempts: z.ZodDefault; - last_activity_at: z.ZodNullable; - checkpoint: z.ZodOptional; - created_at: z.ZodString; - agent_status_message: z.ZodDefault>>; - agent_status_updated_at: z.ZodDefault>>; - }, z.core.$strip>>; - beads: z.ZodArray; - status: z.ZodEnum<{ - closed: "closed"; - failed: "failed"; - in_progress: "in_progress"; - in_review: "in_review"; - open: "open"; - }>; - title: z.ZodString; - body: z.ZodNullable; - rig_id: z.ZodNullable; - parent_bead_id: z.ZodNullable; - assignee_agent_bead_id: z.ZodNullable; - priority: z.ZodEnum<{ - critical: "critical"; - high: "high"; - low: "low"; - medium: "medium"; - }>; - labels: z.ZodArray; - metadata: z.ZodRecord; - created_by: z.ZodNullable; - created_at: z.ZodString; - updated_at: z.ZodString; - closed_at: z.ZodNullable; - }, z.core.$strip>>; -}, z.core.$strip>>; + agents: z.ZodArray< + z.ZodObject< + { + id: z.ZodString; + rig_id: z.ZodNullable; + role: z.ZodUnion< + [ + z.ZodEnum<{ + mayor: 'mayor'; + polecat: 'polecat'; + refinery: 'refinery'; + }>, + z.ZodString, + ] + >; + name: z.ZodString; + identity: z.ZodString; + status: z.ZodUnion< + [ + z.ZodEnum<{ + dead: 'dead'; + idle: 'idle'; + stalled: 'stalled'; + working: 'working'; + }>, + z.ZodString, + ] + >; + current_hook_bead_id: z.ZodNullable; + dispatch_attempts: z.ZodDefault; + last_activity_at: z.ZodNullable; + checkpoint: z.ZodOptional; + created_at: z.ZodString; + agent_status_message: z.ZodDefault>>; + agent_status_updated_at: z.ZodDefault>>; + }, + z.core.$strip + > + >; + beads: z.ZodArray< + z.ZodObject< + { + bead_id: z.ZodString; + type: z.ZodEnum<{ + agent: 'agent'; + convoy: 'convoy'; + escalation: 'escalation'; + issue: 'issue'; + merge_request: 'merge_request'; + message: 'message'; + molecule: 'molecule'; + }>; + status: z.ZodEnum<{ + closed: 'closed'; + failed: 'failed'; + in_progress: 'in_progress'; + in_review: 'in_review'; + open: 'open'; + }>; + title: z.ZodString; + body: z.ZodNullable; + rig_id: z.ZodNullable; + parent_bead_id: z.ZodNullable; + assignee_agent_bead_id: z.ZodNullable; + priority: z.ZodEnum<{ + critical: 'critical'; + high: 'high'; + low: 'low'; + medium: 'medium'; + }>; + labels: z.ZodArray; + metadata: z.ZodRecord; + created_by: z.ZodNullable; + created_at: z.ZodString; + updated_at: z.ZodString; + closed_at: z.ZodNullable; + }, + z.core.$strip + > + >; + }, + z.core.$strip +>; +export declare const RpcTownOutput: z.ZodPipe< + z.ZodAny, + z.ZodObject< + { + id: z.ZodString; + name: z.ZodString; + owner_user_id: z.ZodString; + created_at: z.ZodString; + updated_at: z.ZodString; + }, + z.core.$strip + > +>; +export declare const RpcRigOutput: z.ZodPipe< + z.ZodAny, + z.ZodObject< + { + id: z.ZodString; + town_id: z.ZodString; + name: z.ZodString; + git_url: z.ZodString; + default_branch: z.ZodString; + platform_integration_id: z.ZodDefault>>; + created_at: z.ZodString; + updated_at: z.ZodString; + }, + z.core.$strip + > +>; +export declare const RpcBeadOutput: z.ZodPipe< + z.ZodAny, + z.ZodObject< + { + bead_id: z.ZodString; + type: z.ZodEnum<{ + agent: 'agent'; + convoy: 'convoy'; + escalation: 'escalation'; + issue: 'issue'; + merge_request: 'merge_request'; + message: 'message'; + molecule: 'molecule'; + }>; + status: z.ZodEnum<{ + closed: 'closed'; + failed: 'failed'; + in_progress: 'in_progress'; + in_review: 'in_review'; + open: 'open'; + }>; + title: z.ZodString; + body: z.ZodNullable; + rig_id: z.ZodNullable; + parent_bead_id: z.ZodNullable; + assignee_agent_bead_id: z.ZodNullable; + priority: z.ZodEnum<{ + critical: 'critical'; + high: 'high'; + low: 'low'; + medium: 'medium'; + }>; + labels: z.ZodArray; + metadata: z.ZodRecord; + created_by: z.ZodNullable; + created_at: z.ZodString; + updated_at: z.ZodString; + closed_at: z.ZodNullable; + }, + z.core.$strip + > +>; +export declare const RpcAgentOutput: z.ZodPipe< + z.ZodAny, + z.ZodObject< + { + id: z.ZodString; + rig_id: z.ZodNullable; + role: z.ZodUnion< + [ + z.ZodEnum<{ + mayor: 'mayor'; + polecat: 'polecat'; + refinery: 'refinery'; + }>, + z.ZodString, + ] + >; + name: z.ZodString; + identity: z.ZodString; + status: z.ZodUnion< + [ + z.ZodEnum<{ + dead: 'dead'; + idle: 'idle'; + stalled: 'stalled'; + working: 'working'; + }>, + z.ZodString, + ] + >; + current_hook_bead_id: z.ZodNullable; + dispatch_attempts: z.ZodDefault; + last_activity_at: z.ZodNullable; + checkpoint: z.ZodOptional; + created_at: z.ZodString; + agent_status_message: z.ZodDefault>>; + agent_status_updated_at: z.ZodDefault>>; + }, + z.core.$strip + > +>; +export declare const RpcBeadEventOutput: z.ZodPipe< + z.ZodAny, + z.ZodObject< + { + bead_event_id: z.ZodString; + bead_id: z.ZodString; + agent_id: z.ZodNullable; + event_type: z.ZodString; + old_value: z.ZodNullable; + new_value: z.ZodNullable; + metadata: z.ZodRecord; + created_at: z.ZodString; + rig_id: z.ZodOptional; + rig_name: z.ZodOptional; + }, + z.core.$strip + > +>; +export declare const RpcMayorSendResultOutput: z.ZodPipe< + z.ZodAny, + z.ZodObject< + { + agentId: z.ZodString; + sessionStatus: z.ZodEnum<{ + active: 'active'; + idle: 'idle'; + starting: 'starting'; + }>; + }, + z.core.$strip + > +>; +export declare const RpcMayorStatusOutput: z.ZodPipe< + z.ZodAny, + z.ZodObject< + { + configured: z.ZodBoolean; + townId: z.ZodNullable; + session: z.ZodNullable< + z.ZodObject< + { + agentId: z.ZodString; + sessionId: z.ZodString; + status: z.ZodEnum<{ + active: 'active'; + idle: 'idle'; + starting: 'starting'; + }>; + lastActivityAt: z.ZodString; + }, + z.core.$strip + > + >; + }, + z.core.$strip + > +>; +export declare const RpcStreamTicketOutput: z.ZodPipe< + z.ZodAny, + z.ZodObject< + { + url: z.ZodString; + ticket: z.ZodString; + }, + z.core.$strip + > +>; +export declare const RpcPtySessionOutput: z.ZodPipe< + z.ZodAny, + z.ZodObject< + { + pty: z.ZodObject< + { + id: z.ZodString; + }, + z.core.$loose + >; + wsUrl: z.ZodString; + }, + z.core.$strip + > +>; +export declare const RpcConvoyOutput: z.ZodPipe< + z.ZodAny, + z.ZodObject< + { + id: z.ZodString; + title: z.ZodString; + status: z.ZodEnum<{ + active: 'active'; + landed: 'landed'; + }>; + staged: z.ZodBoolean; + total_beads: z.ZodNumber; + closed_beads: z.ZodNumber; + created_by: z.ZodNullable; + created_at: z.ZodString; + landed_at: z.ZodNullable; + feature_branch: z.ZodNullable; + merge_mode: z.ZodNullable; + }, + z.core.$strip + > +>; +export declare const RpcConvoyDetailOutput: z.ZodPipe< + z.ZodAny, + z.ZodObject< + { + id: z.ZodString; + title: z.ZodString; + status: z.ZodEnum<{ + active: 'active'; + landed: 'landed'; + }>; + staged: z.ZodBoolean; + total_beads: z.ZodNumber; + closed_beads: z.ZodNumber; + created_by: z.ZodNullable; + created_at: z.ZodString; + landed_at: z.ZodNullable; + feature_branch: z.ZodNullable; + merge_mode: z.ZodNullable; + beads: z.ZodArray< + z.ZodObject< + { + bead_id: z.ZodString; + title: z.ZodString; + status: z.ZodString; + rig_id: z.ZodNullable; + assignee_agent_name: z.ZodNullable; + }, + z.core.$strip + > + >; + dependency_edges: z.ZodArray< + z.ZodObject< + { + bead_id: z.ZodString; + depends_on_bead_id: z.ZodString; + }, + z.core.$strip + > + >; + }, + z.core.$strip + > +>; +export declare const RpcSlingResultOutput: z.ZodPipe< + z.ZodAny, + z.ZodObject< + { + bead: z.ZodObject< + { + bead_id: z.ZodString; + type: z.ZodEnum<{ + agent: 'agent'; + convoy: 'convoy'; + escalation: 'escalation'; + issue: 'issue'; + merge_request: 'merge_request'; + message: 'message'; + molecule: 'molecule'; + }>; + status: z.ZodEnum<{ + closed: 'closed'; + failed: 'failed'; + in_progress: 'in_progress'; + in_review: 'in_review'; + open: 'open'; + }>; + title: z.ZodString; + body: z.ZodNullable; + rig_id: z.ZodNullable; + parent_bead_id: z.ZodNullable; + assignee_agent_bead_id: z.ZodNullable; + priority: z.ZodEnum<{ + critical: 'critical'; + high: 'high'; + low: 'low'; + medium: 'medium'; + }>; + labels: z.ZodArray; + metadata: z.ZodRecord; + created_by: z.ZodNullable; + created_at: z.ZodString; + updated_at: z.ZodString; + closed_at: z.ZodNullable; + }, + z.core.$strip + >; + agent: z.ZodObject< + { + id: z.ZodString; + rig_id: z.ZodNullable; + role: z.ZodUnion< + [ + z.ZodEnum<{ + mayor: 'mayor'; + polecat: 'polecat'; + refinery: 'refinery'; + }>, + z.ZodString, + ] + >; + name: z.ZodString; + identity: z.ZodString; + status: z.ZodUnion< + [ + z.ZodEnum<{ + dead: 'dead'; + idle: 'idle'; + stalled: 'stalled'; + working: 'working'; + }>, + z.ZodString, + ] + >; + current_hook_bead_id: z.ZodNullable; + dispatch_attempts: z.ZodDefault; + last_activity_at: z.ZodNullable; + checkpoint: z.ZodOptional; + created_at: z.ZodString; + agent_status_message: z.ZodDefault>>; + agent_status_updated_at: z.ZodDefault>>; + }, + z.core.$strip + >; + }, + z.core.$strip + > +>; +export declare const RpcAlarmStatusOutput: z.ZodPipe< + z.ZodAny, + z.ZodObject< + { + alarm: z.ZodObject< + { + nextFireAt: z.ZodNullable; + intervalMs: z.ZodNumber; + intervalLabel: z.ZodString; + }, + z.core.$strip + >; + agents: z.ZodObject< + { + working: z.ZodNumber; + idle: z.ZodNumber; + stalled: z.ZodNumber; + dead: z.ZodNumber; + total: z.ZodNumber; + }, + z.core.$strip + >; + beads: z.ZodObject< + { + open: z.ZodNumber; + inProgress: z.ZodNumber; + inReview: z.ZodNumber; + failed: z.ZodNumber; + triageRequests: z.ZodNumber; + }, + z.core.$strip + >; + patrol: z.ZodObject< + { + guppWarnings: z.ZodNumber; + guppEscalations: z.ZodNumber; + stalledAgents: z.ZodNumber; + orphanedHooks: z.ZodNumber; + }, + z.core.$strip + >; + recentEvents: z.ZodArray< + z.ZodObject< + { + time: z.ZodString; + type: z.ZodString; + message: z.ZodString; + }, + z.core.$strip + > + >; + }, + z.core.$strip + > +>; +export declare const RpcRigDetailOutput: z.ZodPipe< + z.ZodAny, + z.ZodObject< + { + id: z.ZodString; + town_id: z.ZodString; + name: z.ZodString; + git_url: z.ZodString; + default_branch: z.ZodString; + platform_integration_id: z.ZodDefault>>; + created_at: z.ZodString; + updated_at: z.ZodString; + agents: z.ZodArray< + z.ZodObject< + { + id: z.ZodString; + rig_id: z.ZodNullable; + role: z.ZodUnion< + [ + z.ZodEnum<{ + mayor: 'mayor'; + polecat: 'polecat'; + refinery: 'refinery'; + }>, + z.ZodString, + ] + >; + name: z.ZodString; + identity: z.ZodString; + status: z.ZodUnion< + [ + z.ZodEnum<{ + dead: 'dead'; + idle: 'idle'; + stalled: 'stalled'; + working: 'working'; + }>, + z.ZodString, + ] + >; + current_hook_bead_id: z.ZodNullable; + dispatch_attempts: z.ZodDefault; + last_activity_at: z.ZodNullable; + checkpoint: z.ZodOptional; + created_at: z.ZodString; + agent_status_message: z.ZodDefault>>; + agent_status_updated_at: z.ZodDefault>>; + }, + z.core.$strip + > + >; + beads: z.ZodArray< + z.ZodObject< + { + bead_id: z.ZodString; + type: z.ZodEnum<{ + agent: 'agent'; + convoy: 'convoy'; + escalation: 'escalation'; + issue: 'issue'; + merge_request: 'merge_request'; + message: 'message'; + molecule: 'molecule'; + }>; + status: z.ZodEnum<{ + closed: 'closed'; + failed: 'failed'; + in_progress: 'in_progress'; + in_review: 'in_review'; + open: 'open'; + }>; + title: z.ZodString; + body: z.ZodNullable; + rig_id: z.ZodNullable; + parent_bead_id: z.ZodNullable; + assignee_agent_bead_id: z.ZodNullable; + priority: z.ZodEnum<{ + critical: 'critical'; + high: 'high'; + low: 'low'; + medium: 'medium'; + }>; + labels: z.ZodArray; + metadata: z.ZodRecord; + created_by: z.ZodNullable; + created_at: z.ZodString; + updated_at: z.ZodString; + closed_at: z.ZodNullable; + }, + z.core.$strip + > + >; + }, + z.core.$strip + > +>; From 945efdc4d38d5be9681b689550bd0235f3135be5 Mon Sep 17 00:00:00 2001 From: John Fawcett Date: Sat, 14 Mar 2026 20:22:34 -0500 Subject: [PATCH 8/9] fix(gastown): move staged flag clear to after agent-hooking loop startConvoy now clears the staged flag only after all agents are successfully hooked. If getOrCreateAgent or hookBead throws partway through, the convoy remains staged so the caller can safely retry. --- cloudflare-gastown/src/dos/Town.do.ts | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/cloudflare-gastown/src/dos/Town.do.ts b/cloudflare-gastown/src/dos/Town.do.ts index 3060e84ca2..4ea17e050e 100644 --- a/cloudflare-gastown/src/dos/Town.do.ts +++ b/cloudflare-gastown/src/dos/Town.do.ts @@ -2069,17 +2069,6 @@ export class TownDO extends DurableObject { if (!convoy) throw new Error(`Convoy not found: ${convoyId}`); if (!convoy.staged) throw new Error(`Convoy is not staged: ${convoyId}`); - // Mark convoy as active - query( - this.sql, - /* sql */ ` - UPDATE ${convoy_metadata} - SET ${convoy_metadata.columns.staged} = 0 - WHERE ${convoy_metadata.bead_id} = ? - `, - [convoyId] - ); - // Find all beads tracked by this convoy const trackedRows = [ ...query( @@ -2128,6 +2117,18 @@ export class TownDO extends DurableObject { results.push({ bead: updatedBead, agent: hookedAgent }); } + // Clear the staged flag only after all agents are successfully hooked. + // If the loop above throws, the convoy stays staged so the caller can retry. + query( + this.sql, + /* sql */ ` + UPDATE ${convoy_metadata} + SET ${convoy_metadata.columns.staged} = 0 + WHERE ${convoy_metadata.bead_id} = ? + `, + [convoyId] + ); + await this.armAlarmIfNeeded(); const updatedConvoy = this.getConvoy(convoyId); From 799265e37082791b44cff3b6a9486b39ac0e2056 Mon Sep 17 00:00:00 2001 From: John Fawcett Date: Sat, 14 Mar 2026 20:31:26 -0500 Subject: [PATCH 9/9] fix(gastown): make startConvoy retry-safe by skipping already-hooked beads If startConvoy throws after hooking some beads, the convoy stays staged for retry. On retry, skip beads that already have an assignee to avoid duplicate hooks and orphaned agents. --- cloudflare-gastown/src/dos/Town.do.ts | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/cloudflare-gastown/src/dos/Town.do.ts b/cloudflare-gastown/src/dos/Town.do.ts index 4ea17e050e..877f3234f9 100644 --- a/cloudflare-gastown/src/dos/Town.do.ts +++ b/cloudflare-gastown/src/dos/Town.do.ts @@ -2097,11 +2097,25 @@ export class TownDO extends DurableObject { const rigId = bead.rig_id; if (!rigId) continue; - const agent = agents.getOrCreateAgent(this.sql, 'polecat', rigId, this.townId); - agents.hookBead(this.sql, agent.id, beadId); + // Skip beads already hooked from a prior partial attempt (retry-safe). + let hookedAgent: Agent; + if (bead.assignee_agent_bead_id) { + const existing = agents.getAgent(this.sql, bead.assignee_agent_bead_id); + if (existing) { + hookedAgent = existing; + } else { + // Orphaned assignee reference — re-hook with a fresh agent + const agent = agents.getOrCreateAgent(this.sql, 'polecat', rigId, this.townId); + agents.hookBead(this.sql, agent.id, beadId); + hookedAgent = agents.getAgent(this.sql, agent.id) ?? agent; + } + } else { + const agent = agents.getOrCreateAgent(this.sql, 'polecat', rigId, this.townId); + agents.hookBead(this.sql, agent.id, beadId); + hookedAgent = agents.getAgent(this.sql, agent.id) ?? agent; + } - const hookedAgent = agents.getAgent(this.sql, agent.id) ?? agent; - // Re-read bead after hookBead so assignee_agent_bead_id is up to date + // Re-read bead after potential hookBead so assignee_agent_bead_id is up to date const updatedBead = beadOps.getBead(this.sql, beadId) ?? bead; if (!beadOps.hasUnresolvedBlockers(this.sql, beadId)) {