Repository Public
1/** Browser-facing DTOs (REST /api/v1). Auth DTOs are unchanged from Claude Remote and live in the server. */2import { z } from 'zod';3import { Budget, DoneCriterion, Effort, Provider, ResultEnvelope, RiskClass, RunStatus, Usage } from './core.js';45const iso = z.string();6export const Id = z.string().uuid();78export const Branding = z.object({ agent: z.literal('aos'), productName: z.string(), agentName: z.string() });910export const ProjectDto = z.object({11 id: Id, name: z.string(), description: z.string(), path: z.string(), gitRemote: z.string().nullable(),12 gitBranch: z.string().nullable(), instructions: z.string(), missions: z.number(), createdAt: iso,13});14export type ProjectDto = z.infer<typeof ProjectDto>;15export const CreateProject = z.object({16 name: z.string().min(1).max(80), description: z.string().max(2000).default(''),17 mode: z.enum(['create', 'existing', 'clone']), path: z.string().max(300).optional(), gitUrl: z.string().max(500).optional(),18 instructions: z.string().max(8000).default(''),19});2021export const ModelInfo = z.object({22 provider: Provider, id: z.string(), label: z.string(), tier: z.enum(['frontier', 'main', 'worker', 'volume']),23 contextTokens: z.number().nullable(), maxOutputTokens: z.number().nullable(),24 inputUsd: z.number().nullable(), outputUsd: z.number().nullable(), efforts: z.array(Effort), available: z.boolean(),25});26export type ModelInfo = z.infer<typeof ModelInfo>;2728export const RunDto = z.object({29 id: Id, missionId: Id, parentRunId: Id.nullable(), depth: z.number(), role: z.string(),30 objective: z.string(), provider: Provider, model: z.string(), effort: Effort.nullable(),31 status: RunStatus, usage: Usage, budget: Budget, sandboxTier: z.number(),32 result: ResultEnvelope.nullable(), createdAt: iso, startedAt: iso.nullable(), endedAt: iso.nullable(),33 pendingWaits: z.number(),34});35export type RunDto = z.infer<typeof RunDto>;3637export const MissionDto = z.object({38 id: Id, projectId: Id.nullable(), projectName: z.string().nullable(), title: z.string(), objective: z.string(),39 doneCriteria: z.array(DoneCriterion), status: RunStatus, budgetUsd: z.number(), spentUsd: z.number(),40 network: z.enum(['none', 'open']), rootRunId: Id.nullable(), runs: z.number(), pendingWaits: z.number(),41 createdAt: iso, startedAt: iso.nullable(), endedAt: iso.nullable(),42 // Additive (integration, 2026-11-10): provider / model / effort of the ROOT run, so a list needs no request per mission.43 provider: Provider.nullable().optional(), model: z.string().nullable().optional(), effort: Effort.nullable().optional(),44});45export type MissionDto = z.infer<typeof MissionDto>;4647export const CreateMission = z.object({48 projectId: Id,49 title: z.string().min(1).max(160).optional(), // default: first 80 chars of objective50 objective: z.string().min(1).max(8000),51 doneCriteria: z.array(z.string().min(1).max(1000)).max(50).default([]), // empty ⇒ the agent proposes them first, owner sees them52 provider: Provider.optional(), model: z.string().max(80).optional(), effort: Effort.optional(), // default from settings53 budgetUsd: z.number().positive().max(1000).optional(),54 network: z.enum(['none', 'open']).default('none'),55});56export type CreateMission = z.infer<typeof CreateMission>;5758export const StepDto = z.object({59 runId: Id, seq: z.number(), kind: z.string(), name: z.string(), effect: z.string(),60 status: z.enum(['started', 'completed', 'failed', 'needs_reconcile']),61 request: z.unknown(), result: z.unknown().nullable(), error: z.unknown().nullable(), usage: Usage.partial().nullable(),62 startedAt: iso, completedAt: iso.nullable(),63});64export type StepDto = z.infer<typeof StepDto>;6566export const WaitDto = z.object({67 id: Id, runId: Id, missionId: Id, missionTitle: z.string(), stepSeq: z.number(),68 kind: z.enum(['approval', 'question', 'timer', 'child']),69 payload: z.record(z.string(), z.unknown()),70 status: z.enum(['pending', 'resolved', 'expired', 'cancelled']),71 resolution: z.record(z.string(), z.unknown()).nullable(), resolveBy: iso.nullable(), createdAt: iso, resolvedAt: iso.nullable(),72});73export type WaitDto = z.infer<typeof WaitDto>;74export const ResolveWait = z.discriminatedUnion('kind', [75 z.object({ kind: z.literal('approval'), decision: z.enum(['approve', 'deny']), remember: z.boolean().default(false), note: z.string().max(2000).optional() }),76 z.object({ kind: z.literal('question'), answer: z.string().max(8000) }),77]);78export type ResolveWait = z.infer<typeof ResolveWait>;7980export const PolicyRuleDto = z.object({81 id: Id, projectId: Id.nullable(), decision: z.enum(['deny', 'ask', 'allow']), tool: z.string(),82 match: z.record(z.string(), z.unknown()), note: z.string(), createdAt: iso,83});84export const CreatePolicyRule = PolicyRuleDto.omit({ id: true, createdAt: true });8586export const AosSettings = z.object({87 theme: z.enum(['light', 'dark', 'system']).default('light'),88 defaultProvider: Provider.default('anthropic'),89 defaultModel: z.string().default('claude-opus-5-5'),90 defaultEffort: Effort.default('high'),91 missionBudgetUsd: z.number().positive().default(15),92 dailyBudgetUsd: z.number().positive().default(60),93 maxConcurrentRuns: z.number().int().min(1).max(32).default(4),94 approvalTimeoutHours: z.number().min(1).max(24 * 14).default(72),95 notifications: z.object({ inApp: z.boolean(), detail: z.enum(['generic', 'titles']) }).default({ inApp: true, detail: 'titles' }),96 layout: z.record(z.string(), z.unknown()).default({}),97});98export type AosSettings = z.infer<typeof AosSettings>;99100export const SpendSummary = z.object({101 todayUsd: z.number(), dailyBudgetUsd: z.number(), last7Days: z.array(z.object({ day: z.string(), usd: z.number() })),102 byModel: z.array(z.object({ provider: Provider, model: z.string(), usd: z.number(), inputTokens: z.number(), outputTokens: z.number() })),103});104export type SpendSummary = z.infer<typeof SpendSummary>;105106export const RiskLabel = RiskClass;107