@hoststack.dev/mcp 0.15.0 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server-factory.ts","../src/version.ts","../src/api-client.ts","../src/prompts/registry.ts","../src/resources/registry.ts","../src/registry.ts","../src/prompts/deploy-prompts.ts","../src/lib/shape.ts","../src/resources/hoststack-resources.ts","../src/tools/activity-log.ts","../src/lib/respond.ts","../src/tools/alerts.ts","../src/tools/cron.ts","../src/tools/databases.ts","../src/tools/deploys.ts","../src/tools/dns-records.ts","../src/tools/domains.ts","../src/tools/env-vars.ts","../src/tools/environments.ts","../src/tools/meta.ts","../src/tools/notifications.ts","../src/tools/projects.ts","../src/tools/services.ts","../src/tools/volumes.ts"],"sourcesContent":["import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { HostStack } from '@hoststack.dev/sdk';\n\nimport { ApiClient } from './api-client.js';\nimport { attachPrompts } from './prompts/registry.js';\nimport { attachResources } from './resources/registry.js';\nimport { attachTools, type ToolCallSink, type ToolContext } from './registry.js';\nimport { MCP_VERSION } from './version.js';\n\nexport type { ToolCallEvent, ToolCallSink } from './registry.js';\n\n// Importing each tool/prompt/resource module runs its top-level define*()\n// calls and populates the shared registries. ESM caches modules, so each\n// registry is built exactly once per process.\nimport './prompts/deploy-prompts.js';\nimport './resources/hoststack-resources.js';\nimport './tools/activity-log.js';\nimport './tools/alerts.js';\nimport './tools/cron.js';\nimport './tools/databases.js';\nimport './tools/deploys.js';\nimport './tools/dns-records.js';\nimport './tools/domains.js';\nimport './tools/env-vars.js';\nimport './tools/environments.js';\nimport './tools/meta.js';\nimport './tools/notifications.js';\nimport './tools/projects.js';\nimport './tools/services.js';\nimport './tools/volumes.js';\n\nexport interface CreateServerOptions {\n\t/** HostStack API key (hs_live_… or hs_test_…). Required. */\n\tapiKey: string;\n\t/** Base URL for the HostStack API. Defaults to https://hoststack.dev */\n\tbaseUrl?: string;\n\t/**\n\t * Server identity advertised in the MCP `initialize` response. Defaults\n\t * to `{ name: \"hoststack\", version: PACKAGE_VERSION }`.\n\t */\n\tserverInfo?: { name: string; version: string };\n\t/**\n\t * Optional telemetry sink invoked once per tool call (success or failure).\n\t * Runs on the microtask queue; sink errors are swallowed so tool execution\n\t * never blocks on telemetry.\n\t */\n\tonToolCall?: ToolCallSink;\n}\n\nexport const PACKAGE_NAME = 'hoststack';\n// Injected from package.json at build time (see tsup.config.ts `define`) so the\n// MCP `initialize` handshake advertises the real published version.\nexport const PACKAGE_VERSION = MCP_VERSION;\n\ninterface MeResponse {\n\tuser: { id: number };\n\tteam?: { id: number };\n}\n\n/**\n * Build a fully-wired MCP server. Used by both the stdio CLI entry-point and\n * the HTTP transport mounted by the API server. A new server (and its\n * underlying SDK + ApiClient) is created per call, so the HTTP transport can\n * scope each connection to a single API key without cross-contamination.\n */\nexport function createMcpServer(options: CreateServerOptions): McpServer {\n\tconst baseUrl = (options.baseUrl ?? 'https://hoststack.dev').replace(/\\/$/, '');\n\tconst hoststack = new HostStack({ apiKey: options.apiKey, baseUrl });\n\tconst api = new ApiClient(options.apiKey, baseUrl);\n\n\tconst server = new McpServer({\n\t\tname: options.serverInfo?.name ?? PACKAGE_NAME,\n\t\tversion: options.serverInfo?.version ?? PACKAGE_VERSION,\n\t});\n\n\t// Cache the team lookup. The first tool call pays one /auth/me round-trip;\n\t// every subsequent call reuses the cached promise. We store the in-flight\n\t// promise (not the resolved value) so concurrent first-calls don't fan out\n\t// into duplicate /auth/me requests.\n\tlet teamIdPromise: Promise<number> | null = null;\n\tconst resolveTeamId = (): Promise<number> => {\n\t\tif (!teamIdPromise) {\n\t\t\tteamIdPromise = api.get<MeResponse>('/api/auth/me').then((me) => {\n\t\t\t\tif (!me.team?.id) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t'No team bound to API key. Generate a team-scoped key in the dashboard.',\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn me.team.id;\n\t\t\t});\n\t\t\t// If the lookup fails, clear the cache so a retry can succeed once\n\t\t\t// the user fixes their key. Without this, every subsequent tool\n\t\t\t// call would re-throw the same cached rejection.\n\t\t\tteamIdPromise.catch(() => {\n\t\t\t\tteamIdPromise = null;\n\t\t\t});\n\t\t}\n\t\treturn teamIdPromise;\n\t};\n\n\tconst ctx: ToolContext = { hoststack, api, resolveTeamId };\n\tattachTools(server, ctx, options.onToolCall);\n\tattachPrompts(server, ctx);\n\tattachResources(server, ctx);\n\n\treturn server;\n}\n","/**\n * Package version, injected at build time by tsup's `define`\n * (`__MCP_VERSION__` ← package.json `version`). The `declare` keeps the source\n * typecheckable without a build; the `?? '0.0.0-dev'` fallback keeps the\n * un-bundled source (tests, ts-node) working when the define is absent.\n */\ndeclare const __MCP_VERSION__: string | undefined;\n\nexport const MCP_VERSION: string =\n\ttypeof __MCP_VERSION__ === 'string' ? __MCP_VERSION__ : '0.0.0-dev';\n\n/** User-Agent sent on every MCP-originated request, e.g. `hoststack-mcp/0.13.1`. */\nexport const USER_AGENT = `hoststack-mcp/${MCP_VERSION}`;\n","import { USER_AGENT } from './version.js';\n\n/**\n * Lightweight API client for HostStack endpoints not yet covered by the SDK\n * (logs snapshots, activity log, runtime metrics, /me lookup). Uses the same\n * auth and base URL as the SDK instance.\n */\nexport class ApiClient {\n\tconstructor(\n\t\tprivate readonly apiKey: string,\n\t\tprivate readonly baseUrl: string,\n\t) {}\n\n\tprivate get headers(): Record<string, string> {\n\t\treturn {\n\t\t\tAuthorization: `Bearer ${this.apiKey}`,\n\t\t\t'Content-Type': 'application/json',\n\t\t\t'User-Agent': USER_AGENT,\n\t\t};\n\t}\n\n\tasync get<T>(path: string, params?: Record<string, string | number | undefined>): Promise<T> {\n\t\tconst url = new URL(`${this.baseUrl}${path}`);\n\t\tif (params) {\n\t\t\tfor (const [key, value] of Object.entries(params)) {\n\t\t\t\tif (value !== undefined) url.searchParams.set(key, String(value));\n\t\t\t}\n\t\t}\n\t\tconst res = await fetch(url.toString(), { headers: this.headers });\n\t\treturn this.handle<T>(res);\n\t}\n\n\tasync post<T>(path: string, body?: unknown): Promise<T> {\n\t\tconst init: RequestInit = {\n\t\t\tmethod: 'POST',\n\t\t\theaders: this.headers,\n\t\t};\n\t\tif (body !== undefined) init.body = JSON.stringify(body);\n\t\tconst res = await fetch(`${this.baseUrl}${path}`, init);\n\t\treturn this.handle<T>(res);\n\t}\n\n\tasync patch<T>(path: string, body: unknown): Promise<T> {\n\t\tconst res = await fetch(`${this.baseUrl}${path}`, {\n\t\t\tmethod: 'PATCH',\n\t\t\theaders: this.headers,\n\t\t\tbody: JSON.stringify(body),\n\t\t});\n\t\treturn this.handle<T>(res);\n\t}\n\n\tasync put<T>(path: string, body: unknown): Promise<T> {\n\t\tconst res = await fetch(`${this.baseUrl}${path}`, {\n\t\t\tmethod: 'PUT',\n\t\t\theaders: this.headers,\n\t\t\tbody: JSON.stringify(body),\n\t\t});\n\t\treturn this.handle<T>(res);\n\t}\n\n\tasync delete<T>(path: string): Promise<T> {\n\t\tconst res = await fetch(`${this.baseUrl}${path}`, {\n\t\t\tmethod: 'DELETE',\n\t\t\theaders: this.headers,\n\t\t});\n\t\treturn this.handle<T>(res);\n\t}\n\n\tprivate async handle<T>(res: Response): Promise<T> {\n\t\tif (!res.ok) {\n\t\t\tconst error = (await res.json().catch(() => ({ error: res.statusText }))) as {\n\t\t\t\terror?: string;\n\t\t\t};\n\t\t\tthrow new Error(error.error ?? `API error: ${res.status}`);\n\t\t}\n\t\tif (res.status === 204) {\n\t\t\treturn undefined as T;\n\t\t}\n\t\treturn res.json() as Promise<T>;\n\t}\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { GetPromptResult } from '@modelcontextprotocol/sdk/types.js';\nimport type { HostStack } from '@hoststack.dev/sdk';\nimport type { ZodRawShape, z } from 'zod';\n\nimport type { ApiClient } from '../api-client.js';\n\nexport interface PromptContext {\n\thoststack: HostStack;\n\tapi: ApiClient;\n\tresolveTeamId(): Promise<number>;\n}\n\ninterface InternalPromptDefinition {\n\tname: string;\n\tdescription: string;\n\targs: ZodRawShape;\n\thandler: (\n\t\targs: Record<string, string | undefined>,\n\t\tctx: PromptContext,\n\t) => Promise<GetPromptResult>;\n}\n\nexport type PromptDefinition = Readonly<InternalPromptDefinition>;\n\nconst prompts: InternalPromptDefinition[] = [];\n\n/**\n * Register a single prompt. The generic over `TArgs` lets the handler receive\n * precisely-typed args while the registry stores the widened shape — same\n * trick as `defineTool` to keep the compiler's instantiation budget in check.\n */\nexport function definePrompt<TArgs extends ZodRawShape>(def: {\n\tname: string;\n\tdescription: string;\n\targs: TArgs;\n\thandler: (args: z.infer<z.ZodObject<TArgs>>, ctx: PromptContext) => Promise<GetPromptResult>;\n}): void {\n\tprompts.push({\n\t\tname: def.name,\n\t\tdescription: def.description,\n\t\targs: def.args,\n\t\thandler: def.handler as InternalPromptDefinition['handler'],\n\t});\n}\n\nexport function listPromptDefinitions(): ReadonlyArray<PromptDefinition> {\n\treturn prompts;\n}\n\n/** Iterate the registry and wire each prompt into the MCP server. */\nexport function attachPrompts(server: McpServer, ctx: PromptContext): void {\n\ttype PromptMethod = (\n\t\tname: string,\n\t\tdescription: string,\n\t\targsSchema: ZodRawShape,\n\t\tcb: (args: Record<string, string | undefined>) => Promise<GetPromptResult>,\n\t) => unknown;\n\n\tconst register = server.prompt.bind(server) as unknown as PromptMethod;\n\n\tfor (const def of prompts) {\n\t\tregister(def.name, def.description, def.args, (args) => def.handler(args, ctx));\n\t}\n}\n\n/**\n * Helper to build a single user-role text message — the most common shape for\n * these prompts (we're guiding the agent, not modeling assistant responses).\n */\nexport function userMessage(text: string): GetPromptResult['messages'][number] {\n\treturn { role: 'user', content: { type: 'text', text } };\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ReadResourceResult } from '@modelcontextprotocol/sdk/types.js';\nimport type { HostStack } from '@hoststack.dev/sdk';\n\nimport type { ApiClient } from '../api-client.js';\n\ninterface ResourceContext {\n\thoststack: HostStack;\n\tapi: ApiClient;\n\tresolveTeamId(): Promise<number>;\n}\n\ninterface StaticResourceDef {\n\tkind: 'static';\n\tname: string;\n\turi: string;\n\tdescription: string;\n\tmimeType?: string;\n\tread: (uri: URL, ctx: ResourceContext) => Promise<ReadResourceResult>;\n}\n\nexport type ResourceDefinition = Readonly<StaticResourceDef>;\n\nconst resources: StaticResourceDef[] = [];\n\nexport function defineResource(def: StaticResourceDef): void {\n\tresources.push(def);\n}\n\nexport function listResourceDefinitions(): ReadonlyArray<ResourceDefinition> {\n\treturn resources;\n}\n\nexport function attachResources(server: McpServer, ctx: ResourceContext): void {\n\tfor (const def of resources) {\n\t\tserver.resource(\n\t\t\tdef.name,\n\t\t\tdef.uri,\n\t\t\t{\n\t\t\t\tdescription: def.description,\n\t\t\t\t...(def.mimeType ? { mimeType: def.mimeType } : {}),\n\t\t\t},\n\t\t\t(uri) => def.read(uri, ctx),\n\t\t);\n\t}\n}\n\n/**\n * Pack a JSON value into the resource read-result envelope. The MCP spec\n * requires `text` for application/json resources — we serialise here so each\n * resource handler stays a one-liner.\n */\nexport function jsonResource(uri: URL, data: unknown): ReadResourceResult {\n\treturn {\n\t\tcontents: [\n\t\t\t{\n\t\t\t\turi: uri.toString(),\n\t\t\t\tmimeType: 'application/json',\n\t\t\t\ttext: JSON.stringify(data, null, 2),\n\t\t\t},\n\t\t],\n\t};\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport type { HostStack } from '@hoststack.dev/sdk';\nimport type { ZodRawShape, z } from 'zod';\n\nimport type { ApiClient } from './api-client.js';\n\nexport type ToolCategory =\n\t| 'projects'\n\t| 'services'\n\t| 'deploys'\n\t| 'databases'\n\t| 'domains'\n\t| 'dns'\n\t| 'volumes'\n\t| 'env-vars'\n\t| 'environments'\n\t| 'cron'\n\t| 'logs'\n\t| 'activity-log'\n\t| 'alerts'\n\t| 'meta';\n\nexport interface ToolContext {\n\thoststack: HostStack;\n\tapi: ApiClient;\n\t/**\n\t * Lazy resolver for the team ID bound to the API key. The agent never has\n\t * to pass `teamId` to a tool — every SDK route is team-scoped, so the MCP\n\t * looks it up once via `/api/auth/me` and caches it for the rest of the\n\t * server's lifetime. Throws if the API key is invalid or unbound.\n\t */\n\tresolveTeamId(): Promise<number>;\n}\n\ninterface InternalToolDefinition {\n\tname: string;\n\tcategory: ToolCategory;\n\tdescription: string;\n\tinput: ZodRawShape;\n\thandler: (args: Record<string, unknown>, ctx: ToolContext) => Promise<CallToolResult>;\n}\n\nexport type ToolDefinition = Readonly<InternalToolDefinition>;\n\nconst tools: InternalToolDefinition[] = [];\n\n/**\n * Register a single tool definition. The generic over `TInput` lets the\n * handler receive precisely-typed arguments while the registry stores the\n * widened shape.\n */\nexport function defineTool<TInput extends ZodRawShape>(def: {\n\tname: string;\n\tcategory: ToolCategory;\n\tdescription: string;\n\tinput: TInput;\n\thandler: (args: z.infer<z.ZodObject<TInput>>, ctx: ToolContext) => Promise<CallToolResult>;\n}): void {\n\ttools.push({\n\t\tname: def.name,\n\t\tcategory: def.category,\n\t\tdescription: def.description,\n\t\tinput: def.input,\n\t\thandler: def.handler as InternalToolDefinition['handler'],\n\t});\n}\n\n/** Snapshot the currently-registered tool definitions (for tests / docs). */\nexport function listToolDefinitions(): ReadonlyArray<ToolDefinition> {\n\treturn tools;\n}\n\n/**\n * Telemetry event emitted once per tool invocation. The MCP package never\n * persists these — it just hands them to the optional `onToolCall` sink so\n * the host (HTTP transport, CLI, tests) can decide where they go.\n *\n * Privacy: `inputHash` is a hash over the JSON-stringified args; we never\n * expose the args themselves so PII from tool inputs (env-var values, domain\n * names) never reaches a sink.\n */\nexport interface ToolCallEvent {\n\ttool: string;\n\tdurationMs: number;\n\tok: boolean;\n\terrorCode: string | null;\n\tinputHash: string | null;\n\tstartedAt: Date;\n}\n\nexport type ToolCallSink = (event: ToolCallEvent) => void | Promise<void>;\n\n/** Iterate the registry and wire each tool into the MCP server. */\nexport function attachTools(server: McpServer, ctx: ToolContext, sink?: ToolCallSink): void {\n\ttype ToolMethod = (\n\t\tname: string,\n\t\tdescription: string,\n\t\tschema: ZodRawShape,\n\t\tcb: (args: Record<string, unknown>) => Promise<CallToolResult>,\n\t) => unknown;\n\n\tconst register = server.tool.bind(server) as unknown as ToolMethod;\n\n\tfor (const def of tools) {\n\t\tregister(def.name, def.description, def.input, async (args) => {\n\t\t\tconst startedAt = new Date();\n\t\t\tconst start = performance.now();\n\t\t\tlet ok = true;\n\t\t\tlet errorCode: string | null = null;\n\t\t\ttry {\n\t\t\t\tconst result = await def.handler(args, ctx);\n\t\t\t\tif (result.isError) {\n\t\t\t\t\tok = false;\n\t\t\t\t\terrorCode = 'tool_error';\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t} catch (err) {\n\t\t\t\tok = false;\n\t\t\t\terrorCode =\n\t\t\t\t\terr instanceof Error ? (err.name || 'Error').slice(0, 64) : 'unknown_error';\n\t\t\t\tthrow err;\n\t\t\t} finally {\n\t\t\t\tif (sink) {\n\t\t\t\t\tconst durationMs = Math.round(performance.now() - start);\n\t\t\t\t\tconst event: ToolCallEvent = {\n\t\t\t\t\t\ttool: def.name,\n\t\t\t\t\t\tdurationMs,\n\t\t\t\t\t\tok,\n\t\t\t\t\t\terrorCode,\n\t\t\t\t\t\tinputHash: hashArgs(args),\n\t\t\t\t\t\tstartedAt,\n\t\t\t\t\t};\n\t\t\t\t\tPromise.resolve()\n\t\t\t\t\t\t.then(() => sink(event))\n\t\t\t\t\t\t.catch(() => undefined);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n}\n\nfunction hashArgs(args: Record<string, unknown>): string | null {\n\ttry {\n\t\tconst json = JSON.stringify(args);\n\t\tconst bunGlobal = (globalThis as { Bun?: { hash?: (data: string) => bigint } }).Bun;\n\t\tif (bunGlobal?.hash) {\n\t\t\treturn bunGlobal.hash(json).toString(16);\n\t\t}\n\t\treturn `len:${json.length}`;\n\t} catch {\n\t\treturn null;\n\t}\n}\n","import { z } from 'zod';\n\nimport { definePrompt, userMessage } from './registry.js';\n\ndefinePrompt({\n\tname: 'diagnose_failed_deploy',\n\tdescription:\n\t\t'Walk the agent through diagnosing a failed deploy: pull the latest deploys for the named service, find the most recent failure, fetch its build/deploy logs, and propose a fix. Stops at suggestion — does not retrigger automatically.',\n\targs: {\n\t\tservice_id: z.string().describe('Service publicId (e.g. svc_abc123).'),\n\t},\n\thandler: async ({ service_id }) => {\n\t\tconst text = `Goal: diagnose the most recent failed deploy on service ${service_id} and propose a fix.\n\nPlan (use these tools in order):\n1. \\`list_deploys({ service_id: \"${service_id}\" })\\` — pull recent deploys, newest first. Identify the most recent deploy with status \\`failed\\` (or \\`cancelled\\` if the user wants to investigate that too). Capture its publicId, branch, and commitSha.\n2. \\`get_deploy_logs({ service_id: \"${service_id}\", deploy_id: \"<dpl_…>\" })\\` — read the full build output. Scan for: stack traces, \"ERROR\" / \"error:\" lines, exit codes, missing env vars, OOM-killed signals, network failures pulling dependencies.\n3. \\`get_service({ service_id: \"${service_id}\" })\\` — confirm the service's runtime, plan, and whether autoDeploy is on. Plan tier matters because OOMs at small tiers point at \\`maxMemoryMb\\`.\n4. (Optional) \\`list_env_vars({ service_id: \"${service_id}\" })\\` — only if the build error mentions a missing variable. Don't fetch otherwise; values are masked anyway.\n\nThen write a short diagnosis for the user with three sections:\n- **Root cause** — one sentence pointing at the actual failure line.\n- **Evidence** — 3–6 line excerpt from the logs that proves the diagnosis.\n- **Suggested fix** — concrete next steps, including which tool to call (e.g. \"set MISSING_KEY with set_env_var, then trigger_deploy\"). Do NOT call trigger_deploy automatically; the user decides.\n\nIf the deploy logs are empty or only contain queued/pending markers, surface that — the build never started, which is its own class of bug (likely a builder-pool or quota issue).`;\n\n\t\treturn { messages: [userMessage(text)] };\n\t},\n});\n\ndefinePrompt({\n\tname: 'deploy_status_check',\n\tdescription:\n\t\t\"Quick orientation prompt: who am I, what's running, and is anything currently deploying? Useful at the start of a session.\",\n\targs: {},\n\thandler: async () => {\n\t\tconst text = `Goal: produce a 30-second status check on this HostStack team.\n\nPlan:\n1. \\`get_me()\\` — confirm which user + team the API key belongs to.\n2. \\`list_services()\\` — every service with current status (running, suspended, building, deploying, failed). Note any service in a non-running state.\n3. For each service whose status is \\`building\\` or \\`deploying\\`, call \\`list_deploys({ service_id })\\` and surface the latest deploy's commitMessage + author.\n4. \\`list_activity_log({ per_page: 10 })\\` — last 10 audit events to spot recent changes (deploys triggered, env vars edited, services restarted).\n\nWrite a status report shaped like:\n\n> **Team**: <name>\n> **Services**: <n> total — <breakdown by status>\n> **In flight**: <list of building/deploying services with commit info, or \"none\">\n> **Recent activity**: <3-5 most relevant events from the audit log, newest first>\n\nKeep it tight (under 200 words). The user can drill in with follow-up tools.`;\n\n\t\treturn { messages: [userMessage(text)] };\n\t},\n});\n\ndefinePrompt({\n\tname: 'rotate_secret',\n\tdescription:\n\t\t'Guide the agent through rotating an env-var secret on a service. Lists current vars to confirm the target key exists, asks the user for the new value, sets it, and offers to trigger a deploy.',\n\targs: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tkey: z.string().describe('Env-var key to rotate (e.g. DATABASE_URL).'),\n\t},\n\thandler: async ({ service_id, key }) => {\n\t\tconst text = `Goal: rotate the secret \\`${key}\\` on service ${service_id}.\n\nPlan:\n1. \\`list_env_vars({ service_id: \"${service_id}\" })\\` — confirm \\`${key}\\` exists. Note its \\`isSecret\\` flag (it should be true; if not, flag this — you're about to mark it secret on rotation, which is a behaviour change).\n2. **Ask the user for the new value before calling any write tool.** The agent must NOT invent or generate the secret; it has to come from the user's clipboard / vault. Phrase the ask explicitly: \"Paste the new value for ${key} (it will be encrypted at rest and masked everywhere except the running container).\"\n3. Once the user provides the value:\n - \\`set_env_var({ service_id: \"${service_id}\", key: \"${key}\", value: \"<new value>\", is_secret: true })\\` — upserts by key.\n4. After the write succeeds, ask the user whether to redeploy (so the new value lands in the running container). If yes:\n - \\`trigger_deploy({ service_id: \"${service_id}\" })\\` — kicks off a build with the rotated secret.\n - \\`get_deploy({ service_id: \"${service_id}\", deploy_id: \"<dpl_…>\" })\\` — poll until status is \\`live\\` or \\`failed\\`. On failure, hand off to \\`diagnose_failed_deploy\\`.\n\nSafety rails:\n- Never echo the new value back in your reply; the user should verify it from their own source of truth, not from your context window.\n- If the user says \"generate a new one\", suggest \\`openssl rand -hex 32\\` (or similar) for them to run locally and paste in. Do NOT generate it for them — secrets that pass through an LLM context are no longer secrets.\n- If \\`set_env_var\\` returned \\`action: \"created\"\\` instead of \\`\"updated\"\\`, the key didn't exist before. Pause and confirm with the user — they may have typo'd the key name.`;\n\n\t\treturn { messages: [userMessage(text)] };\n\t},\n});\n","/**\n * Per-resource shape pickers. Each function takes a raw API/SDK response and\n * returns the agent-friendly subset: drops internal foreign keys (teamId,\n * userId, ...) and null-valued columns, leaves ISO-8601 timestamps as-is.\n *\n * Pickers must be permissive about input shape — different SDK methods may\n * return slightly different fields (e.g. list vs get) and the API may grow\n * fields over time. We never throw on missing fields.\n */\n\nconst INTERNAL_FIELDS = new Set([\n\t'teamId',\n\t'team_id',\n\t'userId',\n\t'user_id',\n\t'accountId',\n\t'account_id',\n\t'tenantId',\n\t'tenant_id',\n\t'createdById',\n\t'updatedById',\n]);\n\ntype Obj = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is Obj {\n\treturn value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction dropNullsAndInternals(obj: Obj): Obj {\n\tconst out: Obj = {};\n\tfor (const [key, value] of Object.entries(obj)) {\n\t\tif (INTERNAL_FIELDS.has(key)) continue;\n\t\tif (value === null || value === undefined) continue;\n\t\tout[key] = value;\n\t}\n\treturn out;\n}\n\n/** Generic shape — drop internals, drop nulls, keep everything else. */\nexport function shape(value: unknown): unknown {\n\tif (Array.isArray(value)) return value.map(shape);\n\tif (isObject(value)) return dropNullsAndInternals(value);\n\treturn value;\n}\n\nfunction shapeAll<T>(arr: unknown, shaper: (item: unknown) => T): T[] {\n\tif (!Array.isArray(arr)) return [];\n\treturn arr.map(shaper);\n}\n\n/**\n * Unwrap a HostStack list response. The API returns shapes like\n * `{ projects: [...] }`, `{ services: [...] }`, etc. — the key varies by\n * resource. Pass the key explicitly so the wrapper stays type-loose.\n */\nexport function shapeList<T>(\n\tresponse: unknown,\n\tkey: string,\n\tshaper: (item: unknown) => T,\n): { items: T[] } {\n\tif (!isObject(response)) return { items: [] };\n\treturn { items: shapeAll(response[key], shaper) };\n}\n\n// ──────────────────────────────────────────────────────────────────────\n// Per-resource pickers — typed convenience wrappers around shape().\n// All return a plain Obj (never null), keeping the registry handlers simple.\n// ──────────────────────────────────────────────────────────────────────\n\nexport function shapeProject(value: unknown): Obj {\n\treturn isObject(value) ? dropNullsAndInternals(value) : {};\n}\n\nexport function shapeService(value: unknown): Obj {\n\treturn isObject(value) ? dropNullsAndInternals(value) : {};\n}\n\nexport function shapeDeploy(value: unknown): Obj {\n\treturn isObject(value) ? dropNullsAndInternals(value) : {};\n}\n\nexport function shapeDatabase(value: unknown): Obj {\n\treturn isObject(value) ? dropNullsAndInternals(value) : {};\n}\n\nexport function shapeDomain(value: unknown): Obj {\n\treturn isObject(value) ? dropNullsAndInternals(value) : {};\n}\n\nexport function shapeEnvVar(value: unknown): Obj {\n\treturn isObject(value) ? dropNullsAndInternals(value) : {};\n}\n\nexport function shapeCronExecution(value: unknown): Obj {\n\treturn isObject(value) ? dropNullsAndInternals(value) : {};\n}\n\nexport function shapeActivity(value: unknown): Obj {\n\treturn isObject(value) ? dropNullsAndInternals(value) : {};\n}\n\nexport function shapeUser(value: unknown): Obj {\n\treturn isObject(value) ? dropNullsAndInternals(value) : {};\n}\n\nexport function shapeTeam(value: unknown): Obj {\n\treturn isObject(value) ? dropNullsAndInternals(value) : {};\n}\n\nexport function shapeVolume(value: unknown): Obj {\n\treturn isObject(value) ? dropNullsAndInternals(value) : {};\n}\n","import { shapeProject, shapeService, shapeTeam, shapeUser } from '../lib/shape.js';\nimport { defineResource, jsonResource } from './registry.js';\n\ninterface MeResponse {\n\tuser: unknown;\n\tteam?: unknown;\n}\n\ndefineResource({\n\tkind: 'static',\n\tname: 'team',\n\turi: 'hoststack://team',\n\tdescription:\n\t\t'Authenticated team identity + a quick orientation snapshot. Includes the team record, the user behind the API key, and counts of projects and services so an agent can decide whether to fan out into list_projects / list_services without an extra round-trip.',\n\tmimeType: 'application/json',\n\tread: async (uri, { hoststack, api, resolveTeamId }) => {\n\t\tconst teamId = await resolveTeamId();\n\n\t\t// Resource handlers must not throw on transient downstream failures —\n\t\t// clients call resources/read for orientation and a network blip\n\t\t// shouldn't poison the entire session. Tolerate partial failure and\n\t\t// surface what we can.\n\t\tconst [me, projectsResult, servicesResult] = await Promise.all([\n\t\t\tapi.get<MeResponse>('/api/auth/me').catch(() => null),\n\t\t\thoststack.projects.list(teamId).catch(() => ({ projects: [] as unknown[] })),\n\t\t\thoststack.services.list(teamId).catch(() => ({ services: [] as unknown[] })),\n\t\t]);\n\n\t\tconst projects = (projectsResult.projects as unknown[]).slice(0, 10).map(shapeProject);\n\t\tconst services = (servicesResult.services as unknown[]).slice(0, 10).map(shapeService);\n\n\t\treturn jsonResource(uri, {\n\t\t\tuser: me?.user ? shapeUser(me.user) : null,\n\t\t\tteam: me?.team ? shapeTeam(me.team) : null,\n\t\t\tproject_count: (projectsResult.projects as unknown[]).length,\n\t\t\tservice_count: (servicesResult.services as unknown[]).length,\n\t\t\t// First 10 of each so the resource stays small while still useful\n\t\t\t// for orientation. Use list_projects / list_services for the full set.\n\t\t\tprojects_preview: projects,\n\t\t\tservices_preview: services,\n\t\t});\n\t},\n});\n","import { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond } from '../lib/respond.js';\nimport { shape, shapeActivity } from '../lib/shape.js';\n\ninterface ActivityLogResponse {\n\tdata?: unknown[];\n\t// Older API style: pagination meta as a single nested object. Some\n\t// callers still serve this shape, so keep accepting it.\n\tmeta?: unknown;\n\t// Current API style: pagination meta fields are spread flat on the\n\t// response root (`{ data, page, perPage, total, totalPages }`).\n\tpage?: number;\n\tperPage?: number;\n\ttotal?: number;\n\ttotalPages?: number;\n}\n\ndefineTool({\n\tname: 'list_activity_log',\n\tcategory: 'activity-log',\n\tdescription: [\n\t\t'List the team activity audit log: who did what, when. Backed by /api/activity-log/:teamId.',\n\t\t'',\n\t\t'When to use: investigate why a service was changed unexpectedly (\"who deleted that env var?\"), correlate a deploy with a user, or pull recent admin events for a status update.',\n\t\t'',\n\t\t'Inputs (all optional):',\n\t\t' - page: 1-based page index (default 1).',\n\t\t' - per_page: items per page (default 25, hard cap 100).',\n\t\t' - action: filter to a specific action (e.g. \"service.created\", \"deploy.triggered\").',\n\t\t' - resource_type: filter by resource type (e.g. \"service\", \"deploy\", \"domain\").',\n\t\t' - user_id: filter by acting user numeric ID.',\n\t\t' - since/until: ISO-8601 timestamp OR a relative offset like \"-15m\" / \"-2h\" / \"-7d\" — narrow to a time window (handy for correlating a deploy with a log spike).',\n\t\t'',\n\t\t'Returns: { items: ActivityLogEntry[], meta: { page, perPage, total, totalPages } } — each entry has id, action, resourceType, resourceId, actorEmail, ipAddress, createdAt, and a context payload. Use meta.totalPages to tell whether you have more.',\n\t\t'',\n\t\t'Example: list_activity_log({ resource_type: \"deploy\", per_page: 10 }) → { items: [{ action: \"deploy.triggered\", actorEmail: \"ada@…\", … }], meta: { total: 47, page: 1 } }',\n\t].join('\\n'),\n\tinput: {\n\t\tpage: z.number().int().positive().optional().describe('Page index, 1-based.'),\n\t\tper_page: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.positive()\n\t\t\t.max(100)\n\t\t\t.optional()\n\t\t\t.describe('Items per page, hard cap 100.'),\n\t\taction: z.string().optional().describe('Action filter, e.g. \"service.created\".'),\n\t\tresource_type: z.string().optional().describe('Resource type filter.'),\n\t\tuser_id: z.number().int().positive().optional().describe('Numeric acting-user filter.'),\n\t\tsince: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe('ISO-8601 timestamp or relative offset (e.g. \"-15m\", \"-2h\", \"-7d\").'),\n\t\tuntil: z.string().optional().describe('ISO-8601 timestamp or relative offset upper bound.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst params: Record<string, string | number | undefined> = {};\n\t\tif (args.page !== undefined) params['page'] = String(args.page);\n\t\tif (args.per_page !== undefined) params['perPage'] = String(args.per_page);\n\t\tif (args.action !== undefined) params['action'] = args.action;\n\t\tif (args.resource_type !== undefined) params['resourceType'] = args.resource_type;\n\t\tif (args.user_id !== undefined) params['userId'] = String(args.user_id);\n\t\tif (args.since !== undefined) params['since'] = args.since;\n\t\tif (args.until !== undefined) params['until'] = args.until;\n\n\t\tconst response = await ctx.api.get<ActivityLogResponse>(\n\t\t\t`/api/activity-log/${teamId}`,\n\t\t\tparams,\n\t\t);\n\t\tconst items = Array.isArray(response.data) ? response.data.map(shapeActivity) : [];\n\t\tconst data: { items: unknown[]; meta?: unknown } = { items };\n\t\t// The API spreads pagination at the top level (`{ data, page, perPage,\n\t\t// total, totalPages }`). Older variants nested it under `meta`.\n\t\t// Surface a single `meta` object regardless so MCP callers don't have\n\t\t// to learn two shapes.\n\t\tif (response.meta !== undefined) {\n\t\t\tdata.meta = shape(response.meta);\n\t\t} else if (\n\t\t\tresponse.page !== undefined ||\n\t\t\tresponse.perPage !== undefined ||\n\t\t\tresponse.total !== undefined ||\n\t\t\tresponse.totalPages !== undefined\n\t\t) {\n\t\t\tdata.meta = shape({\n\t\t\t\tpage: response.page,\n\t\t\t\tperPage: response.perPage,\n\t\t\t\ttotal: response.total,\n\t\t\t\ttotalPages: response.totalPages,\n\t\t\t});\n\t\t}\n\n\t\treturn respond({\n\t\t\tsummary:\n\t\t\t\titems.length === 0\n\t\t\t\t\t? 'No activity log entries match the given filters.'\n\t\t\t\t\t: `Returned ${items.length} activity log entr${items.length === 1 ? 'y' : 'ies'}.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n","import type { CallToolResult, ContentBlock } from '@modelcontextprotocol/sdk/types.js';\n\ninterface RespondInput {\n\tsummary: string;\n\tdata?: unknown;\n}\n\nexport const SUMMARY_MAX_LEN = 500;\n\n/**\n * Build an MCP tool response with a 1–3 line plain-text summary, a fenced\n * JSON block for human readability, and a structuredContent object that\n * agents can parse without re-tokenising the JSON text.\n */\nexport function respond({ summary, data }: RespondInput): CallToolResult {\n\tconst trimmed = summary.trim();\n\tif (trimmed.length === 0) {\n\t\tthrow new Error('respond(): summary must be non-empty');\n\t}\n\tif (trimmed.length > SUMMARY_MAX_LEN) {\n\t\tthrow new Error(`respond(): summary too long (${trimmed.length} > ${SUMMARY_MAX_LEN})`);\n\t}\n\n\tconst blocks: ContentBlock[] = [{ type: 'text', text: trimmed }];\n\n\tif (data !== undefined) {\n\t\tblocks.push({\n\t\t\ttype: 'text',\n\t\t\ttext: '```json\\n' + JSON.stringify(data, null, 2) + '\\n```',\n\t\t});\n\t}\n\n\tconst result: CallToolResult = { content: blocks };\n\tif (data !== undefined) {\n\t\tresult.structuredContent = toStructuredContent(data);\n\t}\n\treturn result;\n}\n\nexport function respondError(message: string, data?: unknown): CallToolResult {\n\tconst blocks: ContentBlock[] = [{ type: 'text', text: `Error: ${message}` }];\n\tif (data !== undefined) {\n\t\tblocks.push({\n\t\t\ttype: 'text',\n\t\t\ttext: '```json\\n' + JSON.stringify(data, null, 2) + '\\n```',\n\t\t});\n\t}\n\tconst result: CallToolResult = { content: blocks, isError: true };\n\tif (data !== undefined) {\n\t\tresult.structuredContent = toStructuredContent(data);\n\t}\n\treturn result;\n}\n\nfunction toStructuredContent(data: unknown): Record<string, unknown> {\n\tif (data !== null && typeof data === 'object' && !Array.isArray(data)) {\n\t\treturn data as Record<string, unknown>;\n\t}\n\treturn { result: data };\n}\n","import { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond } from '../lib/respond.js';\nimport { shape } from '../lib/shape.js';\n\ninterface AlertsResponse {\n\talerts: unknown[];\n\taggregated: boolean;\n}\n\ndefineTool({\n\tname: 'list_alerts',\n\tcategory: 'alerts',\n\tdescription: [\n\t\t'List recent alert-shaped events for the team: deploy failures, git auth losses, service health failures, auto-restarts, ACME cert failures, resource alerts (high CPU), database backup/restore failures, registrant verification lapses.',\n\t\t'',\n\t\t\"When to use: triage 'what's currently broken or recently broke for this team'. Pairs with list_activity_log for the full audit feed; this tool is the alert-shaped subset.\",\n\t\t'',\n\t\t'By default events are AGGREGATED by (action, resourceId) so flapping events collapse to one row with a fire count + first/last timestamps — e.g. \"service.auto_restarted on service 31, 8 times in the last hour, last at 14:22\". Pass aggregate=false to see every raw row.',\n\t\t'',\n\t\t'ACTIVE vs HISTORICAL (v89): each aggregated entry now has an `active` boolean and a `lastResolvedAt` timestamp. `active=true` means the most recent occurrence has NOT been resolved — the alert is still on fire. The default `active=true` filter hides resolved/historical alerts so triage starts with \"what is broken right now\". Pass `active=false` to include resolved entries too (useful for post-mortems). Resolution is automatic for some alert kinds — e.g. `deploy.failed_consecutive` is cleared when the next deploy of the same service goes live.',\n\t\t'',\n\t\t'Database backup_failed entries (v89) include `containerStatus` / `containerHealth` / `containerExitCode` in lastMetadata when the agent could resolve the container at failure time, so you can tell \"Redis is overloaded\" apart from \"Redis is restarting\" without a second tool call.',\n\t\t'',\n\t\t'Deploy.failed_consecutive entries (v89) carry the offending `commitHash` in lastMetadata, and the streak now dedupes per (service, commitHash) — one critical per bad commit, not one every 6 retries.',\n\t\t'',\n\t\t'Inputs (all optional):',\n\t\t' - since: ISO-8601 timestamp OR relative offset like \"-1h\" / \"-2d\". Default: -24h.',\n\t\t' - until: ISO-8601 upper bound (ignored when aggregating — aggregated view always extends to now).',\n\t\t' - limit: max rows (default 100, hard cap 500).',\n\t\t' - aggregate: true (default) collapses by (action, resourceId); false returns raw rows.',\n\t\t' - active: true (default) shows only alerts that are still on fire (resolved_at IS NULL on the most recent row). false includes resolved historical alerts.',\n\t\t'',\n\t\t'Returns: { alerts: Array, aggregated: boolean, activeOnly: boolean }. Each aggregated entry includes action, resourceType, resourceId, severity, count, firstFiredAt, lastFiredAt, lastResolvedAt (nullable), active (boolean), lastMetadata. Each raw entry adds resolvedAt (nullable).',\n\t\t'',\n\t\t\"Example: list_alerts({ since: '-1h' }) → { alerts: [{ action: 'deploy.failed_consecutive', resourceId: 31, severity: 'critical', active: true, count: 3, lastFiredAt: '…', lastResolvedAt: null, lastMetadata: { commitHash: 'abc1234' }, … }] }.\",\n\t].join('\\n'),\n\tinput: {\n\t\tsince: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe('ISO-8601 timestamp or relative offset (e.g. \"-1h\", \"-2d\"). Default: -24h.'),\n\t\tuntil: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe('ISO-8601 upper bound. Only honored when aggregate=false.'),\n\t\tlimit: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.positive()\n\t\t\t.max(500)\n\t\t\t.optional()\n\t\t\t.describe('Max rows (default 100, hard cap 500).'),\n\t\taggregate: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe('Collapse by (action, resourceId). Default true.'),\n\t\tactive: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t'Only return alerts still on fire (resolved_at IS NULL on the most recent row). Default true. Pass false to include resolved historical alerts.',\n\t\t\t),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst params: Record<string, string | number | undefined> = {};\n\t\tif (args.since !== undefined) params['since'] = args.since;\n\t\tif (args.until !== undefined) params['until'] = args.until;\n\t\tif (args.limit !== undefined) params['limit'] = String(args.limit);\n\t\t// API expects aggregate=1|0; default behavior on the API side is\n\t\t// aggregate=true. Pass explicit \"0\" only when caller opts out so\n\t\t// we don't ship spurious query params.\n\t\tif (args.aggregate === false) params['aggregate'] = '0';\n\t\t// v89: same convention for active=1|0. Default true on the API\n\t\t// side, so we only ship `active=0` when the caller opts in to\n\t\t// historical entries.\n\t\tif (args.active === false) params['active'] = '0';\n\n\t\tconst response = await ctx.api.get<AlertsResponse>(`/api/alerts/${teamId}`, params);\n\t\tconst items = Array.isArray(response.alerts) ? response.alerts.map(shape) : [];\n\t\tconst aggregated = Boolean(response.aggregated);\n\t\tconst activeOnly = args.active !== false;\n\t\tconst summary =\n\t\t\titems.length === 0\n\t\t\t\t? activeOnly\n\t\t\t\t\t? 'No active alerts in the requested window — everything is operating normally.'\n\t\t\t\t\t: 'No alerts in the requested window (active or resolved).'\n\t\t\t\t: aggregated\n\t\t\t\t\t? `Returned ${items.length} alert group${items.length === 1 ? '' : 's'}${activeOnly ? ' (active only — pass active=false for resolved history)' : ''} (flapping events collapsed).`\n\t\t\t\t\t: `Returned ${items.length} raw alert event${items.length === 1 ? '' : 's'}.`;\n\t\treturn respond({ summary, data: { alerts: items, aggregated, activeOnly } });\n\t},\n});\n","import { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond } from '../lib/respond.js';\nimport { shapeCronExecution, shapeList } from '../lib/shape.js';\n\ndefineTool({\n\tname: 'list_cron_executions',\n\tcategory: 'cron',\n\tdescription: [\n\t\t'List recent execution records for a cron service (newest first).',\n\t\t'',\n\t\t'When to use: investigating whether a scheduled job ran on time, finding the most recent failure, or auditing cron run-times. Only works on services of type \"cron\"; for web services this returns an error.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the cron service.',\n\t\t' - limit (optional): how many executions to fetch (default 50, max enforced server-side).',\n\t\t'',\n\t\t'Returns: { items: CronExecution[] } — id, publicId, status (succeeded|failed|running|queued), startedAt, finishedAt, exitCode, triggeredBy.',\n\t\t'',\n\t\t'Example: list_cron_executions({ service_id: \"svc_cron\" }) → { items: [{ status: \"succeeded\", exitCode: 0, … }, …] }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Cron service publicId.'),\n\t\tlimit: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.positive()\n\t\t\t.max(200)\n\t\t\t.optional()\n\t\t\t.describe('Max executions to return (default 50).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst opts = args.limit !== undefined ? { limit: args.limit } : undefined;\n\t\tconst response = await ctx.hoststack.cron.list(teamId, args.service_id, opts);\n\t\tconst data = shapeList(response, 'executions', shapeCronExecution);\n\t\tconst summary =\n\t\t\tdata.items.length === 0\n\t\t\t\t? `No cron executions yet for ${args.service_id}.`\n\t\t\t\t: `Found ${data.items.length} cron execution${data.items.length === 1 ? '' : 's'} for ${args.service_id}.`;\n\t\treturn respond({ summary, data });\n\t},\n});\n\ndefineTool({\n\tname: 'get_cron_execution',\n\tcategory: 'cron',\n\tdescription: [\n\t\t'Fetch a single cron execution record. Includes status, exit code, and timing.',\n\t\t'',\n\t\t'When to use: drilling into a specific run after list_cron_executions surfaced a failure, or correlating an execution timestamp with logs.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the cron service.',\n\t\t' - execution_id: publicId of the execution record.',\n\t\t'',\n\t\t'Returns: { execution: CronExecution }.',\n\t\t'',\n\t\t'Example: get_cron_execution({ service_id: \"svc_cron\", execution_id: \"exe_xyz\" }) → { execution: { status: \"failed\", exitCode: 1, … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Cron service publicId.'),\n\t\texecution_id: z.string().describe('Execution publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.cron.get(teamId, args.service_id, args.execution_id);\n\t\tconst data = { execution: shapeCronExecution(response.execution) };\n\t\tconst status =\n\t\t\tdata.execution && 'status' in data.execution\n\t\t\t\t? (data.execution as { status: string }).status\n\t\t\t\t: 'unknown';\n\t\treturn respond({ summary: `Execution ${args.execution_id} ${status}.`, data });\n\t},\n});\n","import { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond } from '../lib/respond.js';\nimport { shapeDatabase, shapeList } from '../lib/shape.js';\n\ndefineTool({\n\tname: 'list_databases',\n\tcategory: 'databases',\n\tdescription: [\n\t\t'List managed databases (Postgres, Redis, MySQL, MariaDB, MongoDB, Meilisearch, NATS) inside a project.',\n\t\t'',\n\t\t'When to use: an agent needs to know what data stores exist in a project before connecting a service or running a migration. Pair with list_projects to discover project IDs.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - project_id: numeric project ID (from list_projects).',\n\t\t'',\n\t\t'Returns: { items: Database[] } — id, publicId, name, type, status, version, projectId, createdAt.',\n\t\t'',\n\t\t'Example: list_databases({ project_id: 12 }) → { items: [{ publicId: \"db_…\", type: \"postgres\", status: \"running\", … }] }',\n\t].join('\\n'),\n\tinput: {\n\t\tproject_id: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.positive()\n\t\t\t.describe('Numeric project ID (from list_projects).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.databases.list(teamId, args.project_id);\n\t\tconst data = shapeList(response, 'databases', shapeDatabase);\n\t\tconst summary =\n\t\t\tdata.items.length === 0\n\t\t\t\t? `No databases in project ${args.project_id}.`\n\t\t\t\t: `Found ${data.items.length} database${data.items.length === 1 ? '' : 's'} in project ${args.project_id}.`;\n\t\treturn respond({ summary, data });\n\t},\n});\n\ndefineTool({\n\tname: 'update_database',\n\tcategory: 'databases',\n\tdescription: [\n\t\t'Update a managed database — rename, change plan tier (memory/CPU), or grow disk size.',\n\t\t'',\n\t\t'When to use: the user wants to resize a database (disk or plan), or rename it. Disk can only grow — shrinking is rejected because the underlying filesystem would orphan data.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - database_id: publicId of the database (e.g. \"db_…\").',\n\t\t' - name (optional): new database name.',\n\t\t' - plan (optional): \"free\" | \"micro\" | \"starter\" | \"standard\" | \"pro\" — changes memory tier.',\n\t\t' - disk_size_gb (optional): new disk size in GB (must be ≥ current).',\n\t\t'',\n\t\t'Returns: { database: Database } — the updated record.',\n\t\t'',\n\t\t'Example: update_database({ database_id: \"db_xyz\", disk_size_gb: 50 }) → { database: { diskSizeGb: 50, … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tdatabase_id: z.string().describe('Database publicId (e.g. db_xyz).'),\n\t\tname: z.string().min(1).max(100).optional().describe('New database name.'),\n\t\tplan: z\n\t\t\t.enum(['free', 'micro', 'starter', 'standard', 'pro'])\n\t\t\t.optional()\n\t\t\t.describe('Plan tier (memory/CPU).'),\n\t\tdisk_size_gb: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(1)\n\t\t\t.max(1024)\n\t\t\t.optional()\n\t\t\t.describe('New disk size in GB. Must be ≥ current.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst input: {\n\t\t\tname?: string;\n\t\t\tplan?: 'free' | 'micro' | 'starter' | 'standard' | 'pro';\n\t\t\tdiskSizeGb?: number;\n\t\t} = {};\n\t\tif (args.name !== undefined) input.name = args.name;\n\t\tif (args.plan !== undefined) input.plan = args.plan;\n\t\tif (args.disk_size_gb !== undefined) input.diskSizeGb = args.disk_size_gb;\n\t\tif (Object.keys(input).length === 0) {\n\t\t\treturn respond({ summary: 'No fields to update.', data: {} });\n\t\t}\n\t\tconst response = await ctx.hoststack.databases.update(teamId, args.database_id, input);\n\t\tconst data = { database: shapeDatabase(response.database) };\n\t\tconst fields = Object.keys(input).join(', ');\n\t\treturn respond({ summary: `Updated ${fields} on database ${args.database_id}.`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'get_database',\n\tcategory: 'databases',\n\tdescription: [\n\t\t'Fetch a single managed database by ID. Includes status, type, version, and project link.',\n\t\t'',\n\t\t'When to use: confirming the version of a database before generating connection strings, or checking the status of a recently created database. To retrieve the actual connection credentials, use the dashboard — credentials are intentionally not exposed via this MCP tool.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - database_id: publicId of the database (e.g. \"db_…\").',\n\t\t'',\n\t\t'Returns: { database: Database }.',\n\t\t'',\n\t\t'Example: get_database({ database_id: \"db_xyz\" }) → { database: { type: \"postgres\", version: \"16\", status: \"running\", … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tdatabase_id: z.string().describe('Database publicId (e.g. db_xyz).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.databases.get(teamId, args.database_id);\n\t\tconst data = { database: shapeDatabase(response.database) };\n\t\tconst type =\n\t\t\tdata.database && 'type' in data.database\n\t\t\t\t? (data.database as { type: string }).type\n\t\t\t\t: 'unknown';\n\t\tconst status =\n\t\t\tdata.database && 'status' in data.database\n\t\t\t\t? (data.database as { status: string }).status\n\t\t\t\t: 'unknown';\n\t\treturn respond({ summary: `Database ${args.database_id} (${type}) is ${status}.`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'query_database',\n\tcategory: 'databases',\n\tdescription: [\n\t\t'Run a single READ-ONLY SQL statement against a managed Postgres database.',\n\t\t'',\n\t\t'When to use: ad-hoc data inspection — checking row counts, sampling rows, debugging a constraint. For schema changes or seed data, ship a Drizzle migration instead.',\n\t\t'',\n\t\t'Safety model (server-side, not bypassable):',\n\t\t' - Wrapped in `BEGIN TRANSACTION READ ONLY` — INSERT/UPDATE/DELETE/DDL fail with a clear \"cannot execute … in a read-only transaction\" error.',\n\t\t' - 30s statement_timeout — runaway queries are killed.',\n\t\t' - 1000-row cap; result CSV is also size-capped at 1 MiB. Both surface via `truncated: true`.',\n\t\t' - Postgres engine only (v1). Other engines return a 400.',\n\t\t' - Single statement only; no embedded `;` and no psql meta-commands (`\\\\…`).',\n\t\t' - Every call is audit-logged (success or failure) as `database.query` so an admin can answer \"who queried this DB, when, with what SQL\".',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - database_id: publicId of the postgres database (e.g. \"db_…\"). Resolved via the SDK\\'s publicId helper.',\n\t\t' - sql: a single SELECT/WITH/SHOW/EXPLAIN statement, no trailing `;`. Max 16 KiB.',\n\t\t'',\n\t\t'Returns: { columns: string[], rows: string[][], rowCount: number, truncated: boolean, durationMs: number }. Values come back as strings (psql --csv); cast on the caller side when needed.',\n\t\t'',\n\t\t'Example:',\n\t\t' - query_database({ database_id: \"db_abc\", sql: \"SELECT count(*) FROM users\" }) → { columns: [\"count\"], rows: [[\"1234\"]], … }',\n\t\t' - query_database({ database_id: \"db_abc\", sql: \"SELECT id, email FROM users WHERE created_at > now() - interval \\'1 day\\' LIMIT 50\" })',\n\t].join('\\n'),\n\tinput: {\n\t\tdatabase_id: z.string().describe('Database publicId (e.g. db_abc).'),\n\t\tsql: z\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(16_384)\n\t\t\t.describe(\n\t\t\t\t'A single READ-ONLY SQL statement. No trailing `;`, no embedded `;`, no psql meta-commands.',\n\t\t\t),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst result = await ctx.hoststack.databases.query(teamId, args.database_id, args.sql);\n\t\tconst summary = result.truncated\n\t\t\t? `Query returned ${result.rowCount} row${result.rowCount === 1 ? '' : 's'} (truncated; raise LIMIT if needed) in ${result.durationMs}ms.`\n\t\t\t: `Query returned ${result.rowCount} row${result.rowCount === 1 ? '' : 's'} in ${result.durationMs}ms.`;\n\t\treturn respond({ summary, data: result });\n\t},\n});\n\ndefineTool({\n\tname: 'upgrade_database_to_ha',\n\tcategory: 'databases',\n\tdescription: [\n\t\t'Trigger a single-node → HA migration on a managed Postgres database. The agent runs pg_dump → bootstrap 3-node Patroni cluster (1 leader + 2 sync replicas + HAProxy) → pg_restore. Customer connections to this database are briefly read-only during the cutover; the standalone container stays running (read-only) for 24 h as a rollback target before automatic decommission.',\n\t\t'',\n\t\t'Requires: PATRONI_ENABLED env on the HostStack deployment + `teams.ha_beta = true` on the calling team. Returns 403 otherwise. Returns 400 if the database is already HA, not Postgres, not on the standard or pro tier, or has a pg_database_size over 1 GB (in-memory archive transfer cap).',\n\t\t'',\n\t\t'When to use: a customer needs failover protection on an existing standalone Postgres. For new databases on an HA-eligible team, just call create_database — the cluster path is automatic.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - database_id: publicId of the postgres database to upgrade.',\n\t\t'',\n\t\t'Returns: 202 Accepted. The upgrade is async — poll get_database until `pg_engine_type === \"patroni\"` and `status === \"available\"` to confirm completion. The Cluster tab on the dashboard mirrors the same data.',\n\t\t'',\n\t\t'Example: upgrade_database_to_ha({ database_id: \"db_abc\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tdatabase_id: z.string().describe('Database publicId (e.g. db_abc) to upgrade to HA.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.databases.upgradeToHa(teamId, args.database_id);\n\t\treturn respond({\n\t\t\tsummary: `HA migration started for ${args.database_id}. Poll get_database until pg_engine_type=patroni to confirm.`,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'upgrade_database_version',\n\tcategory: 'databases',\n\tdescription: [\n\t\t'Upgrade a standalone managed database (postgres or redis) to a newer engine version in place. The agent dumps the live data, recreates the container at the target version under the same DNS name, and restores — so connection URLs stay valid and services do NOT need a redeploy. The database is briefly unavailable (seconds) during the cut-over; on any failure the original container is rolled back automatically.',\n\t\t'',\n\t\t'`version` must be a supported, strictly-newer version for the engine (postgres: 18/17/16/15, redis: 8/7/6). Downgrades are rejected. Returns 400 for unsupported engines (mysql/mariadb/mongodb upgrades are not implemented yet), for HA (Patroni) clusters, or if the database is not currently `available`.',\n\t\t'',\n\t\t'When to use: a customer wants to move to a newer Postgres/Redis major version. Check get_database first — the `version` field shows the current version; compare against the engine latest.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - database_id: publicId of the postgres/redis database to upgrade.',\n\t\t' - version: target engine version (e.g. \"18\" for postgres, \"8\" for redis).',\n\t\t'',\n\t\t'Returns: 202 Accepted. The upgrade is async — poll get_database until `version` matches the target and `status === \"available\"` to confirm.',\n\t\t'',\n\t\t'Example: upgrade_database_version({ database_id: \"db_abc\", version: \"18\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tdatabase_id: z.string().describe('Database publicId (e.g. db_abc) to upgrade.'),\n\t\tversion: z\n\t\t\t.string()\n\t\t\t.describe('Target engine version, e.g. \"18\" for postgres or \"8\" for redis.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.databases.upgradeVersion(teamId, args.database_id, args.version);\n\t\treturn respond({\n\t\t\tsummary: `Version upgrade to v${args.version} started for ${args.database_id}. Poll get_database until version=${args.version} and status=available to confirm.`,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'get_database_cluster',\n\tcategory: 'databases',\n\tdescription: [\n\t\t'Get the live + retired cluster members and failover history for a Patroni HA Postgres database.',\n\t\t'',\n\t\t'When to use: confirm an HA cluster is healthy (1 leader + 2 sync replicas + 1 proxy + 1 etcd live) or investigate a failover that fired. For standalone databases this returns 400 — call get_database first if you need to branch.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - database_id: publicId of the postgres database (must be HA).',\n\t\t'',\n\t\t\"Returns: { members: { id, memberRole: 'etcd' | 'primary-candidate' | 'replica' | 'proxy', containerId, workerHostId, joinedAt, leftAt }[], failovers: { id, createdAt, oldLeader, newLeader }[] }.\",\n\t\t'',\n\t\t'Example: get_database_cluster({ database_id: \"db_abc\" }) → { members: [...5 live rows], failovers: [] }',\n\t].join('\\n'),\n\tinput: {\n\t\tdatabase_id: z.string().describe('Database publicId for the HA cluster.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst result = await ctx.hoststack.databases.getCluster(teamId, args.database_id);\n\t\tconst live = result.members.filter((m) => m.leftAt === null);\n\t\tconst summary = `${live.length} live members (${live.map((m) => m.memberRole).join(', ')}); ${result.failovers.length} historical failovers.`;\n\t\treturn respond({ summary, data: result });\n\t},\n});\n","import { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond } from '../lib/respond.js';\nimport { shape, shapeDeploy, shapeList } from '../lib/shape.js';\n\ndefineTool({\n\tname: 'list_deploys',\n\tcategory: 'deploys',\n\tdescription: [\n\t\t'List deploys for a service in reverse-chronological order (newest first).',\n\t\t'',\n\t\t'When to use: investigating a recent deploy outcome, finding the last successful deploy ID, comparing run-times, or just checking deploy history before triggering a new one.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service (e.g. \"svc_abc123\"). Use list_services to find it.',\n\t\t'',\n\t\t'Returns: { items: Deploy[] } — each deploy includes id, publicId, status (pending|building|deploying|live|failed|cancelled), commitSha, commitMessage, branch, triggeredBy, startedAt, finishedAt, imageBuildMs (docker build / image-pull only; null on skip-build redeploys — v89), containerBootMs (deploying → live wall-clock; null on builds that failed before container start — v89), buildDurationMs (legacy alias of imageBuildMs kept for back-compat), totalDurationMs (full deploy wall-clock = finishedAt − startedAt). Use imageBuildMs + containerBootMs together to tell \"build is slow\" apart from \"boot is slow\".',\n\t\t'',\n\t\t'Example: list_deploys({ service_id: \"svc_abc\" }) → { items: [{ publicId: \"dpl_…\", status: \"live\", commitMessage: \"Fix login\", … }, …] }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId (e.g. svc_abc123).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.deploys.list(teamId, args.service_id);\n\t\t// Deploys list is paginated and returns `{ data, page, ... }` — not the\n\t\t// bare `{ deploys: [] }` shape every other list endpoint uses.\n\t\tconst data = shapeList(response, 'data', shapeDeploy);\n\t\tconst summary =\n\t\t\tdata.items.length === 0\n\t\t\t\t? `No deploys yet for service ${args.service_id}.`\n\t\t\t\t: `Found ${data.items.length} deploy${data.items.length === 1 ? '' : 's'} for service ${args.service_id} (page ${response.page} of ${response.totalPages}, ${response.total} total).`;\n\t\treturn respond({ summary, data });\n\t},\n});\n\ndefineTool({\n\tname: 'get_deploy',\n\tcategory: 'deploys',\n\tdescription: [\n\t\t'Fetch a single deploy by ID, including its current status, commit metadata, and timestamps.',\n\t\t'',\n\t\t\"When to use: drilling into the details of a specific deploy after list_deploys, polling a build's status, or grabbing the commit SHA so you can correlate logs with code.\",\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - deploy_id: publicId of the deploy (e.g. \"dpl_…\").',\n\t\t'',\n\t\t'Returns: { deploy: Deploy } — full deploy record (status, commitSha, commitMessage, branch, imageBuildMs + containerBootMs (v89 split timings; legacy buildDurationMs preserved as alias), totalDurationMs, finishedAt, etc).',\n\t\t'',\n\t\t'Example: get_deploy({ service_id: \"svc_abc\", deploy_id: \"dpl_xyz\" }) → { deploy: { status: \"live\", … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tdeploy_id: z.string().describe('Deploy publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.deploys.get(teamId, args.service_id, args.deploy_id);\n\t\tconst data = { deploy: shapeDeploy(response.deploy) };\n\t\tconst status =\n\t\t\tdata.deploy && typeof data.deploy === 'object' && 'status' in data.deploy\n\t\t\t\t? (data.deploy as { status: string }).status\n\t\t\t\t: 'unknown';\n\t\treturn respond({ summary: `Deploy ${args.deploy_id} is ${status}.`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'trigger_deploy',\n\tcategory: 'deploys',\n\tdescription: [\n\t\t'Kick off a new deploy. Defaults to the latest commit on the service branch; pass commit_hash or branch to deploy something else.',\n\t\t'',\n\t\t'When to use: the user explicitly asks to deploy (\"ship it\", \"redeploy\", \"kick off a new build\"). For services with auto-deploy enabled, a fresh git push already triggers a deploy automatically — only call this for manual triggers or after a config change.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - commit_hash (optional): build a specific commit instead of HEAD on the configured branch.',\n\t\t' - branch (optional): build the tip of a non-default branch.',\n\t\t'',\n\t\t'Returns: { deploy: Deploy } — the new deploy record. Status will start as \"pending\" then transition through \"building\" → \"deploying\" → \"live\" or \"failed\".',\n\t\t'',\n\t\t'Example: trigger_deploy({ service_id: \"svc_abc\" }) → { deploy: { publicId: \"dpl_…\", status: \"pending\", … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tcommit_hash: z\n\t\t\t.string()\n\t\t\t.max(40)\n\t\t\t.optional()\n\t\t\t.describe('Specific commit to build (default: branch HEAD).'),\n\t\tbranch: z\n\t\t\t.string()\n\t\t\t.max(200)\n\t\t\t.optional()\n\t\t\t.describe('Branch to build (default: service configured branch).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst input: { commitHash?: string; branch?: string } = {};\n\t\tif (args.commit_hash !== undefined) input.commitHash = args.commit_hash;\n\t\tif (args.branch !== undefined) input.branch = args.branch;\n\t\tconst response = await ctx.hoststack.deploys.trigger(teamId, args.service_id, input);\n\t\tconst data = { deploy: shapeDeploy(response.deploy) };\n\t\tconst publicId =\n\t\t\tdata.deploy && 'publicId' in data.deploy\n\t\t\t\t? (data.deploy as { publicId: string }).publicId\n\t\t\t\t: 'unknown';\n\t\treturn respond({\n\t\t\tsummary: `Triggered deploy ${publicId} on service ${args.service_id}.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'cancel_deploy',\n\tcategory: 'deploys',\n\tdescription: [\n\t\t'Cancel a running deploy. Stops the build/deploy pipeline mid-flight; the previously live revision keeps serving traffic.',\n\t\t'',\n\t\t'When to use: the user notices a bad commit was pushed and wants to abort before it lands, or a build is hanging. Has no effect on already-finished deploys.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - deploy_id: publicId of the deploy to cancel.',\n\t\t'',\n\t\t'Returns: { ok: true }.',\n\t\t'',\n\t\t'Example: cancel_deploy({ service_id: \"svc_abc\", deploy_id: \"dpl_xyz\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tdeploy_id: z.string().describe('Deploy publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.deploys.cancel(teamId, args.service_id, args.deploy_id);\n\t\treturn respond({\n\t\t\tsummary: `Cancelled deploy ${args.deploy_id} on service ${args.service_id}.`,\n\t\t\tdata: { ok: true },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'get_deploy_logs',\n\tcategory: 'deploys',\n\tdescription: [\n\t\t'Fetch the build/deploy logs for a single deploy. Returns the entire log buffer the agent can then search for errors.',\n\t\t'',\n\t\t'When to use: a deploy failed and you need to read the build output to diagnose. Pair with get_deploy to find a failed deploy_id, then call this. For runtime (post-deploy) logs of the running container, use get_service_logs instead.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - deploy_id: publicId of the deploy.',\n\t\t'',\n\t\t'Returns: { logs: string, lineCount: number, nextAfterId: number | null } — flattened build output joined with newlines, line count, and a cursor for pagination (pass back as after_id to fetch the next page).',\n\t\t'',\n\t\t'Example: get_deploy_logs({ service_id: \"svc_abc\", deploy_id: \"dpl_xyz\" }) → { logs: \"Building…\\\\nStep 1/8…\\\\n…\", lineCount: 42, nextAfterId: 1234 }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tdeploy_id: z.string().describe('Deploy publicId.'),\n\t\tafter_id: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.optional()\n\t\t\t.describe('Pagination cursor from a previous response’s nextAfterId.'),\n\t\tlimit: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(1)\n\t\t\t.max(5000)\n\t\t\t.optional()\n\t\t\t.describe('Max log entries to fetch (default 500, hard cap 5000).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.deploys.getLogs(\n\t\t\tteamId,\n\t\t\targs.service_id,\n\t\t\targs.deploy_id,\n\t\t\t{\n\t\t\t\t...(args.after_id !== undefined ? { afterId: args.after_id } : {}),\n\t\t\t\t...(args.limit !== undefined ? { limit: args.limit } : {}),\n\t\t\t},\n\t\t);\n\t\tconst entries = response.logs;\n\t\tconst logs = entries.map((e) => e.message).join('\\n');\n\t\treturn respond({\n\t\t\tsummary: `Fetched ${entries.length} log line${entries.length === 1 ? '' : 's'} for deploy ${args.deploy_id}.`,\n\t\t\tdata: { logs, lineCount: entries.length, nextAfterId: response.nextAfterId },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'diagnose_deploy',\n\tcategory: 'deploys',\n\tdescription: [\n\t\t\"One-shot diagnostic bundle for a deploy: full deploy record + tail of build logs + tail of runtime logs starting at the deploy's start time. Lets you investigate any deploy failure mode (build-time failure, health-check timeout, post-deploy runtime crash) without juggling two log endpoints and two IDs.\",\n\t\t'',\n\t\t'When to use: a deploy is failed/superseded/stuck and you want the whole story in one call. For just the build output, use get_deploy_logs. For just runtime logs of the running service, use get_service_logs.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - deploy_id: publicId of the deploy to diagnose.',\n\t\t' - build_log_lines (optional): how many trailing build log lines to include. Default 200, max 2000.',\n\t\t' - runtime_log_lines (optional): how many trailing runtime log lines (since the deploy started) to include. Default 100, max 1000. Set to 0 to skip runtime logs (saves a round-trip when investigating a pure build-time failure).',\n\t\t'',\n\t\t'Returns: { deploy, build: { logs, lineCount }, runtime: { logs, lineCount } } — runtime is omitted when runtime_log_lines is 0 or the deploy never started a container.',\n\t\t'',\n\t\t'Example: diagnose_deploy({ service_id: \"svc_abc\", deploy_id: \"dpl_xyz\" }) → all three sections in one call.',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tdeploy_id: z.string().describe('Deploy publicId.'),\n\t\tbuild_log_lines: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(1)\n\t\t\t.max(2000)\n\t\t\t.optional()\n\t\t\t.describe('Trailing build log lines. Default 200, max 2000.'),\n\t\truntime_log_lines: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(0)\n\t\t\t.max(1000)\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t'Trailing runtime log lines since deploy start. Default 100, max 1000. 0 = skip.',\n\t\t\t),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst buildLimit = args.build_log_lines ?? 200;\n\t\tconst runtimeLimit = args.runtime_log_lines ?? 100;\n\n\t\t// Pull deploy + build logs in parallel — build logs don't depend on\n\t\t// the deploy record's metadata. Runtime logs need the deploy's\n\t\t// startedAt for the `since` window so they wait for the deploy fetch.\n\t\tconst [deployResp, buildResp] = await Promise.all([\n\t\t\tctx.hoststack.deploys.get(teamId, args.service_id, args.deploy_id),\n\t\t\tctx.hoststack.deploys.getLogs(teamId, args.service_id, args.deploy_id, {\n\t\t\t\tlimit: buildLimit,\n\t\t\t}),\n\t\t]);\n\n\t\tconst buildEntries = buildResp.logs;\n\t\tconst buildLogs = buildEntries.map((e) => e.message).join('\\n');\n\n\t\tconst deployShape = shapeDeploy(deployResp.deploy);\n\t\tconst deployStatus =\n\t\t\tdeployShape && 'status' in deployShape\n\t\t\t\t? (deployShape as { status: string }).status\n\t\t\t\t: 'unknown';\n\t\tconst startedAtRaw =\n\t\t\tdeployShape && 'startedAt' in deployShape\n\t\t\t\t? (deployShape as { startedAt: unknown }).startedAt\n\t\t\t\t: undefined;\n\t\tconst startedAt = typeof startedAtRaw === 'string' ? startedAtRaw : undefined;\n\n\t\tconst data: Record<string, unknown> = {\n\t\t\tdeploy: deployShape,\n\t\t\tbuild: { logs: buildLogs, lineCount: buildEntries.length },\n\t\t};\n\n\t\t// Skip the runtime tail when caller asked us to OR when the deploy\n\t\t// never reached the container-start phase (build-time failure).\n\t\t// `startedAt` is set by the API when the deploy row is created, so\n\t\t// it's almost always present; the more reliable container-started\n\t\t// signal is whether status ever passed the build phase.\n\t\tconst hadContainer = deployStatus !== 'pending' && deployStatus !== 'building';\n\t\tif (runtimeLimit > 0 && hadContainer) {\n\t\t\tconst runtimeResp = await ctx.hoststack.services.getRuntimeLogs(\n\t\t\t\tteamId,\n\t\t\t\targs.service_id,\n\t\t\t\t{\n\t\t\t\t\tlines: runtimeLimit,\n\t\t\t\t\t...(startedAt ? { since: startedAt } : {}),\n\t\t\t\t},\n\t\t\t);\n\t\t\tif ('count' in runtimeResp) {\n\t\t\t\t// getRuntimeLogs without countOnly should never return this\n\t\t\t\t// shape; defensive branch for future-proofing.\n\t\t\t\tdata['runtime'] = { logs: '', lineCount: runtimeResp.count };\n\t\t\t} else {\n\t\t\t\tconst runtimeEntries = Array.isArray(runtimeResp.logs)\n\t\t\t\t\t? runtimeResp.logs\n\t\t\t\t\t: typeof runtimeResp.logs === 'string'\n\t\t\t\t\t\t? runtimeResp.logs.split('\\n').map((line) => ({ message: line }))\n\t\t\t\t\t\t: [];\n\t\t\t\tconst runtimeText = runtimeEntries\n\t\t\t\t\t.map((e) =>\n\t\t\t\t\t\ttypeof e === 'object' && 'message' in e ? String(e.message) : String(e),\n\t\t\t\t\t)\n\t\t\t\t\t.join('\\n');\n\t\t\t\tdata['runtime'] = {\n\t\t\t\t\tlogs: runtimeText,\n\t\t\t\t\tlineCount: runtimeEntries.length,\n\t\t\t\t\tsinceWindow: startedAt ?? null,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\t// Surface anything that might explain a failure — these field names\n\t\t// vary slightly across deploy phases (build, deploy, healthcheck) so\n\t\t// we look at the deploy shape directly rather than hard-coding.\n\t\tconst failureSummary = shape({\n\t\t\tstatus: deployStatus,\n\t\t\terrorMessage:\n\t\t\t\tdeployShape && 'errorMessage' in deployShape\n\t\t\t\t\t? (deployShape as { errorMessage: unknown }).errorMessage\n\t\t\t\t\t: undefined,\n\t\t});\n\t\tdata['summary'] = failureSummary;\n\n\t\treturn respond({\n\t\t\tsummary: `Diagnostic bundle for deploy ${args.deploy_id} (${deployStatus}): ${buildEntries.length} build log line${buildEntries.length === 1 ? '' : 's'}${runtimeLimit > 0 && hadContainer ? ', runtime log tail included' : ''}.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n","import { z } from 'zod';\nimport type { DnsRecord, DnsRecordType, DnsZone, HostStack } from '@hoststack.dev/sdk';\n\nimport { defineTool } from '../registry.js';\nimport { respond, respondError } from '../lib/respond.js';\nimport { shape } from '../lib/shape.js';\n\n/**\n * DNS-zone + record management. These tools delegate to the SDK's\n * `DnsResource` (`ctx.hoststack.dns`), which wraps the same HTTP routes\n * the dashboard uses — `/api/dns-zones/:teamId/...` — so tenancy, audit\n * logging, PowerDNS sync, and idempotency behavior all match the\n * dashboard exactly. We never bypass the service layer.\n *\n * The HTTP-domain tools (list_domains, add_domain, verify_domain,\n * remove_domain) are about binding a hostname to a service for HTTP\n * routing + Let's Encrypt; they don't touch the underlying DNS zone.\n * Use these tools for actual record CRUD (TXT for verification, A/AAAA\n * for custom routing, MX for email, etc.).\n */\n// Source of truth for record types is `@hoststack/shared`'s\n// `dnsRecordTypeSchema`, surfaced through the SDK's `DnsRecordType`. This array\n// drives the zod input shape (a value, so it can't be the bare type); the\n// `satisfies` clause makes the build fail if it ever drifts from the SDK union.\nconst DNS_RECORD_TYPES = [\n\t'A',\n\t'AAAA',\n\t'CNAME',\n\t'MX',\n\t'TXT',\n\t'NS',\n\t'SRV',\n\t'CAA',\n\t'ALIAS',\n] as const satisfies readonly DnsRecordType[];\n\n// Exhaustiveness guard the other direction: every DnsRecordType must appear in\n// the array above. If the SDK adds a record type, this errors until it's added.\nconst _dnsTypesExhaustive: Record<DnsRecordType, true> = {\n\tA: true,\n\tAAAA: true,\n\tCNAME: true,\n\tMX: true,\n\tTXT: true,\n\tNS: true,\n\tSRV: true,\n\tCAA: true,\n\tALIAS: true,\n};\nvoid _dnsTypesExhaustive;\n\n/**\n * Resolve `{ zone_id?, domain? }` to the zone's `publicId`. Accepts\n * either the zone publicId directly or a domain name (apex or\n * subdomain) and walks parent labels to find the longest-matching\n * hosted zone, same suffix-match semantics as\n * `DnsService.findHostedZoneForDomain` (apps/api/src/services/dns.service.ts:193).\n *\n * Returns the zone's publicId so the caller can address subsequent\n * routes by it, plus a human-readable hint about which zone matched.\n */\nasync function resolveZonePublicId(\n\thoststack: HostStack,\n\tteamId: number,\n\tinput: { zone_id?: string; domain?: string },\n): Promise<{ publicId: string; domainName: string }> {\n\tif (input.zone_id) {\n\t\tconst { zones } = await hoststack.dns.listZones(teamId);\n\t\tconst match = zones.find((z) => z.publicId === input.zone_id);\n\t\tif (!match) {\n\t\t\tthrow new Error(`Zone ${input.zone_id} not found on this team.`);\n\t\t}\n\t\treturn { publicId: match.publicId, domainName: match.domainName };\n\t}\n\tif (!input.domain) {\n\t\tthrow new Error('Provide either zone_id or domain.');\n\t}\n\tconst { zones } = await hoststack.dns.listZones(teamId);\n\tconst fqdn = input.domain.toLowerCase().replace(/\\.$/, '');\n\tconst labels = fqdn.split('.');\n\tfor (let i = 0; i < labels.length - 1; i++) {\n\t\tconst candidate = labels.slice(i).join('.');\n\t\tconst match = zones.find((z) => z.domainName.toLowerCase() === candidate);\n\t\tif (match && match.status !== 'deleting') {\n\t\t\treturn { publicId: match.publicId, domainName: match.domainName };\n\t\t}\n\t}\n\tthrow new Error(\n\t\t`No hosted zone matches ${input.domain}. Create the zone in the dashboard (Domains → DNS) first, then retry.`,\n\t);\n}\n\ndefineTool({\n\tname: 'list_dns_zones',\n\tcategory: 'dns',\n\tdescription: [\n\t\t\"List authoritative DNS zones the team owns on HostStack's PowerDNS infrastructure. Each zone is the apex domain (e.g. example.com) under which DNS records live.\",\n\t\t'',\n\t\t'When to use: discover which apex domains support record management before calling create_dns_record / list_dns_records. The dashboard equivalent is Domains → DNS.',\n\t\t'',\n\t\t'Returns: { items: Zone[] } — each zone exposes publicId, domainName, status (\"active\" | \"syncing\" | \"failed\" | \"deleting\"), nsRecords (the nameservers the parent registry must delegate to), provider, createdAt.',\n\t\t'',\n\t\t'Example: list_dns_zones() → { items: [{ publicId: \"dnz_abc\", domainName: \"micci.dk\", status: \"active\", nsRecords: [\"ns1.hoststack.dev\",\"ns2.hoststack.dev\"] }] }',\n\t].join('\\n'),\n\tinput: {},\n\thandler: async (_args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.dns.listZones(teamId);\n\t\tconst items = Array.isArray(response.zones) ? response.zones.map(shape) : [];\n\t\tconst summary =\n\t\t\titems.length === 0\n\t\t\t\t? 'No DNS zones hosted on this team. Create one in the dashboard (Domains → DNS).'\n\t\t\t\t: `Found ${items.length} hosted DNS zone${items.length === 1 ? '' : 's'}.`;\n\t\treturn respond({ summary, data: { items } });\n\t},\n});\n\ndefineTool({\n\tname: 'list_dns_records',\n\tcategory: 'dns',\n\tdescription: [\n\t\t'List every active record in a hosted DNS zone. Records are addressed by their type + name + value tuple; PowerDNS gathers records with the same (name, type) into an RRset on the wire.',\n\t\t'',\n\t\t'When to use: audit what is currently published for a zone before editing, verify a recently-created record landed, or read existing TXT verification strings.',\n\t\t'',\n\t\t'Provide EITHER zone_id (the zone publicId, e.g. \"dnz_abc\") OR domain (an apex or subdomain — the longest-matching hosted apex wins; \"app.example.com\" matches a hosted \"example.com\" zone).',\n\t\t'',\n\t\t'Returns: { zone: { publicId, domainName }, items: Record[] } — each record includes publicId, type, name (\"@\" for apex, or label), value, ttl, priority?, status (\"active\" | \"syncing\" | \"failed\"), managedBy (\"user\" | \"hoststack\" | \"poststack\"), createdAt.',\n\t\t'',\n\t\t'Example: list_dns_records({ domain: \"micci.dk\" }) → { zone: { domainName: \"micci.dk\", … }, items: [{ type: \"TXT\", name: \"@\", value: \"google-site-verification=…\", ttl: 300, … }] }',\n\t].join('\\n'),\n\tinput: {\n\t\tzone_id: z.string().optional().describe('Zone publicId (e.g. \"dnz_abc\").'),\n\t\tdomain: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe('Apex or subdomain — resolves to the longest-matching hosted zone.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst zoneInput: { zone_id?: string; domain?: string } = {};\n\t\tif (args.zone_id !== undefined) zoneInput.zone_id = args.zone_id;\n\t\tif (args.domain !== undefined) zoneInput.domain = args.domain;\n\t\tconst zone = await resolveZonePublicId(ctx.hoststack, teamId, zoneInput);\n\t\tconst response = await ctx.hoststack.dns.listRecords(teamId, zone.publicId);\n\t\tconst items = Array.isArray(response.records) ? response.records.map(shape) : [];\n\t\tconst summary =\n\t\t\titems.length === 0\n\t\t\t\t? `Zone ${zone.domainName} has no records yet.`\n\t\t\t\t: `Returned ${items.length} record${items.length === 1 ? '' : 's'} for ${zone.domainName}.`;\n\t\treturn respond({\n\t\t\tsummary,\n\t\t\tdata: { zone: { publicId: zone.publicId, domainName: zone.domainName }, items },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'get_dns_record',\n\tcategory: 'dns',\n\tdescription: [\n\t\t'Fetch a single DNS record by its publicId. Useful for confirming the record landed after create_dns_record / update_dns_record (status transitions from \"syncing\" to \"active\" once PowerDNS acknowledges).',\n\t\t'',\n\t\t'When to use: verify a record exists, inspect its current ttl/value, or check the sync status of an in-flight write.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - record_id: record publicId (e.g. \"dnr_abc\"). Returned by list_dns_records and create_dns_record.',\n\t\t'',\n\t\t'Returns: { record: Record }. Mirrors the shape returned by list_dns_records.',\n\t\t'',\n\t\t'Example: get_dns_record({ record_id: \"dnr_abc\" }) → { record: { type: \"TXT\", name: \"@\", value: \"…\", status: \"active\", … } }',\n\t].join('\\n'),\n\tinput: {\n\t\trecord_id: z.string().describe('Record publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\t// Records have no direct GET-by-id route — walk the team's zones\n\t\t// and scan each for the matching publicId. Zones-per-team is tiny\n\t\t// (≤ a few dozen even on heavy users) so this is cheap.\n\t\tconst { zones } = await ctx.hoststack.dns.listZones(teamId);\n\t\tfor (const zone of zones) {\n\t\t\tconst { records } = await ctx.hoststack.dns.listRecords(teamId, zone.publicId);\n\t\t\tconst match = records.find((r) => r.publicId === args.record_id);\n\t\t\tif (match) {\n\t\t\t\treturn respond({\n\t\t\t\t\tsummary: `Record ${match.type} ${match.name} on ${zone.domainName}.`,\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tzone: { publicId: zone.publicId, domainName: zone.domainName },\n\t\t\t\t\t\trecord: shape(match),\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn respondError(`Record ${args.record_id} not found on any zone owned by this team.`);\n\t},\n});\n\ndefineTool({\n\tname: 'create_dns_record',\n\tcategory: 'dns',\n\tdescription: [\n\t\t'Create a DNS record on a hosted zone. Writes to the DB first, then mirrors to PowerDNS — record returns with status=\"syncing\" until the provider acknowledges, then flips to \"active\". Re-creating the same (zone, type, name, value) tuple is idempotent and returns the existing row.',\n\t\t'',\n\t\t'When to use: add TXT verification records (Google Search Console, domain ownership challenges, DKIM), A/AAAA records pointing a subdomain at an IP, CNAME aliases, MX records, etc.',\n\t\t'',\n\t\t'Provide EITHER zone_id (zone publicId) OR domain (resolves via longest-suffix match against hosted zones).',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - type: \"A\" | \"AAAA\" | \"CNAME\" | \"MX\" | \"TXT\" | \"NS\" | \"SRV\" | \"CAA\" | \"ALIAS\".',\n\t\t' - name: \"@\" for the zone apex, or a subdomain label (\"www\", \"api\", \"_acme-challenge\"). Do NOT include the zone suffix — the backend prepends it. \"bounce\" on zone \"micci.dk\" publishes \"bounce.micci.dk\"; passing \"bounce.micci.dk\" works (the backend strips the suffix) but is non-idiomatic.',\n\t\t' - content: the literal record value. For TXT pass the unquoted string — the PowerDNS layer handles quoting. For CNAME / MX / NS / SRV / ALIAS the target may be passed with or without a trailing dot; the adapter FQDN-izes it.',\n\t\t' - ttl (optional): 60–86400 seconds, default 3600.',\n\t\t' - priority (optional, required for MX and SRV): 0–65535.',\n\t\t'',\n\t\t'Returns: { record: Record } — see get_dns_record for the shape.',\n\t\t'',\n\t\t'Notes:',\n\t\t' - CNAME at the apex is rejected (RFC 1034 forbids CNAME coexisting with NS/SOA). Use type=\"ALIAS\" for apex aliasing.',\n\t\t'',\n\t\t'Example: create_dns_record({ domain: \"micci.dk\", type: \"TXT\", name: \"@\", content: \"google-site-verification=C0V0scK48g2…\", ttl: 300 })',\n\t].join('\\n'),\n\tinput: {\n\t\tzone_id: z.string().optional().describe('Zone publicId.'),\n\t\tdomain: z.string().optional().describe('Apex or subdomain to resolve a hosted zone.'),\n\t\ttype: z.enum(DNS_RECORD_TYPES).describe('DNS record type.'),\n\t\tname: z\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(253)\n\t\t\t.describe('\"@\" for apex, or a bare label. Do NOT include the zone suffix.'),\n\t\tcontent: z.string().min(1).max(2000).describe('Record value; TXT values are unquoted.'),\n\t\tttl: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(60)\n\t\t\t.max(86_400)\n\t\t\t.optional()\n\t\t\t.describe('TTL in seconds (default 3600).'),\n\t\tpriority: z.number().int().min(0).max(65_535).optional().describe('Required for MX / SRV.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\t// MX/SRV records carry priority on the wire; the shared upsert\n\t\t// schema enforces this with a superRefine. The MCP `input` shape\n\t\t// is a flat ZodRawShape so we can't express cross-field rules\n\t\t// there — surface a clean error from the handler instead of\n\t\t// letting the backend's 400 bubble up.\n\t\tif ((args.type === 'MX' || args.type === 'SRV') && args.priority === undefined) {\n\t\t\treturn respondError(`Priority is required for ${args.type} records (0–65535).`);\n\t\t}\n\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst zoneInput: { zone_id?: string; domain?: string } = {};\n\t\tif (args.zone_id !== undefined) zoneInput.zone_id = args.zone_id;\n\t\tif (args.domain !== undefined) zoneInput.domain = args.domain;\n\t\tconst zone = await resolveZonePublicId(ctx.hoststack, teamId, zoneInput);\n\n\t\tconst body: {\n\t\t\ttype: DnsRecordType;\n\t\t\tname: string;\n\t\t\tvalue: string;\n\t\t\tttl?: number;\n\t\t\tpriority?: number;\n\t\t} = {\n\t\t\ttype: args.type,\n\t\t\tname: args.name,\n\t\t\tvalue: args.content,\n\t\t};\n\t\tif (args.ttl !== undefined) body.ttl = args.ttl;\n\t\tif (args.priority !== undefined) body.priority = args.priority;\n\n\t\tconst response = await ctx.hoststack.dns.createRecord(teamId, zone.publicId, body);\n\t\treturn respond({\n\t\t\tsummary: `Created ${args.type} ${args.name} on ${zone.domainName}.`,\n\t\t\tdata: {\n\t\t\t\tzone: { publicId: zone.publicId, domainName: zone.domainName },\n\t\t\t\trecord: shape(response.record),\n\t\t\t},\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'update_dns_record',\n\tcategory: 'dns',\n\tdescription: [\n\t\t'Update an existing DNS record by its publicId. Use this to change a TTL, swap a value, or move the record to a different (name, type) bucket. Full-record PUT semantics: every mutable field must be provided.',\n\t\t'',\n\t\t'When to use: rotate a DKIM key, repoint an A record at a new IP, bump TTL ahead of a planned change.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - record_id: record publicId.',\n\t\t' - type, name, content: the new values (the route is full-replace, not patch — fetch with get_dns_record first if you only want to tweak one field).',\n\t\t' - ttl (optional), priority (optional, required for MX / SRV).',\n\t\t'',\n\t\t'Returns: { record: Record } reflecting the new state.',\n\t\t'',\n\t\t'Example: update_dns_record({ record_id: \"dnr_abc\", type: \"A\", name: \"api\", content: \"203.0.113.42\", ttl: 300 })',\n\t].join('\\n'),\n\tinput: {\n\t\trecord_id: z.string().describe('Record publicId.'),\n\t\ttype: z.enum(DNS_RECORD_TYPES).describe('DNS record type.'),\n\t\tname: z\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(253)\n\t\t\t.describe('\"@\" for apex, or a bare label. Do NOT include the zone suffix.'),\n\t\tcontent: z.string().min(1).max(2000).describe('Record value; TXT unquoted.'),\n\t\tttl: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(60)\n\t\t\t.max(86_400)\n\t\t\t.optional()\n\t\t\t.describe('TTL in seconds (default 3600).'),\n\t\tpriority: z.number().int().min(0).max(65_535).optional().describe('Required for MX / SRV.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tif ((args.type === 'MX' || args.type === 'SRV') && args.priority === undefined) {\n\t\t\treturn respondError(`Priority is required for ${args.type} records (0–65535).`);\n\t\t}\n\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst target = await findRecordZone(ctx.hoststack, teamId, args.record_id);\n\t\tif (!target) {\n\t\t\treturn respondError(\n\t\t\t\t`Record ${args.record_id} not found on any zone owned by this team.`,\n\t\t\t);\n\t\t}\n\n\t\tconst body: {\n\t\t\ttype: DnsRecordType;\n\t\t\tname: string;\n\t\t\tvalue: string;\n\t\t\tttl?: number;\n\t\t\tpriority?: number;\n\t\t} = {\n\t\t\ttype: args.type,\n\t\t\tname: args.name,\n\t\t\tvalue: args.content,\n\t\t};\n\t\tif (args.ttl !== undefined) body.ttl = args.ttl;\n\t\tif (args.priority !== undefined) body.priority = args.priority;\n\n\t\tconst response = await ctx.hoststack.dns.updateRecord(\n\t\t\tteamId,\n\t\t\ttarget.zone.publicId,\n\t\t\targs.record_id,\n\t\t\tbody,\n\t\t);\n\t\treturn respond({\n\t\t\tsummary: `Updated ${args.type} ${args.name} on ${target.zone.domainName}.`,\n\t\t\tdata: {\n\t\t\t\tzone: {\n\t\t\t\t\tpublicId: target.zone.publicId,\n\t\t\t\t\tdomainName: target.zone.domainName,\n\t\t\t\t},\n\t\t\t\trecord: shape(response.record),\n\t\t\t},\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'delete_dns_record',\n\tcategory: 'dns',\n\tdescription: [\n\t\t'Soft-delete a DNS record and remove it from PowerDNS. DESTRUCTIVE: resolvers stop returning the value as soon as the change propagates. Same code path as the dashboard delete button — the row is marked deleted and the RRset is re-pushed without it.',\n\t\t'',\n\t\t'When to use: retire a TXT verification record once the challenge has been confirmed; drop an A record for a decommissioned subdomain.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - record_id: record publicId.',\n\t\t'',\n\t\t'Returns: { ok: true }.',\n\t\t'',\n\t\t'Example: delete_dns_record({ record_id: \"dnr_abc\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\trecord_id: z.string().describe('Record publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst target = await findRecordZone(ctx.hoststack, teamId, args.record_id);\n\t\tif (!target) {\n\t\t\treturn respondError(\n\t\t\t\t`Record ${args.record_id} not found on any zone owned by this team.`,\n\t\t\t);\n\t\t}\n\t\tawait ctx.hoststack.dns.deleteRecord(teamId, target.zone.publicId, args.record_id);\n\t\treturn respond({\n\t\t\tsummary: `Deleted record ${args.record_id} from ${target.zone.domainName}.`,\n\t\t\tdata: { ok: true },\n\t\t});\n\t},\n});\n\n/**\n * The DNS HTTP routes nest records under their zone, so update/delete\n * by record publicId needs the owning zone's publicId too. Walk the\n * team's zones until we find a record match. Cheap — zone count is\n * bounded by team-tier limits.\n */\nasync function findRecordZone(\n\thoststack: HostStack,\n\tteamId: number,\n\trecordPublicId: string,\n): Promise<{ zone: DnsZone; record: DnsRecord } | null> {\n\tconst { zones } = await hoststack.dns.listZones(teamId);\n\tfor (const zone of zones) {\n\t\tconst { records } = await hoststack.dns.listRecords(teamId, zone.publicId);\n\t\tconst match = records.find((r) => r.publicId === recordPublicId);\n\t\tif (match) return { zone, record: match };\n\t}\n\treturn null;\n}\n","import { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond } from '../lib/respond.js';\nimport { shapeDomain, shapeList } from '../lib/shape.js';\n\ndefineTool({\n\tname: 'list_domains',\n\tcategory: 'domains',\n\tdescription: [\n\t\t\"List every custom domain attached to the team's services.\",\n\t\t'',\n\t\t'When to use: enumerate live domains, audit DNS verification status, or find which service a hostname resolves to before troubleshooting routing.',\n\t\t'',\n\t\t'Returns: { items: Domain[] } — id, publicId, hostname, serviceId, verified, dnsTargets, sslStatus, createdAt.',\n\t\t'',\n\t\t'Example: list_domains() → { items: [{ hostname: \"api.example.com\", verified: true, sslStatus: \"active\", … }] }',\n\t].join('\\n'),\n\tinput: {},\n\thandler: async (_args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.domains.list(teamId);\n\t\tconst data = shapeList(response, 'domains', shapeDomain);\n\t\tconst summary =\n\t\t\tdata.items.length === 0\n\t\t\t\t? 'No custom domains configured.'\n\t\t\t\t: `Found ${data.items.length} custom domain${data.items.length === 1 ? '' : 's'}.`;\n\t\treturn respond({ summary, data });\n\t},\n});\n\ndefineTool({\n\tname: 'add_domain',\n\tcategory: 'domains',\n\tdescription: [\n\t\t'Attach a custom hostname to the team — optionally pinned to a specific service. After adding, point your DNS at the targets returned and call verify_domain.',\n\t\t'',\n\t\t'When to use: the user wants to put a custom domain in front of a HostStack service (e.g. point api.example.com at svc_abc). The hostname must be unique across the team.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - hostname: the domain to add (e.g. \"api.example.com\").',\n\t\t' - service_id: publicId of the service to bind the domain to.',\n\t\t' - path_prefix (optional): when set, only requests under this URL prefix route to this service. Use for path-based fan-out (e.g. `/api` to an api service, `/` to a web service on the same hostname).',\n\t\t'',\n\t\t'Returns: { domain: Domain } — includes dnsTargets you must configure (CNAME / A records).',\n\t\t'',\n\t\t'Example: add_domain({ hostname: \"api.example.com\", service_id: \"svc_abc\" }) → { domain: { hostname: \"api.example.com\", dnsTargets: [...], verified: false, … } }',\n\t].join('\\n'),\n\tinput: {\n\t\thostname: z\n\t\t\t.string()\n\t\t\t.min(3)\n\t\t\t.max(253)\n\t\t\t.describe('Fully-qualified hostname (e.g. api.example.com).'),\n\t\tservice_id: z.string().describe('Service publicId to bind to.'),\n\t\tpath_prefix: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe('Optional URL prefix for path-based routing (e.g. \"/api\").'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst input: { domain: string; serviceId: string; pathPrefix?: string } = {\n\t\t\tdomain: args.hostname,\n\t\t\tserviceId: args.service_id,\n\t\t};\n\t\tif (args.path_prefix !== undefined) input.pathPrefix = args.path_prefix;\n\t\tconst response = await ctx.hoststack.domains.add(teamId, input);\n\t\tconst data = { domain: shapeDomain(response.domain) };\n\t\treturn respond({\n\t\t\tsummary: `Added domain ${args.hostname}. Configure DNS, then call verify_domain.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'verify_domain',\n\tcategory: 'domains',\n\tdescription: [\n\t\t'Trigger DNS verification for a previously-added domain. HostStack checks that the dnsTargets returned by add_domain are configured at the registrar.',\n\t\t'',\n\t\t'When to use: the user has set up DNS records and is ready to flip the domain live. Returns success when verification passes; the domain stays in pending state if DNS is still propagating.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - domain_id: publicId of the domain (from list_domains or add_domain).',\n\t\t'',\n\t\t'Returns: { ok: true }. Re-call list_domains to inspect the updated verified flag and SSL status.',\n\t\t'',\n\t\t'Example: verify_domain({ domain_id: \"dom_xyz\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tdomain_id: z.string().describe('Domain publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.domains.verify(teamId, args.domain_id);\n\t\treturn respond({\n\t\t\tsummary: `Triggered DNS verification for ${args.domain_id}.`,\n\t\t\tdata: { ok: true },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'remove_domain',\n\tcategory: 'domains',\n\tdescription: [\n\t\t'Detach a custom hostname from the team. DESTRUCTIVE: the domain stops routing immediately and any pinned service must fall back to its default hostname.',\n\t\t'',\n\t\t'When to use: the user wants to retire a custom domain. Confirm with the user first — the change is immediate and cannot be undone except by re-adding the domain and re-verifying DNS.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - domain_id: publicId of the domain to remove.',\n\t\t'',\n\t\t'Returns: { ok: true }.',\n\t\t'',\n\t\t'Example: remove_domain({ domain_id: \"dom_xyz\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tdomain_id: z.string().describe('Domain publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.domains.remove(teamId, args.domain_id);\n\t\treturn respond({ summary: `Removed domain ${args.domain_id}.`, data: { ok: true } });\n\t},\n});\n","import { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond, respondError } from '../lib/respond.js';\nimport { shapeEnvVar, shapeList } from '../lib/shape.js';\n\ninterface ExistingEnvVar {\n\tid: number;\n\tpublicId?: string;\n\tkey: string;\n\tisSecret: boolean;\n}\n\ndefineTool({\n\tname: 'list_env_vars',\n\tcategory: 'env-vars',\n\tdescription: [\n\t\t'List environment variables for a service. Secret values are masked server-side (\"••••••\"); only non-secret values come through in the clear.',\n\t\t'',\n\t\t'When to use: auditing what configuration a service has, finding the key for a value the user mentions by name, or confirming a variable was set after a write. Never assume the value field is plaintext for secret rows — it is masked.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t'',\n\t\t'Returns: { items: EnvVar[] } — id, publicId, key, value (masked if isSecret), isSecret, target, linkedDatabaseId, createdAt.',\n\t\t'',\n\t\t'Example: list_env_vars({ service_id: \"svc_abc\" }) → { items: [{ key: \"DATABASE_URL\", value: \"••••••\", isSecret: true }, { key: \"PORT\", value: \"3000\", isSecret: false }] }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.envVars.list(teamId, args.service_id);\n\t\tconst data = shapeList(response, 'envVars', shapeEnvVar);\n\t\tconst summary =\n\t\t\tdata.items.length === 0\n\t\t\t\t? `No env vars set on service ${args.service_id}.`\n\t\t\t\t: `Found ${data.items.length} env var${data.items.length === 1 ? '' : 's'} on service ${args.service_id}.`;\n\t\treturn respond({ summary, data });\n\t},\n});\n\ndefineTool({\n\tname: 'set_env_var',\n\tcategory: 'env-vars',\n\tdescription: [\n\t\t'Upsert a single environment variable on a service: creates the key if missing, updates the value if it already exists. Match is by key (case-sensitive).',\n\t\t'',\n\t\t'When to use: rotate a secret, add a new config knob, or change a value the user dictated. The MCP layer looks up the existing var by key first; you do not need to know the env-var ID.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - key: env-var name (e.g. \"DATABASE_URL\").',\n\t\t' - value: new value (will be encrypted at rest if is_secret=true).',\n\t\t' - is_secret (optional): true marks the value as secret (masked on read). On create, defaults to true for safety. On update, omitting it leaves the existing flag untouched — pass it explicitly only when you want to change classification.',\n\t\t' - target (optional): where the var is injected — \"build\", \"runtime\", or \"both\". On create, defaults to \"both\". On update, omitting it leaves the existing target untouched.',\n\t\t'',\n\t\t'Returns: { envVar: EnvVar, action: \"created\" | \"updated\" }.',\n\t\t'',\n\t\t'Example: set_env_var({ service_id: \"svc_abc\", key: \"DATABASE_URL\", value: \"postgres://…\", is_secret: true }) → { envVar: { key: \"DATABASE_URL\", value: \"••••••\", … }, action: \"updated\" }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tkey: z.string().min(1).max(128).describe('Env-var key.'),\n\t\tvalue: z.string().describe('New value.'),\n\t\tis_secret: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe('Mark as secret (encrypted, masked on read). Default true.'),\n\t\ttarget: z\n\t\t\t.enum(['build', 'runtime', 'both'])\n\t\t\t.optional()\n\t\t\t.describe('Injection target: build, runtime, or both. Default both.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst existing = await ctx.hoststack.envVars.list(teamId, args.service_id);\n\t\tconst match = (existing.envVars as ExistingEnvVar[]).find((v) => v.key === args.key);\n\n\t\tif (match) {\n\t\t\t// On update, only forward `isSecret`/`target` when the caller\n\t\t\t// passed them explicitly. Defaulting `isSecret` to `true` here\n\t\t\t// would silently flip previously-plaintext keys (PORT, NODE_ENV,\n\t\t\t// …) to secret on every value change.\n\t\t\tconst updatePayload: {\n\t\t\t\tvalue: string;\n\t\t\t\tisSecret?: boolean;\n\t\t\t\ttarget?: 'build' | 'runtime' | 'both';\n\t\t\t} = { value: args.value };\n\t\t\tif (args.is_secret !== undefined) updatePayload.isSecret = args.is_secret;\n\t\t\tif (args.target !== undefined) updatePayload.target = args.target;\n\t\t\tconst response = await ctx.hoststack.envVars.update(\n\t\t\t\tteamId,\n\t\t\t\targs.service_id,\n\t\t\t\tString(match.id),\n\t\t\t\tupdatePayload,\n\t\t\t);\n\t\t\tconst data = {\n\t\t\t\tenvVar: shapeEnvVar(response.envVar),\n\t\t\t\taction: 'updated' as const,\n\t\t\t};\n\t\t\treturn respond({ summary: `Updated ${args.key} on service ${args.service_id}.`, data });\n\t\t}\n\n\t\tconst response = await ctx.hoststack.envVars.create(teamId, args.service_id, {\n\t\t\tkey: args.key,\n\t\t\tvalue: args.value,\n\t\t\tisSecret: args.is_secret ?? true,\n\t\t\t...(args.target !== undefined ? { target: args.target } : {}),\n\t\t});\n\t\tconst data = {\n\t\t\tenvVar: shapeEnvVar(response.envVar),\n\t\t\taction: 'created' as const,\n\t\t};\n\t\treturn respond({ summary: `Created ${args.key} on service ${args.service_id}.`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'delete_env_var',\n\tcategory: 'env-vars',\n\tdescription: [\n\t\t'Remove an environment variable from a service by key (case-sensitive).',\n\t\t'',\n\t\t'When to use: cleaning up unused config, or rotating away from a leaked secret. The MCP looks up the env-var ID from the key automatically.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - key: env-var name to delete.',\n\t\t'',\n\t\t'Returns: { ok: true } on success. Returns an error if the key was not found.',\n\t\t'',\n\t\t'Example: delete_env_var({ service_id: \"svc_abc\", key: \"OLD_FLAG\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tkey: z.string().min(1).max(128).describe('Env-var key to delete.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst existing = await ctx.hoststack.envVars.list(teamId, args.service_id);\n\t\tconst match = (existing.envVars as ExistingEnvVar[]).find((v) => v.key === args.key);\n\t\tif (!match) {\n\t\t\treturn respondError(`Env var \"${args.key}\" not found on service ${args.service_id}.`, {\n\t\t\t\tkey: args.key,\n\t\t\t\tservice_id: args.service_id,\n\t\t\t});\n\t\t}\n\t\tawait ctx.hoststack.envVars.delete(teamId, args.service_id, String(match.id));\n\t\treturn respond({\n\t\t\tsummary: `Deleted ${args.key} from service ${args.service_id}.`,\n\t\t\tdata: { ok: true },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'bulk_set_env_vars',\n\tcategory: 'env-vars',\n\tdescription: [\n\t\t'Replace the entire env-var set on a service with the given list. Equivalent to deleting all current vars and creating the supplied ones — use with care.',\n\t\t'',\n\t\t'When to use: importing a .env file, mirroring config from a sibling service, or doing a clean reset. For incremental changes, use set_env_var per key — bulk_set is destructive for any key not in the supplied list.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - env_vars: array of { key, value, is_secret?, target? }. is_secret defaults to FALSE per row (a row is stored in the clear unless you set is_secret:true); target defaults to \"both\". Note this differs from set_env_var, which defaults a newly-created var to secret.',\n\t\t'',\n\t\t'Returns: { ok: true }. Re-list with list_env_vars to confirm the new state.',\n\t\t'',\n\t\t'Example: bulk_set_env_vars({ service_id: \"svc_abc\", env_vars: [{ key: \"PORT\", value: \"3000\", is_secret: false }, { key: \"DATABASE_URL\", value: \"…\", is_secret: true }] }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tenv_vars: z\n\t\t\t.array(\n\t\t\t\tz.object({\n\t\t\t\t\tkey: z.string().min(1).max(128),\n\t\t\t\t\tvalue: z.string(),\n\t\t\t\t\tis_secret: z.boolean().optional(),\n\t\t\t\t\ttarget: z.enum(['build', 'runtime', 'both']).optional(),\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.max(500)\n\t\t\t.describe('Array of env-var rows. Hard cap 500.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst payload = {\n\t\t\tvars: args.env_vars.map((v) => {\n\t\t\t\tconst row: {\n\t\t\t\t\tkey: string;\n\t\t\t\t\tvalue: string;\n\t\t\t\t\tisSecret?: boolean;\n\t\t\t\t\ttarget?: 'build' | 'runtime' | 'both';\n\t\t\t\t} = {\n\t\t\t\t\tkey: v.key,\n\t\t\t\t\tvalue: v.value,\n\t\t\t\t};\n\t\t\t\tif (v.is_secret !== undefined) row.isSecret = v.is_secret;\n\t\t\t\tif (v.target !== undefined) row.target = v.target;\n\t\t\t\treturn row;\n\t\t\t}),\n\t\t};\n\t\tawait ctx.hoststack.envVars.bulkSet(teamId, args.service_id, payload);\n\t\treturn respond({\n\t\t\tsummary: `Replaced env-var set on service ${args.service_id} with ${args.env_vars.length} entr${args.env_vars.length === 1 ? 'y' : 'ies'}.`,\n\t\t\tdata: { ok: true, count: args.env_vars.length },\n\t\t});\n\t},\n});\n","import { z } from 'zod';\n\nimport { respond } from '../lib/respond.js';\nimport { shape, shapeList } from '../lib/shape.js';\nimport { defineTool } from '../registry.js';\n\n/**\n * v66 P5: MCP tools for project environment management.\n *\n * Environments isolate services in the same project — staging vs\n * production, for example. Each project automatically gets a Production\n * environment; users can add staging/development/preview envs to run\n * sibling services side-by-side and promote builds between them.\n */\n\ndefineTool({\n\tname: 'list_environments',\n\tcategory: 'environments',\n\tdescription: [\n\t\t'List every environment for a project (production / staging / development / preview).',\n\t\t'',\n\t\t'When to use: the user wants to see what envs exist before creating a service in one or promoting a deploy. Every project has at least Production.',\n\t\t'',\n\t\t// §2.2: these are project deployment environments, not cloud Dev Boxes — point agents at the\n\t\t// right surface so the two \"dev\" concepts stay distinct (bidirectional cross-reference).\n\t\t'NOTE — these are project deployment environments (Production / Staging / Preview), NOT agentic cloud Dev Boxes. To list Dev Boxes use list_dev_environments; to create one use create_dev_environment / create_standalone_dev_environment / spin_up_dev_environment.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - project_id: project publicId (e.g. \"prj_abc123\").',\n\t\t'',\n\t\t'Returns: { items: Environment[] } — id, publicId, name, type, isDefault, isProtected.',\n\t\t'',\n\t\t'Example: list_environments({ project_id: \"prj_abc\" }) → { items: [{ name: \"Production\", type: \"production\", isDefault: true }, { name: \"Staging\", type: \"staging\" }] }',\n\t].join('\\n'),\n\tinput: {\n\t\tproject_id: z.string().describe('Project publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.environments.list(teamId, args.project_id);\n\t\tconst data = shapeList(response, 'environments', shape);\n\t\tconst summary =\n\t\t\tdata.items.length === 0\n\t\t\t\t? 'No environments yet — every project should have Production by default.'\n\t\t\t\t: `Found ${data.items.length} environment${data.items.length === 1 ? '' : 's'}.`;\n\t\treturn respond({ summary, data });\n\t},\n});\n\ndefineTool({\n\tname: 'create_environment',\n\tcategory: 'environments',\n\tdescription: [\n\t\t'Create a new environment in a project (e.g. Staging, QA, Preview).',\n\t\t'',\n\t\t'When to use: the user wants to add an env so they can run a sibling service alongside production for testing or staging before release.',\n\t\t'',\n\t\t// §2.1/§2.2: steer callers away from the agentic cloud Dev Box tools (which live in\n\t\t// services.ts) — an environment is a deployment target, NOT a Dev Box. Bidirectional with\n\t\t// the cross-references those dev-box tools point back here.\n\t\t'NOTE — this is NOT a cloud Dev Box. An environment is a project deployment target (Production / Staging / Preview); type=\"development\" just gives services a -dev hostname suffix. For an agentic cloud Dev Box (a terminal you drive coding agents in) use create_dev_environment / create_standalone_dev_environment / spin_up_dev_environment instead.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - project_id: project publicId.',\n\t\t' - name: human-readable name (1–64 chars). Shown in the env switcher.',\n\t\t' - type: \"production\" | \"staging\" | \"development\" | \"preview\". Determines the hostname suffix on services in this env (production stays clean; others get -staging / -dev / -preview). type=\"development\" creates a PROJECT deployment environment (a -dev hostname suffix), NOT an agentic Dev Box — for a cloud dev box use create_dev_environment / create_standalone_dev_environment / spin_up_dev_environment.',\n\t\t' - is_protected (optional): require admin role for destructive actions in this env. Default false.',\n\t\t'',\n\t\t'Returns: { environment: Environment }.',\n\t\t'',\n\t\t'Example: create_environment({ project_id: \"prj_abc\", name: \"Staging\", type: \"staging\" }) → { environment: { id: 7, publicId: \"env_…\", name: \"Staging\", type: \"staging\" } }',\n\t].join('\\n'),\n\tinput: {\n\t\tproject_id: z.string().describe('Project publicId.'),\n\t\tname: z.string().min(1).max(64).describe('Environment name (1–64 chars).'),\n\t\ttype: z.enum(['production', 'staging', 'development', 'preview']).describe(\n\t\t\t// §2.1: \"development\" here is a project deployment env, NOT a cloud Dev Box.\n\t\t\t'Environment type — drives the hostname suffix. type=\"development\" creates a PROJECT deployment environment (a -dev hostname suffix), NOT an agentic Dev Box — for a cloud dev box use create_dev_environment / create_standalone_dev_environment / spin_up_dev_environment.',\n\t\t),\n\t\tis_protected: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe('Require admin role for destructive actions. Default false.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst input: {\n\t\t\tname: string;\n\t\t\ttype: 'production' | 'staging' | 'development' | 'preview';\n\t\t\tisProtected?: boolean;\n\t\t} = {\n\t\t\tname: args.name,\n\t\t\ttype: args.type,\n\t\t};\n\t\tif (args.is_protected !== undefined) input.isProtected = args.is_protected;\n\t\tconst response = await ctx.hoststack.environments.create(teamId, args.project_id, input);\n\t\tconst data = { environment: shape(response.environment) };\n\t\treturn respond({\n\t\t\tsummary: `Created environment \"${args.name}\" (${args.type}) in project ${args.project_id}.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'delete_environment',\n\tcategory: 'environments',\n\tdescription: [\n\t\t'Delete an environment from a project.',\n\t\t'',\n\t\t'When to use: an env is no longer used (e.g. tearing down a feature branch staging). Blocked when the env still has live services or databases attached — destroy or move them first. The default env (usually Production) cannot be deleted.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - project_id: project publicId.',\n\t\t' - environment_id: environment publicId or numeric id.',\n\t\t'',\n\t\t'Returns: { success: true } on success.',\n\t\t'',\n\t\t'Example: delete_environment({ project_id: \"prj_abc\", environment_id: \"env_xyz\" }) → { success: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tproject_id: z.string().describe('Project publicId.'),\n\t\tenvironment_id: z\n\t\t\t.union([z.string(), z.number()])\n\t\t\t.describe('Environment publicId or numeric id.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.environments.delete(teamId, args.project_id, args.environment_id);\n\t\treturn respond({\n\t\t\tsummary: `Deleted environment ${String(args.environment_id)} from project ${args.project_id}.`,\n\t\t\tdata: { success: true },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'promote_deploy',\n\tcategory: 'environments',\n\tdescription: [\n\t\t'Promote a built deploy from one environment to another (build-once, run-many).',\n\t\t'',\n\t\t'When to use: the user has tested a deploy in staging and wants to ship that exact image to production without rebuilding. Atomic and image-based — same docker image runs on the sibling service in the target env.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: source service publicId (the one that owns the deploy).',\n\t\t' - deploy_id: source deploy publicId. Must have `dockerImageId` set (i.e. a successful build).',\n\t\t\" - target_environment_id: env publicId or numeric id to promote into. Must be in the same project. Cannot be the source service's own env.\",\n\t\t'',\n\t\t\"Behaviour: if a sibling service with the same name already exists in the target env, the new deploy lands on it. Otherwise the API auto-clones the source service's build/runtime config into the target env first. Env-specific config (env vars, secret files, volumes, IP allowlists, custom domains) is NOT copied — those are per-env by design.\",\n\t\t'',\n\t\t'Returns: { deploy: Deploy } — the new deploy on the target service.',\n\t\t'',\n\t\t'Example: promote_deploy({ service_id: \"svc_staging\", deploy_id: \"dpl_built\", target_environment_id: \"env_prod\" }) → { deploy: { id: 99, status: \"pending\", trigger: \"rollback\", dockerImageId: \"sha256:…\" } }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Source service publicId.'),\n\t\tdeploy_id: z.string().describe('Source deploy publicId (must have a built image).'),\n\t\ttarget_environment_id: z\n\t\t\t.union([z.string(), z.number()])\n\t\t\t.describe('Target environment publicId or numeric id.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\t// Resolve target env to numeric id; the API expects a number.\n\t\tconst targetEnvId = await ctx.hoststack.resolveId(args.target_environment_id, {\n\t\t\tkind: 'environment',\n\t\t\tteamId: await ctx.hoststack.resolveId(teamId, { kind: 'team' }),\n\t\t});\n\t\tconst response = await ctx.hoststack.deploys.promote(\n\t\t\tteamId,\n\t\t\targs.service_id,\n\t\t\targs.deploy_id,\n\t\t\ttargetEnvId,\n\t\t);\n\t\tconst data = { deploy: shape(response.deploy) };\n\t\treturn respond({\n\t\t\tsummary: `Promoted deploy ${args.deploy_id} from service ${args.service_id} to env ${String(args.target_environment_id)}.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n","import { defineTool, listToolDefinitions } from '../registry.js';\nimport { respond } from '../lib/respond.js';\nimport { shapeTeam, shapeUser } from '../lib/shape.js';\n// Reuse the build-time-injected package version (the same value the MCP\n// `initialize` handshake advertises — see server-factory's PACKAGE_VERSION,\n// which is itself just MCP_VERSION). Importing from ../version.js keeps this in\n// one place and avoids an @hoststack/shared import (workspace-trap: it would\n// drag the whole monorepo into the published package).\nimport { MCP_VERSION } from '../version.js';\n\ninterface MeResponse {\n\tuser: unknown;\n\tteam?: unknown;\n}\n\n/**\n * The Dev Box tools this MCP build ships. A driving agent can compare this list\n * (returned by `describe_mcp`) against what its client actually surfaced to\n * detect a STALE npx/npm cache silently presenting an old tool set.\n *\n * KEEP IN SYNC with the tool names registered in ./services.ts. We list the\n * names as a literal (rather than filtering the registry by category) so the\n * marker stays meaningful even if the underlying categories are reshuffled —\n * these are the dev-env capabilities a caller most often finds missing.\n */\nconst DEV_ENV_TOOL_NAMES = [\n\t'create_dev_environment',\n\t'create_standalone_dev_environment',\n\t'spin_up_dev_environment',\n\t'list_dev_environments',\n\t'resize_dev_environment',\n\t'delete_dev_environment',\n] as const;\n\ndefineTool({\n\tname: 'get_me',\n\tcategory: 'meta',\n\tdescription: [\n\t\t'Return the user and team identity bound to the current API key. Useful at the start of a conversation to confirm which account the agent is operating on, especially when a user has multiple HostStack environments.',\n\t\t'',\n\t\t'When to use: orient yourself at the start of a session, confirm which team the API key targets, or surface the email/team-name in a reply to the user.',\n\t\t'',\n\t\t'Returns: { user: { id, email, name, ... }, team?: { id, publicId, name, plan, ... } }.',\n\t\t'',\n\t\t'Example: get_me() → { user: { id: 1, email: \"ada@…\", … }, team: { id: 7, name: \"acme\", plan: \"pro\" } }',\n\t].join('\\n'),\n\tinput: {},\n\thandler: async (_args, ctx) => {\n\t\tconst me = await ctx.api.get<MeResponse>('/api/auth/me');\n\t\tconst data: { user: ReturnType<typeof shapeUser>; team?: ReturnType<typeof shapeTeam> } = {\n\t\t\tuser: shapeUser(me.user),\n\t\t};\n\t\tif (me.team) data.team = shapeTeam(me.team);\n\t\tconst teamLabel =\n\t\t\tme.team && typeof me.team === 'object' && 'name' in me.team\n\t\t\t\t? ` on team ${(me.team as { name: string }).name}`\n\t\t\t\t: '';\n\t\tconst userEmail =\n\t\t\tme.user && typeof me.user === 'object' && 'email' in me.user\n\t\t\t\t? (me.user as { email: string }).email\n\t\t\t\t: 'unknown';\n\t\treturn respond({ summary: `Authenticated as ${userEmail}${teamLabel}.`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'describe_mcp',\n\tcategory: 'meta',\n\tdescription: [\n\t\t'Report this MCP build: its package version, total tool count, and the list of Dev Box tools it exposes. Read-only — touches no account data.',\n\t\t'',\n\t\t'When to use: at the start of a session to confirm the live MCP build, OR when a Dev Box tool you expect (create_dev_environment, create_standalone_dev_environment, spin_up_dev_environment, list_dev_environments, resize_dev_environment, delete_dev_environment) seems to be missing. A STALE npx/npm cache can silently present an old tool set with no other signal — call this and check `devEnvToolsPresent`; if it is false, the cached build predates the Dev Box tools and the user should refresh it (e.g. `npx --yes @hoststack.dev/mcp@latest` / clear the npx cache).',\n\t\t'',\n\t\t'Note on terminology: a \"Dev Box\" (a.k.a. Cloud Dev Box) is an agentic cloud box you code inside (create_dev_environment & friends). It is NOT a project \"environment\" (create_environment), which is a deployment target like Production / Staging / Preview. This tool only reports the Dev Box tool set.',\n\t\t'',\n\t\t'Inputs: none.',\n\t\t'',\n\t\t'Returns: { version, toolCount, devEnvTools: string[], devEnvToolsPresent: boolean } — version is the @hoststack.dev/mcp package version, toolCount is every registered tool, devEnvTools is the expected Dev Box tool names, and devEnvToolsPresent is true only if all of them are actually registered in this build.',\n\t\t'',\n\t\t'Example: describe_mcp() → { version: \"0.14.0\", toolCount: 30, devEnvTools: [\"create_dev_environment\", …], devEnvToolsPresent: true }',\n\t].join('\\n'),\n\tinput: {},\n\thandler: async (_args, _ctx) => {\n\t\tconst registered = new Set(listToolDefinitions().map((t) => t.name));\n\t\tconst devEnvToolsPresent = DEV_ENV_TOOL_NAMES.every((name) => registered.has(name));\n\t\tconst data = {\n\t\t\tversion: MCP_VERSION,\n\t\t\ttoolCount: registered.size,\n\t\t\tdevEnvTools: [...DEV_ENV_TOOL_NAMES],\n\t\t\tdevEnvToolsPresent,\n\t\t};\n\t\tconst summary = devEnvToolsPresent\n\t\t\t? `hoststack MCP v${MCP_VERSION} — ${data.toolCount} tools, all ${DEV_ENV_TOOL_NAMES.length} Dev Box tools present.`\n\t\t\t: `hoststack MCP v${MCP_VERSION} — ${data.toolCount} tools, but Dev Box tools are MISSING (stale build — refresh the npx/npm cache).`;\n\t\treturn respond({ summary, data });\n\t},\n});\n","import { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond } from '../lib/respond.js';\nimport { shape, shapeList } from '../lib/shape.js';\n\n/**\n * Source of truth: packages/shared/src/schemas/notification-channel.ts.\n * Kept in sync manually because the MCP package's Zod schemas are\n * what the model sees — pulling these from `@hoststack/shared` at\n * runtime would add a dependency that the published `@hoststack.dev/mcp`\n * shouldn't carry.\n */\nconst NOTIFICATION_EVENTS = [\n\t'deploy.started',\n\t'deploy.succeeded',\n\t'deploy.failed',\n\t'deploy.failed_consecutive',\n\t'service.created',\n\t'service.deleted',\n\t'service.suspended',\n\t'service.resumed',\n\t'service.restart_failed',\n\t'service.auto_suspended',\n\t'service.acme_cert_failed',\n\t'git.auth_failed',\n] as const;\n\ndefineTool({\n\tname: 'list_notification_channels',\n\tcategory: 'alerts',\n\tdescription: [\n\t\t'List configured notification channels for the team (Slack/Discord webhooks + email recipients). Each channel has a list of events it subscribes to — fire only happens when an event in that list occurs.',\n\t\t'',\n\t\t\"When to use: setting up alerts ('which channels are notifying us on deploy failures?'), auditing why someone got/didn't get paged, or before subscribing a new event.\",\n\t\t'',\n\t\t'Returns: { items: Channel[] } — each channel includes id, type, name, webhookUrl (masked), active, events, createdAt.',\n\t\t'',\n\t\t\"Example: list_notification_channels() → { items: [{ id: 3, type: 'slack', name: 'eng-alerts', events: ['deploy.failed', 'git.auth_failed'], … }] }\",\n\t].join('\\n'),\n\tinput: {},\n\thandler: async (_args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.notifications.listChannels(teamId);\n\t\tconst data = shapeList(response, 'channels', shape);\n\t\tconst summary =\n\t\t\tdata.items.length === 0\n\t\t\t\t? 'No notification channels yet — create one with create_notification_channel.'\n\t\t\t\t: `Found ${data.items.length} notification channel${data.items.length === 1 ? '' : 's'}.`;\n\t\treturn respond({ summary, data });\n\t},\n});\n\ndefineTool({\n\tname: 'create_notification_channel',\n\tcategory: 'alerts',\n\tdescription: [\n\t\t'Create a Slack, Discord, or email notification channel and subscribe it to a list of events.',\n\t\t'',\n\t\t'When to use: setting up alert delivery for a team — paging the on-call when a deploy fails, posting to #incidents when git auth breaks, emailing the owner on ACME renewal failure.',\n\t\t'',\n\t\t'For type=email, `webhook_url` is the recipient email address. For type=slack or type=discord, it is the incoming webhook URL. The URL is stored encrypted server-side and masked in list responses.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - type: \"slack\" | \"discord\" | \"email\".',\n\t\t' - name: human-readable label (1–128 chars).',\n\t\t' - webhook_url: Slack/Discord webhook URL OR email address.',\n\t\t' - events: list of event names to subscribe to. Pass an empty list to create a channel that fires for nothing (manual subscribe later with update_notification_channel).',\n\t\t'',\n\t\t'Valid events: deploy.started, deploy.succeeded, deploy.failed, deploy.failed_consecutive, service.created, service.deleted, service.suspended, service.resumed, service.restart_failed, service.auto_suspended, service.acme_cert_failed, git.auth_failed.',\n\t\t'',\n\t\t'Returns: { channel: Channel }.',\n\t\t'',\n\t\t\"Example: create_notification_channel({ type: 'slack', name: 'eng-alerts', webhook_url: 'https://hooks.slack.com/…', events: ['deploy.failed', 'git.auth_failed', 'service.restart_failed'] })\",\n\t].join('\\n'),\n\tinput: {\n\t\ttype: z.enum(['slack', 'discord', 'email']).describe('Channel type.'),\n\t\tname: z.string().min(1).max(128).describe('Human-readable label.'),\n\t\twebhook_url: z\n\t\t\t.string()\n\t\t\t.max(500)\n\t\t\t.describe('Slack/Discord webhook URL or email address (when type=email).'),\n\t\tevents: z\n\t\t\t.array(z.enum(NOTIFICATION_EVENTS))\n\t\t\t.describe(\n\t\t\t\t'List of events the channel subscribes to. Empty list = subscribe to nothing.',\n\t\t\t),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.notifications.createChannel(teamId, {\n\t\t\ttype: args.type,\n\t\t\tname: args.name,\n\t\t\twebhookUrl: args.webhook_url,\n\t\t\tevents: args.events,\n\t\t});\n\t\tconst data = { channel: shape(response.channel) };\n\t\treturn respond({\n\t\t\tsummary: `Created ${args.type} channel \"${args.name}\" subscribed to ${args.events.length} event${args.events.length === 1 ? '' : 's'}.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'update_notification_channel',\n\tcategory: 'alerts',\n\tdescription: [\n\t\t'Update a notification channel: rename, enable/disable, or change its event subscription list. The webhook URL and type are immutable — create a new channel if those need to change.',\n\t\t'',\n\t\t'When to use: silencing a noisy channel (active=false), adding a new event to an existing list, or relabeling.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - channel_id: numeric id of the channel.',\n\t\t' - name (optional): new label.',\n\t\t' - active (optional): false to silence, true to re-enable.',\n\t\t' - events (optional): replace the full subscription list. Passing [] silences all events without disabling the channel.',\n\t\t'',\n\t\t'Returns: { channel: Channel }.',\n\t\t'',\n\t\t\"Example: update_notification_channel({ channel_id: 3, events: ['deploy.failed', 'service.restart_failed', 'git.auth_failed'] })\",\n\t].join('\\n'),\n\tinput: {\n\t\tchannel_id: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.positive()\n\t\t\t.describe('Numeric channel id from list_notification_channels.'),\n\t\tname: z.string().min(1).max(128).optional().describe('New label.'),\n\t\tactive: z.boolean().optional().describe('false silences without deleting.'),\n\t\tevents: z\n\t\t\t.array(z.enum(NOTIFICATION_EVENTS))\n\t\t\t.optional()\n\t\t\t.describe('Replaces the full subscription list.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst update: { name?: string; active?: boolean; events?: readonly string[] } = {};\n\t\tif (args.name !== undefined) update.name = args.name;\n\t\tif (args.active !== undefined) update.active = args.active;\n\t\tif (args.events !== undefined) update.events = args.events;\n\n\t\tif (Object.keys(update).length === 0) {\n\t\t\treturn respond({ summary: 'No fields to update.', data: {} });\n\t\t}\n\t\t// Cast: SDK's events type is the typed enum array; passing through\n\t\t// from the Zod-validated args is safe at the type level even if\n\t\t// TS can't bridge the readonly tuple to the SDK signature.\n\t\tconst response = await ctx.hoststack.notifications.updateChannel(\n\t\t\tteamId,\n\t\t\targs.channel_id,\n\t\t\tupdate as Parameters<typeof ctx.hoststack.notifications.updateChannel>[2],\n\t\t);\n\t\tconst data = { channel: shape(response.channel) };\n\t\treturn respond({\n\t\t\tsummary: `Updated notification channel #${args.channel_id}.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'delete_notification_channel',\n\tcategory: 'alerts',\n\tdescription: [\n\t\t'Permanently delete a notification channel. Use update_notification_channel({ active: false }) to silence without deleting if you might want it back later.',\n\t\t'',\n\t\t'When to use: a channel is no longer needed (decommissioned Slack workspace, team member left, webhook leaked) and you want it gone from the team config entirely.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - channel_id: numeric id of the channel.',\n\t\t'',\n\t\t'Returns: { ok: true }.',\n\t\t'',\n\t\t'Example: delete_notification_channel({ channel_id: 3 }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tchannel_id: z.number().int().positive().describe('Numeric channel id.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.notifications.deleteChannel(teamId, args.channel_id);\n\t\treturn respond({\n\t\t\tsummary: `Deleted notification channel #${args.channel_id}.`,\n\t\t\tdata: { ok: true },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'test_notification_channel',\n\tcategory: 'alerts',\n\tdescription: [\n\t\t'Fire a synthetic test event to the channel so the user can confirm the webhook is wired up correctly. The webhook receives an unmistakeable \"test message\" payload.',\n\t\t'',\n\t\t\"When to use: after creating a channel, or when alerts stop arriving — quickest way to tell whether the issue is on HostStack's side or the channel's.\",\n\t\t'',\n\t\t'Inputs:',\n\t\t' - channel_id: numeric id of the channel.',\n\t\t'',\n\t\t'Returns: { success: boolean, error?: string } — false + error string when the webhook returned non-2xx.',\n\t\t'',\n\t\t'Example: test_notification_channel({ channel_id: 3 }) → { success: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tchannel_id: z.number().int().positive().describe('Numeric channel id.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.notifications.testChannel(teamId, args.channel_id);\n\t\tconst data = shape(response);\n\t\tconst okFlag =\n\t\t\tdata && typeof data === 'object' && 'success' in data\n\t\t\t\t? (data as { success: boolean }).success\n\t\t\t\t: false;\n\t\treturn respond({\n\t\t\tsummary: okFlag\n\t\t\t\t? `Test event delivered to channel #${args.channel_id}.`\n\t\t\t\t: `Test event FAILED for channel #${args.channel_id}: ${(data as { error?: string }).error ?? 'unknown error'}.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n","import { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond } from '../lib/respond.js';\nimport { shapeList, shapeProject } from '../lib/shape.js';\n\n// HostStack region IDs (matches @hoststack/shared REGION_IDS and the SDK's\n// internal RegionId). The SDK narrows region to this union but doesn't export\n// the type name, so we mirror the literals here — structurally identical, so\n// it stays assignable to the SDK's create-project param.\n//\n// AVAILABLE_REGION_IDS mirrors @hoststack/shared's list of regions we actually\n// run workers in — only these may be selected when creating a project, since a\n// project pinned to a region with no fleet can never deploy. Keep in lockstep\n// with the shared constant when a new region goes live.\nconst AVAILABLE_REGION_IDS = ['eu-central-1'] as const;\ntype RegionId = (typeof AVAILABLE_REGION_IDS)[number];\n\ndefineTool({\n\tname: 'list_projects',\n\tcategory: 'projects',\n\tdescription: [\n\t\t'List every project in the active HostStack team.',\n\t\t'',\n\t\t'When to use: the agent needs an overview of what projects exist before drilling into services, deploys, or databases. Use this as the first step when the user mentions a project by name and you need to resolve its ID.',\n\t\t'',\n\t\t'Returns: { items: Project[] } — each project includes id, publicId, name, description, createdAt.',\n\t\t'',\n\t\t'Example: list_projects() → { items: [{ id: 12, publicId: \"prj_…\", name: \"billing-api\", … }] }',\n\t].join('\\n'),\n\tinput: {},\n\thandler: async (_args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.projects.list(teamId);\n\t\tconst data = shapeList(response, 'projects', shapeProject);\n\t\tconst summary =\n\t\t\tdata.items.length === 0\n\t\t\t\t? 'No projects yet — create one in the dashboard or via create_project.'\n\t\t\t\t: `Found ${data.items.length} project${data.items.length === 1 ? '' : 's'}.`;\n\t\treturn respond({ summary, data });\n\t},\n});\n\ndefineTool({\n\tname: 'create_project',\n\tcategory: 'projects',\n\tdescription: [\n\t\t'Create a new project (logical grouping of services + databases).',\n\t\t'',\n\t\t\"When to use: the user wants to set up a new app or environment in HostStack. Projects are a free organisational layer — they don't cost anything until you add services or databases inside them.\",\n\t\t'',\n\t\t'Inputs:',\n\t\t' - name: human-readable project name (1–60 chars).',\n\t\t' - description (optional): short blurb shown in the dashboard.',\n\t\t' - region (optional): \"eu-central-1\" (Falkenstein). Currently the only region with available capacity; defaults to eu-central-1.',\n\t\t'',\n\t\t'Returns: { project: Project } — includes the new id and publicId.',\n\t\t'',\n\t\t'Example: create_project({ name: \"billing-api\", description: \"Stripe webhooks\", region: \"eu-central-1\" }) → { project: { id: 12, publicId: \"prj_…\", … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tname: z.string().min(1).max(60).describe('Project name (1–60 chars).'),\n\t\tdescription: z.string().max(500).optional().describe('Short description (≤500 chars).'),\n\t\tregion: z\n\t\t\t.enum(AVAILABLE_REGION_IDS)\n\t\t\t.optional()\n\t\t\t.describe('Region: eu-central-1 (Falkenstein) — currently the only available region.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst input: { name: string; description?: string; region?: RegionId } = {\n\t\t\tname: args.name,\n\t\t};\n\t\tif (args.description !== undefined) input.description = args.description;\n\t\tif (args.region !== undefined) input.region = args.region;\n\t\tconst response = await ctx.hoststack.projects.create(teamId, input);\n\t\tconst data = { project: shapeProject(response.project) };\n\t\tconst publicId =\n\t\t\tdata.project && 'publicId' in data.project\n\t\t\t\t? (data.project as { publicId: string }).publicId\n\t\t\t\t: 'unknown';\n\t\treturn respond({ summary: `Created project \"${args.name}\" (${publicId}).`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'update_project',\n\tcategory: 'projects',\n\tdescription: [\n\t\t'Rename a project or update its description.',\n\t\t'',\n\t\t'When to use: the user wants to fix a typo in a project name, attach a clearer description, or align the dashboard label with their internal naming.',\n\t\t'',\n\t\t'Inputs (all optional, at least one required):',\n\t\t' - project_id: publicId of the project (required).',\n\t\t' - name: new name (1–60 chars).',\n\t\t' - description: new description (≤500 chars).',\n\t\t'',\n\t\t'Returns: { project: Project } — the updated record.',\n\t\t'',\n\t\t'Example: update_project({ project_id: \"prj_abc\", name: \"billing-prod\" }) → { project: { name: \"billing-prod\", … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tproject_id: z.string().describe('Project publicId.'),\n\t\tname: z.string().min(1).max(60).optional().describe('New name (1–60 chars).'),\n\t\tdescription: z.string().max(500).optional().describe('New description (≤500 chars).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tif (args.name === undefined && args.description === undefined) {\n\t\t\treturn respond({\n\t\t\t\tsummary: 'No fields to update — pass `name` and/or `description`.',\n\t\t\t\tdata: {},\n\t\t\t});\n\t\t}\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst input: { name?: string; description?: string } = {};\n\t\tif (args.name !== undefined) input.name = args.name;\n\t\tif (args.description !== undefined) input.description = args.description;\n\t\tconst response = await ctx.hoststack.projects.update(teamId, args.project_id, input);\n\t\tconst data = { project: shapeProject(response.project) };\n\t\treturn respond({ summary: `Updated project ${args.project_id}.`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'get_project',\n\tcategory: 'projects',\n\tdescription: [\n\t\t'Fetch a single project by ID. Includes name, description, and timestamps.',\n\t\t'',\n\t\t'When to use: confirming a project exists before creating resources inside it, or pulling the canonical name/description for a reply to the user.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - project_id: publicId of the project (e.g. \"prj_abc123\").',\n\t\t'',\n\t\t'Returns: { project: Project }.',\n\t\t'',\n\t\t'Example: get_project({ project_id: \"prj_abc\" }) → { project: { id: 12, name: \"billing\", … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tproject_id: z.string().describe('Project publicId (e.g. prj_abc123).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.projects.get(teamId, args.project_id);\n\t\tconst data = { project: shapeProject(response.project) };\n\t\tconst name =\n\t\t\tdata.project && 'name' in data.project\n\t\t\t\t? (data.project as { name: string }).name\n\t\t\t\t: args.project_id;\n\t\treturn respond({ summary: `Project \"${name}\".`, data });\n\t},\n});\n","import type { CreateDevEnvironmentInput } from '@hoststack.dev/sdk';\nimport { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond, respondError } from '../lib/respond.js';\nimport { shape, shapeList, shapeService } from '../lib/shape.js';\n\n// Keep in sync with the `dev-environment` preset in\n// packages/shared/src/templates.ts (the dashboard wizard's source of truth)\n// and the catalog/floor constants in packages/shared/src/constants/pricing.ts.\n// The MCP package only depends on the SDK (it publishes to npm and must NOT\n// import the private @hoststack/shared package, which would drag the whole\n// monorepo into the bundle), so these constants are duplicated here\n// intentionally rather than imported. Drift is caught by review, not the type\n// system — update both sides together.\nconst DEV_ENV_IMAGE = 'hoststack/dev-env:latest';\nconst DEV_ENV_VOLUME = { name: 'workspace', mountPath: '/workspace', sizeGb: 10 };\n\nconst SERVICE_TYPES = [\n\t'web_service',\n\t'private_service',\n\t'worker',\n\t'cron_job',\n\t'static_site',\n] as const;\n// The real service catalog, ascending — mirrors the server's\n// SERVICE_SIZE_ORDER. `pico↓xlarge` are shared-CPU; `pro_*` are dedicated-CPU.\n// Note: `starter` is a DATABASE/addon size, not a service size — do not add it.\nconst SERVICE_PLANS = [\n\t'pico',\n\t'nano',\n\t'micro',\n\t'small',\n\t'standard',\n\t'large',\n\t'xlarge',\n\t'pro_standard',\n\t'pro_large',\n] as const;\n\n// The OOM-safe floor for dev boxes — mirrors DEV_ENV_MIN_SIZE in\n// packages/shared/src/constants/pricing.ts. A coding agent + build OOMs on\n// anything below `standard` (2 GB). The server floors a sub-standard plan\n// too; we clamp here so the MCP tool never even requests an undersized box.\nconst DEV_ENV_MIN_SIZE = 'standard';\n\n/**\n * Clamp a requested service size up to the dev-env floor. Mirrors the\n * server-side `coerceDevEnvSize`: an unknown/omitted/sub-`standard` value\n * becomes `standard`; a known size at/above the floor is left untouched.\n * Duplicated (not imported) per the workspace constraint above.\n */\nfunction coerceDevEnvSize(value: string | undefined): (typeof SERVICE_PLANS)[number] {\n\tconst minIdx = SERVICE_PLANS.indexOf(DEV_ENV_MIN_SIZE);\n\tconst idx = value ? SERVICE_PLANS.indexOf(value as (typeof SERVICE_PLANS)[number]) : -1;\n\treturn idx >= minIdx ? (value as (typeof SERVICE_PLANS)[number]) : DEV_ENV_MIN_SIZE;\n}\n\ndefineTool({\n\tname: 'list_services',\n\tcategory: 'services',\n\tdescription: [\n\t\t'List services (web, worker, cron, private, static) in the active HostStack team.',\n\t\t'',\n\t\t'When to use: the agent needs to find a service by name, check what is deployed, or pick a target for a follow-up tool (logs, deploys, env vars). This is the canonical way to resolve a publicId from a human-friendly name.',\n\t\t'',\n\t\t'Note: agentic Dev Boxes (cloud dev environments) are EXCLUDED by default. Pass dev_environment:true to include them, or use list_dev_environments for the dedicated, annotated dev-box listing.',\n\t\t'',\n\t\t'Inputs (all optional):',\n\t\t' - project_id: narrow to one project (numeric id or publicId \"prj_…\").',\n\t\t' - environment_id: narrow to one environment (numeric id or publicId \"env_…\").',\n\t\t' - status: \"active\" | \"deploying\" | \"suspended\" | \"failed\" | \"not_deployed\".',\n\t\t' - type: \"web_service\" | \"private_service\" | \"worker\" | \"cron_job\" | \"static_site\".',\n\t\t' - dev_environment: include Dev Boxes in the results (excluded by default).',\n\t\t'',\n\t\t'Returns: { items: Service[] } — each service includes id, publicId, name, type, status, projectId, repoUrl, branch, runtime, createdAt.',\n\t\t'',\n\t\t'Example: list_services({ status: \"failed\" }) → only services that need attention.',\n\t].join('\\n'),\n\tinput: {\n\t\tproject_id: z\n\t\t\t.union([z.number().int().positive(), z.string()])\n\t\t\t.optional()\n\t\t\t.describe('Project filter — numeric id or publicId.'),\n\t\tenvironment_id: z\n\t\t\t.union([z.number().int().positive(), z.string()])\n\t\t\t.optional()\n\t\t\t.describe('Environment filter — numeric id or publicId.'),\n\t\tstatus: z\n\t\t\t.enum(['active', 'deploying', 'suspended', 'failed', 'not_deployed'])\n\t\t\t.optional()\n\t\t\t.describe('Filter by current runtime status.'),\n\t\ttype: z\n\t\t\t.enum(['web_service', 'private_service', 'worker', 'cron_job', 'static_site'])\n\t\t\t.optional()\n\t\t\t.describe('Filter by service type.'),\n\t\tdev_environment: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t'Include agentic Dev Boxes in the results (excluded by default; see list_dev_environments).',\n\t\t\t),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst filters: Parameters<typeof ctx.hoststack.services.list>[1] = {};\n\t\tif (args.dev_environment) filters.devEnvironment = true;\n\t\tif (args.project_id !== undefined) {\n\t\t\t// SDK accepts publicId or numeric id; let resolveId handle it.\n\t\t\tconst resolved = await ctx.hoststack.resolveId(args.project_id, {\n\t\t\t\tkind: 'project',\n\t\t\t\tteamId,\n\t\t\t});\n\t\t\tfilters.projectId = resolved;\n\t\t}\n\t\tif (args.environment_id !== undefined) {\n\t\t\tconst resolved = await ctx.hoststack.resolveId(args.environment_id, {\n\t\t\t\tkind: 'environment',\n\t\t\t\tteamId,\n\t\t\t});\n\t\t\tfilters.environmentId = resolved;\n\t\t}\n\t\tif (args.status) filters.status = args.status;\n\t\tif (args.type) filters.type = args.type;\n\n\t\tconst response = await ctx.hoststack.services.list(teamId, filters);\n\t\tconst data = shapeList(response, 'services', shapeService);\n\t\tconst filterDesc = [\n\t\t\targs.project_id !== undefined ? `project=${args.project_id}` : null,\n\t\t\targs.environment_id !== undefined ? `env=${args.environment_id}` : null,\n\t\t\targs.status ? `status=${args.status}` : null,\n\t\t\targs.type ? `type=${args.type}` : null,\n\t\t\targs.dev_environment ? 'devBoxes=included' : null,\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(', ');\n\t\tconst summary =\n\t\t\tdata.items.length === 0\n\t\t\t\t? filterDesc\n\t\t\t\t\t? `No services match the given filters (${filterDesc}).`\n\t\t\t\t\t: 'No services yet — create one with create_service (or create_dev_environment for an AI dev box), or via the dashboard.'\n\t\t\t\t: `Found ${data.items.length} service${data.items.length === 1 ? '' : 's'}${filterDesc ? ` matching ${filterDesc}` : ''}.`;\n\t\treturn respond({ summary, data });\n\t},\n});\n\ndefineTool({\n\tname: 'create_service',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Create a new service in a project. Source is either a connected git repo (github_repo_id) OR a pre-built docker_image — never both.',\n\t\t'',\n\t\t'When to use: the user wants to deploy something new. For a one-command AI dev environment specifically, prefer create_dev_environment (it also attaches the /workspace volume and sets the MCP keys).',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - project_id: numeric id or publicId (\"prj_…\") of the target project.',\n\t\t' - name: service name (1–100 chars).',\n\t\t' - type: \"web_service\" | \"private_service\" | \"worker\" | \"cron_job\" | \"static_site\".',\n\t\t' - docker_image (optional): pre-built image ref to deploy instead of building from source.',\n\t\t' - github_repo_id (optional): connect a previously-linked GitHub repo by numeric id.',\n\t\t' - branch (optional): git branch (default \"main\").',\n\t\t' - install_command / build_command / start_command (optional): build/run shell commands. start_command is required for web/private services without a docker_image.',\n\t\t' - cron_schedule (optional): cron expression — required for cron_job.',\n\t\t' - publish_path (optional): static-site output dir (e.g. \"dist\").',\n\t\t' - runtime (optional): \"node\" | \"bun\" | \"python\" | … (auto-detected from a repo when omitted).',\n\t\t' - plan (optional): service size (default \"micro\").',\n\t\t' - environment_id (optional): bind to a specific environment; defaults to the project Production env.',\n\t\t' - auto_deploy (optional, default true): trigger the first deploy immediately when a source is present.',\n\t\t'',\n\t\t'Returns: { service: Service, deployId: number | null }.',\n\t\t'',\n\t\t'Example: create_service({ project_id: \"prj_abc\", name: \"api\", type: \"web_service\", github_repo_id: 42 }) → { service: { publicId: \"svc_…\" }, deployId: 1234 }',\n\t].join('\\n'),\n\tinput: {\n\t\tproject_id: z\n\t\t\t.union([z.number().int().positive(), z.string()])\n\t\t\t.describe('Target project — numeric id or publicId.'),\n\t\tname: z.string().min(1).max(100).describe('Service name (1–100 chars).'),\n\t\ttype: z.enum(SERVICE_TYPES).describe('Service type.'),\n\t\tdocker_image: z\n\t\t\t.string()\n\t\t\t.max(500)\n\t\t\t.optional()\n\t\t\t.describe('Pre-built image ref. Mutually exclusive with github_repo_id.'),\n\t\tgithub_repo_id: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.positive()\n\t\t\t.optional()\n\t\t\t.describe('Linked GitHub repo numeric id. Mutually exclusive with docker_image.'),\n\t\tbranch: z.string().max(200).optional().describe('Git branch (default \"main\").'),\n\t\tinstall_command: z.string().max(1000).optional().describe('Install shell command.'),\n\t\tbuild_command: z.string().max(1000).optional().describe('Build shell command.'),\n\t\tstart_command: z\n\t\t\t.string()\n\t\t\t.max(1000)\n\t\t\t.optional()\n\t\t\t.describe('Start shell command (required for web/private services without an image).'),\n\t\tcron_schedule: z\n\t\t\t.string()\n\t\t\t.max(100)\n\t\t\t.optional()\n\t\t\t.describe('Cron expression — required for cron_job.'),\n\t\tpublish_path: z.string().max(500).optional().describe('Static-site output dir.'),\n\t\truntime: z.string().max(50).optional().describe('Runtime hint (node/bun/python/…).'),\n\t\tplan: z.enum(SERVICE_PLANS).optional().describe('Service size (default \"micro\").'),\n\t\tenvironment_id: z\n\t\t\t.union([z.number().int().positive(), z.string()])\n\t\t\t.optional()\n\t\t\t.describe('Bind to a specific environment; defaults to Production.'),\n\t\tauto_deploy: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe('Trigger the first deploy immediately (default true).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst projectId = await ctx.hoststack.resolveId(args.project_id, {\n\t\t\tkind: 'project',\n\t\t\tteamId,\n\t\t});\n\n\t\tconst input: Parameters<typeof ctx.hoststack.services.create>[1] = {\n\t\t\tname: args.name,\n\t\t\ttype: args.type,\n\t\t\tprojectId,\n\t\t};\n\t\tif (args.docker_image !== undefined) input.dockerImage = args.docker_image;\n\t\tif (args.github_repo_id !== undefined) input.githubRepoId = args.github_repo_id;\n\t\tif (args.branch !== undefined) input.branch = args.branch;\n\t\tif (args.install_command !== undefined) input.installCommand = args.install_command;\n\t\tif (args.build_command !== undefined) input.buildCommand = args.build_command;\n\t\tif (args.start_command !== undefined) input.startCommand = args.start_command;\n\t\tif (args.cron_schedule !== undefined) input.cronSchedule = args.cron_schedule;\n\t\tif (args.publish_path !== undefined) input.publishPath = args.publish_path;\n\t\tif (args.runtime !== undefined) input.runtime = args.runtime;\n\t\tif (args.plan !== undefined) input.plan = args.plan;\n\t\tif (args.auto_deploy !== undefined) input.autoDeploy = args.auto_deploy;\n\t\tif (args.environment_id !== undefined) {\n\t\t\tinput.environmentId = await ctx.hoststack.resolveId(args.environment_id, {\n\t\t\t\tkind: 'environment',\n\t\t\t\tteamId,\n\t\t\t});\n\t\t}\n\n\t\tconst response = await ctx.hoststack.services.create(teamId, input);\n\t\tconst data = {\n\t\t\tservice: shapeService(response.service),\n\t\t\tdeployId: (response as { deployId?: number | null }).deployId ?? null,\n\t\t};\n\t\tconst publicId =\n\t\t\tdata.service && 'publicId' in data.service\n\t\t\t\t? (data.service as { publicId: string }).publicId\n\t\t\t\t: 'unknown';\n\t\treturn respond({ summary: `Created service \"${args.name}\" (${publicId}).`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'create_dev_environment',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Spin up an AI Dev Box in one call: a cloud \"Dev Box\" (an agentic container from the dev-env image — Claude Code + Codex + OpenCode + MCPs preinstalled) inside a project, with a persistent /workspace volume and the MCP API keys set, then fire the first deploy.',\n\t\t'',\n\t\t'This makes a cloud Dev Box, NOT a project deploy environment. A project \"environment\" (create_environment → Production / Staging / Preview) is a deployment target; this is a workspace you code in. If you actually want a -dev deploy target, use create_environment instead.',\n\t\t'',\n\t\t'When to use: the user wants a cloud terminal / Dev Box they can drive coding agents in (from a desk or a phone). This mirrors the dashboard\\'s \"AI Dev Environment\" wizard preset — create (deploy deferred) → set keys → attach /workspace → deploy, so the first container boots with its volume and keys already in place.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - project_id: numeric id or publicId (\"prj_…\") of the target project.',\n\t\t' - name (optional): service name (default \"dev-environment\").',\n\t\t' - plan (optional): box size. Defaults to \"standard\" (2 GB) — the OOM-safe floor (DEV_ENV_MIN_SIZE); a coding agent + build OOMs below it. A smaller plan is clamped up to \"standard\".',\n\t\t' - disk_gb (optional): /workspace volume size in GB (default 10, 1–100).',\n\t\t' - hoststack_api_key (optional): sets HOSTSTACK_API_KEY so the hoststack MCP works inside the container.',\n\t\t' - poststack_api_key (optional): sets POSTSTACK_API_KEY so the poststack MCP works inside the container.',\n\t\t' - repo_url (optional): clone this git URL into /workspace on first boot (with optional branch).',\n\t\t'',\n\t\t'Returns: { service: Service, volumeAttached: boolean, deployId: number | null }. Open the Terminal tab on the service (dashboard or phone) once it is running; log in once with `claude /login` inside the container.',\n\t\t'',\n\t\t'Example: create_dev_environment({ project_id: \"prj_abc\", name: \"scratch\", hoststack_api_key: \"hs_live_…\" })',\n\t].join('\\n'),\n\tinput: {\n\t\tproject_id: z\n\t\t\t.union([z.number().int().positive(), z.string()])\n\t\t\t.describe('Target project — numeric id or publicId.'),\n\t\tname: z\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(100)\n\t\t\t.optional()\n\t\t\t.describe('Service name (default \"dev-environment\").'),\n\t\tplan: z\n\t\t\t.enum(SERVICE_PLANS)\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t'Box size (default \"standard\" — 2 GB, the OOM-safe floor; a smaller plan is clamped up to \"standard\").',\n\t\t\t),\n\t\tdisk_gb: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(1)\n\t\t\t.max(100)\n\t\t\t.optional()\n\t\t\t.describe('/workspace volume size in GB (default 10).'),\n\t\thoststack_api_key: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe('Value for HOSTSTACK_API_KEY (enables the hoststack MCP in-container).'),\n\t\tpoststack_api_key: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe('Value for POSTSTACK_API_KEY (enables the poststack MCP in-container).'),\n\t\trepo_url: z\n\t\t\t.string()\n\t\t\t.max(500)\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t'Clone this git URL into /workspace on first boot (HTTPS, or SSH once a key is set).',\n\t\t\t),\n\t\tbranch: z.string().max(200).optional().describe('Branch to clone (with repo_url).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst projectId = await ctx.hoststack.resolveId(args.project_id, {\n\t\t\tkind: 'project',\n\t\t\tteamId,\n\t\t});\n\t\tconst name = args.name ?? 'dev-environment';\n\t\tconst sizeGb = args.disk_gb ?? DEV_ENV_VOLUME.sizeGb;\n\t\t// Defence in depth: clamp the requested plan up to the OOM-safe dev-env\n\t\t// floor BEFORE asking the SDK to create the box. The server floors it\n\t\t// too, but this guarantees the tool never even requests a sub-`standard`\n\t\t// box that would OOM a coding agent on first boot.\n\t\tconst plan = coerceDevEnvSize(args.plan);\n\n\t\t// Defer the first deploy (autoDeploy:false) so we can set the MCP keys\n\t\t// and attach /workspace BEFORE the container boots — same ordering as\n\t\t// the dashboard wizard's use-new-service-form.\n\t\tconst createInput: Parameters<typeof ctx.hoststack.services.create>[1] = {\n\t\t\tname,\n\t\t\ttype: 'private_service',\n\t\t\tprojectId,\n\t\t\tdockerImage: DEV_ENV_IMAGE,\n\t\t\tautoDeploy: false,\n\t\t\tplan,\n\t\t};\n\t\tconst created = await ctx.hoststack.services.create(teamId, createInput);\n\t\tconst service = created.service;\n\n\t\t// From here on the service EXISTS and is billable. Any later failure\n\t\t// must tear it back down so we never orphan a half-provisioned,\n\t\t// non-persistent box — see rollback() below. (The server's own\n\t\t// rollbackPartialDevBox only covers the dedicated dev-env create path,\n\t\t// not this generic create-then-attach sequence.)\n\t\tconst rollback = async (): Promise<void> => {\n\t\t\ttry {\n\t\t\t\t// tearDownDevEnvironment cascades the box + volume + cloned DB;\n\t\t\t\t// it only accepts dev-env services, which this is (dev-env image).\n\t\t\t\tawait ctx.hoststack.services.tearDownDevEnvironment(teamId, service.id);\n\t\t\t} catch {\n\t\t\t\ttry {\n\t\t\t\t\tawait ctx.hoststack.services.delete(teamId, service.id);\n\t\t\t\t} catch {\n\t\t\t\t\t// Best-effort: surface the original failure to the caller\n\t\t\t\t\t// even if cleanup itself fails (orphan will need manual\n\t\t\t\t\t// removal via delete_dev_environment / the dashboard).\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\ttry {\n\t\t\tconst envVars: { key: string; value: string; isSecret: boolean }[] = [];\n\t\t\tif (args.hoststack_api_key)\n\t\t\t\tenvVars.push({\n\t\t\t\t\tkey: 'HOSTSTACK_API_KEY',\n\t\t\t\t\tvalue: args.hoststack_api_key,\n\t\t\t\t\tisSecret: true,\n\t\t\t\t});\n\t\t\tif (args.poststack_api_key)\n\t\t\t\tenvVars.push({\n\t\t\t\t\tkey: 'POSTSTACK_API_KEY',\n\t\t\t\t\tvalue: args.poststack_api_key,\n\t\t\t\t\tisSecret: true,\n\t\t\t\t});\n\t\t\t// Clone an arbitrary repo at boot (the image entrypoint reads these).\n\t\t\tif (args.repo_url) {\n\t\t\t\tenvVars.push({\n\t\t\t\t\tkey: 'HOSTSTACK_DEVENV_REPO_URL',\n\t\t\t\t\tvalue: args.repo_url,\n\t\t\t\t\tisSecret: false,\n\t\t\t\t});\n\t\t\t\tif (args.branch)\n\t\t\t\t\tenvVars.push({\n\t\t\t\t\t\tkey: 'HOSTSTACK_DEVENV_BRANCH',\n\t\t\t\t\t\tvalue: args.branch,\n\t\t\t\t\t\tisSecret: false,\n\t\t\t\t\t});\n\t\t\t}\n\t\t\tif (envVars.length > 0) {\n\t\t\t\tawait ctx.hoststack.envVars.bulkSet(teamId, service.id, { vars: envVars });\n\t\t\t}\n\n\t\t\t// A Dev Box without its /workspace volume silently loses all\n\t\t\t// out-of-image work on the next recreate. ABORT rather than deploy\n\t\t\t// a non-persistent box: a missing volume is a hard failure here.\n\t\t\ttry {\n\t\t\t\tawait ctx.hoststack.volumes.create(teamId, service.id, {\n\t\t\t\t\tname: DEV_ENV_VOLUME.name,\n\t\t\t\t\tmountPath: DEV_ENV_VOLUME.mountPath,\n\t\t\t\t\tsizeGb,\n\t\t\t\t});\n\t\t\t} catch (error: unknown) {\n\t\t\t\tconst reason = error instanceof Error ? error.message : String(error);\n\t\t\t\tawait rollback();\n\t\t\t\treturn respondError(\n\t\t\t\t\t`Failed to attach the /workspace volume for Dev Box \"${name}\" — aborted and rolled back rather than deploy a box that would lose all work on recreate. Volume error: ${reason}`,\n\t\t\t\t\t{ volumeError: reason, rolledBack: true },\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst deploy = await ctx.hoststack.deploys.trigger(teamId, service.id);\n\t\t\tconst deployId = deploy.deploy?.id ?? null;\n\n\t\t\treturn respond({\n\t\t\t\tsummary: `Created AI Dev Box \"${name}\" (${service.publicId}) with a /workspace volume — deploying. Open it in the dashboard's Dev Boxes section (or the service's Terminal tab) once running.`,\n\t\t\t\tdata: { service: shapeService(service), volumeAttached: true, deployId },\n\t\t\t});\n\t\t} catch (error: unknown) {\n\t\t\t// Any post-create failure (env-var set, deploy trigger, …) tears the\n\t\t\t// billable box back down so nothing is orphaned.\n\t\t\tconst reason = error instanceof Error ? error.message : String(error);\n\t\t\tawait rollback();\n\t\t\treturn respondError(\n\t\t\t\t`Failed to provision Dev Box \"${name}\" — rolled back the partially-created box. Error: ${reason}`,\n\t\t\t\t{ rolledBack: true },\n\t\t\t);\n\t\t}\n\t},\n});\n\ndefineTool({\n\tname: 'spin_up_dev_environment',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Spin up an agentic Dev Box FROM an existing service so you can reproduce a bug, fix it, view it, and ship it. Creates a cloud Dev Box (Claude/Codex/OpenCode + MCPs) that RUNS a clone of the app: the repo is auto-cloned into /workspace, the service env-vars are copied, and its linked database is cloned (so the box never touches the prod DB). The box gets an unguessable public dev URL and seamless `git push`.',\n\t\t'',\n\t\t'This makes a cloud Dev Box, NOT a project deploy environment — for a -dev/-staging deploy target use create_environment instead.',\n\t\t'',\n\t\t'When to use: \"spin up a dev environment for <service>\", \"I found a bug on <service>, give me a box to fix it\". Distinct from create_dev_environment, which makes a BARE box not tied to any app.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: the source service to debug — numeric id or publicId (\"svc_…\").',\n\t\t' - include_database_clone (optional): clone the linked database so the app runs on a copy of real data (default true).',\n\t\t' - name (optional): dev box name (default \"<source>-dev\").',\n\t\t'',\n\t\t'Returns: { service, devUrl, deployId }. Once it is live: open the Terminal tab, run `claude`, start the dev server (it must bind $PORT), and view the app at https://<devUrl>. Tear it all down later with delete_dev_environment.',\n\t\t'',\n\t\t'Example: spin_up_dev_environment({ service_id: \"svc_api\" }) → a dev box running a clone of the api service (repo + env-vars + cloned DB) with a public dev URL.',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z\n\t\t\t.union([z.number().int().positive(), z.string()])\n\t\t\t.describe('Source service to debug — numeric id or publicId.'),\n\t\tinclude_database_clone: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe('Clone the linked database so the app runs on copied data (default true).'),\n\t\tname: z\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(100)\n\t\t\t.optional()\n\t\t\t.describe('Dev box name (default \"<source>-dev\").'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst serviceId = await ctx.hoststack.resolveId(args.service_id, {\n\t\t\tkind: 'service',\n\t\t\tteamId,\n\t\t});\n\t\tconst opts: { includeDatabaseClone?: boolean; name?: string } = {};\n\t\tif (args.include_database_clone !== undefined)\n\t\t\topts.includeDatabaseClone = args.include_database_clone;\n\t\tif (args.name !== undefined) opts.name = args.name;\n\t\tconst result = await ctx.hoststack.services.spinUpDevEnvironment(teamId, serviceId, opts);\n\t\treturn respond({\n\t\t\tsummary: `Spun up dev environment \"${result.service.name}\" (${result.service.publicId}) — deploying. Once live: open the Terminal tab, run \\`claude\\`, start the dev server on $PORT, and view it at https://${result.devUrl}. \\`git push\\` works from inside.`,\n\t\t\tdata: {\n\t\t\t\tservice: shapeService(result.service),\n\t\t\t\tdevUrl: result.devUrl,\n\t\t\t\tdeployId: result.deployId,\n\t\t\t},\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'delete_dev_environment',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Tear down an agentic Dev Box in one call: removes the cloud Dev Box AND cascade-deletes its cloned database, its /workspace volume, and the auto-created `development` environment if it is now empty.',\n\t\t'',\n\t\t'This deletes a cloud Dev Box, NOT a project deploy environment — to remove a -dev/-staging deploy target use delete_environment instead.',\n\t\t'',\n\t\t'When to use: \"delete / tear down the dev environment\", once you have shipped the fix and no longer need the box.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: the dev box to tear down — numeric id or publicId.',\n\t\t'',\n\t\t'Returns: { ok: true }. Irreversible — the cloned database and workspace volume are deleted.',\n\t\t'',\n\t\t'Example: delete_dev_environment({ service_id: \"svc_api_dev\" }) → removes the dev box, its cloned database, and the /workspace volume.',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z\n\t\t\t.union([z.number().int().positive(), z.string()])\n\t\t\t.describe('The dev box to tear down — numeric id or publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst serviceId = await ctx.hoststack.resolveId(args.service_id, {\n\t\t\tkind: 'service',\n\t\t\tteamId,\n\t\t});\n\t\tawait ctx.hoststack.services.tearDownDevEnvironment(teamId, serviceId);\n\t\treturn respond({\n\t\t\tsummary:\n\t\t\t\t'Dev environment torn down — box, cloned database, /workspace volume, and empty development environment removed.',\n\t\t\tdata: { ok: true },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'resize_dev_environment',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Resize a cloud Dev Box (or any service) to a different size tier — the supported way to give it more memory/CPU/disk headroom (e.g. when ESLint/tsc OOMs).',\n\t\t'',\n\t\t'This resizes a cloud Dev Box, NOT a project deploy environment.',\n\t\t'',\n\t\t'When to use: a Dev Box OOM-killed (see exitReason/recommendedSize from list_dev_environments), or you just want more headroom. This changes the SIZE TIER — unlike per-config memory/CPU overrides, which are clamped to the current tier and so cannot grow a box past it.',\n\t\t'',\n\t\t\"How it applies: the new tier's memory + CPU take effect LIVE on the running container (no recreate, no dropped shell sessions); a larger disk takes effect on the next recreate (suspend→resume). Dev boxes are floored to the OOM-safe minimum size server-side.\",\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: the box to resize — numeric id or publicId.',\n\t\t' - size: target tier — one of the service catalog sizes (e.g. \"standard\", \"large\", \"xlarge\").',\n\t\t'',\n\t\t'Returns: { service } with the new plan.',\n\t\t'',\n\t\t'Example: resize_dev_environment({ service_id: \"svc_skyskraber_dev\", size: \"large\" }) → bumps the box to the large tier, applied live.',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z\n\t\t\t.union([z.number().int().positive(), z.string()])\n\t\t\t.describe('The box to resize — numeric id or publicId.'),\n\t\tsize: z\n\t\t\t.enum(SERVICE_PLANS)\n\t\t\t.describe(\n\t\t\t\t'Target size tier (service catalog size, e.g. \"standard\", \"large\", \"xlarge\").',\n\t\t\t),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst serviceId = await ctx.hoststack.resolveId(args.service_id, {\n\t\t\tkind: 'service',\n\t\t\tteamId,\n\t\t});\n\t\tconst { service } = await ctx.hoststack.services.resize(teamId, serviceId, args.size);\n\t\treturn respond({\n\t\t\tsummary: `Resized to ${service.plan} — memory/CPU applied live; disk grows on next recreate.`,\n\t\t\tdata: { service: shapeService(service) },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'list_dev_environments',\n\tcategory: 'services',\n\tdescription: [\n\t\t'List the team\\'s cloud Dev Boxes (the dashboard \"Dev Boxes\" / Development section), each annotated with the companion services attached to it.',\n\t\t'',\n\t\t\"These are cloud Dev Boxes, NOT project deploy environments — to list a project's deploy targets (Production / Staging / Preview) use list_environments instead.\",\n\t\t'',\n\t\t'When to use: \"show my dev environments\", before opening/tearing one down, to find a box\\'s id.',\n\t\t'',\n\t\t'Returns: { items: [{ ...service, devUrl, databases, exitReason, recommendedSize }] } where `databases` lists the companion engines wired into the box (e.g. [\"postgres\",\"redis\"]). `exitReason` is \"oom_killed\" / \"crashed\" / null for the box\\'s last container exit; when it is \"oom_killed\", `recommendedSize` is the next tier up to rescale to (use resize_dev_environment).',\n\t\t'',\n\t\t'Example: list_dev_environments() → every dev box for the active team.',\n\t].join('\\n'),\n\tinput: {},\n\thandler: async (_args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst { environments } = await ctx.hoststack.services.listDevEnvironments(teamId);\n\t\tconst oomCount = environments.filter((e) => e.exitReason === 'oom_killed').length;\n\t\treturn respond({\n\t\t\tsummary:\n\t\t\t\t`${environments.length} dev environment${environments.length === 1 ? '' : 's'}.` +\n\t\t\t\t(oomCount > 0\n\t\t\t\t\t? ` ${oomCount} recently OOM-killed — consider resize_dev_environment.`\n\t\t\t\t\t: ''),\n\t\t\tdata: {\n\t\t\t\titems: environments.map((env) => ({\n\t\t\t\t\t...shapeService(env),\n\t\t\t\t\tdevUrl: env.devUrl ?? null,\n\t\t\t\t\tdatabases: env.databases ?? [],\n\t\t\t\t\texitReason: env.exitReason ?? null,\n\t\t\t\t\trecommendedSize: env.recommendedSize ?? null,\n\t\t\t\t})),\n\t\t\t},\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'list_templates',\n\tcategory: 'services',\n\tdescription: [\n\t\t'List the canonical Dev Box (AI dev environment) preset so an agent can see, without guessing, what a `create_standalone_dev_environment` / `create_dev_environment` actually provisions: the container image, the persistent /workspace volume (mount + default size), the OOM-safe size floor, and the companion database options.',\n\t\t'',\n\t\t'When to use: before creating a Dev Box, to confirm the image, the default /workspace size, the minimum plan, or which companion engines can be attached — instead of hand-duplicating those constants.',\n\t\t'',\n\t\t'Returns: { templates: [{ id, name, image, volume: { name, mountPath, sizeGb }, minPlan, companions }] }. Today there is one preset (\"dev-environment\").',\n\t\t'',\n\t\t'Example: list_templates() → { templates: [{ id: \"dev-environment\", image: \"hoststack/dev-env:latest\", volume: { mountPath: \"/workspace\", sizeGb: 10 }, minPlan: \"standard\", companions: [\"postgres\",\"redis\",\"meilisearch\"] }] }',\n\t].join('\\n'),\n\tinput: {},\n\thandler: async () => {\n\t\t// The canonical Dev Box preset, assembled from THIS package's own\n\t\t// constants (DEV_ENV_IMAGE / DEV_ENV_VOLUME / DEV_ENV_MIN_SIZE). Kept in\n\t\t// sync by review with packages/shared/src/templates.ts — NOT imported,\n\t\t// per the workspace constraint (the MCP package must not depend on the\n\t\t// private @hoststack/shared package). Duplicated intentionally.\n\t\tconst templates = [\n\t\t\t{\n\t\t\t\tid: 'dev-environment',\n\t\t\t\tname: 'AI Dev Environment',\n\t\t\t\timage: DEV_ENV_IMAGE,\n\t\t\t\tvolume: {\n\t\t\t\t\tname: DEV_ENV_VOLUME.name,\n\t\t\t\t\tmountPath: DEV_ENV_VOLUME.mountPath,\n\t\t\t\t\tsizeGb: DEV_ENV_VOLUME.sizeGb,\n\t\t\t\t},\n\t\t\t\t/** OOM-safe plan floor — a coding agent + build needs at least this. */\n\t\t\t\tminPlan: DEV_ENV_MIN_SIZE,\n\t\t\t\t/** Companion engines you can attach (fresh + empty), like local `make db-up`. */\n\t\t\t\tcompanions: ['postgres', 'redis', 'meilisearch'],\n\t\t\t},\n\t\t];\n\t\treturn respond({\n\t\t\tsummary: `${templates.length} Dev Box template${templates.length === 1 ? '' : 's'} available (image ${DEV_ENV_IMAGE}, /workspace ${DEV_ENV_VOLUME.sizeGb} GB, floor \"${DEV_ENV_MIN_SIZE}\").`,\n\t\t\tdata: { templates },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'create_standalone_dev_environment',\n\tcategory: 'services',\n\tdescription: [\n\t\t\"Create a STANDALONE Dev Box in one call: a cloud box (Claude Code + Codex + OpenCode + MCPs) on a persistent /workspace, from a connected GitHub repo, an arbitrary clone URL, or blank — with optional companion Postgres / Redis / Meilisearch wired into its env (mirrors a local `make db-up`). The box lives in the team's hidden Development home, NOT under a project.\",\n\t\t'',\n\t\t'This makes a cloud Dev Box, NOT a project deploy environment (create_environment → Production / Staging / Preview). It is a workspace you code in, not a deployment target.',\n\t\t'',\n\t\t'When to use: \"create a dev environment for <repo>\", \"spin me up a cloud dev box with a Postgres\". Distinct from spin_up_dev_environment (which clones an EXISTING service) and create_dev_environment (a bare box in a chosen project).',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - name: the Dev Box name.',\n\t\t' - source_kind: \"github_repo\" (clone a connected repo — needs github_repo_id), \"url\" (clone any http(s) git URL — needs clone_url), or \"blank\" (empty box).',\n\t\t' - github_repo_id (for github_repo): numeric id of a connected GitHub repo.',\n\t\t' - clone_url (for url): an http(s) git clone URL.',\n\t\t' - branch (optional): branch to clone.',\n\t\t' - databases (optional): companion services to attach — any of \"postgres\", \"redis\", \"meilisearch\".',\n\t\t' - plan (optional): box size. Defaults to \"standard\" (2 GB) — the OOM-safe floor (DEV_ENV_MIN_SIZE); a smaller plan is floored up to \"standard\" server-side.',\n\t\t\" - agent_accounts (optional): bind specific saved agent logins by account id per provider. OMIT to auto-inherit the box owner's default logins (claude/codex/opencode), so `claude` is already authenticated on first boot — no manual login.\",\n\t\t'',\n\t\t'Returns: { service, devUrl, deployId } — deploying. Once live: open the Terminal tab, run `claude`, start the dev server on $PORT, view at https://<devUrl>. Tear down with delete_dev_environment.',\n\t\t'',\n\t\t'Example: create_standalone_dev_environment({ name: \"app-dev\", source_kind: \"github_repo\", github_repo_id: 42, databases: [\"postgres\",\"redis\"] })',\n\t].join('\\n'),\n\tinput: {\n\t\tname: z.string().min(1).max(100).describe('Dev Box name.'),\n\t\tsource_kind: z.enum(['github_repo', 'url', 'blank']).describe('Where the code comes from.'),\n\t\tgithub_repo_id: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.positive()\n\t\t\t.optional()\n\t\t\t.describe('Connected GitHub repo id (required when source_kind=\"github_repo\").'),\n\t\tclone_url: z\n\t\t\t.string()\n\t\t\t.url()\n\t\t\t.optional()\n\t\t\t.describe('http(s) git clone URL (required when source_kind=\"url\").'),\n\t\tbranch: z.string().min(1).max(255).optional().describe('Branch to clone.'),\n\t\tdatabases: z\n\t\t\t.array(z.enum(['postgres', 'redis', 'meilisearch']))\n\t\t\t.optional()\n\t\t\t.describe('Companion services to attach (fresh + empty).'),\n\t\tplan: z\n\t\t\t.enum(SERVICE_PLANS)\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t'Box size (default \"standard\" — 2 GB; a smaller plan is floored to \"standard\").',\n\t\t\t),\n\t\tagent_accounts: z\n\t\t\t.array(\n\t\t\t\tz.object({\n\t\t\t\t\tprovider: z.enum(['claude', 'codex', 'opencode']),\n\t\t\t\t\taccount_id: z.number().int().positive(),\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.max(3)\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t\"Bind saved agent logins by account id per provider. Omit to inherit the box owner's default logins automatically.\",\n\t\t\t),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tlet source: CreateDevEnvironmentInput['source'];\n\t\tif (args.source_kind === 'github_repo') {\n\t\t\tif (!args.github_repo_id) {\n\t\t\t\treturn respond({\n\t\t\t\t\tsummary: 'github_repo_id is required when source_kind is \"github_repo\".',\n\t\t\t\t\tdata: { ok: false },\n\t\t\t\t});\n\t\t\t}\n\t\t\tsource = {\n\t\t\t\tkind: 'github_repo',\n\t\t\t\tgithubRepoId: args.github_repo_id,\n\t\t\t\t...(args.branch ? { branch: args.branch } : {}),\n\t\t\t};\n\t\t} else if (args.source_kind === 'url') {\n\t\t\tif (!args.clone_url) {\n\t\t\t\treturn respond({\n\t\t\t\t\tsummary: 'clone_url is required when source_kind is \"url\".',\n\t\t\t\t\tdata: { ok: false },\n\t\t\t\t});\n\t\t\t}\n\t\t\tsource = {\n\t\t\t\tkind: 'url',\n\t\t\t\tcloneUrl: args.clone_url,\n\t\t\t\t...(args.branch ? { branch: args.branch } : {}),\n\t\t\t};\n\t\t} else {\n\t\t\tsource = { kind: 'blank' };\n\t\t}\n\t\tconst input: CreateDevEnvironmentInput = {\n\t\t\tname: args.name,\n\t\t\tsource,\n\t\t\t...(args.databases ? { databases: args.databases } : {}),\n\t\t\t...(args.plan ? { plan: args.plan } : {}),\n\t\t\t...(args.agent_accounts && args.agent_accounts.length > 0\n\t\t\t\t? {\n\t\t\t\t\t\tagentAccounts: args.agent_accounts.map((a) => ({\n\t\t\t\t\t\t\tprovider: a.provider,\n\t\t\t\t\t\t\taccountId: a.account_id,\n\t\t\t\t\t\t})),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t};\n\t\tconst result = await ctx.hoststack.services.createDevEnvironment(teamId, input);\n\t\treturn respond({\n\t\t\tsummary: `Created dev environment \"${result.service.name}\" (${result.service.publicId}) — deploying. Once live: open the Terminal tab, run \\`claude\\`, start the dev server on $PORT, and view it at https://${result.devUrl}.`,\n\t\t\tdata: {\n\t\t\t\tservice: shapeService(result.service),\n\t\t\t\tdevUrl: result.devUrl,\n\t\t\t\tdeployId: result.deployId,\n\t\t\t},\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'get_service',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Fetch a single service by ID with its current status AND its service_config row (resources, health-check tuning, scaling, restart policy).',\n\t\t'',\n\t\t'When to use: drilling into a service after list_services, checking deploy/runtime status, grabbing the repo+branch before triggering a deploy, or inspecting the health-check / autoscale knobs before tweaking them via update_service_config.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service (e.g. \"svc_abc123\").',\n\t\t'',\n\t\t'Returns: { service: Service, config: ServiceConfig } — service has type/status/runtime/repoUrl/branch/autoDeploy/region/plan/timestamps; config has memoryMb, cpuShares, diskSizeGb, port, protocol, healthCheckEnabled, healthCheckInterval, healthCheckTimeout, healthCheckGracePeriodSec, restartPolicy, preDeployCommand, min/maxInstances, scale thresholds.',\n\t\t'',\n\t\t'Example: get_service({ service_id: \"svc_abc\" }) → { service: { type: \"web\", status: \"running\", … }, config: { healthCheckGracePeriodSec: 120, … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId (e.g. svc_abc123).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\t// Bundle service + config so a single call answers both \"how is it\n\t\t// running?\" and \"how is it tuned?\". Previously callers had to follow\n\t\t// up with a separate read for any of the health-check / scaling /\n\t\t// resource knobs, which lived only on the service_config row.\n\t\tconst [serviceResponse, configResponse] = await Promise.all([\n\t\t\tctx.hoststack.services.get(teamId, args.service_id),\n\t\t\tctx.hoststack.services.getConfig(teamId, args.service_id),\n\t\t]);\n\t\tconst data = {\n\t\t\tservice: shapeService(serviceResponse.service),\n\t\t\tconfig: shape(configResponse.config),\n\t\t};\n\t\tconst status =\n\t\t\tdata.service && 'status' in data.service\n\t\t\t\t? (data.service as { status: string }).status\n\t\t\t\t: 'unknown';\n\t\treturn respond({ summary: `Service ${args.service_id} is ${status}.`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'get_service_metrics',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Fetch the latest CPU, memory, network, and request-rate metrics for a service.',\n\t\t'',\n\t\t'When to use: a service is reportedly slow, you suspect resource pressure, or you want a quick health snapshot before scaling. Returns a single point-in-time sample. For a time series — \"is memory growing?\", \"did CPU spike during that deploy?\" — use get_service_metrics_history instead.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t'',\n\t\t'Returns: { metrics: { cpu, memory, network, requests } } — values are normalised utilisation/throughput numbers.',\n\t\t'',\n\t\t'Example: get_service_metrics({ service_id: \"svc_abc\" }) → { metrics: { cpu: 0.42, memory: 0.71, … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.services.getMetrics(teamId, args.service_id);\n\t\tconst data = { metrics: shape(response.metrics) };\n\t\treturn respond({ summary: `Metrics snapshot for service ${args.service_id}.`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'get_service_metrics_history',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Fetch a metrics time series (CPU, memory, network, disk) for a service.',\n\t\t'',\n\t\t'When to use: answering \"is memory growing over the last hour?\", \"did CPU spike during deploy X?\", or \"what does normal look like for this service?\". Pairs well with get_deploy to align spikes against deploy times.',\n\t\t'',\n\t\t'Inputs (all optional — omit both for the trailing hour):',\n\t\t' - service_id: publicId of the service.',\n\t\t' - from: ISO-8601 lower bound OR relative offset like \"-15m\" / \"-2h\" / \"-7d\".',\n\t\t' - to: ISO-8601 upper bound (or relative offset). Defaults to now.',\n\t\t'',\n\t\t'Resolution: ≤7d → raw samples (~minute granularity), ≤30d → hourly pre-aggregates, >30d → daily. Up to ~500 points returned.',\n\t\t'',\n\t\t'Returns: { history: Array<{ timestamp, cpuPercent, memoryUsedMb, memoryLimitMb, networkRxBytes, networkTxBytes, diskUsedMb }> }.',\n\t\t'',\n\t\t'Example: get_service_metrics_history({ service_id: \"svc_abc\", from: \"-1h\" }) → 60-ish points for the last hour.',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tfrom: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe('ISO-8601 lower bound or relative offset (e.g. \"-1h\", \"-2d\").'),\n\t\tto: z.string().optional().describe('ISO-8601 upper bound; defaults to now.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\t// Translate the same `-Nm/h/d` relative shorthand we accept in logs\n\t\t// so callers don't have to learn a second convention. The metrics\n\t\t// history endpoint expects ISO timestamps server-side; we resolve\n\t\t// relative offsets here for symmetry with get_service_logs.\n\t\tconst opts: { from?: string; to?: string } = {};\n\t\tconst resolveRel = (raw: string): string => {\n\t\t\tconst rel = /^-(\\d+)(s|m|h|d)$/.exec(raw.trim());\n\t\t\tif (!rel) return raw;\n\t\t\tconst amount = Number.parseInt(rel[1] as string, 10);\n\t\t\tconst unit = rel[2] as 's' | 'm' | 'h' | 'd';\n\t\t\tconst ms =\n\t\t\t\tunit === 's'\n\t\t\t\t\t? amount * 1000\n\t\t\t\t\t: unit === 'm'\n\t\t\t\t\t\t? amount * 60_000\n\t\t\t\t\t\t: unit === 'h'\n\t\t\t\t\t\t\t? amount * 3_600_000\n\t\t\t\t\t\t\t: amount * 86_400_000;\n\t\t\treturn new Date(Date.now() - ms).toISOString();\n\t\t};\n\t\tif (args.from) opts.from = resolveRel(args.from);\n\t\tif (args.to) opts.to = resolveRel(args.to);\n\n\t\tconst response = await ctx.hoststack.services.getMetricsHistory(\n\t\t\tteamId,\n\t\t\targs.service_id,\n\t\t\topts,\n\t\t);\n\t\tconst points = Array.isArray(response.history) ? response.history.length : 0;\n\t\treturn respond({\n\t\t\tsummary: `Returned ${points} metric point${points === 1 ? '' : 's'} for service ${args.service_id}.`,\n\t\t\tdata: { history: response.history },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'update_service',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Rename a service. Only the human-readable name changes — the publicId is permanent.',\n\t\t'',\n\t\t'When to use: the user wants to relabel a service in the dashboard. For deeper config edits (build command, branch, scale, plan), use update_service_config.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - name: new name (1–60 chars).',\n\t\t'',\n\t\t'Returns: { service: Service }.',\n\t\t'',\n\t\t'Example: update_service({ service_id: \"svc_abc\", name: \"api-prod\" }) → { service: { name: \"api-prod\", … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tname: z.string().min(1).max(60).describe('New service name (1–60 chars).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.services.update(teamId, args.service_id, {\n\t\t\tname: args.name,\n\t\t});\n\t\tconst data = { service: shapeService(response.service) };\n\t\treturn respond({ summary: `Renamed service ${args.service_id} to \"${args.name}\".`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'update_service_config',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Update build/runtime configuration for a service. All fields optional — pass only what you want to change.',\n\t\t'',\n\t\t'When to use: the user wants to tweak how a service builds, runs, scales, or health-checks. Build/runtime fields (branch, install/build/start command, root, dockerfile) take effect on the next deploy — call trigger_deploy after if you need them applied immediately. Instance_count, resource and health-check changes rescale or rewire without a redeploy.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - install_command, build_command, start_command (optional): shell commands. Pass null to clear.',\n\t\t' - branch (optional): git branch to track.',\n\t\t' - root_directory (optional): build context root inside the repo.',\n\t\t' - dockerfile_path (optional): path to Dockerfile relative to root_directory. Pass null to clear.',\n\t\t' - auto_deploy (optional): boolean — auto-deploy on git push.',\n\t\t' - health_check_path (optional): HTTP path the platform GETs to verify liveness (e.g. \"/health\"). Pass null for TCP-only check.',\n\t\t' - health_check_enabled (optional): boolean — toggle health checking on/off.',\n\t\t' - health_check_interval (optional): integer 5–300 seconds — how often the check runs.',\n\t\t' - health_check_timeout (optional): integer 1–60 seconds — single-attempt timeout.',\n\t\t' - health_check_grace_period_sec (optional): integer 1–1800 seconds — startup tolerance before failures count. RAISE THIS (e.g. 180) when the agent reports \"Health check timed out\" on a cold-boot app (Bun + Vite SSR typically need 90–180s).',\n\t\t' - memory_mb (optional): integer 128–16384 — container memory cap.',\n\t\t' - cpu_shares (optional): integer 128–4096 — relative CPU weight.',\n\t\t' - disk_size_gb (optional): integer 1–100 — ephemeral disk cap.',\n\t\t' - port (optional): integer 1–65535 — container port the platform forwards traffic to.',\n\t\t' - protocol (optional): \"http\" | \"tcp\".',\n\t\t' - restart_policy (optional): \"always\" | \"on-failure\" | \"no\".',\n\t\t' - pre_deploy_command (optional): shell command run before the new release accepts traffic (typical use: migrations).',\n\t\t' - instance_count (optional): integer 1–50 — pin both min and max instances to this value.',\n\t\t' - min_instances, max_instances (optional): integers — autoscale bounds. Use instead of instance_count when you want a range.',\n\t\t' - scale_cpu_threshold, scale_memory_threshold (optional): integer 10–100 — autoscale trigger percentage.',\n\t\t' - log_filter_rules (optional): list of { pattern, action } rules applied to runtime logs at query time. Pattern matches the message by case-insensitive substring; action is \"drop\" (filter out) or \"downgrade\" (flip stderr → stdout so it stops looking like an error). Pass [] to clear all rules. Capped at 50 rules.',\n\t\t'',\n\t\t'Returns: { service?: Service, config?: ServiceConfig } — whichever rows were touched.',\n\t\t'',\n\t\t'Example: update_service_config({ service_id: \"svc_abc\", health_check_grace_period_sec: 180 }) → { config: { healthCheckGracePeriodSec: 180, … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tinstall_command: z\n\t\t\t.string()\n\t\t\t.nullable()\n\t\t\t.optional()\n\t\t\t.describe('Install shell command. Null clears.'),\n\t\tbuild_command: z\n\t\t\t.string()\n\t\t\t.nullable()\n\t\t\t.optional()\n\t\t\t.describe('Build shell command. Null clears.'),\n\t\tstart_command: z\n\t\t\t.string()\n\t\t\t.nullable()\n\t\t\t.optional()\n\t\t\t.describe('Start shell command. Null clears.'),\n\t\tbranch: z.string().optional().describe('Git branch to track.'),\n\t\troot_directory: z.string().optional().describe('Build context root.'),\n\t\tdockerfile_path: z\n\t\t\t.string()\n\t\t\t.nullable()\n\t\t\t.optional()\n\t\t\t.describe('Path to Dockerfile relative to root. Null clears.'),\n\t\tauto_deploy: z.boolean().optional().describe('Auto-deploy on push.'),\n\t\thealth_check_path: z\n\t\t\t.string()\n\t\t\t.nullable()\n\t\t\t.optional()\n\t\t\t.describe('HTTP health-check path (e.g. \"/health\"). Null = TCP-only check.'),\n\t\thealth_check_enabled: z.boolean().optional().describe('Toggle health checking on/off.'),\n\t\thealth_check_interval: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(5)\n\t\t\t.max(300)\n\t\t\t.optional()\n\t\t\t.describe('How often the check runs, in seconds (5–300).'),\n\t\thealth_check_timeout: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(1)\n\t\t\t.max(60)\n\t\t\t.optional()\n\t\t\t.describe('Single-attempt timeout in seconds (1–60).'),\n\t\thealth_check_grace_period_sec: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(1)\n\t\t\t.max(1800)\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t'Startup grace period in seconds (1–1800). Raise this if the app needs more time to boot before health checks start counting failures.',\n\t\t\t),\n\t\tmemory_mb: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(128)\n\t\t\t.max(16384)\n\t\t\t.optional()\n\t\t\t.describe('Container memory cap in MB (128–16384).'),\n\t\tcpu_shares: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(128)\n\t\t\t.max(4096)\n\t\t\t.optional()\n\t\t\t.describe('Relative CPU weight (128–4096).'),\n\t\tdisk_size_gb: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(1)\n\t\t\t.max(100)\n\t\t\t.optional()\n\t\t\t.describe('Ephemeral disk size in GB (1–100).'),\n\t\tport: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(1)\n\t\t\t.max(65535)\n\t\t\t.optional()\n\t\t\t.describe('Container port the platform forwards traffic to.'),\n\t\tprotocol: z.enum(['http', 'tcp']).optional().describe('Traffic protocol.'),\n\t\trestart_policy: z\n\t\t\t.enum(['always', 'on-failure', 'no'])\n\t\t\t.optional()\n\t\t\t.describe('Docker restart policy.'),\n\t\tpre_deploy_command: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe('Shell command run before the new release accepts traffic.'),\n\t\tinstance_count: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.positive()\n\t\t\t.max(50)\n\t\t\t.optional()\n\t\t\t.describe('Pin min and max instances to this value (1–50).'),\n\t\tmin_instances: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(0)\n\t\t\t.max(50)\n\t\t\t.optional()\n\t\t\t.describe('Autoscale lower bound. Use with max_instances for a range.'),\n\t\tmax_instances: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(1)\n\t\t\t.max(50)\n\t\t\t.optional()\n\t\t\t.describe('Autoscale upper bound. Use with min_instances for a range.'),\n\t\tscale_cpu_threshold: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(10)\n\t\t\t.max(100)\n\t\t\t.optional()\n\t\t\t.describe('Autoscale CPU trigger percentage (10–100).'),\n\t\tscale_memory_threshold: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(10)\n\t\t\t.max(100)\n\t\t\t.optional()\n\t\t\t.describe('Autoscale memory trigger percentage (10–100).'),\n\t\tlog_filter_rules: z\n\t\t\t.array(\n\t\t\t\tz.object({\n\t\t\t\t\tpattern: z.string().min(1).max(200),\n\t\t\t\t\taction: z.enum(['drop', 'downgrade']),\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.max(50)\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t'Runtime-log filter rules. Empty array [] clears all rules. Each pattern is case-insensitive substring match against the message.',\n\t\t\t),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\n\t\t// services-row fields (PATCH /services/:tid/:sid). Note: nullable\n\t\t// fields take `null` to clear, distinct from `undefined` which means\n\t\t// \"leave unchanged\" — passing `null` through to the underlying API\n\t\t// is what flips the column to NULL on the row.\n\t\tconst serviceUpdate: Record<string, unknown> = {};\n\t\tif (args.install_command !== undefined)\n\t\t\tserviceUpdate['installCommand'] = args.install_command;\n\t\tif (args.build_command !== undefined) serviceUpdate['buildCommand'] = args.build_command;\n\t\tif (args.start_command !== undefined) serviceUpdate['startCommand'] = args.start_command;\n\t\tif (args.dockerfile_path !== undefined)\n\t\t\tserviceUpdate['dockerfilePath'] = args.dockerfile_path;\n\t\tif (args.branch !== undefined) serviceUpdate['branch'] = args.branch;\n\t\tif (args.root_directory !== undefined) serviceUpdate['rootDirectory'] = args.root_directory;\n\t\tif (args.auto_deploy !== undefined) serviceUpdate['autoDeploy'] = args.auto_deploy;\n\t\tif (args.health_check_path !== undefined)\n\t\t\tserviceUpdate['healthCheckPath'] = args.health_check_path;\n\n\t\t// service_config-row fields (PATCH /services/:tid/:sid/config). The\n\t\t// schema expects min_instances/max_instances; \"pin to N\" means setting\n\t\t// both to the same value.\n\t\tconst configUpdate: Record<string, unknown> = {};\n\t\tif (args.health_check_enabled !== undefined)\n\t\t\tconfigUpdate['healthCheckEnabled'] = args.health_check_enabled;\n\t\tif (args.health_check_interval !== undefined)\n\t\t\tconfigUpdate['healthCheckInterval'] = args.health_check_interval;\n\t\tif (args.health_check_timeout !== undefined)\n\t\t\tconfigUpdate['healthCheckTimeout'] = args.health_check_timeout;\n\t\tif (args.health_check_grace_period_sec !== undefined)\n\t\t\tconfigUpdate['healthCheckGracePeriodSec'] = args.health_check_grace_period_sec;\n\t\tif (args.memory_mb !== undefined) configUpdate['memoryMb'] = args.memory_mb;\n\t\tif (args.cpu_shares !== undefined) configUpdate['cpuShares'] = args.cpu_shares;\n\t\tif (args.disk_size_gb !== undefined) configUpdate['diskSizeGb'] = args.disk_size_gb;\n\t\tif (args.port !== undefined) configUpdate['port'] = args.port;\n\t\tif (args.protocol !== undefined) configUpdate['protocol'] = args.protocol;\n\t\tif (args.restart_policy !== undefined) configUpdate['restartPolicy'] = args.restart_policy;\n\t\tif (args.pre_deploy_command !== undefined)\n\t\t\tconfigUpdate['preDeployCommand'] = args.pre_deploy_command;\n\t\tif (args.instance_count !== undefined) {\n\t\t\tconfigUpdate['minInstances'] = args.instance_count;\n\t\t\tconfigUpdate['maxInstances'] = args.instance_count;\n\t\t}\n\t\tif (args.min_instances !== undefined) configUpdate['minInstances'] = args.min_instances;\n\t\tif (args.max_instances !== undefined) configUpdate['maxInstances'] = args.max_instances;\n\t\tif (args.scale_cpu_threshold !== undefined)\n\t\t\tconfigUpdate['scaleCpuThreshold'] = args.scale_cpu_threshold;\n\t\tif (args.scale_memory_threshold !== undefined)\n\t\t\tconfigUpdate['scaleMemoryThreshold'] = args.scale_memory_threshold;\n\t\tif (args.log_filter_rules !== undefined) {\n\t\t\t// Empty array is a meaningful value (clears all rules);\n\t\t\t// undefined leaves rules unchanged. Don't short-circuit.\n\t\t\tconfigUpdate['logFilterRules'] = args.log_filter_rules;\n\t\t}\n\n\t\tif (Object.keys(serviceUpdate).length === 0 && Object.keys(configUpdate).length === 0) {\n\t\t\treturn respond({ summary: 'No fields to update.', data: {} });\n\t\t}\n\n\t\tconst data: Record<string, unknown> = {};\n\t\tconst touchedFields: string[] = [];\n\t\tif (Object.keys(serviceUpdate).length > 0) {\n\t\t\tconst serviceResponse = await ctx.hoststack.services.update(\n\t\t\t\tteamId,\n\t\t\t\targs.service_id,\n\t\t\t\tserviceUpdate,\n\t\t\t);\n\t\t\tdata['service'] = shape(serviceResponse.service);\n\t\t\ttouchedFields.push(...Object.keys(serviceUpdate));\n\t\t}\n\t\tif (Object.keys(configUpdate).length > 0) {\n\t\t\tconst configResponse = await ctx.hoststack.services.updateConfig(\n\t\t\t\tteamId,\n\t\t\t\targs.service_id,\n\t\t\t\tconfigUpdate,\n\t\t\t);\n\t\t\tdata['config'] = shape(configResponse.config);\n\t\t\ttouchedFields.push(...Object.keys(configUpdate));\n\t\t}\n\n\t\treturn respond({\n\t\t\tsummary: `Updated ${touchedFields.join(', ')} on service ${args.service_id}.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'suspend_service',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Suspend a service: stop all running instances and pause auto-deploys. The service stays configured and can be resumed later with resume_service.',\n\t\t'',\n\t\t'When to use: the user wants to temporarily stop traffic and billing without deleting the service (for example: dev environment overnight, debugging).',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t'',\n\t\t'Returns: { ok: true }.',\n\t\t'',\n\t\t'Example: suspend_service({ service_id: \"svc_dev\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.services.suspend(teamId, args.service_id);\n\t\treturn respond({ summary: `Suspended service ${args.service_id}.`, data: { ok: true } });\n\t},\n});\n\ndefineTool({\n\tname: 'resume_service',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Resume a previously suspended service: start instances back up and re-enable auto-deploys.',\n\t\t'',\n\t\t'When to use: the user wants to bring a suspended service back online. Pair with suspend_service.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t'',\n\t\t'Returns: { ok: true }.',\n\t\t'',\n\t\t'Example: resume_service({ service_id: \"svc_dev\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.services.resume(teamId, args.service_id);\n\t\treturn respond({ summary: `Resumed service ${args.service_id}.`, data: { ok: true } });\n\t},\n});\n\ndefineTool({\n\tname: 'get_service_logs',\n\tcategory: 'logs',\n\tdescription: [\n\t\t\"Fetch a snapshot of the running container's recent runtime logs (stdout/stderr). For *deploy* logs (build output), use get_deploy_logs instead.\",\n\t\t'',\n\t\t'When to use: a service is misbehaving in production and you need to read what it is currently logging. The tool returns a snapshot — there is no streaming over MCP. Re-call to get newer entries.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - lines (optional): tail size (default 200, max 1000).',\n\t\t' - since/until (optional): ISO-8601 timestamp OR a relative offset like \"-5m\", \"-1h\", \"-2d\".',\n\t\t' - stream (optional): \"stdout\" | \"stderr\". Omit to combine.',\n\t\t' - level (optional): real log level — trace/debug/info/warn/error/fatal. For structured JSON logs (pino, bunyan, OpenTelemetry severity) this filters on the parsed inner level field. For plain text logs it falls back to a stream-alias hint (info/debug → stdout, warn/error/fatal → stderr).',\n\t\t' - search (optional): case-insensitive substring grep, ≤100 chars.',\n\t\t' - count_only (optional): when true, returns { count } only — much cheaper for \"how many error lines in last 5m\" polling.',\n\t\t'',\n\t\t'Returns: { logs: LogEntry[] | string } when count_only is false. Each entry has { timestamp, level?, stream, message }. `level` is the parsed inner level when the message is a structured JSON envelope (pino numeric or string), and undefined for plain-text logs. `stream` is always one of stdout/stderr. Or { count: number } when count_only is true.',\n\t\t'',\n\t\t'Example: get_service_logs({ service_id: \"svc_abc\", search: \"OOM\", since: \"-15m\" }) → { logs: [...] }.',\n\t\t'',\n\t\t'More examples:',\n\t\t' - Last 50 stderr lines from the past hour: get_service_logs({ service_id: \"svc_abc\", lines: 50, stream: \"stderr\", since: \"-1h\" })',\n\t\t' - Just count error lines without fetching them: get_service_logs({ service_id: \"svc_abc\", level: \"error\", since: \"-5m\", count_only: true }) → { count: 47 }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tlines: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.positive()\n\t\t\t.max(1000)\n\t\t\t.optional()\n\t\t\t.describe('Tail size; default 200, hard cap 1000.'),\n\t\tsince: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe('ISO-8601 timestamp or relative offset (e.g. \"-5m\", \"-1h\").'),\n\t\tuntil: z.string().optional().describe('ISO-8601 timestamp or relative offset upper bound.'),\n\t\tstream: z.enum(['stdout', 'stderr']).optional().describe('Restrict to one stream.'),\n\t\tlevel: z\n\t\t\t.enum(['stdout', 'stderr', 'trace', 'debug', 'info', 'warn', 'error', 'fatal'])\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t'Filter by structured JSON log level (pino/bunyan/severity). Falls back to a stream-alias hint for plain-text logs (info/debug→stdout, warn/error/fatal→stderr).',\n\t\t\t),\n\t\tsearch: z.string().max(100).optional().describe('Case-insensitive substring filter.'),\n\t\tcount_only: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe('When true, return only { count } — skips the log payload.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst opts: {\n\t\t\tlines?: number;\n\t\t\tsince?: string;\n\t\t\tuntil?: string;\n\t\t\tstream?: 'stdout' | 'stderr';\n\t\t\tlevel?: 'stdout' | 'stderr' | 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';\n\t\t\tsearch?: string;\n\t\t\tcountOnly?: boolean;\n\t\t} = {\n\t\t\tlines: args.lines ?? 200,\n\t\t};\n\t\tif (args.since) opts.since = args.since;\n\t\tif (args.until) opts.until = args.until;\n\t\tif (args.stream) opts.stream = args.stream;\n\t\tif (args.level) opts.level = args.level;\n\t\tif (args.search) opts.search = args.search;\n\t\tif (args.count_only) opts.countOnly = args.count_only;\n\n\t\tconst response = await ctx.hoststack.services.getRuntimeLogs(teamId, args.service_id, opts);\n\t\tif ('count' in response) {\n\t\t\treturn respond({\n\t\t\t\tsummary: `${response.count} matching log line${response.count === 1 ? '' : 's'} for service ${args.service_id}.`,\n\t\t\t\tdata: { count: response.count },\n\t\t\t});\n\t\t}\n\t\tconst count = Array.isArray(response.logs)\n\t\t\t? response.logs.length\n\t\t\t: typeof response.logs === 'string'\n\t\t\t\t? response.logs.split('\\n').length\n\t\t\t\t: 0;\n\t\treturn respond({\n\t\t\tsummary: `Fetched ${count} log line${count === 1 ? '' : 's'} for service ${args.service_id}.`,\n\t\t\tdata: { logs: response.logs },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'get_service_logs_bulk',\n\tcategory: 'logs',\n\tdescription: [\n\t\t'Fetch runtime logs for multiple services in parallel and return one response keyed by service_id. Single round-trip from the MCP client perspective.',\n\t\t'',\n\t\t'When to use: investigating something that spans a project — \"what does every service in the auth-fleet say about the OOM at 14:00?\", \"did anything log an error in the last 5 minutes across these 4 services?\". Pair with list_services (filter by project/status) to get the service_ids list first.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_ids: list of service publicIds (svc_…). Hard cap 10 to bound work — for larger fleets, partition the call.',\n\t\t' - lines_per_service (optional): tail size per service (default 100, max 500). Smaller default than get_service_logs since you are fanning out.',\n\t\t' - since/until (optional): same shape as get_service_logs (ISO-8601 or \"-5m\", \"-1h\").',\n\t\t' - stream (optional): \"stdout\" | \"stderr\".',\n\t\t' - level (optional): structured-log level filter (trace/debug/info/warn/error/fatal).',\n\t\t' - search (optional): case-insensitive substring filter applied to every service.',\n\t\t' - count_only (optional): when true, return { results: { [service_id]: { count } } } — much cheaper for \"how many error lines per service in the last 5m\" surveys.',\n\t\t'',\n\t\t'Returns: { results: { [service_id]: { logs?, count?, error? } } } — per-service result, with `error` populated when one service failed (the rest still succeed).',\n\t\t'',\n\t\t'Example: get_service_logs_bulk({ service_ids: [\"svc_api\", \"svc_worker\"], level: \"error\", since: \"-15m\", count_only: true }) → { results: { svc_api: { count: 0 }, svc_worker: { count: 12 } } }.',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_ids: z\n\t\t\t.array(z.string())\n\t\t\t.min(1)\n\t\t\t.max(10)\n\t\t\t.describe('Service publicIds (1–10). Hard cap 10 to bound parallel work.'),\n\t\tlines_per_service: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.positive()\n\t\t\t.max(500)\n\t\t\t.optional()\n\t\t\t.describe('Tail size per service; default 100, hard cap 500.'),\n\t\tsince: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe('ISO-8601 timestamp or relative offset (e.g. \"-5m\", \"-1h\").'),\n\t\tuntil: z.string().optional().describe('ISO-8601 timestamp or relative offset upper bound.'),\n\t\tstream: z.enum(['stdout', 'stderr']).optional().describe('Restrict to one stream.'),\n\t\tlevel: z\n\t\t\t.enum(['stdout', 'stderr', 'trace', 'debug', 'info', 'warn', 'error', 'fatal'])\n\t\t\t.optional()\n\t\t\t.describe('Structured log level filter (same as get_service_logs).'),\n\t\tsearch: z.string().max(100).optional().describe('Case-insensitive substring filter.'),\n\t\tcount_only: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe('When true, return only counts per service — skips the log payload.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst linesPerService = args.lines_per_service ?? 100;\n\n\t\t// Build a single options object reused across all fan-outs so we\n\t\t// don't reconstruct identical params in a loop.\n\t\tconst baseOpts: {\n\t\t\tlines: number;\n\t\t\tsince?: string;\n\t\t\tuntil?: string;\n\t\t\tstream?: 'stdout' | 'stderr';\n\t\t\tlevel?: 'stdout' | 'stderr' | 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';\n\t\t\tsearch?: string;\n\t\t\tcountOnly?: boolean;\n\t\t} = { lines: linesPerService };\n\t\tif (args.since) baseOpts.since = args.since;\n\t\tif (args.until) baseOpts.until = args.until;\n\t\tif (args.stream) baseOpts.stream = args.stream;\n\t\tif (args.level) baseOpts.level = args.level;\n\t\tif (args.search) baseOpts.search = args.search;\n\t\tif (args.count_only) baseOpts.countOnly = args.count_only;\n\n\t\t// Promise.allSettled so one failing service (e.g. deleted between\n\t\t// list_services and this call) doesn't void the rest.\n\t\tconst settled = await Promise.allSettled(\n\t\t\targs.service_ids.map(async (sid) => {\n\t\t\t\tconst response = await ctx.hoststack.services.getRuntimeLogs(teamId, sid, baseOpts);\n\t\t\t\treturn { sid, response };\n\t\t\t}),\n\t\t);\n\n\t\tconst results: Record<string, unknown> = {};\n\t\tlet okCount = 0;\n\t\tlet errorCount = 0;\n\t\tfor (let i = 0; i < settled.length; i += 1) {\n\t\t\tconst outcome = settled[i] as PromiseSettledResult<{\n\t\t\t\tsid: string;\n\t\t\t\tresponse: { logs?: unknown; count?: number };\n\t\t\t}>;\n\t\t\tconst sid = args.service_ids[i] as string;\n\t\t\tif (outcome.status === 'fulfilled') {\n\t\t\t\tconst { response } = outcome.value;\n\t\t\t\tif ('count' in response) {\n\t\t\t\t\tresults[sid] = { count: response.count };\n\t\t\t\t} else {\n\t\t\t\t\tresults[sid] = { logs: response.logs };\n\t\t\t\t}\n\t\t\t\tokCount += 1;\n\t\t\t} else {\n\t\t\t\tconst reason = outcome.reason as { message?: string } | string;\n\t\t\t\tresults[sid] = {\n\t\t\t\t\terror:\n\t\t\t\t\t\ttypeof reason === 'string' ? reason : (reason?.message ?? 'Unknown error'),\n\t\t\t\t};\n\t\t\t\terrorCount += 1;\n\t\t\t}\n\t\t}\n\n\t\tconst summary =\n\t\t\terrorCount === 0\n\t\t\t\t? `Fetched logs from ${okCount} service${okCount === 1 ? '' : 's'}.`\n\t\t\t\t: `Fetched logs from ${okCount} of ${args.service_ids.length} service${args.service_ids.length === 1 ? '' : 's'} (${errorCount} failed — see per-service .error field).`;\n\t\treturn respond({ summary, data: { results } });\n\t},\n});\n","import { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond } from '../lib/respond.js';\nimport { shape, shapeList, shapeVolume } from '../lib/shape.js';\n\ndefineTool({\n\tname: 'list_volumes',\n\tcategory: 'volumes',\n\tdescription: [\n\t\t'List persistent disks attached to a service. Volumes mount writable storage into the container at the path you choose, surviving redeploys and restarts.',\n\t\t'',\n\t\t'When to use: auditing what disks are attached, checking sizes before adding more, or confirming a volume took effect after creation. Note: storage is metered for billing — use this to spot oversized disks.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t'',\n\t\t'Returns: { items: Volume[] } — each entry has id, publicId, name, mountPath, sizeGb, status (pending|active|deleting), createdAt, updatedAt.',\n\t\t'',\n\t\t'Example: list_volumes({ service_id: \"svc_abc\" }) → { items: [{ name: \"data\", mountPath: \"/var/data\", sizeGb: 10, status: \"active\" }] }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId (e.g. svc_abc123).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.volumes.list(teamId, args.service_id);\n\t\tconst data = shapeList(response, 'volumes', shapeVolume);\n\t\tconst summary =\n\t\t\tdata.items.length === 0\n\t\t\t\t? `No volumes attached to service ${args.service_id}.`\n\t\t\t\t: `Found ${data.items.length} volume${data.items.length === 1 ? '' : 's'} on service ${args.service_id}.`;\n\t\treturn respond({ summary, data });\n\t},\n});\n\ndefineTool({\n\tname: 'create_volume',\n\tcategory: 'volumes',\n\tdescription: [\n\t\t'Attach a new persistent disk to a service. The disk gets provisioned on the host and bind-mounted into the container at `mount_path` on the next deploy. Use this when an app needs writable persistent storage — uploads, caches, SQLite databases, anything that must survive container restarts.',\n\t\t'',\n\t\t'When to use: the user mentions storing files, uploads, or any data that needs to outlive a container restart. For purely ephemeral scratch space, point the app at /tmp instead (already tmpfs-mounted, free, no provisioning needed) — see HOSTSTACK_TMP_DIR.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service to attach to.',\n\t\t' - name: lowercase alphanumeric + hyphens, ≤64 chars (used as the docker volume identifier — change with care once data is written).',\n\t\t' - mount_path: in-container absolute path (e.g. \"/var/data\").',\n\t\t' - size_gb: optional, 1–100, default 1. Counts against your plan storage quota and is metered for billing.',\n\t\t'',\n\t\t'Returns: { volume: Volume } — the created record.',\n\t\t'',\n\t\t'Example: create_volume({ service_id: \"svc_abc\", name: \"data\", mount_path: \"/var/data\", size_gb: 10 }) → { volume: { name: \"data\", mountPath: \"/var/data\", sizeGb: 10, status: \"active\" } }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tname: z\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(64)\n\t\t\t.regex(/^[a-z0-9-]+$/)\n\t\t\t.describe('Volume name (lowercase alphanumeric + hyphens).'),\n\t\tmount_path: z\n\t\t\t.string()\n\t\t\t.startsWith('/')\n\t\t\t.max(500)\n\t\t\t.describe('In-container mount path (absolute).'),\n\t\tsize_gb: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(1)\n\t\t\t.max(100)\n\t\t\t.optional()\n\t\t\t.describe('Disk size in GB (default 1, max 100).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst input: { name: string; mountPath: string; sizeGb?: number } = {\n\t\t\tname: args.name,\n\t\t\tmountPath: args.mount_path,\n\t\t};\n\t\tif (args.size_gb !== undefined) input.sizeGb = args.size_gb;\n\t\tconst response = await ctx.hoststack.volumes.create(teamId, args.service_id, input);\n\t\tconst data = { volume: shape(response.volume) };\n\t\treturn respond({\n\t\t\tsummary: `Attached volume \"${args.name}\" (${args.size_gb ?? 1}GB) at ${args.mount_path} on service ${args.service_id}.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'update_volume',\n\tcategory: 'volumes',\n\tdescription: [\n\t\t\"Update a volume's mountPath or sizeGb. Resizes take effect on the next deploy; shrinking is rejected at the storage layer (filesystems can't safely shrink under live data).\",\n\t\t'',\n\t\t'When to use: the user wants to grow the disk for an existing volume, or move where it mounts inside the container.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - volume_id: publicId of the volume to update.',\n\t\t' - mount_path (optional): new in-container mount path.',\n\t\t' - size_gb (optional): new size in GB (must be ≥ current).',\n\t\t'',\n\t\t'Returns: { volume: Volume } — the updated record.',\n\t\t'',\n\t\t'Example: update_volume({ service_id: \"svc_abc\", volume_id: \"vol_xyz\", size_gb: 20 }) → { volume: { sizeGb: 20, … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tvolume_id: z.string().describe('Volume publicId (e.g. vol_…).'),\n\t\tmount_path: z.string().startsWith('/').max(500).optional().describe('New mount path.'),\n\t\tsize_gb: z.number().int().min(1).max(100).optional().describe('New size in GB.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst input: { mountPath?: string; sizeGb?: number } = {};\n\t\tif (args.mount_path !== undefined) input.mountPath = args.mount_path;\n\t\tif (args.size_gb !== undefined) input.sizeGb = args.size_gb;\n\t\tif (Object.keys(input).length === 0) {\n\t\t\treturn respond({ summary: 'No fields to update.', data: {} });\n\t\t}\n\t\tconst response = await ctx.hoststack.volumes.update(\n\t\t\tteamId,\n\t\t\targs.service_id,\n\t\t\targs.volume_id,\n\t\t\tinput,\n\t\t);\n\t\tconst data = { volume: shape(response.volume) };\n\t\tconst fields = Object.keys(input).join(', ');\n\t\treturn respond({ summary: `Updated ${fields} on volume ${args.volume_id}.`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'delete_volume',\n\tcategory: 'volumes',\n\tdescription: [\n\t\t'Detach and deprovision a volume. The underlying disk is destroyed — back up any data first. Async: marks the row deleting, the host agent finalises removal once it acks. A periodic reaper retries if the agent was offline at delete time.',\n\t\t'',\n\t\t\"When to use: the user explicitly says to remove a volume, or you're cleaning up after retiring a service. Confirm before calling on production data.\",\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - volume_id: publicId of the volume.',\n\t\t'',\n\t\t'Returns: { ok: true }.',\n\t\t'',\n\t\t'Example: delete_volume({ service_id: \"svc_abc\", volume_id: \"vol_xyz\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tvolume_id: z.string().describe('Volume publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.volumes.delete(teamId, args.service_id, args.volume_id);\n\t\treturn respond({\n\t\t\tsummary: `Detached volume ${args.volume_id} from service ${args.service_id} (deprovisioning).`,\n\t\t\tdata: { ok: true },\n\t\t});\n\t},\n});\n"],"mappings":"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","names":["z","z","z","z","z","z","z","z","z","z","z","zones","z","z","z","z","z","response","data","z","z","z","z","z","z","z","z","z","z"]}
1
+ {"version":3,"sources":["../src/server-factory.ts","../src/version.ts","../src/api-client.ts","../src/prompts/registry.ts","../src/resources/registry.ts","../src/registry.ts","../src/prompts/deploy-prompts.ts","../src/lib/shape.ts","../src/resources/hoststack-resources.ts","../src/tools/activity-log.ts","../src/lib/respond.ts","../src/tools/alerts.ts","../src/tools/cron.ts","../src/tools/databases.ts","../src/tools/deploys.ts","../src/tools/dns-records.ts","../src/tools/domains.ts","../src/tools/env-vars.ts","../src/tools/environments.ts","../src/tools/github.ts","../src/tools/meta.ts","../src/tools/notifications.ts","../src/tools/projects.ts","../src/tools/resource-links.ts","../src/tools/services.ts","../src/tools/volumes.ts"],"sourcesContent":["import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { HostStack } from '@hoststack.dev/sdk';\n\nimport { ApiClient } from './api-client.js';\nimport { attachPrompts } from './prompts/registry.js';\nimport { attachResources } from './resources/registry.js';\nimport { attachTools, type ToolCallSink, type ToolContext } from './registry.js';\nimport { MCP_VERSION } from './version.js';\n\nexport type { ToolCallEvent, ToolCallSink } from './registry.js';\n\n// Importing each tool/prompt/resource module runs its top-level define*()\n// calls and populates the shared registries. ESM caches modules, so each\n// registry is built exactly once per process.\nimport './prompts/deploy-prompts.js';\nimport './resources/hoststack-resources.js';\nimport './tools/activity-log.js';\nimport './tools/alerts.js';\nimport './tools/cron.js';\nimport './tools/databases.js';\nimport './tools/deploys.js';\nimport './tools/dns-records.js';\nimport './tools/domains.js';\nimport './tools/env-vars.js';\nimport './tools/environments.js';\nimport './tools/github.js';\nimport './tools/meta.js';\nimport './tools/notifications.js';\nimport './tools/projects.js';\nimport './tools/resource-links.js';\nimport './tools/services.js';\nimport './tools/volumes.js';\n\nexport interface CreateServerOptions {\n\t/** HostStack API key (hs_live_… or hs_test_…). Required. */\n\tapiKey: string;\n\t/** Base URL for the HostStack API. Defaults to https://hoststack.dev */\n\tbaseUrl?: string;\n\t/**\n\t * Server identity advertised in the MCP `initialize` response. Defaults\n\t * to `{ name: \"hoststack\", version: PACKAGE_VERSION }`.\n\t */\n\tserverInfo?: { name: string; version: string };\n\t/**\n\t * Optional telemetry sink invoked once per tool call (success or failure).\n\t * Runs on the microtask queue; sink errors are swallowed so tool execution\n\t * never blocks on telemetry.\n\t */\n\tonToolCall?: ToolCallSink;\n}\n\nexport const PACKAGE_NAME = 'hoststack';\n// Injected from package.json at build time (see tsup.config.ts `define`) so the\n// MCP `initialize` handshake advertises the real published version.\nexport const PACKAGE_VERSION = MCP_VERSION;\n\ninterface MeResponse {\n\tuser: { id: number };\n\tteam?: { id: number };\n}\n\n/**\n * Build a fully-wired MCP server. Used by both the stdio CLI entry-point and\n * the HTTP transport mounted by the API server. A new server (and its\n * underlying SDK + ApiClient) is created per call, so the HTTP transport can\n * scope each connection to a single API key without cross-contamination.\n */\nexport function createMcpServer(options: CreateServerOptions): McpServer {\n\tconst baseUrl = (options.baseUrl ?? 'https://hoststack.dev').replace(/\\/$/, '');\n\tconst hoststack = new HostStack({ apiKey: options.apiKey, baseUrl });\n\tconst api = new ApiClient(options.apiKey, baseUrl);\n\n\tconst server = new McpServer({\n\t\tname: options.serverInfo?.name ?? PACKAGE_NAME,\n\t\tversion: options.serverInfo?.version ?? PACKAGE_VERSION,\n\t});\n\n\t// Cache the team lookup. The first tool call pays one /auth/me round-trip;\n\t// every subsequent call reuses the cached promise. We store the in-flight\n\t// promise (not the resolved value) so concurrent first-calls don't fan out\n\t// into duplicate /auth/me requests.\n\tlet teamIdPromise: Promise<number> | null = null;\n\tconst resolveTeamId = (): Promise<number> => {\n\t\tif (!teamIdPromise) {\n\t\t\tteamIdPromise = api.get<MeResponse>('/api/auth/me').then((me) => {\n\t\t\t\tif (!me.team?.id) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t'No team bound to API key. Generate a team-scoped key in the dashboard.',\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn me.team.id;\n\t\t\t});\n\t\t\t// If the lookup fails, clear the cache so a retry can succeed once\n\t\t\t// the user fixes their key. Without this, every subsequent tool\n\t\t\t// call would re-throw the same cached rejection.\n\t\t\tteamIdPromise.catch(() => {\n\t\t\t\tteamIdPromise = null;\n\t\t\t});\n\t\t}\n\t\treturn teamIdPromise;\n\t};\n\n\tconst ctx: ToolContext = { hoststack, api, resolveTeamId };\n\tattachTools(server, ctx, options.onToolCall);\n\tattachPrompts(server, ctx);\n\tattachResources(server, ctx);\n\n\treturn server;\n}\n","/**\n * Package version, injected at build time by tsup's `define`\n * (`__MCP_VERSION__` ← package.json `version`). The `declare` keeps the source\n * typecheckable without a build; the `?? '0.0.0-dev'` fallback keeps the\n * un-bundled source (tests, ts-node) working when the define is absent.\n */\ndeclare const __MCP_VERSION__: string | undefined;\n\nexport const MCP_VERSION: string =\n\ttypeof __MCP_VERSION__ === 'string' ? __MCP_VERSION__ : '0.0.0-dev';\n\n/** User-Agent sent on every MCP-originated request, e.g. `hoststack-mcp/0.13.1`. */\nexport const USER_AGENT = `hoststack-mcp/${MCP_VERSION}`;\n","import { USER_AGENT } from './version.js';\n\n/**\n * Lightweight API client for HostStack endpoints not yet covered by the SDK\n * (logs snapshots, activity log, runtime metrics, /me lookup). Uses the same\n * auth and base URL as the SDK instance.\n */\nexport class ApiClient {\n\tconstructor(\n\t\tprivate readonly apiKey: string,\n\t\tprivate readonly baseUrl: string,\n\t) {}\n\n\tprivate get headers(): Record<string, string> {\n\t\treturn {\n\t\t\tAuthorization: `Bearer ${this.apiKey}`,\n\t\t\t'Content-Type': 'application/json',\n\t\t\t'User-Agent': USER_AGENT,\n\t\t};\n\t}\n\n\tasync get<T>(path: string, params?: Record<string, string | number | undefined>): Promise<T> {\n\t\tconst url = new URL(`${this.baseUrl}${path}`);\n\t\tif (params) {\n\t\t\tfor (const [key, value] of Object.entries(params)) {\n\t\t\t\tif (value !== undefined) url.searchParams.set(key, String(value));\n\t\t\t}\n\t\t}\n\t\tconst res = await fetch(url.toString(), { headers: this.headers });\n\t\treturn this.handle<T>(res);\n\t}\n\n\tasync post<T>(path: string, body?: unknown): Promise<T> {\n\t\tconst init: RequestInit = {\n\t\t\tmethod: 'POST',\n\t\t\theaders: this.headers,\n\t\t};\n\t\tif (body !== undefined) init.body = JSON.stringify(body);\n\t\tconst res = await fetch(`${this.baseUrl}${path}`, init);\n\t\treturn this.handle<T>(res);\n\t}\n\n\tasync patch<T>(path: string, body: unknown): Promise<T> {\n\t\tconst res = await fetch(`${this.baseUrl}${path}`, {\n\t\t\tmethod: 'PATCH',\n\t\t\theaders: this.headers,\n\t\t\tbody: JSON.stringify(body),\n\t\t});\n\t\treturn this.handle<T>(res);\n\t}\n\n\tasync put<T>(path: string, body: unknown): Promise<T> {\n\t\tconst res = await fetch(`${this.baseUrl}${path}`, {\n\t\t\tmethod: 'PUT',\n\t\t\theaders: this.headers,\n\t\t\tbody: JSON.stringify(body),\n\t\t});\n\t\treturn this.handle<T>(res);\n\t}\n\n\tasync delete<T>(path: string): Promise<T> {\n\t\tconst res = await fetch(`${this.baseUrl}${path}`, {\n\t\t\tmethod: 'DELETE',\n\t\t\theaders: this.headers,\n\t\t});\n\t\treturn this.handle<T>(res);\n\t}\n\n\tprivate async handle<T>(res: Response): Promise<T> {\n\t\tif (!res.ok) {\n\t\t\tconst body = (await res.json().catch(() => ({ error: res.statusText }))) as unknown;\n\t\t\tthrow new Error(formatApiError(body, res.status));\n\t\t}\n\t\tif (res.status === 204) {\n\t\t\treturn undefined as T;\n\t\t}\n\t\treturn res.json() as Promise<T>;\n\t}\n}\n\n/**\n * Turn an API error body into something an operator can act on.\n *\n * The service layer returns `{ error: \"<string>\" }`, but a request rejected by\n * `zValidator` returns `{ success: false, error: <ZodError> }` — an OBJECT.\n * The old code typed `error` as `string | undefined` and passed it straight to\n * `new Error(...)`, which stringified the ZodError to the literal text\n * `[object Object]`. Every schema rejection therefore surfaced with no\n * indication of which field was wrong or why: `create_volume({ size_gb: 2 })`\n * reported `[object Object]` when the real answer was \"size_gb must be at\n * least 10\". Flatten the issues into `field: message` instead.\n */\nexport function formatApiError(body: unknown, status: number): string {\n\tconst fallback = `API error: ${status}`;\n\tif (!body || typeof body !== 'object') return fallback;\n\tconst err = (body as { error?: unknown }).error;\n\n\t// A string error is the service layer's `{ error: \"...\" }` shape. Blank or\n\t// whitespace-only carries no information, so fall through to the status\n\t// rather than quoting an empty string back at the caller.\n\tif (typeof err === 'string') return err.trim() ? err : fallback;\n\n\t// Zod rejection: `issues` is either on the error object or (older shapes)\n\t// the error IS the issue array.\n\tconst issues = Array.isArray(err)\n\t\t? err\n\t\t: err && typeof err === 'object' && Array.isArray((err as { issues?: unknown }).issues)\n\t\t\t? (err as { issues: unknown[] }).issues\n\t\t\t: null;\n\n\tif (issues && issues.length > 0) {\n\t\tconst rendered = issues\n\t\t\t.map((issue) => {\n\t\t\t\tif (!issue || typeof issue !== 'object') return String(issue);\n\t\t\t\tconst { path, message } = issue as { path?: unknown; message?: unknown };\n\t\t\t\tconst field = Array.isArray(path) && path.length > 0 ? path.join('.') : null;\n\t\t\t\tconst text = typeof message === 'string' ? message : 'invalid value';\n\t\t\t\treturn field ? `${field}: ${text}` : text;\n\t\t\t})\n\t\t\t.join('; ');\n\t\treturn `Invalid request — ${rendered}`;\n\t}\n\n\t// Anything else structured: show it rather than collapsing it to\n\t// `[object Object]`.\n\tif (err !== undefined) {\n\t\ttry {\n\t\t\treturn `${fallback}: ${JSON.stringify(err)}`;\n\t\t} catch {\n\t\t\treturn fallback;\n\t\t}\n\t}\n\treturn fallback;\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { GetPromptResult } from '@modelcontextprotocol/sdk/types.js';\nimport type { HostStack } from '@hoststack.dev/sdk';\nimport type { ZodRawShape, z } from 'zod';\n\nimport type { ApiClient } from '../api-client.js';\n\nexport interface PromptContext {\n\thoststack: HostStack;\n\tapi: ApiClient;\n\tresolveTeamId(): Promise<number>;\n}\n\ninterface InternalPromptDefinition {\n\tname: string;\n\tdescription: string;\n\targs: ZodRawShape;\n\thandler: (\n\t\targs: Record<string, string | undefined>,\n\t\tctx: PromptContext,\n\t) => Promise<GetPromptResult>;\n}\n\nexport type PromptDefinition = Readonly<InternalPromptDefinition>;\n\nconst prompts: InternalPromptDefinition[] = [];\n\n/**\n * Register a single prompt. The generic over `TArgs` lets the handler receive\n * precisely-typed args while the registry stores the widened shape — same\n * trick as `defineTool` to keep the compiler's instantiation budget in check.\n */\nexport function definePrompt<TArgs extends ZodRawShape>(def: {\n\tname: string;\n\tdescription: string;\n\targs: TArgs;\n\thandler: (args: z.infer<z.ZodObject<TArgs>>, ctx: PromptContext) => Promise<GetPromptResult>;\n}): void {\n\tprompts.push({\n\t\tname: def.name,\n\t\tdescription: def.description,\n\t\targs: def.args,\n\t\thandler: def.handler as InternalPromptDefinition['handler'],\n\t});\n}\n\nexport function listPromptDefinitions(): ReadonlyArray<PromptDefinition> {\n\treturn prompts;\n}\n\n/** Iterate the registry and wire each prompt into the MCP server. */\nexport function attachPrompts(server: McpServer, ctx: PromptContext): void {\n\ttype PromptMethod = (\n\t\tname: string,\n\t\tdescription: string,\n\t\targsSchema: ZodRawShape,\n\t\tcb: (args: Record<string, string | undefined>) => Promise<GetPromptResult>,\n\t) => unknown;\n\n\tconst register = server.prompt.bind(server) as unknown as PromptMethod;\n\n\tfor (const def of prompts) {\n\t\tregister(def.name, def.description, def.args, (args) => def.handler(args, ctx));\n\t}\n}\n\n/**\n * Helper to build a single user-role text message — the most common shape for\n * these prompts (we're guiding the agent, not modeling assistant responses).\n */\nexport function userMessage(text: string): GetPromptResult['messages'][number] {\n\treturn { role: 'user', content: { type: 'text', text } };\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ReadResourceResult } from '@modelcontextprotocol/sdk/types.js';\nimport type { HostStack } from '@hoststack.dev/sdk';\n\nimport type { ApiClient } from '../api-client.js';\n\ninterface ResourceContext {\n\thoststack: HostStack;\n\tapi: ApiClient;\n\tresolveTeamId(): Promise<number>;\n}\n\ninterface StaticResourceDef {\n\tkind: 'static';\n\tname: string;\n\turi: string;\n\tdescription: string;\n\tmimeType?: string;\n\tread: (uri: URL, ctx: ResourceContext) => Promise<ReadResourceResult>;\n}\n\nexport type ResourceDefinition = Readonly<StaticResourceDef>;\n\nconst resources: StaticResourceDef[] = [];\n\nexport function defineResource(def: StaticResourceDef): void {\n\tresources.push(def);\n}\n\nexport function listResourceDefinitions(): ReadonlyArray<ResourceDefinition> {\n\treturn resources;\n}\n\nexport function attachResources(server: McpServer, ctx: ResourceContext): void {\n\tfor (const def of resources) {\n\t\tserver.resource(\n\t\t\tdef.name,\n\t\t\tdef.uri,\n\t\t\t{\n\t\t\t\tdescription: def.description,\n\t\t\t\t...(def.mimeType ? { mimeType: def.mimeType } : {}),\n\t\t\t},\n\t\t\t(uri) => def.read(uri, ctx),\n\t\t);\n\t}\n}\n\n/**\n * Pack a JSON value into the resource read-result envelope. The MCP spec\n * requires `text` for application/json resources — we serialise here so each\n * resource handler stays a one-liner.\n */\nexport function jsonResource(uri: URL, data: unknown): ReadResourceResult {\n\treturn {\n\t\tcontents: [\n\t\t\t{\n\t\t\t\turi: uri.toString(),\n\t\t\t\tmimeType: 'application/json',\n\t\t\t\ttext: JSON.stringify(data, null, 2),\n\t\t\t},\n\t\t],\n\t};\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport type { HostStack } from '@hoststack.dev/sdk';\nimport type { ZodRawShape, z } from 'zod';\n\nimport type { ApiClient } from './api-client.js';\n\nexport type ToolCategory =\n\t| 'projects'\n\t| 'services'\n\t| 'deploys'\n\t| 'databases'\n\t| 'domains'\n\t| 'dns'\n\t| 'volumes'\n\t| 'env-vars'\n\t| 'environments'\n\t| 'resource-links'\n\t| 'cron'\n\t| 'logs'\n\t| 'activity-log'\n\t| 'alerts'\n\t| 'github'\n\t| 'meta';\n\nexport interface ToolContext {\n\thoststack: HostStack;\n\tapi: ApiClient;\n\t/**\n\t * Lazy resolver for the team ID bound to the API key. The agent never has\n\t * to pass `teamId` to a tool — every SDK route is team-scoped, so the MCP\n\t * looks it up once via `/api/auth/me` and caches it for the rest of the\n\t * server's lifetime. Throws if the API key is invalid or unbound.\n\t */\n\tresolveTeamId(): Promise<number>;\n}\n\ninterface InternalToolDefinition {\n\tname: string;\n\tcategory: ToolCategory;\n\tdescription: string;\n\tinput: ZodRawShape;\n\thandler: (args: Record<string, unknown>, ctx: ToolContext) => Promise<CallToolResult>;\n}\n\nexport type ToolDefinition = Readonly<InternalToolDefinition>;\n\nconst tools: InternalToolDefinition[] = [];\n\n/**\n * Register a single tool definition. The generic over `TInput` lets the\n * handler receive precisely-typed arguments while the registry stores the\n * widened shape.\n */\nexport function defineTool<TInput extends ZodRawShape>(def: {\n\tname: string;\n\tcategory: ToolCategory;\n\tdescription: string;\n\tinput: TInput;\n\thandler: (args: z.infer<z.ZodObject<TInput>>, ctx: ToolContext) => Promise<CallToolResult>;\n}): void {\n\ttools.push({\n\t\tname: def.name,\n\t\tcategory: def.category,\n\t\tdescription: def.description,\n\t\tinput: def.input,\n\t\thandler: def.handler as InternalToolDefinition['handler'],\n\t});\n}\n\n/** Snapshot the currently-registered tool definitions (for tests / docs). */\nexport function listToolDefinitions(): ReadonlyArray<ToolDefinition> {\n\treturn tools;\n}\n\n/**\n * Telemetry event emitted once per tool invocation. The MCP package never\n * persists these — it just hands them to the optional `onToolCall` sink so\n * the host (HTTP transport, CLI, tests) can decide where they go.\n *\n * Privacy: `inputHash` is a hash over the JSON-stringified args; we never\n * expose the args themselves so PII from tool inputs (env-var values, domain\n * names) never reaches a sink.\n */\nexport interface ToolCallEvent {\n\ttool: string;\n\tdurationMs: number;\n\tok: boolean;\n\terrorCode: string | null;\n\tinputHash: string | null;\n\tstartedAt: Date;\n}\n\nexport type ToolCallSink = (event: ToolCallEvent) => void | Promise<void>;\n\n/** Iterate the registry and wire each tool into the MCP server. */\nexport function attachTools(server: McpServer, ctx: ToolContext, sink?: ToolCallSink): void {\n\ttype ToolMethod = (\n\t\tname: string,\n\t\tdescription: string,\n\t\tschema: ZodRawShape,\n\t\tcb: (args: Record<string, unknown>) => Promise<CallToolResult>,\n\t) => unknown;\n\n\tconst register = server.tool.bind(server) as unknown as ToolMethod;\n\n\tfor (const def of tools) {\n\t\tregister(def.name, def.description, def.input, async (args) => {\n\t\t\tconst startedAt = new Date();\n\t\t\tconst start = performance.now();\n\t\t\tlet ok = true;\n\t\t\tlet errorCode: string | null = null;\n\t\t\ttry {\n\t\t\t\tconst result = await def.handler(args, ctx);\n\t\t\t\tif (result.isError) {\n\t\t\t\t\tok = false;\n\t\t\t\t\terrorCode = 'tool_error';\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t} catch (err) {\n\t\t\t\tok = false;\n\t\t\t\terrorCode =\n\t\t\t\t\terr instanceof Error ? (err.name || 'Error').slice(0, 64) : 'unknown_error';\n\t\t\t\tthrow err;\n\t\t\t} finally {\n\t\t\t\tif (sink) {\n\t\t\t\t\tconst durationMs = Math.round(performance.now() - start);\n\t\t\t\t\tconst event: ToolCallEvent = {\n\t\t\t\t\t\ttool: def.name,\n\t\t\t\t\t\tdurationMs,\n\t\t\t\t\t\tok,\n\t\t\t\t\t\terrorCode,\n\t\t\t\t\t\tinputHash: hashArgs(args),\n\t\t\t\t\t\tstartedAt,\n\t\t\t\t\t};\n\t\t\t\t\tPromise.resolve()\n\t\t\t\t\t\t.then(() => sink(event))\n\t\t\t\t\t\t.catch(() => undefined);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n}\n\nfunction hashArgs(args: Record<string, unknown>): string | null {\n\ttry {\n\t\tconst json = JSON.stringify(args);\n\t\tconst bunGlobal = (globalThis as { Bun?: { hash?: (data: string) => bigint } }).Bun;\n\t\tif (bunGlobal?.hash) {\n\t\t\treturn bunGlobal.hash(json).toString(16);\n\t\t}\n\t\treturn `len:${json.length}`;\n\t} catch {\n\t\treturn null;\n\t}\n}\n","import { z } from 'zod';\n\nimport { definePrompt, userMessage } from './registry.js';\n\ndefinePrompt({\n\tname: 'diagnose_failed_deploy',\n\tdescription:\n\t\t'Walk the agent through diagnosing a failed deploy: pull the latest deploys for the named service, find the most recent failure, fetch its build/deploy logs, and propose a fix. Stops at suggestion — does not retrigger automatically.',\n\targs: {\n\t\tservice_id: z.string().describe('Service publicId (e.g. svc_abc123).'),\n\t},\n\thandler: async ({ service_id }) => {\n\t\tconst text = `Goal: diagnose the most recent failed deploy on service ${service_id} and propose a fix.\n\nPlan (use these tools in order):\n1. \\`list_deploys({ service_id: \"${service_id}\" })\\` — pull recent deploys, newest first. Identify the most recent deploy with status \\`failed\\` (or \\`cancelled\\` if the user wants to investigate that too). Capture its publicId, branch, and commitSha.\n2. \\`get_deploy_logs({ service_id: \"${service_id}\", deploy_id: \"<dpl_…>\" })\\` — read the full build output. Scan for: stack traces, \"ERROR\" / \"error:\" lines, exit codes, missing env vars, OOM-killed signals, network failures pulling dependencies.\n3. \\`get_service({ service_id: \"${service_id}\" })\\` — confirm the service's runtime, plan, and whether autoDeploy is on. Plan tier matters because OOMs at small tiers point at \\`maxMemoryMb\\`.\n4. (Optional) \\`list_env_vars({ service_id: \"${service_id}\" })\\` — only if the build error mentions a missing variable. Don't fetch otherwise; values are masked anyway.\n\nThen write a short diagnosis for the user with three sections:\n- **Root cause** — one sentence pointing at the actual failure line.\n- **Evidence** — 3–6 line excerpt from the logs that proves the diagnosis.\n- **Suggested fix** — concrete next steps, including which tool to call (e.g. \"set MISSING_KEY with set_env_var, then trigger_deploy\"). Do NOT call trigger_deploy automatically; the user decides.\n\nIf the deploy logs are empty or only contain queued/pending markers, surface that — the build never started, which is its own class of bug (likely a builder-pool or quota issue).`;\n\n\t\treturn { messages: [userMessage(text)] };\n\t},\n});\n\ndefinePrompt({\n\tname: 'deploy_status_check',\n\tdescription:\n\t\t\"Quick orientation prompt: who am I, what's running, and is anything currently deploying? Useful at the start of a session.\",\n\targs: {},\n\thandler: async () => {\n\t\tconst text = `Goal: produce a 30-second status check on this HostStack team.\n\nPlan:\n1. \\`get_me()\\` — confirm which user + team the API key belongs to.\n2. \\`list_services()\\` — every service with current status (running, suspended, building, deploying, failed). Note any service in a non-running state.\n3. For each service whose status is \\`building\\` or \\`deploying\\`, call \\`list_deploys({ service_id })\\` and surface the latest deploy's commitMessage + author.\n4. \\`list_activity_log({ per_page: 10 })\\` — last 10 audit events to spot recent changes (deploys triggered, env vars edited, services restarted).\n\nWrite a status report shaped like:\n\n> **Team**: <name>\n> **Services**: <n> total — <breakdown by status>\n> **In flight**: <list of building/deploying services with commit info, or \"none\">\n> **Recent activity**: <3-5 most relevant events from the audit log, newest first>\n\nKeep it tight (under 200 words). The user can drill in with follow-up tools.`;\n\n\t\treturn { messages: [userMessage(text)] };\n\t},\n});\n\ndefinePrompt({\n\tname: 'rotate_secret',\n\tdescription:\n\t\t'Guide the agent through rotating an env-var secret on a service. Lists current vars to confirm the target key exists, asks the user for the new value, sets it, and offers to trigger a deploy.',\n\targs: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tkey: z.string().describe('Env-var key to rotate (e.g. DATABASE_URL).'),\n\t},\n\thandler: async ({ service_id, key }) => {\n\t\tconst text = `Goal: rotate the secret \\`${key}\\` on service ${service_id}.\n\nPlan:\n1. \\`list_env_vars({ service_id: \"${service_id}\" })\\` — confirm \\`${key}\\` exists. Note its \\`isSecret\\` flag (it should be true; if not, flag this — you're about to mark it secret on rotation, which is a behaviour change).\n2. **Ask the user for the new value before calling any write tool.** The agent must NOT invent or generate the secret; it has to come from the user's clipboard / vault. Phrase the ask explicitly: \"Paste the new value for ${key} (it will be encrypted at rest and masked everywhere except the running container).\"\n3. Once the user provides the value:\n - \\`set_env_var({ service_id: \"${service_id}\", key: \"${key}\", value: \"<new value>\", is_secret: true })\\` — upserts by key.\n4. After the write succeeds, ask the user whether to redeploy (so the new value lands in the running container). If yes:\n - \\`trigger_deploy({ service_id: \"${service_id}\" })\\` — kicks off a build with the rotated secret.\n - \\`get_deploy({ service_id: \"${service_id}\", deploy_id: \"<dpl_…>\" })\\` — poll until status is \\`live\\` or \\`failed\\`. On failure, hand off to \\`diagnose_failed_deploy\\`.\n\nSafety rails:\n- Never echo the new value back in your reply; the user should verify it from their own source of truth, not from your context window.\n- If the user says \"generate a new one\", suggest \\`openssl rand -hex 32\\` (or similar) for them to run locally and paste in. Do NOT generate it for them — secrets that pass through an LLM context are no longer secrets.\n- If \\`set_env_var\\` returned \\`action: \"created\"\\` instead of \\`\"updated\"\\`, the key didn't exist before. Pause and confirm with the user — they may have typo'd the key name.`;\n\n\t\treturn { messages: [userMessage(text)] };\n\t},\n});\n","/**\n * Per-resource shape pickers. Each function takes a raw API/SDK response and\n * returns the agent-friendly subset: drops internal foreign keys (teamId,\n * userId, ...) and null-valued columns, leaves ISO-8601 timestamps as-is.\n *\n * Pickers must be permissive about input shape — different SDK methods may\n * return slightly different fields (e.g. list vs get) and the API may grow\n * fields over time. We never throw on missing fields.\n */\n\nconst INTERNAL_FIELDS = new Set([\n\t'teamId',\n\t'team_id',\n\t'userId',\n\t'user_id',\n\t'accountId',\n\t'account_id',\n\t'tenantId',\n\t'tenant_id',\n\t'createdById',\n\t'updatedById',\n]);\n\ntype Obj = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is Obj {\n\treturn value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction dropNullsAndInternals(obj: Obj): Obj {\n\tconst out: Obj = {};\n\tfor (const [key, value] of Object.entries(obj)) {\n\t\tif (INTERNAL_FIELDS.has(key)) continue;\n\t\tif (value === null || value === undefined) continue;\n\t\tout[key] = value;\n\t}\n\treturn out;\n}\n\n/** Generic shape — drop internals, drop nulls, keep everything else. */\nexport function shape(value: unknown): unknown {\n\tif (Array.isArray(value)) return value.map(shape);\n\tif (isObject(value)) return dropNullsAndInternals(value);\n\treturn value;\n}\n\nfunction shapeAll<T>(arr: unknown, shaper: (item: unknown) => T): T[] {\n\tif (!Array.isArray(arr)) return [];\n\treturn arr.map(shaper);\n}\n\n/**\n * Unwrap a HostStack list response. The API returns shapes like\n * `{ projects: [...] }`, `{ services: [...] }`, etc. — the key varies by\n * resource. Pass the key explicitly so the wrapper stays type-loose.\n */\nexport function shapeList<T>(\n\tresponse: unknown,\n\tkey: string,\n\tshaper: (item: unknown) => T,\n): { items: T[] } {\n\tif (!isObject(response)) return { items: [] };\n\treturn { items: shapeAll(response[key], shaper) };\n}\n\n// ──────────────────────────────────────────────────────────────────────\n// Per-resource pickers — typed convenience wrappers around shape().\n// All return a plain Obj (never null), keeping the registry handlers simple.\n// ──────────────────────────────────────────────────────────────────────\n\nexport function shapeProject(value: unknown): Obj {\n\treturn isObject(value) ? dropNullsAndInternals(value) : {};\n}\n\nexport function shapeService(value: unknown): Obj {\n\treturn isObject(value) ? dropNullsAndInternals(value) : {};\n}\n\nexport function shapeDeploy(value: unknown): Obj {\n\treturn isObject(value) ? dropNullsAndInternals(value) : {};\n}\n\nexport function shapeDatabase(value: unknown): Obj {\n\treturn isObject(value) ? dropNullsAndInternals(value) : {};\n}\n\nexport function shapeDomain(value: unknown): Obj {\n\treturn isObject(value) ? dropNullsAndInternals(value) : {};\n}\n\nexport function shapeEnvVar(value: unknown): Obj {\n\treturn isObject(value) ? dropNullsAndInternals(value) : {};\n}\n\nexport function shapeCronExecution(value: unknown): Obj {\n\treturn isObject(value) ? dropNullsAndInternals(value) : {};\n}\n\nexport function shapeActivity(value: unknown): Obj {\n\treturn isObject(value) ? dropNullsAndInternals(value) : {};\n}\n\nexport function shapeUser(value: unknown): Obj {\n\treturn isObject(value) ? dropNullsAndInternals(value) : {};\n}\n\nexport function shapeTeam(value: unknown): Obj {\n\treturn isObject(value) ? dropNullsAndInternals(value) : {};\n}\n\nexport function shapeVolume(value: unknown): Obj {\n\treturn isObject(value) ? dropNullsAndInternals(value) : {};\n}\n","import { shapeProject, shapeService, shapeTeam, shapeUser } from '../lib/shape.js';\nimport { defineResource, jsonResource } from './registry.js';\n\ninterface MeResponse {\n\tuser: unknown;\n\tteam?: unknown;\n}\n\ndefineResource({\n\tkind: 'static',\n\tname: 'team',\n\turi: 'hoststack://team',\n\tdescription:\n\t\t'Authenticated team identity + a quick orientation snapshot. Includes the team record, the user behind the API key, and counts of projects and services so an agent can decide whether to fan out into list_projects / list_services without an extra round-trip.',\n\tmimeType: 'application/json',\n\tread: async (uri, { hoststack, api, resolveTeamId }) => {\n\t\tconst teamId = await resolveTeamId();\n\n\t\t// Resource handlers must not throw on transient downstream failures —\n\t\t// clients call resources/read for orientation and a network blip\n\t\t// shouldn't poison the entire session. Tolerate partial failure and\n\t\t// surface what we can.\n\t\tconst [me, projectsResult, servicesResult] = await Promise.all([\n\t\t\tapi.get<MeResponse>('/api/auth/me').catch(() => null),\n\t\t\thoststack.projects.list(teamId).catch(() => ({ projects: [] as unknown[] })),\n\t\t\thoststack.services.list(teamId).catch(() => ({ services: [] as unknown[] })),\n\t\t]);\n\n\t\tconst projects = (projectsResult.projects as unknown[]).slice(0, 10).map(shapeProject);\n\t\tconst services = (servicesResult.services as unknown[]).slice(0, 10).map(shapeService);\n\n\t\treturn jsonResource(uri, {\n\t\t\tuser: me?.user ? shapeUser(me.user) : null,\n\t\t\tteam: me?.team ? shapeTeam(me.team) : null,\n\t\t\tproject_count: (projectsResult.projects as unknown[]).length,\n\t\t\tservice_count: (servicesResult.services as unknown[]).length,\n\t\t\t// First 10 of each so the resource stays small while still useful\n\t\t\t// for orientation. Use list_projects / list_services for the full set.\n\t\t\tprojects_preview: projects,\n\t\t\tservices_preview: services,\n\t\t});\n\t},\n});\n","import { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond } from '../lib/respond.js';\nimport { shape, shapeActivity } from '../lib/shape.js';\n\ninterface ActivityLogResponse {\n\tdata?: unknown[];\n\t// Older API style: pagination meta as a single nested object. Some\n\t// callers still serve this shape, so keep accepting it.\n\tmeta?: unknown;\n\t// Current API style: pagination meta fields are spread flat on the\n\t// response root (`{ data, page, perPage, total, totalPages }`).\n\tpage?: number;\n\tperPage?: number;\n\ttotal?: number;\n\ttotalPages?: number;\n}\n\ndefineTool({\n\tname: 'list_activity_log',\n\tcategory: 'activity-log',\n\tdescription: [\n\t\t'List the team activity audit log: who did what, when. Backed by /api/activity-log/:teamId.',\n\t\t'',\n\t\t'When to use: investigate why a service was changed unexpectedly (\"who deleted that env var?\"), correlate a deploy with a user, or pull recent admin events for a status update.',\n\t\t'',\n\t\t'Inputs (all optional):',\n\t\t' - page: 1-based page index (default 1).',\n\t\t' - per_page: items per page (default 25, hard cap 100).',\n\t\t' - action: filter to a specific action (e.g. \"service.created\", \"deploy.triggered\").',\n\t\t' - resource_type: filter by resource type (e.g. \"service\", \"deploy\", \"domain\").',\n\t\t' - user_id: filter by acting user numeric ID.',\n\t\t' - since/until: ISO-8601 timestamp OR a relative offset like \"-15m\" / \"-2h\" / \"-7d\" — narrow to a time window (handy for correlating a deploy with a log spike).',\n\t\t'',\n\t\t'Returns: { items: ActivityLogEntry[], meta: { page, perPage, total, totalPages } } — each entry has id, action, resourceType, resourceId, actorEmail, ipAddress, createdAt, and a context payload. Use meta.totalPages to tell whether you have more.',\n\t\t'',\n\t\t'Example: list_activity_log({ resource_type: \"deploy\", per_page: 10 }) → { items: [{ action: \"deploy.triggered\", actorEmail: \"ada@…\", … }], meta: { total: 47, page: 1 } }',\n\t].join('\\n'),\n\tinput: {\n\t\tpage: z.number().int().positive().optional().describe('Page index, 1-based.'),\n\t\tper_page: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.positive()\n\t\t\t.max(100)\n\t\t\t.optional()\n\t\t\t.describe('Items per page, hard cap 100.'),\n\t\taction: z.string().optional().describe('Action filter, e.g. \"service.created\".'),\n\t\tresource_type: z.string().optional().describe('Resource type filter.'),\n\t\tuser_id: z.number().int().positive().optional().describe('Numeric acting-user filter.'),\n\t\tsince: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe('ISO-8601 timestamp or relative offset (e.g. \"-15m\", \"-2h\", \"-7d\").'),\n\t\tuntil: z.string().optional().describe('ISO-8601 timestamp or relative offset upper bound.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst params: Record<string, string | number | undefined> = {};\n\t\tif (args.page !== undefined) params['page'] = String(args.page);\n\t\tif (args.per_page !== undefined) params['perPage'] = String(args.per_page);\n\t\tif (args.action !== undefined) params['action'] = args.action;\n\t\tif (args.resource_type !== undefined) params['resourceType'] = args.resource_type;\n\t\tif (args.user_id !== undefined) params['userId'] = String(args.user_id);\n\t\tif (args.since !== undefined) params['since'] = args.since;\n\t\tif (args.until !== undefined) params['until'] = args.until;\n\n\t\tconst response = await ctx.api.get<ActivityLogResponse>(\n\t\t\t`/api/activity-log/${teamId}`,\n\t\t\tparams,\n\t\t);\n\t\tconst items = Array.isArray(response.data) ? response.data.map(shapeActivity) : [];\n\t\tconst data: { items: unknown[]; meta?: unknown } = { items };\n\t\t// The API spreads pagination at the top level (`{ data, page, perPage,\n\t\t// total, totalPages }`). Older variants nested it under `meta`.\n\t\t// Surface a single `meta` object regardless so MCP callers don't have\n\t\t// to learn two shapes.\n\t\tif (response.meta !== undefined) {\n\t\t\tdata.meta = shape(response.meta);\n\t\t} else if (\n\t\t\tresponse.page !== undefined ||\n\t\t\tresponse.perPage !== undefined ||\n\t\t\tresponse.total !== undefined ||\n\t\t\tresponse.totalPages !== undefined\n\t\t) {\n\t\t\tdata.meta = shape({\n\t\t\t\tpage: response.page,\n\t\t\t\tperPage: response.perPage,\n\t\t\t\ttotal: response.total,\n\t\t\t\ttotalPages: response.totalPages,\n\t\t\t});\n\t\t}\n\n\t\treturn respond({\n\t\t\tsummary:\n\t\t\t\titems.length === 0\n\t\t\t\t\t? 'No activity log entries match the given filters.'\n\t\t\t\t\t: `Returned ${items.length} activity log entr${items.length === 1 ? 'y' : 'ies'}.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n","import type { CallToolResult, ContentBlock } from '@modelcontextprotocol/sdk/types.js';\n\ninterface RespondInput {\n\tsummary: string;\n\tdata?: unknown;\n}\n\nexport const SUMMARY_MAX_LEN = 500;\n\n/**\n * Build an MCP tool response with a 1–3 line plain-text summary, a fenced\n * JSON block for human readability, and a structuredContent object that\n * agents can parse without re-tokenising the JSON text.\n */\nexport function respond({ summary, data }: RespondInput): CallToolResult {\n\tconst trimmed = summary.trim();\n\tif (trimmed.length === 0) {\n\t\tthrow new Error('respond(): summary must be non-empty');\n\t}\n\tif (trimmed.length > SUMMARY_MAX_LEN) {\n\t\tthrow new Error(`respond(): summary too long (${trimmed.length} > ${SUMMARY_MAX_LEN})`);\n\t}\n\n\tconst blocks: ContentBlock[] = [{ type: 'text', text: trimmed }];\n\n\tif (data !== undefined) {\n\t\tblocks.push({\n\t\t\ttype: 'text',\n\t\t\ttext: '```json\\n' + JSON.stringify(data, null, 2) + '\\n```',\n\t\t});\n\t}\n\n\tconst result: CallToolResult = { content: blocks };\n\tif (data !== undefined) {\n\t\tresult.structuredContent = toStructuredContent(data);\n\t}\n\treturn result;\n}\n\nexport function respondError(message: string, data?: unknown): CallToolResult {\n\tconst blocks: ContentBlock[] = [{ type: 'text', text: `Error: ${message}` }];\n\tif (data !== undefined) {\n\t\tblocks.push({\n\t\t\ttype: 'text',\n\t\t\ttext: '```json\\n' + JSON.stringify(data, null, 2) + '\\n```',\n\t\t});\n\t}\n\tconst result: CallToolResult = { content: blocks, isError: true };\n\tif (data !== undefined) {\n\t\tresult.structuredContent = toStructuredContent(data);\n\t}\n\treturn result;\n}\n\nfunction toStructuredContent(data: unknown): Record<string, unknown> {\n\tif (data !== null && typeof data === 'object' && !Array.isArray(data)) {\n\t\treturn data as Record<string, unknown>;\n\t}\n\treturn { result: data };\n}\n","import { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond } from '../lib/respond.js';\nimport { shape } from '../lib/shape.js';\n\ninterface AlertsResponse {\n\talerts: unknown[];\n\taggregated: boolean;\n}\n\ndefineTool({\n\tname: 'list_alerts',\n\tcategory: 'alerts',\n\tdescription: [\n\t\t'List recent alert-shaped events for the team: deploy failures, git auth losses, service health failures, auto-restarts, ACME cert failures, resource alerts (high CPU), database backup/restore failures, registrant verification lapses.',\n\t\t'',\n\t\t\"When to use: triage 'what's currently broken or recently broke for this team'. Pairs with list_activity_log for the full audit feed; this tool is the alert-shaped subset.\",\n\t\t'',\n\t\t'By default events are AGGREGATED by (action, resourceId) so flapping events collapse to one row with a fire count + first/last timestamps — e.g. \"service.auto_restarted on service 31, 8 times in the last hour, last at 14:22\". Pass aggregate=false to see every raw row.',\n\t\t'',\n\t\t'ACTIVE vs HISTORICAL (v89): each aggregated entry now has an `active` boolean and a `lastResolvedAt` timestamp. `active=true` means the most recent occurrence has NOT been resolved — the alert is still on fire. The default `active=true` filter hides resolved/historical alerts so triage starts with \"what is broken right now\". Pass `active=false` to include resolved entries too (useful for post-mortems). Resolution is automatic for some alert kinds — e.g. `deploy.failed_consecutive` is cleared when the next deploy of the same service goes live.',\n\t\t'',\n\t\t'Database backup_failed entries (v89) include `containerStatus` / `containerHealth` / `containerExitCode` in lastMetadata when the agent could resolve the container at failure time, so you can tell \"Redis is overloaded\" apart from \"Redis is restarting\" without a second tool call.',\n\t\t'',\n\t\t'Deploy.failed_consecutive entries (v89) carry the offending `commitHash` in lastMetadata, and the streak now dedupes per (service, commitHash) — one critical per bad commit, not one every 6 retries.',\n\t\t'',\n\t\t'Inputs (all optional):',\n\t\t' - since: ISO-8601 timestamp OR relative offset like \"-1h\" / \"-2d\". Default: -24h.',\n\t\t' - until: ISO-8601 upper bound (ignored when aggregating — aggregated view always extends to now).',\n\t\t' - limit: max rows (default 100, hard cap 500).',\n\t\t' - aggregate: true (default) collapses by (action, resourceId); false returns raw rows.',\n\t\t' - active: true (default) shows only alerts that are still on fire (resolved_at IS NULL on the most recent row). false includes resolved historical alerts.',\n\t\t'',\n\t\t'Returns: { alerts: Array, aggregated: boolean, activeOnly: boolean }. Each aggregated entry includes action, resourceType, resourceId, severity, count, firstFiredAt, lastFiredAt, lastResolvedAt (nullable), active (boolean), lastMetadata. Each raw entry adds resolvedAt (nullable).',\n\t\t'',\n\t\t\"Example: list_alerts({ since: '-1h' }) → { alerts: [{ action: 'deploy.failed_consecutive', resourceId: 31, severity: 'critical', active: true, count: 3, lastFiredAt: '…', lastResolvedAt: null, lastMetadata: { commitHash: 'abc1234' }, … }] }.\",\n\t].join('\\n'),\n\tinput: {\n\t\tsince: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe('ISO-8601 timestamp or relative offset (e.g. \"-1h\", \"-2d\"). Default: -24h.'),\n\t\tuntil: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe('ISO-8601 upper bound. Only honored when aggregate=false.'),\n\t\tlimit: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.positive()\n\t\t\t.max(500)\n\t\t\t.optional()\n\t\t\t.describe('Max rows (default 100, hard cap 500).'),\n\t\taggregate: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe('Collapse by (action, resourceId). Default true.'),\n\t\tactive: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t'Only return alerts still on fire (resolved_at IS NULL on the most recent row). Default true. Pass false to include resolved historical alerts.',\n\t\t\t),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst params: Record<string, string | number | undefined> = {};\n\t\tif (args.since !== undefined) params['since'] = args.since;\n\t\tif (args.until !== undefined) params['until'] = args.until;\n\t\tif (args.limit !== undefined) params['limit'] = String(args.limit);\n\t\t// API expects aggregate=1|0; default behavior on the API side is\n\t\t// aggregate=true. Pass explicit \"0\" only when caller opts out so\n\t\t// we don't ship spurious query params.\n\t\tif (args.aggregate === false) params['aggregate'] = '0';\n\t\t// v89: same convention for active=1|0. Default true on the API\n\t\t// side, so we only ship `active=0` when the caller opts in to\n\t\t// historical entries.\n\t\tif (args.active === false) params['active'] = '0';\n\n\t\tconst response = await ctx.api.get<AlertsResponse>(`/api/alerts/${teamId}`, params);\n\t\tconst items = Array.isArray(response.alerts) ? response.alerts.map(shape) : [];\n\t\tconst aggregated = Boolean(response.aggregated);\n\t\tconst activeOnly = args.active !== false;\n\t\tconst summary =\n\t\t\titems.length === 0\n\t\t\t\t? activeOnly\n\t\t\t\t\t? 'No active alerts in the requested window — everything is operating normally.'\n\t\t\t\t\t: 'No alerts in the requested window (active or resolved).'\n\t\t\t\t: aggregated\n\t\t\t\t\t? `Returned ${items.length} alert group${items.length === 1 ? '' : 's'}${activeOnly ? ' (active only — pass active=false for resolved history)' : ''} (flapping events collapsed).`\n\t\t\t\t\t: `Returned ${items.length} raw alert event${items.length === 1 ? '' : 's'}.`;\n\t\treturn respond({ summary, data: { alerts: items, aggregated, activeOnly } });\n\t},\n});\n","import { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond } from '../lib/respond.js';\nimport { shapeCronExecution, shapeList } from '../lib/shape.js';\n\ndefineTool({\n\tname: 'list_cron_executions',\n\tcategory: 'cron',\n\tdescription: [\n\t\t'List recent execution records for a cron service (newest first).',\n\t\t'',\n\t\t'When to use: investigating whether a scheduled job ran on time, finding the most recent failure, or auditing cron run-times. Only works on services of type \"cron\"; for web services this returns an error.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the cron service.',\n\t\t' - limit (optional): how many executions to fetch (default 50, max enforced server-side).',\n\t\t'',\n\t\t'Returns: { items: CronExecution[] } — id, publicId, status (succeeded|failed|running|queued), startedAt, finishedAt, exitCode, triggeredBy.',\n\t\t'',\n\t\t'Example: list_cron_executions({ service_id: \"svc_cron\" }) → { items: [{ status: \"succeeded\", exitCode: 0, … }, …] }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Cron service publicId.'),\n\t\tlimit: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.positive()\n\t\t\t.max(200)\n\t\t\t.optional()\n\t\t\t.describe('Max executions to return (default 50).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst opts = args.limit !== undefined ? { limit: args.limit } : undefined;\n\t\tconst response = await ctx.hoststack.cron.list(teamId, args.service_id, opts);\n\t\tconst data = shapeList(response, 'executions', shapeCronExecution);\n\t\tconst summary =\n\t\t\tdata.items.length === 0\n\t\t\t\t? `No cron executions yet for ${args.service_id}.`\n\t\t\t\t: `Found ${data.items.length} cron execution${data.items.length === 1 ? '' : 's'} for ${args.service_id}.`;\n\t\treturn respond({ summary, data });\n\t},\n});\n\ndefineTool({\n\tname: 'get_cron_execution',\n\tcategory: 'cron',\n\tdescription: [\n\t\t'Fetch a single cron execution record. Includes status, exit code, and timing.',\n\t\t'',\n\t\t'When to use: drilling into a specific run after list_cron_executions surfaced a failure, or correlating an execution timestamp with logs.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the cron service.',\n\t\t' - execution_id: publicId of the execution record.',\n\t\t'',\n\t\t'Returns: { execution: CronExecution }.',\n\t\t'',\n\t\t'Example: get_cron_execution({ service_id: \"svc_cron\", execution_id: \"exe_xyz\" }) → { execution: { status: \"failed\", exitCode: 1, … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Cron service publicId.'),\n\t\texecution_id: z.string().describe('Execution publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.cron.get(teamId, args.service_id, args.execution_id);\n\t\tconst data = { execution: shapeCronExecution(response.execution) };\n\t\tconst status =\n\t\t\tdata.execution && 'status' in data.execution\n\t\t\t\t? (data.execution as { status: string }).status\n\t\t\t\t: 'unknown';\n\t\treturn respond({ summary: `Execution ${args.execution_id} ${status}.`, data });\n\t},\n});\n","import { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond } from '../lib/respond.js';\nimport { shapeDatabase, shapeList } from '../lib/shape.js';\n\n/**\n * Supported + default engine versions. DUPLICATED from\n * packages/shared/src/constants/database-versions.ts on purpose — the MCP\n * package must not depend on the private @hoststack/shared workspace package\n * (see the same note in tools/services.ts). Kept in sync by review.\n */\nconst DATABASE_VERSIONS = {\n\tpostgres: { default: '18', supported: ['18', '17', '16', '15'] },\n\tredis: { default: '8', supported: ['8', '7', '6'] },\n\tmysql: { default: '8.4', supported: ['8.4', '8.0', '5.7'] },\n\tmariadb: { default: '11.4', supported: ['11.4', '10.11'] },\n\tmongodb: { default: '8', supported: ['8', '7', '6'] },\n} as const;\n\nconst DB_ENGINES = ['postgres', 'redis', 'mysql', 'mariadb', 'mongodb'] as const;\n\nconst VERSION_HELP = (Object.keys(DATABASE_VERSIONS) as (keyof typeof DATABASE_VERSIONS)[])\n\t.map(\n\t\t(e) =>\n\t\t\t`${e}: ${DATABASE_VERSIONS[e].supported.join('/')} (default ${DATABASE_VERSIONS[e].default})`,\n\t)\n\t.join('; ');\n\ndefineTool({\n\tname: 'create_database',\n\tcategory: 'databases',\n\tdescription: [\n\t\t'Provision a MANAGED database (Postgres, Redis, MySQL, MariaDB, MongoDB) in a project. This is the correct and ONLY supported way to add a database to a HostStack app.',\n\t\t'',\n\t\t'When to use: any time an app needs a datastore — \"add a database\", \"I need Postgres\", \"set up Redis\", \"give this service a DB\". Also the right call when scaffolding a new app that will need persistence.',\n\t\t'',\n\t\t'*** Do NOT hand-roll a database as a service. *** Deploying `postgres:16` (or redis/mysql/mongo) via create_service with a docker_image is NOT how databases work on this platform: it gets no managed backups, no automated version upgrades, no HA/failover path, no credential rotation, no metrics, no persistent volume wired up, and nothing will inject its connection URL into your app. If the user says \"add a database\", \"I need Postgres\", \"set up Redis\" — call THIS tool.',\n\t\t'',\n\t\t'How a database reaches your app (the whole flow — 3 calls, no secrets handled):',\n\t\t' 1. create_database({ project_id, name, engine }) — provisions it.',\n\t\t' 2. link_resource_to_service({ service_id, resource_type: \"database\", resource_id: <database.id>, alias: \"APP_DB\" }) — binds it to the service that needs it.',\n\t\t' 3. trigger_deploy({ service_id }) — on that deploy the platform injects the connection info as env vars.',\n\t\t'After step 3 the container has `DATABASE_URL` (postgres/mysql/mariadb), `REDIS_URL` (redis) or `MONGO_URL` (mongodb) set automatically, plus alias-prefixed vars. An app reading `process.env.DATABASE_URL` needs zero code changes. You never have to fetch, generate or paste a password.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - project_id: numeric id or publicId (\"prj_…\") of the target project.',\n\t\t' - name: database name (1–100 chars).',\n\t\t` - engine: ${DB_ENGINES.join(' | ')}.`,\n\t\t` - version (optional): engine version. Supported — ${VERSION_HELP}. Omit to get the default (recommended).`,\n\t\t' - plan (optional): \"micro\" | \"starter\" | \"standard\" | \"pro\" (default \"starter\"). \"starter\" is the smallest always-on tier that includes backups.',\n\t\t' - environment_id (optional): bind to a specific environment; defaults to the project Production env.',\n\t\t' - postgis (optional): provision the PostGIS image variant so `CREATE EXTENSION postgis` works. Postgres only.',\n\t\t' - pgvector (optional): provision the pgvector image variant so `CREATE EXTENSION vector` works. Postgres only, mutually exclusive with postgis.',\n\t\t'',\n\t\t'Returns: { database: Database } — note BOTH `id` (numeric — this is what link_resource_to_service wants) and `publicId` (\"db_…\" — what the other database tools want).',\n\t\t'',\n\t\t'Provisioning is async: the row comes back immediately, usually as `creating`. Poll get_database until `status === \"available\"` before linking or connecting.',\n\t\t'',\n\t\t'Example: create_database({ project_id: \"prj_abc\", name: \"app-db\", engine: \"postgres\" }) → { database: { id: 42, publicId: \"db_…\", status: \"creating\" } }',\n\t].join('\\n'),\n\tinput: {\n\t\tproject_id: z\n\t\t\t.union([z.number().int().positive(), z.string()])\n\t\t\t.describe('Target project — numeric id or publicId (\"prj_…\").'),\n\t\tname: z.string().min(1).max(100).describe('Database name (1–100 chars).'),\n\t\tengine: z.enum(DB_ENGINES).describe('Database engine.'),\n\t\tversion: z\n\t\t\t.string()\n\t\t\t.max(20)\n\t\t\t.optional()\n\t\t\t.describe(`Engine version. ${VERSION_HELP}. Omit for the engine default.`),\n\t\tplan: z\n\t\t\t.enum(['micro', 'starter', 'standard', 'pro'])\n\t\t\t.optional()\n\t\t\t.describe('Plan tier (memory/CPU). Default \"starter\".'),\n\t\tenvironment_id: z\n\t\t\t.union([z.number().int().positive(), z.string()])\n\t\t\t.optional()\n\t\t\t.describe('Environment to bind to. Defaults to the project Production env.'),\n\t\tpostgis: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe('Postgres only — enable the PostGIS extension image.'),\n\t\tpgvector: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t'Postgres only — enable the pgvector extension image. Exclusive with postgis.',\n\t\t\t),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst projectId = await ctx.hoststack.resolveId(args.project_id, {\n\t\t\tkind: 'project',\n\t\t\tteamId,\n\t\t});\n\t\ttype CreateInput = Parameters<typeof ctx.hoststack.databases.create>[1];\n\t\tconst input: CreateInput = {\n\t\t\tname: args.name,\n\t\t\tengine: args.engine,\n\t\t\tprojectId,\n\t\t};\n\t\tif (args.version !== undefined) input.version = args.version;\n\t\tif (args.plan !== undefined) input.plan = args.plan;\n\t\tif (args.environment_id !== undefined) {\n\t\t\tinput.environmentId = await ctx.hoststack.resolveId(args.environment_id, {\n\t\t\t\tkind: 'environment',\n\t\t\t\tteamId,\n\t\t\t});\n\t\t}\n\t\tif (args.postgis !== undefined) input.postgis = args.postgis;\n\t\tif (args.pgvector !== undefined) input.pgvector = args.pgvector;\n\n\t\tconst response = await ctx.hoststack.databases.create(teamId, input);\n\t\tconst data = { database: shapeDatabase(response.database) };\n\t\tconst db = response.database as { id?: number; publicId?: string; status?: string };\n\t\treturn respond({\n\t\t\tsummary: `Created ${args.engine} database \"${args.name}\" (${db.publicId ?? 'unknown'}, numeric id ${db.id ?? '?'}) — status ${db.status ?? 'creating'}. Poll get_database until status=available, then link_resource_to_service to inject its URL into a service.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'delete_database',\n\tcategory: 'databases',\n\tdescription: [\n\t\t'Permanently delete a managed database — the container, its volume, and ALL data it holds.',\n\t\t'',\n\t\t'When to use: the user has explicitly asked to destroy a database they no longer want. This is irreversible and takes the data with it — confirm with the user before calling, and never call it to \"clean up\" as a side effect of another task. If the goal is to stop paying for an idle database while keeping the data, use suspend_database instead.',\n\t\t'',\n\t\t\"Any service still linked to this database will lose the injected connection vars on its next deploy, and will fail at runtime if it depends on them. Check which services consume it first — the dashboard shows this under the database's Linked Services tab.\",\n\t\t'',\n\t\t'Inputs:',\n\t\t' - database_id: publicId of the database (e.g. \"db_…\").',\n\t\t'',\n\t\t'Returns: { ok: true }.',\n\t\t'',\n\t\t'Example: delete_database({ database_id: \"db_abc\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tdatabase_id: z.string().describe('Database publicId (e.g. db_abc) to permanently delete.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.databases.delete(teamId, args.database_id);\n\t\treturn respond({\n\t\t\tsummary: `Deleted database ${args.database_id} and all of its data. This cannot be undone.`,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'suspend_database',\n\tcategory: 'databases',\n\tdescription: [\n\t\t'Suspend a managed database — stops its container while KEEPING the volume and all data. The reversible alternative to delete_database.',\n\t\t'',\n\t\t'When to use: a staging or preview database that nobody is using, to stop burning its compute tier. Connections fail while suspended; resume_database brings it back on the same connection URL.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - database_id: publicId of the database (e.g. \"db_…\").',\n\t\t'',\n\t\t'Returns: { ok: true }.',\n\t\t'',\n\t\t'Example: suspend_database({ database_id: \"db_abc\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tdatabase_id: z.string().describe('Database publicId (e.g. db_abc) to suspend.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.databases.suspend(teamId, args.database_id);\n\t\treturn respond({\n\t\t\tsummary: `Suspended database ${args.database_id}. Data is preserved; resume_database restores it on the same URL.`,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'resume_database',\n\tcategory: 'databases',\n\tdescription: [\n\t\t'Resume a suspended managed database — restarts its container against the existing volume. The connection URL is unchanged, so linked services do NOT need a redeploy.',\n\t\t'',\n\t\t'When to use: undoing a suspend_database, or bringing back a database that was suspended for non-payment once billing is resolved.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - database_id: publicId of the database (e.g. \"db_…\").',\n\t\t'',\n\t\t'Returns: { ok: true }. Poll get_database until `status === \"available\"`.',\n\t\t'',\n\t\t'Example: resume_database({ database_id: \"db_abc\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tdatabase_id: z.string().describe('Database publicId (e.g. db_abc) to resume.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.databases.resume(teamId, args.database_id);\n\t\treturn respond({\n\t\t\tsummary: `Resume dispatched for ${args.database_id}. Poll get_database until status=available.`,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'list_databases',\n\tcategory: 'databases',\n\tdescription: [\n\t\t'List managed databases (Postgres, Redis, MySQL, MariaDB, MongoDB) inside a project. Meilisearch and NATS are NOT databases — they are separate managed resources (search / queue) and do not appear here; see list_service_resources for what a service consumes.',\n\t\t'',\n\t\t'When to use: an agent needs to know what data stores exist in a project before connecting a service or running a migration. Pair with list_projects to discover project IDs.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - project_id: numeric project ID (from list_projects).',\n\t\t'',\n\t\t'Returns: { items: Database[] } — id, publicId, name, type, status, version, projectId, createdAt.',\n\t\t'',\n\t\t'Example: list_databases({ project_id: 12 }) → { items: [{ publicId: \"db_…\", type: \"postgres\", status: \"running\", … }] }',\n\t].join('\\n'),\n\tinput: {\n\t\tproject_id: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.positive()\n\t\t\t.describe('Numeric project ID (from list_projects).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.databases.list(teamId, args.project_id);\n\t\tconst data = shapeList(response, 'databases', shapeDatabase);\n\t\tconst summary =\n\t\t\tdata.items.length === 0\n\t\t\t\t? `No databases in project ${args.project_id}.`\n\t\t\t\t: `Found ${data.items.length} database${data.items.length === 1 ? '' : 's'} in project ${args.project_id}.`;\n\t\treturn respond({ summary, data });\n\t},\n});\n\ndefineTool({\n\tname: 'update_database',\n\tcategory: 'databases',\n\tdescription: [\n\t\t'Update a managed database — rename, change plan tier (memory/CPU), or grow disk size.',\n\t\t'',\n\t\t'When to use: the user wants to resize a database (disk or plan), or rename it. Disk can only grow — shrinking is rejected because the underlying filesystem would orphan data.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - database_id: publicId of the database (e.g. \"db_…\").',\n\t\t' - name (optional): new database name.',\n\t\t' - plan (optional): \"free\" | \"micro\" | \"starter\" | \"standard\" | \"pro\" — changes memory tier.',\n\t\t' - disk_size_gb (optional): new disk size in GB (must be ≥ current).',\n\t\t'',\n\t\t'Returns: { database: Database } — the updated record.',\n\t\t'',\n\t\t'Example: update_database({ database_id: \"db_xyz\", disk_size_gb: 50 }) → { database: { diskSizeGb: 50, … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tdatabase_id: z.string().describe('Database publicId (e.g. db_xyz).'),\n\t\tname: z.string().min(1).max(100).optional().describe('New database name.'),\n\t\tplan: z\n\t\t\t.enum(['free', 'micro', 'starter', 'standard', 'pro'])\n\t\t\t.optional()\n\t\t\t.describe('Plan tier (memory/CPU).'),\n\t\tdisk_size_gb: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(1)\n\t\t\t.max(1024)\n\t\t\t.optional()\n\t\t\t.describe('New disk size in GB. Must be ≥ current.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst input: {\n\t\t\tname?: string;\n\t\t\tplan?: 'free' | 'micro' | 'starter' | 'standard' | 'pro';\n\t\t\tdiskSizeGb?: number;\n\t\t} = {};\n\t\tif (args.name !== undefined) input.name = args.name;\n\t\tif (args.plan !== undefined) input.plan = args.plan;\n\t\tif (args.disk_size_gb !== undefined) input.diskSizeGb = args.disk_size_gb;\n\t\tif (Object.keys(input).length === 0) {\n\t\t\treturn respond({ summary: 'No fields to update.', data: {} });\n\t\t}\n\t\tconst response = await ctx.hoststack.databases.update(teamId, args.database_id, input);\n\t\tconst data = { database: shapeDatabase(response.database) };\n\t\tconst fields = Object.keys(input).join(', ');\n\t\treturn respond({ summary: `Updated ${fields} on database ${args.database_id}.`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'get_database',\n\tcategory: 'databases',\n\tdescription: [\n\t\t'Fetch a single managed database by ID. Includes status, type, version, and project link.',\n\t\t'',\n\t\t'When to use: confirming the version of a database before generating connection strings, or checking the status of a recently created database. To retrieve the actual connection credentials, use the dashboard — credentials are intentionally not exposed via this MCP tool.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - database_id: publicId of the database (e.g. \"db_…\").',\n\t\t'',\n\t\t'Returns: { database: Database }.',\n\t\t'',\n\t\t'Example: get_database({ database_id: \"db_xyz\" }) → { database: { type: \"postgres\", version: \"16\", status: \"running\", … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tdatabase_id: z.string().describe('Database publicId (e.g. db_xyz).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.databases.get(teamId, args.database_id);\n\t\tconst data = { database: shapeDatabase(response.database) };\n\t\tconst type =\n\t\t\tdata.database && 'type' in data.database\n\t\t\t\t? (data.database as { type: string }).type\n\t\t\t\t: 'unknown';\n\t\tconst status =\n\t\t\tdata.database && 'status' in data.database\n\t\t\t\t? (data.database as { status: string }).status\n\t\t\t\t: 'unknown';\n\t\treturn respond({ summary: `Database ${args.database_id} (${type}) is ${status}.`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'query_database',\n\tcategory: 'databases',\n\tdescription: [\n\t\t'Run a single READ-ONLY SQL statement against a managed Postgres database.',\n\t\t'',\n\t\t'When to use: ad-hoc data inspection — checking row counts, sampling rows, debugging a constraint. For schema changes or seed data, ship a Drizzle migration instead.',\n\t\t'',\n\t\t'Safety model (server-side, not bypassable):',\n\t\t' - Wrapped in `BEGIN TRANSACTION READ ONLY` — INSERT/UPDATE/DELETE/DDL fail with a clear \"cannot execute … in a read-only transaction\" error.',\n\t\t' - 30s statement_timeout — runaway queries are killed.',\n\t\t' - 1000-row cap; result CSV is also size-capped at 1 MiB. Both surface via `truncated: true`.',\n\t\t' - Postgres engine only (v1). Other engines return a 400.',\n\t\t' - Single statement only; no embedded `;` and no psql meta-commands (`\\\\…`).',\n\t\t' - Every call is audit-logged (success or failure) as `database.query` so an admin can answer \"who queried this DB, when, with what SQL\".',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - database_id: publicId of the postgres database (e.g. \"db_…\"). Resolved via the SDK\\'s publicId helper.',\n\t\t' - sql: a single SELECT/WITH/SHOW/EXPLAIN statement, no trailing `;`. Max 16 KiB.',\n\t\t'',\n\t\t'Returns: { columns: string[], rows: string[][], rowCount: number, truncated: boolean, durationMs: number }. Values come back as strings (psql --csv); cast on the caller side when needed.',\n\t\t'',\n\t\t'Example:',\n\t\t' - query_database({ database_id: \"db_abc\", sql: \"SELECT count(*) FROM users\" }) → { columns: [\"count\"], rows: [[\"1234\"]], … }',\n\t\t' - query_database({ database_id: \"db_abc\", sql: \"SELECT id, email FROM users WHERE created_at > now() - interval \\'1 day\\' LIMIT 50\" })',\n\t].join('\\n'),\n\tinput: {\n\t\tdatabase_id: z.string().describe('Database publicId (e.g. db_abc).'),\n\t\tsql: z\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(16_384)\n\t\t\t.describe(\n\t\t\t\t'A single READ-ONLY SQL statement. No trailing `;`, no embedded `;`, no psql meta-commands.',\n\t\t\t),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst result = await ctx.hoststack.databases.query(teamId, args.database_id, args.sql);\n\t\tconst summary = result.truncated\n\t\t\t? `Query returned ${result.rowCount} row${result.rowCount === 1 ? '' : 's'} (truncated; raise LIMIT if needed) in ${result.durationMs}ms.`\n\t\t\t: `Query returned ${result.rowCount} row${result.rowCount === 1 ? '' : 's'} in ${result.durationMs}ms.`;\n\t\treturn respond({ summary, data: result });\n\t},\n});\n\ndefineTool({\n\tname: 'upgrade_database_to_ha',\n\tcategory: 'databases',\n\tdescription: [\n\t\t'Trigger a single-node → HA migration on a managed Postgres database. The agent runs pg_dump → bootstrap 3-node Patroni cluster (1 leader + 2 sync replicas + HAProxy) → pg_restore. Customer connections to this database are briefly read-only during the cutover; the standalone container stays running (read-only) for 24 h as a rollback target before automatic decommission.',\n\t\t'',\n\t\t'Requires: PATRONI_ENABLED env on the HostStack deployment + `teams.ha_beta = true` on the calling team. Returns 403 otherwise. Returns 400 if the database is already HA, not Postgres, not on the standard or pro tier, or has a pg_database_size over 1 GB (in-memory archive transfer cap).',\n\t\t'',\n\t\t'When to use: a customer needs failover protection on an existing standalone Postgres. For new databases on an HA-eligible team, just call create_database — the cluster path is automatic.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - database_id: publicId of the postgres database to upgrade.',\n\t\t'',\n\t\t'Returns: 202 Accepted. The upgrade is async — poll get_database until `pg_engine_type === \"patroni\"` and `status === \"available\"` to confirm completion. The Cluster tab on the dashboard mirrors the same data.',\n\t\t'',\n\t\t'Example: upgrade_database_to_ha({ database_id: \"db_abc\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tdatabase_id: z.string().describe('Database publicId (e.g. db_abc) to upgrade to HA.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.databases.upgradeToHa(teamId, args.database_id);\n\t\treturn respond({\n\t\t\tsummary: `HA migration started for ${args.database_id}. Poll get_database until pg_engine_type=patroni to confirm.`,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'upgrade_database_version',\n\tcategory: 'databases',\n\tdescription: [\n\t\t'Upgrade a standalone managed database (postgres or redis) to a newer engine version in place. The agent dumps the live data, recreates the container at the target version under the same DNS name, and restores — so connection URLs stay valid and services do NOT need a redeploy. The database is briefly unavailable (seconds) during the cut-over; on any failure the original container is rolled back automatically.',\n\t\t'',\n\t\t'`version` must be a supported, strictly-newer version for the engine (postgres: 18/17/16/15, redis: 8/7/6). Downgrades are rejected. Returns 400 for unsupported engines (mysql/mariadb/mongodb upgrades are not implemented yet), for HA (Patroni) clusters, or if the database is not currently `available`.',\n\t\t'',\n\t\t'When to use: a customer wants to move to a newer Postgres/Redis major version. Check get_database first — the `version` field shows the current version; compare against the engine latest.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - database_id: publicId of the postgres/redis database to upgrade.',\n\t\t' - version: target engine version (e.g. \"18\" for postgres, \"8\" for redis).',\n\t\t'',\n\t\t'Returns: 202 Accepted. The upgrade is async — poll get_database until `version` matches the target and `status === \"available\"` to confirm.',\n\t\t'',\n\t\t'Example: upgrade_database_version({ database_id: \"db_abc\", version: \"18\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tdatabase_id: z.string().describe('Database publicId (e.g. db_abc) to upgrade.'),\n\t\tversion: z\n\t\t\t.string()\n\t\t\t.describe('Target engine version, e.g. \"18\" for postgres or \"8\" for redis.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.databases.upgradeVersion(teamId, args.database_id, args.version);\n\t\treturn respond({\n\t\t\tsummary: `Version upgrade to v${args.version} started for ${args.database_id}. Poll get_database until version=${args.version} and status=available to confirm.`,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'restart_database',\n\tcategory: 'databases',\n\tdescription: [\n\t\t'Restart a managed database in place — `docker restart` of its container: same container, same volume, same connection URL. The database is briefly unavailable (a few seconds) while it bounces; no redeploy of connected services is needed.',\n\t\t'',\n\t\t'When to use: a database is wedged (stuck connection, needs to reload a config change, leaking memory) and a clean bounce is the fix — the database-equivalent of restarting a service.',\n\t\t'',\n\t\t'The database must be `available`. A suspended database has no running container (resume it first → 409); a creating/migrating one is mid-operation (409). For a Patroni HA cluster this bounces the current leader, which triggers a normal failover while replicas keep serving reads.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - database_id: publicId of the database to restart.',\n\t\t'',\n\t\t'Returns: { ok: true } once the restart command reaches an agent (dispatched optimistically, like a service restart). Poll get_service_logs / get_database to confirm it came back.',\n\t\t'',\n\t\t'Example: restart_database({ database_id: \"db_abc\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tdatabase_id: z.string().describe('Database publicId (e.g. db_abc) to restart.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.databases.restart(teamId, args.database_id);\n\t\treturn respond({\n\t\t\tsummary: `Restart dispatched for ${args.database_id}. It will be briefly unavailable while the container bounces.`,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'get_database_cluster',\n\tcategory: 'databases',\n\tdescription: [\n\t\t'Get the live + retired cluster members and failover history for a Patroni HA Postgres database.',\n\t\t'',\n\t\t'When to use: confirm an HA cluster is healthy (1 leader + 2 sync replicas + 1 proxy + 1 etcd live) or investigate a failover that fired. For standalone databases this returns 400 — call get_database first if you need to branch.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - database_id: publicId of the postgres database (must be HA).',\n\t\t'',\n\t\t\"Returns: { members: { id, memberRole: 'etcd' | 'primary-candidate' | 'replica' | 'proxy', containerId, workerHostId, joinedAt, leftAt }[], failovers: { id, createdAt, oldLeader, newLeader }[] }.\",\n\t\t'',\n\t\t'Example: get_database_cluster({ database_id: \"db_abc\" }) → { members: [...5 live rows], failovers: [] }',\n\t].join('\\n'),\n\tinput: {\n\t\tdatabase_id: z.string().describe('Database publicId for the HA cluster.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst result = await ctx.hoststack.databases.getCluster(teamId, args.database_id);\n\t\tconst live = result.members.filter((m) => m.leftAt === null);\n\t\tconst summary = `${live.length} live members (${live.map((m) => m.memberRole).join(', ')}); ${result.failovers.length} historical failovers.`;\n\t\treturn respond({ summary, data: result });\n\t},\n});\n","import { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond } from '../lib/respond.js';\nimport { shape, shapeDeploy, shapeList } from '../lib/shape.js';\n\ndefineTool({\n\tname: 'list_deploys',\n\tcategory: 'deploys',\n\tdescription: [\n\t\t'List deploys for a service in reverse-chronological order (newest first).',\n\t\t'',\n\t\t'When to use: investigating a recent deploy outcome, finding the last successful deploy ID, comparing run-times, or just checking deploy history before triggering a new one.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service (e.g. \"svc_abc123\"). Use list_services to find it.',\n\t\t'',\n\t\t'Returns: { items: Deploy[] } — each deploy includes id, publicId, status (pending|building|deploying|live|failed|cancelled), commitSha, commitMessage, branch, triggeredBy, startedAt, finishedAt, imageBuildMs (docker build / image-pull only; null on skip-build redeploys — v89), containerBootMs (deploying → live wall-clock; null on builds that failed before container start — v89), buildDurationMs (legacy alias of imageBuildMs kept for back-compat), totalDurationMs (full deploy wall-clock = finishedAt − startedAt). Use imageBuildMs + containerBootMs together to tell \"build is slow\" apart from \"boot is slow\".',\n\t\t'',\n\t\t'Example: list_deploys({ service_id: \"svc_abc\" }) → { items: [{ publicId: \"dpl_…\", status: \"live\", commitMessage: \"Fix login\", … }, …] }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId (e.g. svc_abc123).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.deploys.list(teamId, args.service_id);\n\t\t// Deploys list is paginated and returns `{ data, page, ... }` — not the\n\t\t// bare `{ deploys: [] }` shape every other list endpoint uses.\n\t\tconst data = shapeList(response, 'data', shapeDeploy);\n\t\tconst summary =\n\t\t\tdata.items.length === 0\n\t\t\t\t? `No deploys yet for service ${args.service_id}.`\n\t\t\t\t: `Found ${data.items.length} deploy${data.items.length === 1 ? '' : 's'} for service ${args.service_id} (page ${response.page} of ${response.totalPages}, ${response.total} total).`;\n\t\treturn respond({ summary, data });\n\t},\n});\n\ndefineTool({\n\tname: 'get_deploy',\n\tcategory: 'deploys',\n\tdescription: [\n\t\t'Fetch a single deploy by ID, including its current status, commit metadata, and timestamps.',\n\t\t'',\n\t\t\"When to use: drilling into the details of a specific deploy after list_deploys, polling a build's status, or grabbing the commit SHA so you can correlate logs with code.\",\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - deploy_id: publicId of the deploy (e.g. \"dpl_…\").',\n\t\t'',\n\t\t'Returns: { deploy: Deploy } — full deploy record (status, commitSha, commitMessage, branch, imageBuildMs + containerBootMs (v89 split timings; legacy buildDurationMs preserved as alias), totalDurationMs, finishedAt, etc).',\n\t\t'',\n\t\t'Example: get_deploy({ service_id: \"svc_abc\", deploy_id: \"dpl_xyz\" }) → { deploy: { status: \"live\", … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tdeploy_id: z.string().describe('Deploy publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.deploys.get(teamId, args.service_id, args.deploy_id);\n\t\tconst data = { deploy: shapeDeploy(response.deploy) };\n\t\tconst status =\n\t\t\tdata.deploy && typeof data.deploy === 'object' && 'status' in data.deploy\n\t\t\t\t? (data.deploy as { status: string }).status\n\t\t\t\t: 'unknown';\n\t\treturn respond({ summary: `Deploy ${args.deploy_id} is ${status}.`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'trigger_deploy',\n\tcategory: 'deploys',\n\tdescription: [\n\t\t'Kick off a new deploy. Defaults to the latest commit on the service branch; pass commit_hash or branch to deploy something else.',\n\t\t'',\n\t\t'When to use: the user explicitly asks to deploy (\"ship it\", \"redeploy\", \"kick off a new build\"). For services with auto-deploy enabled, a fresh git push already triggers a deploy automatically — only call this for manual triggers or after a config change.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - commit_hash (optional): build a specific commit instead of HEAD on the configured branch.',\n\t\t' - branch (optional): build the tip of a non-default branch.',\n\t\t'',\n\t\t'Returns: { deploy: Deploy } — the new deploy record. Status will start as \"pending\" then transition through \"building\" → \"deploying\" → \"live\" or \"failed\".',\n\t\t'',\n\t\t'Example: trigger_deploy({ service_id: \"svc_abc\" }) → { deploy: { publicId: \"dpl_…\", status: \"pending\", … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tcommit_hash: z\n\t\t\t.string()\n\t\t\t.max(40)\n\t\t\t.optional()\n\t\t\t.describe('Specific commit to build (default: branch HEAD).'),\n\t\tbranch: z\n\t\t\t.string()\n\t\t\t.max(200)\n\t\t\t.optional()\n\t\t\t.describe('Branch to build (default: service configured branch).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst input: { commitHash?: string; branch?: string } = {};\n\t\tif (args.commit_hash !== undefined) input.commitHash = args.commit_hash;\n\t\tif (args.branch !== undefined) input.branch = args.branch;\n\t\tconst response = await ctx.hoststack.deploys.trigger(teamId, args.service_id, input);\n\t\tconst data = { deploy: shapeDeploy(response.deploy) };\n\t\tconst publicId =\n\t\t\tdata.deploy && 'publicId' in data.deploy\n\t\t\t\t? (data.deploy as { publicId: string }).publicId\n\t\t\t\t: 'unknown';\n\t\treturn respond({\n\t\t\tsummary: `Triggered deploy ${publicId} on service ${args.service_id}.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'cancel_deploy',\n\tcategory: 'deploys',\n\tdescription: [\n\t\t'Cancel a running deploy. Stops the build/deploy pipeline mid-flight; the previously live revision keeps serving traffic.',\n\t\t'',\n\t\t'When to use: the user notices a bad commit was pushed and wants to abort before it lands, or a build is hanging. Also the right call for a deploy stuck in `deploying` because the new container is crash-looping against its health check — that state is cancellable and cancelling it frees the service (and the build queue) immediately instead of waiting out the grace period. Has no effect on already-finished deploys.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - deploy_id: publicId of the deploy to cancel.',\n\t\t'',\n\t\t'Returns: { ok: true }.',\n\t\t'',\n\t\t'Example: cancel_deploy({ service_id: \"svc_abc\", deploy_id: \"dpl_xyz\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tdeploy_id: z.string().describe('Deploy publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.deploys.cancel(teamId, args.service_id, args.deploy_id);\n\t\treturn respond({\n\t\t\tsummary: `Cancelled deploy ${args.deploy_id} on service ${args.service_id}.`,\n\t\t\tdata: { ok: true },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'get_deploy_logs',\n\tcategory: 'deploys',\n\tdescription: [\n\t\t'Fetch the build/deploy logs for a single deploy. Returns the entire log buffer the agent can then search for errors.',\n\t\t'',\n\t\t'When to use: a deploy failed and you need to read the build output to diagnose. Pair with get_deploy to find a failed deploy_id, then call this. For runtime (post-deploy) logs of the running container, use get_service_logs instead.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - deploy_id: publicId of the deploy.',\n\t\t'',\n\t\t'Returns: { logs: string, lineCount: number, nextAfterId: number | null } — flattened build output joined with newlines, line count, and a cursor for pagination (pass back as after_id to fetch the next page).',\n\t\t'',\n\t\t'Example: get_deploy_logs({ service_id: \"svc_abc\", deploy_id: \"dpl_xyz\" }) → { logs: \"Building…\\\\nStep 1/8…\\\\n…\", lineCount: 42, nextAfterId: 1234 }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tdeploy_id: z.string().describe('Deploy publicId.'),\n\t\tafter_id: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.optional()\n\t\t\t.describe('Pagination cursor from a previous response’s nextAfterId.'),\n\t\tlimit: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(1)\n\t\t\t.max(5000)\n\t\t\t.optional()\n\t\t\t.describe('Max log entries to fetch (default 500, hard cap 5000).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.deploys.getLogs(\n\t\t\tteamId,\n\t\t\targs.service_id,\n\t\t\targs.deploy_id,\n\t\t\t{\n\t\t\t\t...(args.after_id !== undefined ? { afterId: args.after_id } : {}),\n\t\t\t\t...(args.limit !== undefined ? { limit: args.limit } : {}),\n\t\t\t},\n\t\t);\n\t\tconst entries = response.logs;\n\t\tconst logs = entries.map((e) => e.message).join('\\n');\n\t\treturn respond({\n\t\t\tsummary: `Fetched ${entries.length} log line${entries.length === 1 ? '' : 's'} for deploy ${args.deploy_id}.`,\n\t\t\tdata: { logs, lineCount: entries.length, nextAfterId: response.nextAfterId },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'diagnose_deploy',\n\tcategory: 'deploys',\n\tdescription: [\n\t\t\"One-shot diagnostic bundle for a deploy: full deploy record + tail of build logs + tail of runtime logs starting at the deploy's start time. Lets you investigate any deploy failure mode (build-time failure, health-check timeout, post-deploy runtime crash) without juggling two log endpoints and two IDs.\",\n\t\t'',\n\t\t'When to use: a deploy is failed/superseded/stuck and you want the whole story in one call. For just the build output, use get_deploy_logs. For just runtime logs of the running service, use get_service_logs.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - deploy_id: publicId of the deploy to diagnose.',\n\t\t' - build_log_lines (optional): how many trailing build log lines to include. Default 200, max 2000.',\n\t\t' - runtime_log_lines (optional): how many trailing runtime log lines (since the deploy started) to include. Default 100, max 1000. Set to 0 to skip runtime logs (saves a round-trip when investigating a pure build-time failure).',\n\t\t'',\n\t\t'Returns: { deploy, build: { logs, lineCount }, runtime: { logs, lineCount } } — runtime is omitted when runtime_log_lines is 0 or the deploy never started a container.',\n\t\t'',\n\t\t'Example: diagnose_deploy({ service_id: \"svc_abc\", deploy_id: \"dpl_xyz\" }) → all three sections in one call.',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tdeploy_id: z.string().describe('Deploy publicId.'),\n\t\tbuild_log_lines: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(1)\n\t\t\t.max(2000)\n\t\t\t.optional()\n\t\t\t.describe('Trailing build log lines. Default 200, max 2000.'),\n\t\truntime_log_lines: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(0)\n\t\t\t.max(1000)\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t'Trailing runtime log lines since deploy start. Default 100, max 1000. 0 = skip.',\n\t\t\t),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst buildLimit = args.build_log_lines ?? 200;\n\t\tconst runtimeLimit = args.runtime_log_lines ?? 100;\n\n\t\t// Pull deploy + build logs in parallel — build logs don't depend on\n\t\t// the deploy record's metadata. Runtime logs need the deploy's\n\t\t// startedAt for the `since` window so they wait for the deploy fetch.\n\t\tconst [deployResp, buildResp] = await Promise.all([\n\t\t\tctx.hoststack.deploys.get(teamId, args.service_id, args.deploy_id),\n\t\t\tctx.hoststack.deploys.getLogs(teamId, args.service_id, args.deploy_id, {\n\t\t\t\tlimit: buildLimit,\n\t\t\t}),\n\t\t]);\n\n\t\tconst buildEntries = buildResp.logs;\n\t\tconst buildLogs = buildEntries.map((e) => e.message).join('\\n');\n\n\t\tconst deployShape = shapeDeploy(deployResp.deploy);\n\t\tconst deployStatus =\n\t\t\tdeployShape && 'status' in deployShape\n\t\t\t\t? (deployShape as { status: string }).status\n\t\t\t\t: 'unknown';\n\t\tconst startedAtRaw =\n\t\t\tdeployShape && 'startedAt' in deployShape\n\t\t\t\t? (deployShape as { startedAt: unknown }).startedAt\n\t\t\t\t: undefined;\n\t\tconst startedAt = typeof startedAtRaw === 'string' ? startedAtRaw : undefined;\n\n\t\tconst data: Record<string, unknown> = {\n\t\t\tdeploy: deployShape,\n\t\t\tbuild: { logs: buildLogs, lineCount: buildEntries.length },\n\t\t};\n\n\t\t// Skip the runtime tail when caller asked us to OR when the deploy\n\t\t// never reached the container-start phase (build-time failure).\n\t\t// `startedAt` is set by the API when the deploy row is created, so\n\t\t// it's almost always present; the more reliable container-started\n\t\t// signal is whether status ever passed the build phase.\n\t\tconst hadContainer = deployStatus !== 'pending' && deployStatus !== 'building';\n\t\tif (runtimeLimit > 0 && hadContainer) {\n\t\t\tconst runtimeResp = await ctx.hoststack.services.getRuntimeLogs(\n\t\t\t\tteamId,\n\t\t\t\targs.service_id,\n\t\t\t\t{\n\t\t\t\t\tlines: runtimeLimit,\n\t\t\t\t\t...(startedAt ? { since: startedAt } : {}),\n\t\t\t\t},\n\t\t\t);\n\t\t\tif ('count' in runtimeResp) {\n\t\t\t\t// getRuntimeLogs without countOnly should never return this\n\t\t\t\t// shape; defensive branch for future-proofing.\n\t\t\t\tdata['runtime'] = { logs: '', lineCount: runtimeResp.count };\n\t\t\t} else {\n\t\t\t\tconst runtimeEntries = Array.isArray(runtimeResp.logs)\n\t\t\t\t\t? runtimeResp.logs\n\t\t\t\t\t: typeof runtimeResp.logs === 'string'\n\t\t\t\t\t\t? runtimeResp.logs.split('\\n').map((line) => ({ message: line }))\n\t\t\t\t\t\t: [];\n\t\t\t\tconst runtimeText = runtimeEntries\n\t\t\t\t\t.map((e) =>\n\t\t\t\t\t\ttypeof e === 'object' && 'message' in e ? String(e.message) : String(e),\n\t\t\t\t\t)\n\t\t\t\t\t.join('\\n');\n\t\t\t\tdata['runtime'] = {\n\t\t\t\t\tlogs: runtimeText,\n\t\t\t\t\tlineCount: runtimeEntries.length,\n\t\t\t\t\tsinceWindow: startedAt ?? null,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\t// Surface anything that might explain a failure — these field names\n\t\t// vary slightly across deploy phases (build, deploy, healthcheck) so\n\t\t// we look at the deploy shape directly rather than hard-coding.\n\t\tconst failureSummary = shape({\n\t\t\tstatus: deployStatus,\n\t\t\terrorMessage:\n\t\t\t\tdeployShape && 'errorMessage' in deployShape\n\t\t\t\t\t? (deployShape as { errorMessage: unknown }).errorMessage\n\t\t\t\t\t: undefined,\n\t\t});\n\t\tdata['summary'] = failureSummary;\n\n\t\treturn respond({\n\t\t\tsummary: `Diagnostic bundle for deploy ${args.deploy_id} (${deployStatus}): ${buildEntries.length} build log line${buildEntries.length === 1 ? '' : 's'}${runtimeLimit > 0 && hadContainer ? ', runtime log tail included' : ''}.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n","import { z } from 'zod';\nimport type { DnsRecord, DnsRecordType, DnsZone, HostStack } from '@hoststack.dev/sdk';\n\nimport { defineTool } from '../registry.js';\nimport { respond, respondError } from '../lib/respond.js';\nimport { shape } from '../lib/shape.js';\n\n/**\n * DNS-zone + record management. These tools delegate to the SDK's\n * `DnsResource` (`ctx.hoststack.dns`), which wraps the same HTTP routes\n * the dashboard uses — `/api/dns-zones/:teamId/...` — so tenancy, audit\n * logging, PowerDNS sync, and idempotency behavior all match the\n * dashboard exactly. We never bypass the service layer.\n *\n * The HTTP-domain tools (list_domains, add_domain, verify_domain,\n * remove_domain) are about binding a hostname to a service for HTTP\n * routing + Let's Encrypt; they don't touch the underlying DNS zone.\n * Use these tools for actual record CRUD (TXT for verification, A/AAAA\n * for custom routing, MX for email, etc.).\n */\n// Source of truth for record types is `@hoststack/shared`'s\n// `dnsRecordTypeSchema`, surfaced through the SDK's `DnsRecordType`. This array\n// drives the zod input shape (a value, so it can't be the bare type); the\n// `satisfies` clause makes the build fail if it ever drifts from the SDK union.\nconst DNS_RECORD_TYPES = [\n\t'A',\n\t'AAAA',\n\t'CNAME',\n\t'MX',\n\t'TXT',\n\t'NS',\n\t'SRV',\n\t'CAA',\n\t'ALIAS',\n] as const satisfies readonly DnsRecordType[];\n\n// Exhaustiveness guard the other direction: every DnsRecordType must appear in\n// the array above. If the SDK adds a record type, this errors until it's added.\nconst _dnsTypesExhaustive: Record<DnsRecordType, true> = {\n\tA: true,\n\tAAAA: true,\n\tCNAME: true,\n\tMX: true,\n\tTXT: true,\n\tNS: true,\n\tSRV: true,\n\tCAA: true,\n\tALIAS: true,\n};\nvoid _dnsTypesExhaustive;\n\n/**\n * Resolve `{ zone_id?, domain? }` to the zone's `publicId`. Accepts\n * either the zone publicId directly or a domain name (apex or\n * subdomain) and walks parent labels to find the longest-matching\n * hosted zone, same suffix-match semantics as\n * `DnsService.findHostedZoneForDomain` (apps/api/src/services/dns.service.ts:193).\n *\n * Returns the zone's publicId so the caller can address subsequent\n * routes by it, plus a human-readable hint about which zone matched.\n */\nasync function resolveZonePublicId(\n\thoststack: HostStack,\n\tteamId: number,\n\tinput: { zone_id?: string; domain?: string },\n): Promise<{ publicId: string; domainName: string }> {\n\tif (input.zone_id) {\n\t\tconst { zones } = await hoststack.dns.listZones(teamId);\n\t\tconst match = zones.find((z) => z.publicId === input.zone_id);\n\t\tif (!match) {\n\t\t\tthrow new Error(`Zone ${input.zone_id} not found on this team.`);\n\t\t}\n\t\treturn { publicId: match.publicId, domainName: match.domainName };\n\t}\n\tif (!input.domain) {\n\t\tthrow new Error('Provide either zone_id or domain.');\n\t}\n\tconst { zones } = await hoststack.dns.listZones(teamId);\n\tconst fqdn = input.domain.toLowerCase().replace(/\\.$/, '');\n\tconst labels = fqdn.split('.');\n\tfor (let i = 0; i < labels.length - 1; i++) {\n\t\tconst candidate = labels.slice(i).join('.');\n\t\tconst match = zones.find((z) => z.domainName.toLowerCase() === candidate);\n\t\tif (match && match.status !== 'deleting') {\n\t\t\treturn { publicId: match.publicId, domainName: match.domainName };\n\t\t}\n\t}\n\tthrow new Error(\n\t\t`No hosted zone matches ${input.domain}. Create the zone in the dashboard (Domains → DNS) first, then retry.`,\n\t);\n}\n\ndefineTool({\n\tname: 'list_dns_zones',\n\tcategory: 'dns',\n\tdescription: [\n\t\t\"List authoritative DNS zones the team owns on HostStack's PowerDNS infrastructure. Each zone is the apex domain (e.g. example.com) under which DNS records live.\",\n\t\t'',\n\t\t'When to use: discover which apex domains support record management before calling create_dns_record / list_dns_records. The dashboard equivalent is Domains → DNS.',\n\t\t'',\n\t\t'Returns: { items: Zone[] } — each zone exposes publicId, domainName, status (\"active\" | \"syncing\" | \"failed\" | \"deleting\"), nsRecords (the nameservers the parent registry must delegate to), provider, createdAt.',\n\t\t'',\n\t\t'Example: list_dns_zones() → { items: [{ publicId: \"dnz_abc\", domainName: \"micci.dk\", status: \"active\", nsRecords: [\"ns1.hoststack.dev\",\"ns2.hoststack.dev\"] }] }',\n\t].join('\\n'),\n\tinput: {},\n\thandler: async (_args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.dns.listZones(teamId);\n\t\tconst items = Array.isArray(response.zones) ? response.zones.map(shape) : [];\n\t\tconst summary =\n\t\t\titems.length === 0\n\t\t\t\t? 'No DNS zones hosted on this team. Create one in the dashboard (Domains → DNS).'\n\t\t\t\t: `Found ${items.length} hosted DNS zone${items.length === 1 ? '' : 's'}.`;\n\t\treturn respond({ summary, data: { items } });\n\t},\n});\n\ndefineTool({\n\tname: 'list_dns_records',\n\tcategory: 'dns',\n\tdescription: [\n\t\t'List every active record in a hosted DNS zone. Records are addressed by their type + name + value tuple; PowerDNS gathers records with the same (name, type) into an RRset on the wire.',\n\t\t'',\n\t\t'When to use: audit what is currently published for a zone before editing, verify a recently-created record landed, or read existing TXT verification strings.',\n\t\t'',\n\t\t'Provide EITHER zone_id (the zone publicId, e.g. \"dnz_abc\") OR domain (an apex or subdomain — the longest-matching hosted apex wins; \"app.example.com\" matches a hosted \"example.com\" zone).',\n\t\t'',\n\t\t'Returns: { zone: { publicId, domainName }, items: Record[] } — each record includes publicId, type, name (\"@\" for apex, or label), value, ttl, priority?, status (\"active\" | \"syncing\" | \"failed\"), managedBy (\"user\" | \"hoststack\" | \"poststack\"), createdAt.',\n\t\t'',\n\t\t'Example: list_dns_records({ domain: \"micci.dk\" }) → { zone: { domainName: \"micci.dk\", … }, items: [{ type: \"TXT\", name: \"@\", value: \"google-site-verification=…\", ttl: 300, … }] }',\n\t].join('\\n'),\n\tinput: {\n\t\tzone_id: z.string().optional().describe('Zone publicId (e.g. \"dnz_abc\").'),\n\t\tdomain: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe('Apex or subdomain — resolves to the longest-matching hosted zone.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst zoneInput: { zone_id?: string; domain?: string } = {};\n\t\tif (args.zone_id !== undefined) zoneInput.zone_id = args.zone_id;\n\t\tif (args.domain !== undefined) zoneInput.domain = args.domain;\n\t\tconst zone = await resolveZonePublicId(ctx.hoststack, teamId, zoneInput);\n\t\tconst response = await ctx.hoststack.dns.listRecords(teamId, zone.publicId);\n\t\tconst items = Array.isArray(response.records) ? response.records.map(shape) : [];\n\t\tconst summary =\n\t\t\titems.length === 0\n\t\t\t\t? `Zone ${zone.domainName} has no records yet.`\n\t\t\t\t: `Returned ${items.length} record${items.length === 1 ? '' : 's'} for ${zone.domainName}.`;\n\t\treturn respond({\n\t\t\tsummary,\n\t\t\tdata: { zone: { publicId: zone.publicId, domainName: zone.domainName }, items },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'get_dns_record',\n\tcategory: 'dns',\n\tdescription: [\n\t\t'Fetch a single DNS record by its publicId. Useful for confirming the record landed after create_dns_record / update_dns_record (status transitions from \"syncing\" to \"active\" once PowerDNS acknowledges).',\n\t\t'',\n\t\t'When to use: verify a record exists, inspect its current ttl/value, or check the sync status of an in-flight write.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - record_id: record publicId (e.g. \"dnr_abc\"). Returned by list_dns_records and create_dns_record.',\n\t\t'',\n\t\t'Returns: { record: Record }. Mirrors the shape returned by list_dns_records.',\n\t\t'',\n\t\t'Example: get_dns_record({ record_id: \"dnr_abc\" }) → { record: { type: \"TXT\", name: \"@\", value: \"…\", status: \"active\", … } }',\n\t].join('\\n'),\n\tinput: {\n\t\trecord_id: z.string().describe('Record publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\t// Records have no direct GET-by-id route — walk the team's zones\n\t\t// and scan each for the matching publicId. Zones-per-team is tiny\n\t\t// (≤ a few dozen even on heavy users) so this is cheap.\n\t\tconst { zones } = await ctx.hoststack.dns.listZones(teamId);\n\t\tfor (const zone of zones) {\n\t\t\tconst { records } = await ctx.hoststack.dns.listRecords(teamId, zone.publicId);\n\t\t\tconst match = records.find((r) => r.publicId === args.record_id);\n\t\t\tif (match) {\n\t\t\t\treturn respond({\n\t\t\t\t\tsummary: `Record ${match.type} ${match.name} on ${zone.domainName}.`,\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tzone: { publicId: zone.publicId, domainName: zone.domainName },\n\t\t\t\t\t\trecord: shape(match),\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn respondError(`Record ${args.record_id} not found on any zone owned by this team.`);\n\t},\n});\n\ndefineTool({\n\tname: 'create_dns_record',\n\tcategory: 'dns',\n\tdescription: [\n\t\t'Create a DNS record on a hosted zone. Writes to the DB first, then mirrors to PowerDNS — record returns with status=\"syncing\" until the provider acknowledges, then flips to \"active\". Re-creating the same (zone, type, name, value) tuple is idempotent and returns the existing row.',\n\t\t'',\n\t\t'When to use: add TXT verification records (Google Search Console, domain ownership challenges, DKIM), A/AAAA records pointing a subdomain at an IP, CNAME aliases, MX records, etc.',\n\t\t'',\n\t\t'Provide EITHER zone_id (zone publicId) OR domain (resolves via longest-suffix match against hosted zones).',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - type: \"A\" | \"AAAA\" | \"CNAME\" | \"MX\" | \"TXT\" | \"NS\" | \"SRV\" | \"CAA\" | \"ALIAS\".',\n\t\t' - name: \"@\" for the zone apex, or a subdomain label (\"www\", \"api\", \"_acme-challenge\"). Do NOT include the zone suffix — the backend prepends it. \"bounce\" on zone \"micci.dk\" publishes \"bounce.micci.dk\"; passing \"bounce.micci.dk\" works (the backend strips the suffix) but is non-idiomatic.',\n\t\t' - content: the literal record value. For TXT pass the unquoted string — the PowerDNS layer handles quoting. For CNAME / MX / NS / SRV / ALIAS the target may be passed with or without a trailing dot; the adapter FQDN-izes it.',\n\t\t' - ttl (optional): 60–86400 seconds, default 3600.',\n\t\t' - priority (optional, required for MX and SRV): 0–65535.',\n\t\t'',\n\t\t'Returns: { record: Record } — see get_dns_record for the shape.',\n\t\t'',\n\t\t'Notes:',\n\t\t' - CNAME at the apex is rejected (RFC 1034 forbids CNAME coexisting with NS/SOA). Use type=\"ALIAS\" for apex aliasing.',\n\t\t'',\n\t\t'Example: create_dns_record({ domain: \"micci.dk\", type: \"TXT\", name: \"@\", content: \"google-site-verification=C0V0scK48g2…\", ttl: 300 })',\n\t].join('\\n'),\n\tinput: {\n\t\tzone_id: z.string().optional().describe('Zone publicId.'),\n\t\tdomain: z.string().optional().describe('Apex or subdomain to resolve a hosted zone.'),\n\t\ttype: z.enum(DNS_RECORD_TYPES).describe('DNS record type.'),\n\t\tname: z\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(253)\n\t\t\t.describe('\"@\" for apex, or a bare label. Do NOT include the zone suffix.'),\n\t\tcontent: z.string().min(1).max(2000).describe('Record value; TXT values are unquoted.'),\n\t\tttl: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(60)\n\t\t\t.max(86_400)\n\t\t\t.optional()\n\t\t\t.describe('TTL in seconds (default 3600).'),\n\t\tpriority: z.number().int().min(0).max(65_535).optional().describe('Required for MX / SRV.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\t// MX/SRV records carry priority on the wire; the shared upsert\n\t\t// schema enforces this with a superRefine. The MCP `input` shape\n\t\t// is a flat ZodRawShape so we can't express cross-field rules\n\t\t// there — surface a clean error from the handler instead of\n\t\t// letting the backend's 400 bubble up.\n\t\tif ((args.type === 'MX' || args.type === 'SRV') && args.priority === undefined) {\n\t\t\treturn respondError(`Priority is required for ${args.type} records (0–65535).`);\n\t\t}\n\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst zoneInput: { zone_id?: string; domain?: string } = {};\n\t\tif (args.zone_id !== undefined) zoneInput.zone_id = args.zone_id;\n\t\tif (args.domain !== undefined) zoneInput.domain = args.domain;\n\t\tconst zone = await resolveZonePublicId(ctx.hoststack, teamId, zoneInput);\n\n\t\tconst body: {\n\t\t\ttype: DnsRecordType;\n\t\t\tname: string;\n\t\t\tvalue: string;\n\t\t\tttl?: number;\n\t\t\tpriority?: number;\n\t\t} = {\n\t\t\ttype: args.type,\n\t\t\tname: args.name,\n\t\t\tvalue: args.content,\n\t\t};\n\t\tif (args.ttl !== undefined) body.ttl = args.ttl;\n\t\tif (args.priority !== undefined) body.priority = args.priority;\n\n\t\tconst response = await ctx.hoststack.dns.createRecord(teamId, zone.publicId, body);\n\t\treturn respond({\n\t\t\tsummary: `Created ${args.type} ${args.name} on ${zone.domainName}.`,\n\t\t\tdata: {\n\t\t\t\tzone: { publicId: zone.publicId, domainName: zone.domainName },\n\t\t\t\trecord: shape(response.record),\n\t\t\t},\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'update_dns_record',\n\tcategory: 'dns',\n\tdescription: [\n\t\t'Update an existing DNS record by its publicId. Use this to change a TTL, swap a value, or move the record to a different (name, type) bucket. Full-record PUT semantics: every mutable field must be provided.',\n\t\t'',\n\t\t'When to use: rotate a DKIM key, repoint an A record at a new IP, bump TTL ahead of a planned change.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - record_id: record publicId.',\n\t\t' - type, name, content: the new values (the route is full-replace, not patch — fetch with get_dns_record first if you only want to tweak one field).',\n\t\t' - ttl (optional), priority (optional, required for MX / SRV).',\n\t\t'',\n\t\t'Returns: { record: Record } reflecting the new state.',\n\t\t'',\n\t\t'Example: update_dns_record({ record_id: \"dnr_abc\", type: \"A\", name: \"api\", content: \"203.0.113.42\", ttl: 300 })',\n\t].join('\\n'),\n\tinput: {\n\t\trecord_id: z.string().describe('Record publicId.'),\n\t\ttype: z.enum(DNS_RECORD_TYPES).describe('DNS record type.'),\n\t\tname: z\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(253)\n\t\t\t.describe('\"@\" for apex, or a bare label. Do NOT include the zone suffix.'),\n\t\tcontent: z.string().min(1).max(2000).describe('Record value; TXT unquoted.'),\n\t\tttl: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(60)\n\t\t\t.max(86_400)\n\t\t\t.optional()\n\t\t\t.describe('TTL in seconds (default 3600).'),\n\t\tpriority: z.number().int().min(0).max(65_535).optional().describe('Required for MX / SRV.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tif ((args.type === 'MX' || args.type === 'SRV') && args.priority === undefined) {\n\t\t\treturn respondError(`Priority is required for ${args.type} records (0–65535).`);\n\t\t}\n\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst target = await findRecordZone(ctx.hoststack, teamId, args.record_id);\n\t\tif (!target) {\n\t\t\treturn respondError(\n\t\t\t\t`Record ${args.record_id} not found on any zone owned by this team.`,\n\t\t\t);\n\t\t}\n\n\t\tconst body: {\n\t\t\ttype: DnsRecordType;\n\t\t\tname: string;\n\t\t\tvalue: string;\n\t\t\tttl?: number;\n\t\t\tpriority?: number;\n\t\t} = {\n\t\t\ttype: args.type,\n\t\t\tname: args.name,\n\t\t\tvalue: args.content,\n\t\t};\n\t\tif (args.ttl !== undefined) body.ttl = args.ttl;\n\t\tif (args.priority !== undefined) body.priority = args.priority;\n\n\t\tconst response = await ctx.hoststack.dns.updateRecord(\n\t\t\tteamId,\n\t\t\ttarget.zone.publicId,\n\t\t\targs.record_id,\n\t\t\tbody,\n\t\t);\n\t\treturn respond({\n\t\t\tsummary: `Updated ${args.type} ${args.name} on ${target.zone.domainName}.`,\n\t\t\tdata: {\n\t\t\t\tzone: {\n\t\t\t\t\tpublicId: target.zone.publicId,\n\t\t\t\t\tdomainName: target.zone.domainName,\n\t\t\t\t},\n\t\t\t\trecord: shape(response.record),\n\t\t\t},\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'delete_dns_record',\n\tcategory: 'dns',\n\tdescription: [\n\t\t'Soft-delete a DNS record and remove it from PowerDNS. DESTRUCTIVE: resolvers stop returning the value as soon as the change propagates. Same code path as the dashboard delete button — the row is marked deleted and the RRset is re-pushed without it.',\n\t\t'',\n\t\t'When to use: retire a TXT verification record once the challenge has been confirmed; drop an A record for a decommissioned subdomain.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - record_id: record publicId.',\n\t\t'',\n\t\t'Returns: { ok: true }.',\n\t\t'',\n\t\t'Example: delete_dns_record({ record_id: \"dnr_abc\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\trecord_id: z.string().describe('Record publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst target = await findRecordZone(ctx.hoststack, teamId, args.record_id);\n\t\tif (!target) {\n\t\t\treturn respondError(\n\t\t\t\t`Record ${args.record_id} not found on any zone owned by this team.`,\n\t\t\t);\n\t\t}\n\t\tawait ctx.hoststack.dns.deleteRecord(teamId, target.zone.publicId, args.record_id);\n\t\treturn respond({\n\t\t\tsummary: `Deleted record ${args.record_id} from ${target.zone.domainName}.`,\n\t\t\tdata: { ok: true },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'resync_dns_record',\n\tcategory: 'dns',\n\tdescription: [\n\t\t'Re-push a DNS record to PowerDNS without changing its value. Recovers a record stuck at status=\"failed\" after a transient provider outage — including managedBy=\"hoststack\" records (auto-created for a service/domain) that create/update/delete refuse to touch.',\n\t\t'',\n\t\t'When to use: a record shows status=\"failed\" with a lastSyncError, or a freshly-attached domain\\'s auto-created A record never went active. Safe and idempotent — a rejected re-push leaves the live RRset untouched (PowerDNS PATCH is atomic), so this can never drop a working record.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - record_id: record publicId (e.g. \"dnr_abc\").',\n\t\t'',\n\t\t'Returns: { record: Record } — the record with its refreshed status (\"active\" on success).',\n\t\t'',\n\t\t'Example: resync_dns_record({ record_id: \"dnr_abc\" }) → { record: { status: \"active\", ... } }',\n\t].join('\\n'),\n\tinput: {\n\t\trecord_id: z.string().describe('Record publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst target = await findRecordZone(ctx.hoststack, teamId, args.record_id);\n\t\tif (!target) {\n\t\t\treturn respondError(\n\t\t\t\t`Record ${args.record_id} not found on any zone owned by this team.`,\n\t\t\t);\n\t\t}\n\t\tconst response = await ctx.hoststack.dns.resyncRecord(\n\t\t\tteamId,\n\t\t\ttarget.zone.publicId,\n\t\t\targs.record_id,\n\t\t);\n\t\treturn respond({\n\t\t\tsummary: `Re-synced record ${args.record_id} on ${target.zone.domainName} (status: ${response.record.status}).`,\n\t\t\tdata: {\n\t\t\t\tzone: {\n\t\t\t\t\tpublicId: target.zone.publicId,\n\t\t\t\t\tdomainName: target.zone.domainName,\n\t\t\t\t},\n\t\t\t\trecord: shape(response.record),\n\t\t\t},\n\t\t});\n\t},\n});\n\n/**\n * The DNS HTTP routes nest records under their zone, so update/delete\n * by record publicId needs the owning zone's publicId too. Walk the\n * team's zones until we find a record match. Cheap — zone count is\n * bounded by team-tier limits.\n */\nasync function findRecordZone(\n\thoststack: HostStack,\n\tteamId: number,\n\trecordPublicId: string,\n): Promise<{ zone: DnsZone; record: DnsRecord } | null> {\n\tconst { zones } = await hoststack.dns.listZones(teamId);\n\tfor (const zone of zones) {\n\t\tconst { records } = await hoststack.dns.listRecords(teamId, zone.publicId);\n\t\tconst match = records.find((r) => r.publicId === recordPublicId);\n\t\tif (match) return { zone, record: match };\n\t}\n\treturn null;\n}\n","import { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond } from '../lib/respond.js';\nimport { shapeDomain, shapeList } from '../lib/shape.js';\n\ndefineTool({\n\tname: 'list_domains',\n\tcategory: 'domains',\n\tdescription: [\n\t\t\"List every custom domain attached to the team's services.\",\n\t\t'',\n\t\t'When to use: enumerate live domains, audit DNS verification status, or find which service a hostname resolves to before troubleshooting routing.',\n\t\t'',\n\t\t'Returns: { items: Domain[] } — id, publicId, hostname, serviceId, verified, dnsTargets, sslStatus, createdAt.',\n\t\t'',\n\t\t'Example: list_domains() → { items: [{ hostname: \"api.example.com\", verified: true, sslStatus: \"active\", … }] }',\n\t].join('\\n'),\n\tinput: {},\n\thandler: async (_args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.domains.list(teamId);\n\t\tconst data = shapeList(response, 'domains', shapeDomain);\n\t\tconst summary =\n\t\t\tdata.items.length === 0\n\t\t\t\t? 'No custom domains configured.'\n\t\t\t\t: `Found ${data.items.length} custom domain${data.items.length === 1 ? '' : 's'}.`;\n\t\treturn respond({ summary, data });\n\t},\n});\n\ndefineTool({\n\tname: 'add_domain',\n\tcategory: 'domains',\n\tdescription: [\n\t\t'Attach a custom hostname to the team — optionally pinned to a specific service. After adding, point your DNS at the targets returned and call verify_domain.',\n\t\t'',\n\t\t'When to use: the user wants to put a custom domain in front of a HostStack service (e.g. point api.example.com at svc_abc). The hostname must be unique across the team.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - hostname: the domain to add (e.g. \"api.example.com\").',\n\t\t' - service_id: publicId of the service to bind the domain to.',\n\t\t' - path_prefix (optional): when set, only requests under this URL prefix route to this service. Use for path-based fan-out (e.g. `/api` to an api service, `/` to a web service on the same hostname).',\n\t\t'',\n\t\t'Returns: { domain: Domain } — includes dnsTargets you must configure (CNAME / A records).',\n\t\t'',\n\t\t'Example: add_domain({ hostname: \"api.example.com\", service_id: \"svc_abc\" }) → { domain: { hostname: \"api.example.com\", dnsTargets: [...], verified: false, … } }',\n\t].join('\\n'),\n\tinput: {\n\t\thostname: z\n\t\t\t.string()\n\t\t\t.min(3)\n\t\t\t.max(253)\n\t\t\t.describe('Fully-qualified hostname (e.g. api.example.com).'),\n\t\tservice_id: z.string().describe('Service publicId to bind to.'),\n\t\tpath_prefix: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe('Optional URL prefix for path-based routing (e.g. \"/api\").'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst input: { domain: string; serviceId: string; pathPrefix?: string } = {\n\t\t\tdomain: args.hostname,\n\t\t\tserviceId: args.service_id,\n\t\t};\n\t\tif (args.path_prefix !== undefined) input.pathPrefix = args.path_prefix;\n\t\tconst response = await ctx.hoststack.domains.add(teamId, input);\n\t\t// When HostStack hosts the zone it auto-creates the A record; if that\n\t\t// write can't reach the provider the API returns the domain plus a\n\t\t// dnsSyncWarning. Relay it so the caller doesn't read the bare pending\n\t\t// status as success. The record recovers via the reconcile sweep or a\n\t\t// manual resync_dns_record call.\n\t\tconst dnsSyncWarning = (response.domain as { dnsSyncWarning?: string }).dnsSyncWarning;\n\t\tconst data = dnsSyncWarning\n\t\t\t? { domain: shapeDomain(response.domain), dnsSyncWarning }\n\t\t\t: { domain: shapeDomain(response.domain) };\n\t\treturn respond({\n\t\t\tsummary: dnsSyncWarning\n\t\t\t\t? `Added domain ${args.hostname}, but its auto-created DNS record hasn't synced yet — ${dnsSyncWarning}`\n\t\t\t\t: `Added domain ${args.hostname}. Configure DNS, then call verify_domain.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'verify_domain',\n\tcategory: 'domains',\n\tdescription: [\n\t\t'Trigger DNS verification for a previously-added domain. HostStack checks that the dnsTargets returned by add_domain are configured at the registrar.',\n\t\t'',\n\t\t'When to use: the user has set up DNS records and is ready to flip the domain live. Returns success when verification passes; the domain stays in pending state if DNS is still propagating.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - domain_id: publicId of the domain (from list_domains or add_domain).',\n\t\t'',\n\t\t'Returns: { ok: true }. Re-call list_domains to inspect the updated verified flag and SSL status.',\n\t\t'',\n\t\t'Example: verify_domain({ domain_id: \"dom_xyz\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tdomain_id: z.string().describe('Domain publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.domains.verify(teamId, args.domain_id);\n\t\treturn respond({\n\t\t\tsummary: `Triggered DNS verification for ${args.domain_id}.`,\n\t\t\tdata: { ok: true },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'remove_domain',\n\tcategory: 'domains',\n\tdescription: [\n\t\t'Detach a custom hostname from the team. DESTRUCTIVE: the domain stops routing immediately and any pinned service must fall back to its default hostname.',\n\t\t'',\n\t\t'When to use: the user wants to retire a custom domain. Confirm with the user first — the change is immediate and cannot be undone except by re-adding the domain and re-verifying DNS.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - domain_id: publicId of the domain to remove.',\n\t\t'',\n\t\t'Returns: { ok: true }.',\n\t\t'',\n\t\t'Example: remove_domain({ domain_id: \"dom_xyz\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tdomain_id: z.string().describe('Domain publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.domains.remove(teamId, args.domain_id);\n\t\treturn respond({ summary: `Removed domain ${args.domain_id}.`, data: { ok: true } });\n\t},\n});\n","import { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond, respondError } from '../lib/respond.js';\nimport { shapeEnvVar, shapeList } from '../lib/shape.js';\n\ninterface ExistingEnvVar {\n\tid: number;\n\tpublicId?: string;\n\tkey: string;\n\tisSecret: boolean;\n}\n\ndefineTool({\n\tname: 'list_env_vars',\n\tcategory: 'env-vars',\n\tdescription: [\n\t\t'List environment variables for a service. Secret values are masked server-side (\"••••••\"); only non-secret values come through in the clear.',\n\t\t'',\n\t\t'When to use: auditing what configuration a service has, finding the key for a value the user mentions by name, or confirming a variable was set after a write. Never assume the value field is plaintext for secret rows — it is masked.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t'',\n\t\t'Returns: { items: EnvVar[] } — id, publicId, key, value (masked if isSecret), isSecret, target, linkedDatabaseId, createdAt.',\n\t\t'',\n\t\t'Example: list_env_vars({ service_id: \"svc_abc\" }) → { items: [{ key: \"DATABASE_URL\", value: \"••••••\", isSecret: true }, { key: \"PORT\", value: \"3000\", isSecret: false }] }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.envVars.list(teamId, args.service_id);\n\t\tconst data = shapeList(response, 'envVars', shapeEnvVar);\n\t\tconst summary =\n\t\t\tdata.items.length === 0\n\t\t\t\t? `No env vars set on service ${args.service_id}.`\n\t\t\t\t: `Found ${data.items.length} env var${data.items.length === 1 ? '' : 's'} on service ${args.service_id}.`;\n\t\treturn respond({ summary, data });\n\t},\n});\n\ndefineTool({\n\tname: 'set_env_var',\n\tcategory: 'env-vars',\n\tdescription: [\n\t\t'Upsert a single environment variable on a service: creates the key if missing, updates the value if it already exists. Match is by key (case-sensitive).',\n\t\t'',\n\t\t'When to use: rotate a secret, add a new config knob, or change a value the user dictated. The MCP layer looks up the existing var by key first; you do not need to know the env-var ID.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - key: env-var name (e.g. \"DATABASE_URL\").',\n\t\t' - value: new value (will be encrypted at rest if is_secret=true).',\n\t\t' - is_secret (optional): true marks the value as secret (masked on read). On create, defaults to true for safety. On update, omitting it leaves the existing flag untouched — pass it explicitly only when you want to change classification.',\n\t\t' - target (optional): where the var is injected — \"build\", \"runtime\", or \"both\". On create, defaults to \"both\". On update, omitting it leaves the existing target untouched.',\n\t\t'',\n\t\t'Returns: { envVar: EnvVar, action: \"created\" | \"updated\" }.',\n\t\t'',\n\t\t'Example: set_env_var({ service_id: \"svc_abc\", key: \"DATABASE_URL\", value: \"postgres://…\", is_secret: true }) → { envVar: { key: \"DATABASE_URL\", value: \"••••••\", … }, action: \"updated\" }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tkey: z.string().min(1).max(128).describe('Env-var key.'),\n\t\tvalue: z.string().describe('New value.'),\n\t\tis_secret: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe('Mark as secret (encrypted, masked on read). Default true.'),\n\t\ttarget: z\n\t\t\t.enum(['build', 'runtime', 'both'])\n\t\t\t.optional()\n\t\t\t.describe('Injection target: build, runtime, or both. Default both.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst existing = await ctx.hoststack.envVars.list(teamId, args.service_id);\n\t\tconst match = (existing.envVars as ExistingEnvVar[]).find((v) => v.key === args.key);\n\n\t\tif (match) {\n\t\t\t// On update, only forward `isSecret`/`target` when the caller\n\t\t\t// passed them explicitly. Defaulting `isSecret` to `true` here\n\t\t\t// would silently flip previously-plaintext keys (PORT, NODE_ENV,\n\t\t\t// …) to secret on every value change.\n\t\t\tconst updatePayload: {\n\t\t\t\tvalue: string;\n\t\t\t\tisSecret?: boolean;\n\t\t\t\ttarget?: 'build' | 'runtime' | 'both';\n\t\t\t} = { value: args.value };\n\t\t\tif (args.is_secret !== undefined) updatePayload.isSecret = args.is_secret;\n\t\t\tif (args.target !== undefined) updatePayload.target = args.target;\n\t\t\tconst response = await ctx.hoststack.envVars.update(\n\t\t\t\tteamId,\n\t\t\t\targs.service_id,\n\t\t\t\tString(match.id),\n\t\t\t\tupdatePayload,\n\t\t\t);\n\t\t\tconst data = {\n\t\t\t\tenvVar: shapeEnvVar(response.envVar),\n\t\t\t\taction: 'updated' as const,\n\t\t\t};\n\t\t\treturn respond({ summary: `Updated ${args.key} on service ${args.service_id}.`, data });\n\t\t}\n\n\t\tconst response = await ctx.hoststack.envVars.create(teamId, args.service_id, {\n\t\t\tkey: args.key,\n\t\t\tvalue: args.value,\n\t\t\tisSecret: args.is_secret ?? true,\n\t\t\t...(args.target !== undefined ? { target: args.target } : {}),\n\t\t});\n\t\tconst data = {\n\t\t\tenvVar: shapeEnvVar(response.envVar),\n\t\t\taction: 'created' as const,\n\t\t};\n\t\treturn respond({ summary: `Created ${args.key} on service ${args.service_id}.`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'delete_env_var',\n\tcategory: 'env-vars',\n\tdescription: [\n\t\t'Remove an environment variable from a service by key (case-sensitive).',\n\t\t'',\n\t\t'When to use: cleaning up unused config, or rotating away from a leaked secret. The MCP looks up the env-var ID from the key automatically.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - key: env-var name to delete.',\n\t\t'',\n\t\t'Returns: { ok: true } on success. Returns an error if the key was not found.',\n\t\t'',\n\t\t'Example: delete_env_var({ service_id: \"svc_abc\", key: \"OLD_FLAG\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tkey: z.string().min(1).max(128).describe('Env-var key to delete.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst existing = await ctx.hoststack.envVars.list(teamId, args.service_id);\n\t\tconst match = (existing.envVars as ExistingEnvVar[]).find((v) => v.key === args.key);\n\t\tif (!match) {\n\t\t\treturn respondError(`Env var \"${args.key}\" not found on service ${args.service_id}.`, {\n\t\t\t\tkey: args.key,\n\t\t\t\tservice_id: args.service_id,\n\t\t\t});\n\t\t}\n\t\tawait ctx.hoststack.envVars.delete(teamId, args.service_id, String(match.id));\n\t\treturn respond({\n\t\t\tsummary: `Deleted ${args.key} from service ${args.service_id}.`,\n\t\t\tdata: { ok: true },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'bulk_set_env_vars',\n\tcategory: 'env-vars',\n\tdescription: [\n\t\t'Replace the entire env-var set on a service with the given list. Equivalent to deleting all current vars and creating the supplied ones — use with care.',\n\t\t'',\n\t\t'When to use: importing a .env file, mirroring config from a sibling service, or doing a clean reset. For incremental changes, use set_env_var per key — bulk_set is destructive for any key not in the supplied list.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - env_vars: array of { key, value, is_secret?, target? }. is_secret defaults to FALSE per row (a row is stored in the clear unless you set is_secret:true); target defaults to \"both\". Note this differs from set_env_var, which defaults a newly-created var to secret.',\n\t\t'',\n\t\t'Returns: { ok: true }. Re-list with list_env_vars to confirm the new state.',\n\t\t'',\n\t\t'Example: bulk_set_env_vars({ service_id: \"svc_abc\", env_vars: [{ key: \"PORT\", value: \"3000\", is_secret: false }, { key: \"DATABASE_URL\", value: \"…\", is_secret: true }] }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tenv_vars: z\n\t\t\t.array(\n\t\t\t\tz.object({\n\t\t\t\t\tkey: z.string().min(1).max(128),\n\t\t\t\t\tvalue: z.string(),\n\t\t\t\t\tis_secret: z.boolean().optional(),\n\t\t\t\t\ttarget: z.enum(['build', 'runtime', 'both']).optional(),\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.max(500)\n\t\t\t.describe('Array of env-var rows. Hard cap 500.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst payload = {\n\t\t\tvars: args.env_vars.map((v) => {\n\t\t\t\tconst row: {\n\t\t\t\t\tkey: string;\n\t\t\t\t\tvalue: string;\n\t\t\t\t\tisSecret?: boolean;\n\t\t\t\t\ttarget?: 'build' | 'runtime' | 'both';\n\t\t\t\t} = {\n\t\t\t\t\tkey: v.key,\n\t\t\t\t\tvalue: v.value,\n\t\t\t\t};\n\t\t\t\tif (v.is_secret !== undefined) row.isSecret = v.is_secret;\n\t\t\t\tif (v.target !== undefined) row.target = v.target;\n\t\t\t\treturn row;\n\t\t\t}),\n\t\t};\n\t\tawait ctx.hoststack.envVars.bulkSet(teamId, args.service_id, payload);\n\t\treturn respond({\n\t\t\tsummary: `Replaced env-var set on service ${args.service_id} with ${args.env_vars.length} entr${args.env_vars.length === 1 ? 'y' : 'ies'}.`,\n\t\t\tdata: { ok: true, count: args.env_vars.length },\n\t\t});\n\t},\n});\n","import { z } from 'zod';\n\nimport { respond } from '../lib/respond.js';\nimport { shape, shapeList } from '../lib/shape.js';\nimport { defineTool } from '../registry.js';\n\n/**\n * v66 P5: MCP tools for project environment management.\n *\n * Environments isolate services in the same project — staging vs\n * production, for example. Each project automatically gets a Production\n * environment; users can add staging/development/preview envs to run\n * sibling services side-by-side and promote builds between them.\n */\n\ndefineTool({\n\tname: 'list_environments',\n\tcategory: 'environments',\n\tdescription: [\n\t\t'List every environment for a project (production / staging / development / preview).',\n\t\t'',\n\t\t'When to use: the user wants to see what envs exist before creating a service in one or promoting a deploy. Every project has at least Production.',\n\t\t'',\n\t\t// §2.2: these are project deployment environments, not cloud Dev Boxes — point agents at the\n\t\t// right surface so the two \"dev\" concepts stay distinct (bidirectional cross-reference).\n\t\t'NOTE — these are project deployment environments (Production / Staging / Preview), NOT agentic cloud Dev Boxes. To list Dev Boxes use list_dev_environments; to create one use create_dev_environment / create_standalone_dev_environment / spin_up_dev_environment.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - project_id: project publicId (e.g. \"prj_abc123\").',\n\t\t'',\n\t\t'Returns: { items: Environment[] } — id, publicId, name, type, isDefault, isProtected.',\n\t\t'',\n\t\t'Example: list_environments({ project_id: \"prj_abc\" }) → { items: [{ name: \"Production\", type: \"production\", isDefault: true }, { name: \"Staging\", type: \"staging\" }] }',\n\t].join('\\n'),\n\tinput: {\n\t\tproject_id: z.string().describe('Project publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.environments.list(teamId, args.project_id);\n\t\tconst data = shapeList(response, 'environments', shape);\n\t\tconst summary =\n\t\t\tdata.items.length === 0\n\t\t\t\t? 'No environments yet — every project should have Production by default.'\n\t\t\t\t: `Found ${data.items.length} environment${data.items.length === 1 ? '' : 's'}.`;\n\t\treturn respond({ summary, data });\n\t},\n});\n\ndefineTool({\n\tname: 'create_environment',\n\tcategory: 'environments',\n\tdescription: [\n\t\t'Create a new environment in a project (e.g. Staging, QA, Preview).',\n\t\t'',\n\t\t'When to use: the user wants to add an env so they can run a sibling service alongside production for testing or staging before release.',\n\t\t'',\n\t\t// §2.1/§2.2: steer callers away from the agentic cloud Dev Box tools (which live in\n\t\t// services.ts) — an environment is a deployment target, NOT a Dev Box. Bidirectional with\n\t\t// the cross-references those dev-box tools point back here.\n\t\t'NOTE — this is NOT a cloud Dev Box. An environment is a project deployment target (Production / Staging / Preview); type=\"development\" just gives services a -dev hostname suffix. For an agentic cloud Dev Box (a terminal you drive coding agents in) use create_dev_environment / create_standalone_dev_environment / spin_up_dev_environment instead.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - project_id: project publicId.',\n\t\t' - name: human-readable name (1–64 chars). Shown in the env switcher.',\n\t\t' - type: \"production\" | \"staging\" | \"development\" | \"preview\". Determines the hostname suffix on services in this env (production stays clean; others get -staging / -dev / -preview). type=\"development\" creates a PROJECT deployment environment (a -dev hostname suffix), NOT an agentic Dev Box — for a cloud dev box use create_dev_environment / create_standalone_dev_environment / spin_up_dev_environment.',\n\t\t' - is_protected (optional): require admin role for destructive actions in this env. Default false.',\n\t\t'',\n\t\t'Returns: { environment: Environment }.',\n\t\t'',\n\t\t'Example: create_environment({ project_id: \"prj_abc\", name: \"Staging\", type: \"staging\" }) → { environment: { id: 7, publicId: \"env_…\", name: \"Staging\", type: \"staging\" } }',\n\t].join('\\n'),\n\tinput: {\n\t\tproject_id: z.string().describe('Project publicId.'),\n\t\tname: z.string().min(1).max(64).describe('Environment name (1–64 chars).'),\n\t\ttype: z.enum(['production', 'staging', 'development', 'preview']).describe(\n\t\t\t// §2.1: \"development\" here is a project deployment env, NOT a cloud Dev Box.\n\t\t\t'Environment type — drives the hostname suffix. type=\"development\" creates a PROJECT deployment environment (a -dev hostname suffix), NOT an agentic Dev Box — for a cloud dev box use create_dev_environment / create_standalone_dev_environment / spin_up_dev_environment.',\n\t\t),\n\t\tis_protected: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe('Require admin role for destructive actions. Default false.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst input: {\n\t\t\tname: string;\n\t\t\ttype: 'production' | 'staging' | 'development' | 'preview';\n\t\t\tisProtected?: boolean;\n\t\t} = {\n\t\t\tname: args.name,\n\t\t\ttype: args.type,\n\t\t};\n\t\tif (args.is_protected !== undefined) input.isProtected = args.is_protected;\n\t\tconst response = await ctx.hoststack.environments.create(teamId, args.project_id, input);\n\t\tconst data = { environment: shape(response.environment) };\n\t\treturn respond({\n\t\t\tsummary: `Created environment \"${args.name}\" (${args.type}) in project ${args.project_id}.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'delete_environment',\n\tcategory: 'environments',\n\tdescription: [\n\t\t'Delete an environment from a project.',\n\t\t'',\n\t\t'When to use: an env is no longer used (e.g. tearing down a feature branch staging). Blocked when the env still has live services or databases attached — destroy or move them first. The default env (usually Production) cannot be deleted.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - project_id: project publicId.',\n\t\t' - environment_id: environment publicId or numeric id.',\n\t\t'',\n\t\t'Returns: { success: true } on success.',\n\t\t'',\n\t\t'Example: delete_environment({ project_id: \"prj_abc\", environment_id: \"env_xyz\" }) → { success: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tproject_id: z.string().describe('Project publicId.'),\n\t\tenvironment_id: z\n\t\t\t.union([z.string(), z.number()])\n\t\t\t.describe('Environment publicId or numeric id.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.environments.delete(teamId, args.project_id, args.environment_id);\n\t\treturn respond({\n\t\t\tsummary: `Deleted environment ${String(args.environment_id)} from project ${args.project_id}.`,\n\t\t\tdata: { success: true },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'promote_deploy',\n\tcategory: 'environments',\n\tdescription: [\n\t\t'Promote a built deploy from one environment to another (build-once, run-many).',\n\t\t'',\n\t\t'When to use: the user has tested a deploy in staging and wants to ship that exact image to production without rebuilding. Atomic and image-based — same docker image runs on the sibling service in the target env.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: source service publicId (the one that owns the deploy).',\n\t\t' - deploy_id: source deploy publicId. Must have `dockerImageId` set (i.e. a successful build).',\n\t\t\" - target_environment_id: env publicId or numeric id to promote into. Must be in the same project. Cannot be the source service's own env.\",\n\t\t'',\n\t\t\"Behaviour: if a sibling service with the same name already exists in the target env, the new deploy lands on it. Otherwise the API auto-clones the source service's build/runtime config into the target env first. Env-specific config (env vars, secret files, volumes, IP allowlists, custom domains) is NOT copied — those are per-env by design.\",\n\t\t'',\n\t\t'Returns: { deploy: Deploy } — the new deploy on the target service.',\n\t\t'',\n\t\t'Example: promote_deploy({ service_id: \"svc_staging\", deploy_id: \"dpl_built\", target_environment_id: \"env_prod\" }) → { deploy: { id: 99, status: \"pending\", trigger: \"rollback\", dockerImageId: \"sha256:…\" } }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Source service publicId.'),\n\t\tdeploy_id: z.string().describe('Source deploy publicId (must have a built image).'),\n\t\ttarget_environment_id: z\n\t\t\t.union([z.string(), z.number()])\n\t\t\t.describe('Target environment publicId or numeric id.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\t// Resolve target env to numeric id; the API expects a number.\n\t\tconst targetEnvId = await ctx.hoststack.resolveId(args.target_environment_id, {\n\t\t\tkind: 'environment',\n\t\t\tteamId: await ctx.hoststack.resolveId(teamId, { kind: 'team' }),\n\t\t});\n\t\tconst response = await ctx.hoststack.deploys.promote(\n\t\t\tteamId,\n\t\t\targs.service_id,\n\t\t\targs.deploy_id,\n\t\t\ttargetEnvId,\n\t\t);\n\t\tconst data = { deploy: shape(response.deploy) };\n\t\treturn respond({\n\t\t\tsummary: `Promoted deploy ${args.deploy_id} from service ${args.service_id} to env ${String(args.target_environment_id)}.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n","import { respond, respondError } from '../lib/respond.js';\nimport { defineTool } from '../registry.js';\n\ninterface Installation {\n\tid: number;\n\taccountLogin: string;\n}\n\ninterface SyncedRepo {\n\tid: number;\n\tfullName: string;\n}\n\ndefineTool({\n\tname: 'sync_github_repos',\n\tcategory: 'github',\n\tdescription: [\n\t\t'Re-sync the repository list from GitHub for every connected GitHub App installation.',\n\t\t'',\n\t\t\"When to use: right after pushing a brand-new repository, HostStack cannot see it until an installation re-sync runs — so create_service with a github_repo_id would fail. Call this first. (Same operation as the dashboard's refresh icon on the repo picker.)\",\n\t\t'',\n\t\t'No inputs.',\n\t\t'',\n\t\t'Returns: { installations: number, repos: [{ account, count }], totalRepos } — the accounts synced and how many repos each now exposes.',\n\t\t'',\n\t\t'Example: sync_github_repos({}) → { installations: 1, repos: [{ account: \"acme\", count: 12 }], totalRepos: 12 }',\n\t].join('\\n'),\n\tinput: {},\n\thandler: async (_args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst { installations } = await ctx.api.get<{ installations: Installation[] }>(\n\t\t\t`/api/github/${teamId}/installations`,\n\t\t);\n\t\tif (installations.length === 0) {\n\t\t\treturn respondError(\n\t\t\t\t'No GitHub installations connected. Install the HostStack GitHub App from the dashboard (Settings → GitHub) first.',\n\t\t\t);\n\t\t}\n\n\t\tconst perAccount: { account: string; count: number }[] = [];\n\t\tlet totalRepos = 0;\n\t\tfor (const inst of installations) {\n\t\t\tconst { repos } = await ctx.api.post<{ repos: SyncedRepo[] }>(\n\t\t\t\t`/api/github/${teamId}/installations/${inst.id}/sync`,\n\t\t\t);\n\t\t\tperAccount.push({ account: inst.accountLogin, count: repos.length });\n\t\t\ttotalRepos += repos.length;\n\t\t}\n\n\t\treturn respond({\n\t\t\tsummary: `Synced ${totalRepos} repositories across ${installations.length} installation(s).`,\n\t\t\tdata: { installations: installations.length, repos: perAccount, totalRepos },\n\t\t});\n\t},\n});\n","import { defineTool, listToolDefinitions } from '../registry.js';\nimport { respond } from '../lib/respond.js';\nimport { shapeTeam, shapeUser } from '../lib/shape.js';\n// Reuse the build-time-injected package version (the same value the MCP\n// `initialize` handshake advertises — see server-factory's PACKAGE_VERSION,\n// which is itself just MCP_VERSION). Importing from ../version.js keeps this in\n// one place and avoids an @hoststack/shared import (workspace-trap: it would\n// drag the whole monorepo into the published package).\nimport { MCP_VERSION } from '../version.js';\n\ninterface MeResponse {\n\tuser: unknown;\n\tteam?: unknown;\n}\n\n/**\n * The Dev Box tools this MCP build ships. A driving agent can compare this list\n * (returned by `describe_mcp`) against what its client actually surfaced to\n * detect a STALE npx/npm cache silently presenting an old tool set.\n *\n * KEEP IN SYNC with the tool names registered in ./services.ts. We list the\n * names as a literal (rather than filtering the registry by category) so the\n * marker stays meaningful even if the underlying categories are reshuffled —\n * these are the dev-env capabilities a caller most often finds missing.\n */\nconst DEV_ENV_TOOL_NAMES = [\n\t'create_dev_environment',\n\t'create_standalone_dev_environment',\n\t'spin_up_dev_environment',\n\t'list_dev_environments',\n\t'resize_dev_environment',\n\t'delete_dev_environment',\n] as const;\n\ndefineTool({\n\tname: 'get_me',\n\tcategory: 'meta',\n\tdescription: [\n\t\t'Return the user and team identity bound to the current API key. Useful at the start of a conversation to confirm which account the agent is operating on, especially when a user has multiple HostStack environments.',\n\t\t'',\n\t\t'When to use: orient yourself at the start of a session, confirm which team the API key targets, or surface the email/team-name in a reply to the user.',\n\t\t'',\n\t\t'Returns: { user: { id, email, name, ... }, team?: { id, publicId, name, plan, ... } }.',\n\t\t'',\n\t\t'Example: get_me() → { user: { id: 1, email: \"ada@…\", … }, team: { id: 7, name: \"acme\", plan: \"pro\" } }',\n\t].join('\\n'),\n\tinput: {},\n\thandler: async (_args, ctx) => {\n\t\tconst me = await ctx.api.get<MeResponse>('/api/auth/me');\n\t\tconst data: { user: ReturnType<typeof shapeUser>; team?: ReturnType<typeof shapeTeam> } = {\n\t\t\tuser: shapeUser(me.user),\n\t\t};\n\t\tif (me.team) data.team = shapeTeam(me.team);\n\t\tconst teamLabel =\n\t\t\tme.team && typeof me.team === 'object' && 'name' in me.team\n\t\t\t\t? ` on team ${(me.team as { name: string }).name}`\n\t\t\t\t: '';\n\t\tconst userEmail =\n\t\t\tme.user && typeof me.user === 'object' && 'email' in me.user\n\t\t\t\t? (me.user as { email: string }).email\n\t\t\t\t: 'unknown';\n\t\treturn respond({ summary: `Authenticated as ${userEmail}${teamLabel}.`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'describe_mcp',\n\tcategory: 'meta',\n\tdescription: [\n\t\t'Report this MCP build: its package version, total tool count, and the list of Dev Box tools it exposes. Read-only — touches no account data.',\n\t\t'',\n\t\t'When to use: at the start of a session to confirm the live MCP build, OR when a Dev Box tool you expect (create_dev_environment, create_standalone_dev_environment, spin_up_dev_environment, list_dev_environments, resize_dev_environment, delete_dev_environment) seems to be missing. A STALE npx/npm cache can silently present an old tool set with no other signal — call this and check `devEnvToolsPresent`; if it is false, the cached build predates the Dev Box tools and the user should refresh it (e.g. `npx --yes @hoststack.dev/mcp@latest` / clear the npx cache).',\n\t\t'',\n\t\t'Note on terminology: a \"Dev Box\" (a.k.a. Cloud Dev Box) is an agentic cloud box you code inside (create_dev_environment & friends). It is NOT a project \"environment\" (create_environment), which is a deployment target like Production / Staging / Preview. This tool only reports the Dev Box tool set.',\n\t\t'',\n\t\t'Inputs: none.',\n\t\t'',\n\t\t'Returns: { version, toolCount, devEnvTools: string[], devEnvToolsPresent: boolean } — version is the @hoststack.dev/mcp package version, toolCount is every registered tool, devEnvTools is the expected Dev Box tool names, and devEnvToolsPresent is true only if all of them are actually registered in this build.',\n\t\t'',\n\t\t'Example: describe_mcp() → { version: \"0.14.0\", toolCount: 30, devEnvTools: [\"create_dev_environment\", …], devEnvToolsPresent: true }',\n\t].join('\\n'),\n\tinput: {},\n\thandler: async (_args, _ctx) => {\n\t\tconst registered = new Set(listToolDefinitions().map((t) => t.name));\n\t\tconst devEnvToolsPresent = DEV_ENV_TOOL_NAMES.every((name) => registered.has(name));\n\t\tconst data = {\n\t\t\tversion: MCP_VERSION,\n\t\t\ttoolCount: registered.size,\n\t\t\tdevEnvTools: [...DEV_ENV_TOOL_NAMES],\n\t\t\tdevEnvToolsPresent,\n\t\t};\n\t\tconst summary = devEnvToolsPresent\n\t\t\t? `hoststack MCP v${MCP_VERSION} — ${data.toolCount} tools, all ${DEV_ENV_TOOL_NAMES.length} Dev Box tools present.`\n\t\t\t: `hoststack MCP v${MCP_VERSION} — ${data.toolCount} tools, but Dev Box tools are MISSING (stale build — refresh the npx/npm cache).`;\n\t\treturn respond({ summary, data });\n\t},\n});\n","import { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond } from '../lib/respond.js';\nimport { shape, shapeList } from '../lib/shape.js';\n\n/**\n * Source of truth: packages/shared/src/schemas/notification-channel.ts.\n * Kept in sync manually because the MCP package's Zod schemas are\n * what the model sees — pulling these from `@hoststack/shared` at\n * runtime would add a dependency that the published `@hoststack.dev/mcp`\n * shouldn't carry.\n */\nconst NOTIFICATION_EVENTS = [\n\t'deploy.started',\n\t'deploy.succeeded',\n\t'deploy.failed',\n\t'deploy.failed_consecutive',\n\t'service.created',\n\t'service.deleted',\n\t'service.suspended',\n\t'service.resumed',\n\t'service.restart_failed',\n\t'service.auto_suspended',\n\t'service.acme_cert_failed',\n\t'service.resource_alert',\n\t'git.auth_failed',\n\t'cron.execution_failed',\n\t'workflow.failed',\n] as const;\n\ndefineTool({\n\tname: 'list_notification_channels',\n\tcategory: 'alerts',\n\tdescription: [\n\t\t'List configured notification channels for the team (Slack/Discord webhooks + email recipients). Each channel has a list of events it subscribes to — fire only happens when an event in that list occurs.',\n\t\t'',\n\t\t\"When to use: setting up alerts ('which channels are notifying us on deploy failures?'), auditing why someone got/didn't get paged, or before subscribing a new event.\",\n\t\t'',\n\t\t'Returns: { items: Channel[] } — each channel includes id, type, name, webhookUrl (masked), active, events, createdAt.',\n\t\t'',\n\t\t\"Example: list_notification_channels() → { items: [{ id: 3, type: 'slack', name: 'eng-alerts', events: ['deploy.failed', 'git.auth_failed'], … }] }\",\n\t].join('\\n'),\n\tinput: {},\n\thandler: async (_args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.notifications.listChannels(teamId);\n\t\tconst data = shapeList(response, 'channels', shape);\n\t\tconst summary =\n\t\t\tdata.items.length === 0\n\t\t\t\t? 'No notification channels yet — create one with create_notification_channel.'\n\t\t\t\t: `Found ${data.items.length} notification channel${data.items.length === 1 ? '' : 's'}.`;\n\t\treturn respond({ summary, data });\n\t},\n});\n\ndefineTool({\n\tname: 'create_notification_channel',\n\tcategory: 'alerts',\n\tdescription: [\n\t\t'Create a Slack, Discord, or email notification channel and subscribe it to a list of events.',\n\t\t'',\n\t\t'When to use: setting up alert delivery for a team — paging the on-call when a deploy fails, posting to #incidents when git auth breaks, emailing the owner on ACME renewal failure.',\n\t\t'',\n\t\t'For type=email, `webhook_url` is the recipient email address. For type=slack or type=discord, it is the incoming webhook URL. The URL is stored encrypted server-side and masked in list responses.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - type: \"slack\" | \"discord\" | \"email\".',\n\t\t' - name: human-readable label (1–128 chars).',\n\t\t' - webhook_url: Slack/Discord webhook URL OR email address.',\n\t\t' - events: list of event names to subscribe to. Pass an empty list to create a channel that fires for nothing (manual subscribe later with update_notification_channel).',\n\t\t'',\n\t\t'Valid events: deploy.started, deploy.succeeded, deploy.failed, deploy.failed_consecutive, service.created, service.deleted, service.suspended, service.resumed, service.restart_failed, service.auto_suspended, service.acme_cert_failed, service.resource_alert, git.auth_failed, cron.execution_failed, workflow.failed.',\n\t\t'',\n\t\t'Returns: { channel: Channel }.',\n\t\t'',\n\t\t\"Example: create_notification_channel({ type: 'slack', name: 'eng-alerts', webhook_url: 'https://hooks.slack.com/…', events: ['deploy.failed', 'git.auth_failed', 'service.restart_failed'] })\",\n\t].join('\\n'),\n\tinput: {\n\t\ttype: z.enum(['slack', 'discord', 'email']).describe('Channel type.'),\n\t\tname: z.string().min(1).max(128).describe('Human-readable label.'),\n\t\twebhook_url: z\n\t\t\t.string()\n\t\t\t.max(500)\n\t\t\t.describe('Slack/Discord webhook URL or email address (when type=email).'),\n\t\tevents: z\n\t\t\t.array(z.enum(NOTIFICATION_EVENTS))\n\t\t\t.describe(\n\t\t\t\t'List of events the channel subscribes to. Empty list = subscribe to nothing.',\n\t\t\t),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.notifications.createChannel(teamId, {\n\t\t\ttype: args.type,\n\t\t\tname: args.name,\n\t\t\twebhookUrl: args.webhook_url,\n\t\t\tevents: args.events,\n\t\t});\n\t\tconst data = { channel: shape(response.channel) };\n\t\treturn respond({\n\t\t\tsummary: `Created ${args.type} channel \"${args.name}\" subscribed to ${args.events.length} event${args.events.length === 1 ? '' : 's'}.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'update_notification_channel',\n\tcategory: 'alerts',\n\tdescription: [\n\t\t'Update a notification channel: rename, enable/disable, or change its event subscription list. The webhook URL and type are immutable — create a new channel if those need to change.',\n\t\t'',\n\t\t'When to use: silencing a noisy channel (active=false), adding a new event to an existing list, or relabeling.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - channel_id: numeric id of the channel.',\n\t\t' - name (optional): new label.',\n\t\t' - active (optional): false to silence, true to re-enable.',\n\t\t' - events (optional): replace the full subscription list. Passing [] silences all events without disabling the channel.',\n\t\t'',\n\t\t'Returns: { channel: Channel }.',\n\t\t'',\n\t\t\"Example: update_notification_channel({ channel_id: 3, events: ['deploy.failed', 'service.restart_failed', 'git.auth_failed'] })\",\n\t].join('\\n'),\n\tinput: {\n\t\tchannel_id: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.positive()\n\t\t\t.describe('Numeric channel id from list_notification_channels.'),\n\t\tname: z.string().min(1).max(128).optional().describe('New label.'),\n\t\tactive: z.boolean().optional().describe('false silences without deleting.'),\n\t\tevents: z\n\t\t\t.array(z.enum(NOTIFICATION_EVENTS))\n\t\t\t.optional()\n\t\t\t.describe('Replaces the full subscription list.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst update: { name?: string; active?: boolean; events?: readonly string[] } = {};\n\t\tif (args.name !== undefined) update.name = args.name;\n\t\tif (args.active !== undefined) update.active = args.active;\n\t\tif (args.events !== undefined) update.events = args.events;\n\n\t\tif (Object.keys(update).length === 0) {\n\t\t\treturn respond({ summary: 'No fields to update.', data: {} });\n\t\t}\n\t\t// Cast: SDK's events type is the typed enum array; passing through\n\t\t// from the Zod-validated args is safe at the type level even if\n\t\t// TS can't bridge the readonly tuple to the SDK signature.\n\t\tconst response = await ctx.hoststack.notifications.updateChannel(\n\t\t\tteamId,\n\t\t\targs.channel_id,\n\t\t\tupdate as Parameters<typeof ctx.hoststack.notifications.updateChannel>[2],\n\t\t);\n\t\tconst data = { channel: shape(response.channel) };\n\t\treturn respond({\n\t\t\tsummary: `Updated notification channel #${args.channel_id}.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'delete_notification_channel',\n\tcategory: 'alerts',\n\tdescription: [\n\t\t'Permanently delete a notification channel. Use update_notification_channel({ active: false }) to silence without deleting if you might want it back later.',\n\t\t'',\n\t\t'When to use: a channel is no longer needed (decommissioned Slack workspace, team member left, webhook leaked) and you want it gone from the team config entirely.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - channel_id: numeric id of the channel.',\n\t\t'',\n\t\t'Returns: { ok: true }.',\n\t\t'',\n\t\t'Example: delete_notification_channel({ channel_id: 3 }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tchannel_id: z.number().int().positive().describe('Numeric channel id.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.notifications.deleteChannel(teamId, args.channel_id);\n\t\treturn respond({\n\t\t\tsummary: `Deleted notification channel #${args.channel_id}.`,\n\t\t\tdata: { ok: true },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'test_notification_channel',\n\tcategory: 'alerts',\n\tdescription: [\n\t\t'Fire a synthetic test event to the channel so the user can confirm the webhook is wired up correctly. The webhook receives an unmistakeable \"test message\" payload.',\n\t\t'',\n\t\t\"When to use: after creating a channel, or when alerts stop arriving — quickest way to tell whether the issue is on HostStack's side or the channel's.\",\n\t\t'',\n\t\t'Inputs:',\n\t\t' - channel_id: numeric id of the channel.',\n\t\t'',\n\t\t'Returns: { success: boolean, error?: string } — false + error string when the webhook returned non-2xx.',\n\t\t'',\n\t\t'Example: test_notification_channel({ channel_id: 3 }) → { success: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tchannel_id: z.number().int().positive().describe('Numeric channel id.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.notifications.testChannel(teamId, args.channel_id);\n\t\tconst data = shape(response);\n\t\tconst okFlag =\n\t\t\tdata && typeof data === 'object' && 'success' in data\n\t\t\t\t? (data as { success: boolean }).success\n\t\t\t\t: false;\n\t\treturn respond({\n\t\t\tsummary: okFlag\n\t\t\t\t? `Test event delivered to channel #${args.channel_id}.`\n\t\t\t\t: `Test event FAILED for channel #${args.channel_id}: ${(data as { error?: string }).error ?? 'unknown error'}.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n","import { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond } from '../lib/respond.js';\nimport { shapeList, shapeProject } from '../lib/shape.js';\n\n// HostStack region IDs (matches @hoststack/shared REGION_IDS and the SDK's\n// internal RegionId). The SDK narrows region to this union but doesn't export\n// the type name, so we mirror the literals here — structurally identical, so\n// it stays assignable to the SDK's create-project param.\n//\n// AVAILABLE_REGION_IDS mirrors @hoststack/shared's list of regions we actually\n// run workers in — only these may be selected when creating a project, since a\n// project pinned to a region with no fleet can never deploy. Keep in lockstep\n// with the shared constant when a new region goes live.\nconst AVAILABLE_REGION_IDS = ['eu-central-1'] as const;\ntype RegionId = (typeof AVAILABLE_REGION_IDS)[number];\n\ndefineTool({\n\tname: 'list_projects',\n\tcategory: 'projects',\n\tdescription: [\n\t\t'List every project in the active HostStack team.',\n\t\t'',\n\t\t'When to use: the agent needs an overview of what projects exist before drilling into services, deploys, or databases. Use this as the first step when the user mentions a project by name and you need to resolve its ID.',\n\t\t'',\n\t\t'Returns: { items: Project[] } — each project includes id, publicId, name, description, createdAt.',\n\t\t'',\n\t\t'Example: list_projects() → { items: [{ id: 12, publicId: \"prj_…\", name: \"billing-api\", … }] }',\n\t].join('\\n'),\n\tinput: {},\n\thandler: async (_args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.projects.list(teamId);\n\t\tconst data = shapeList(response, 'projects', shapeProject);\n\t\tconst summary =\n\t\t\tdata.items.length === 0\n\t\t\t\t? 'No projects yet — create one in the dashboard or via create_project.'\n\t\t\t\t: `Found ${data.items.length} project${data.items.length === 1 ? '' : 's'}.`;\n\t\treturn respond({ summary, data });\n\t},\n});\n\ndefineTool({\n\tname: 'create_project',\n\tcategory: 'projects',\n\tdescription: [\n\t\t'Create a new project (logical grouping of services + databases).',\n\t\t'',\n\t\t\"When to use: the user wants to set up a new app or environment in HostStack. Projects are a free organisational layer — they don't cost anything until you add services or databases inside them.\",\n\t\t'',\n\t\t'Inputs:',\n\t\t' - name: human-readable project name (1–60 chars).',\n\t\t' - description (optional): short blurb shown in the dashboard.',\n\t\t' - region (optional): \"eu-central-1\" (Falkenstein). Currently the only region with available capacity; defaults to eu-central-1.',\n\t\t'',\n\t\t'Returns: { project: Project } — includes the new id and publicId.',\n\t\t'',\n\t\t'Example: create_project({ name: \"billing-api\", description: \"Stripe webhooks\", region: \"eu-central-1\" }) → { project: { id: 12, publicId: \"prj_…\", … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tname: z.string().min(1).max(60).describe('Project name (1–60 chars).'),\n\t\tdescription: z.string().max(500).optional().describe('Short description (≤500 chars).'),\n\t\tregion: z\n\t\t\t.enum(AVAILABLE_REGION_IDS)\n\t\t\t.optional()\n\t\t\t.describe('Region: eu-central-1 (Falkenstein) — currently the only available region.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst input: { name: string; description?: string; region?: RegionId } = {\n\t\t\tname: args.name,\n\t\t};\n\t\tif (args.description !== undefined) input.description = args.description;\n\t\tif (args.region !== undefined) input.region = args.region;\n\t\tconst response = await ctx.hoststack.projects.create(teamId, input);\n\t\tconst data = { project: shapeProject(response.project) };\n\t\tconst publicId =\n\t\t\tdata.project && 'publicId' in data.project\n\t\t\t\t? (data.project as { publicId: string }).publicId\n\t\t\t\t: 'unknown';\n\t\treturn respond({ summary: `Created project \"${args.name}\" (${publicId}).`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'update_project',\n\tcategory: 'projects',\n\tdescription: [\n\t\t'Rename a project or update its description.',\n\t\t'',\n\t\t'When to use: the user wants to fix a typo in a project name, attach a clearer description, or align the dashboard label with their internal naming.',\n\t\t'',\n\t\t'Inputs (all optional, at least one required):',\n\t\t' - project_id: publicId of the project (required).',\n\t\t' - name: new name (1–60 chars).',\n\t\t' - description: new description (≤500 chars).',\n\t\t'',\n\t\t'Returns: { project: Project } — the updated record.',\n\t\t'',\n\t\t'Example: update_project({ project_id: \"prj_abc\", name: \"billing-prod\" }) → { project: { name: \"billing-prod\", … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tproject_id: z.string().describe('Project publicId.'),\n\t\tname: z.string().min(1).max(60).optional().describe('New name (1–60 chars).'),\n\t\tdescription: z.string().max(500).optional().describe('New description (≤500 chars).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tif (args.name === undefined && args.description === undefined) {\n\t\t\treturn respond({\n\t\t\t\tsummary: 'No fields to update — pass `name` and/or `description`.',\n\t\t\t\tdata: {},\n\t\t\t});\n\t\t}\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst input: { name?: string; description?: string } = {};\n\t\tif (args.name !== undefined) input.name = args.name;\n\t\tif (args.description !== undefined) input.description = args.description;\n\t\tconst response = await ctx.hoststack.projects.update(teamId, args.project_id, input);\n\t\tconst data = { project: shapeProject(response.project) };\n\t\treturn respond({ summary: `Updated project ${args.project_id}.`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'get_project',\n\tcategory: 'projects',\n\tdescription: [\n\t\t'Fetch a single project by ID. Includes name, description, and timestamps.',\n\t\t'',\n\t\t'When to use: confirming a project exists before creating resources inside it, or pulling the canonical name/description for a reply to the user.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - project_id: publicId of the project (e.g. \"prj_abc123\").',\n\t\t'',\n\t\t'Returns: { project: Project }.',\n\t\t'',\n\t\t'Example: get_project({ project_id: \"prj_abc\" }) → { project: { id: 12, name: \"billing\", … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tproject_id: z.string().describe('Project publicId (e.g. prj_abc123).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.projects.get(teamId, args.project_id);\n\t\tconst data = { project: shapeProject(response.project) };\n\t\tconst name =\n\t\t\tdata.project && 'name' in data.project\n\t\t\t\t? (data.project as { name: string }).name\n\t\t\t\t: args.project_id;\n\t\treturn respond({ summary: `Project \"${name}\".`, data });\n\t},\n});\n","import { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond } from '../lib/respond.js';\nimport { shape, shapeList } from '../lib/shape.js';\n\nconst RESOURCE_LINK_TYPES = [\n\t'database',\n\t'object_storage',\n\t'queue',\n\t'search',\n\t'email_domain',\n] as const;\n\n/**\n * The env vars a link injects, by resource class. Documented in the tool\n * descriptions so an agent can predict what the container will see WITHOUT\n * fetching credentials — the whole point of the link system.\n */\nconst INJECTION_CONTRACT = [\n\t'What a link injects at deploy time:',\n\t' - Alias-prefixed vars for every field of the resource (alias \"APP_DB\" → APP_DB_HOST, APP_DB_PORT, APP_DB_USER, APP_DB_PASSWORD, APP_DB_URL, …). This is how one service consumes several resources of the same type without collisions.',\n\t' - PLUS the conventional name for the first linked resource of each engine class: `DATABASE_URL` (postgres/mysql/mariadb), `REDIS_URL` (redis), `MONGO_URL` (mongodb). So an app reading `process.env.DATABASE_URL` works with no code changes.',\n\t' - The conventional names are set with `??=` — an env var you set yourself via set_env_var ALWAYS wins over the injected one.',\n].join('\\n');\n\ndefineTool({\n\tname: 'list_managed_resources',\n\tcategory: 'resource-links',\n\tdescription: [\n\t\t'List EVERY managed resource the team owns in one call — databases, object storage buckets, queues, search indexes and email domains — from the unified `managed_resources` read-model.',\n\t\t'',\n\t\t'When to use: to find the NUMERIC `id` that link_resource_to_service needs, especially for resource types with no dedicated list tool of their own (object storage, queues, search, email domains — list_databases only covers databases). Also a fast inventory answer for \"what do we actually have running\".',\n\t\t'',\n\t\t'Team-wide, not project-scoped. Use list_databases when you specifically want databases in one project.',\n\t\t'',\n\t\t'Returns: { items: ManagedResource[] } — id (numeric, for linking), publicId, type, name, status, region, createdAt.',\n\t\t'',\n\t\t'Example: list_managed_resources() → { items: [{ id: 42, type: \"database\", name: \"app-db\", status: \"available\" }, { id: 8, type: \"object_storage\", name: \"uploads\", … }] }',\n\t].join('\\n'),\n\tinput: {},\n\thandler: async (_args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.serviceResourceLinks.listManagedResources(teamId);\n\t\tconst data = shapeList(response, 'resources', shape);\n\t\tconst byType = new Map<string, number>();\n\t\tfor (const item of data.items) {\n\t\t\tconst type =\n\t\t\t\titem && typeof item === 'object' && 'type' in item\n\t\t\t\t\t? String((item as { type: unknown }).type)\n\t\t\t\t\t: 'unknown';\n\t\t\tbyType.set(type, (byType.get(type) ?? 0) + 1);\n\t\t}\n\t\tconst breakdown = [...byType.entries()].map(([t, n]) => `${n} ${t}`).join(', ');\n\t\tconst summary =\n\t\t\tdata.items.length === 0\n\t\t\t\t? 'No managed resources on this team yet.'\n\t\t\t\t: `${data.items.length} managed resource${data.items.length === 1 ? '' : 's'}: ${breakdown}.`;\n\t\treturn respond({ summary, data });\n\t},\n});\n\ndefineTool({\n\tname: 'list_service_resources',\n\tcategory: 'resource-links',\n\tdescription: [\n\t\t'List the managed resources (databases, object storage, queues, search, email domains) linked to a service — i.e. which resources get injected into its container as env vars on deploy.',\n\t\t'',\n\t\t'When to use: before adding a link (to avoid a duplicate or an alias collision), when debugging \"why is DATABASE_URL empty in my app\" (the answer is usually: no link exists, or the service was never redeployed after linking), or to find the linkId needed by unlink_resource_from_service.',\n\t\t'',\n\t\tINJECTION_CONTRACT,\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId (\"svc_…\") or numeric id of the service.',\n\t\t'',\n\t\t'Returns: { items: ServiceResourceLink[] } — id (the linkId), resourceType, resourceId (numeric id of the linked resource), alias, createdAt.',\n\t\t'',\n\t\t'Example: list_service_resources({ service_id: \"svc_abc\" }) → { items: [{ id: 7, resourceType: \"database\", resourceId: 42, alias: \"APP_DB\" }] }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z\n\t\t\t.union([z.number().int().positive(), z.string()])\n\t\t\t.describe('Service — publicId (\"svc_…\") or numeric id.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.serviceResourceLinks.list(teamId, args.service_id);\n\t\tconst data = shapeList(response, 'links', shape);\n\t\tconst summary =\n\t\t\tdata.items.length === 0\n\t\t\t\t? `No resources linked to service ${args.service_id}. Nothing is being injected — link a database with link_resource_to_service.`\n\t\t\t\t: `${data.items.length} resource${data.items.length === 1 ? '' : 's'} linked to service ${args.service_id}.`;\n\t\treturn respond({ summary, data });\n\t},\n});\n\ndefineTool({\n\tname: 'link_resource_to_service',\n\tcategory: 'resource-links',\n\tdescription: [\n\t\t'Link a managed resource to a service so its connection details are injected into the container as environment variables. This is the step that connects a database to an app — creating the database alone does nothing for the app.',\n\t\t'',\n\t\t'When to use: immediately after create_database (or when pointing an existing service at an existing resource). This is step 2 of 3 in the managed-database flow: create_database → link_resource_to_service → trigger_deploy.',\n\t\t'',\n\t\t'*** The link takes effect on the NEXT DEPLOY. *** After calling this, call trigger_deploy({ service_id }) or the running container will not see the new vars. A service that \"cannot connect to the database\" right after linking almost always just needs that redeploy.',\n\t\t'',\n\t\tINJECTION_CONTRACT,\n\t\t'',\n\t\t\"Because the platform injects the credentials directly into the container, you do NOT need to read the password, build a connection string by hand, or store it with set_env_var. Don't.\",\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId (\"svc_…\") or numeric id of the consuming service.',\n\t\t` - resource_type: ${RESOURCE_LINK_TYPES.join(' | ')}.`,\n\t\t' - resource_id: the NUMERIC id of the resource — e.g. the `id` field from create_database / list_databases, NOT the \"db_…\" publicId.',\n\t\t' - alias: uppercase env-var prefix (A–Z, 0–9, underscore; must start with a letter; ≤48 chars), e.g. \"APP_DB\", \"CACHE\", \"CATALOG\". Must be unique within the service.',\n\t\t'',\n\t\t'Returns: { link: ServiceResourceLink } — including `id`, the linkId used to unlink later.',\n\t\t'',\n\t\t'Fails with 409 if this exact resource is already linked to the service, or if the alias is already taken on it.',\n\t\t'',\n\t\t'Example: link_resource_to_service({ service_id: \"svc_abc\", resource_type: \"database\", resource_id: 42, alias: \"APP_DB\" }) → { link: { id: 7, alias: \"APP_DB\" } }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z\n\t\t\t.union([z.number().int().positive(), z.string()])\n\t\t\t.describe('Consuming service — publicId (\"svc_…\") or numeric id.'),\n\t\tresource_type: z.enum(RESOURCE_LINK_TYPES).describe('Kind of resource being linked.'),\n\t\tresource_id: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.positive()\n\t\t\t.describe('NUMERIC id of the resource (e.g. database.id) — not the publicId.'),\n\t\talias: z\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(48)\n\t\t\t.regex(\n\t\t\t\t/^[A-Z][A-Z0-9_]*$/,\n\t\t\t\t'Alias must be uppercase letters, digits and underscores, starting with a letter.',\n\t\t\t)\n\t\t\t.describe('Uppercase env-var prefix, e.g. \"APP_DB\". Unique within the service.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.serviceResourceLinks.create(teamId, args.service_id, {\n\t\t\tresourceType: args.resource_type,\n\t\t\tresourceId: args.resource_id,\n\t\t\talias: args.alias,\n\t\t});\n\t\tconst data = { link: shape(response.link) };\n\t\treturn respond({\n\t\t\tsummary: `Linked ${args.resource_type} ${args.resource_id} to service ${args.service_id} as \"${args.alias}\". Call trigger_deploy({ service_id: \"${args.service_id}\" }) to inject it — the running container will not see the vars until then.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'unlink_resource_from_service',\n\tcategory: 'resource-links',\n\tdescription: [\n\t\t'Remove a resource link from a service. The resource itself is NOT deleted — only the binding.',\n\t\t'',\n\t\t'When to use: repointing a service at a different database, or detaching a resource a service no longer needs. The injected env vars disappear on the next deploy, so a service that still reads DATABASE_URL will break then, not immediately. Use delete_database if the intent is to destroy the data.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId (\"svc_…\") or numeric id of the service.',\n\t\t' - link_id: numeric linkId from list_service_resources (the `id` field on the link, not the resource id).',\n\t\t'',\n\t\t'Returns: { ok: true }.',\n\t\t'',\n\t\t'Example: unlink_resource_from_service({ service_id: \"svc_abc\", link_id: 7 }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z\n\t\t\t.union([z.number().int().positive(), z.string()])\n\t\t\t.describe('Service — publicId (\"svc_…\") or numeric id.'),\n\t\tlink_id: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.positive()\n\t\t\t.describe(\"Numeric linkId from list_service_resources (the link's own `id`).\"),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.serviceResourceLinks.delete(teamId, args.service_id, args.link_id);\n\t\treturn respond({\n\t\t\tsummary: `Unlinked resource link ${args.link_id} from service ${args.service_id}. The resource still exists; its env vars vanish on the next deploy.`,\n\t\t});\n\t},\n});\n","import type { CreateDevEnvironmentInput } from '@hoststack.dev/sdk';\nimport { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond, respondError } from '../lib/respond.js';\nimport { shape, shapeList, shapeService } from '../lib/shape.js';\n\n// Keep in sync with the `dev-environment` preset in\n// packages/shared/src/templates.ts (the dashboard wizard's source of truth)\n// and the catalog/floor constants in packages/shared/src/constants/pricing.ts.\n// The MCP package only depends on the SDK (it publishes to npm and must NOT\n// import the private @hoststack/shared package, which would drag the whole\n// monorepo into the bundle), so these constants are duplicated here\n// intentionally rather than imported. Drift is caught by review, not the type\n// system — update both sides together.\nconst DEV_ENV_IMAGE = 'registry.hoststack.dev/hoststack/dev-env:latest';\nconst DEV_ENV_VOLUME = { name: 'workspace', mountPath: '/workspace', sizeGb: 10 };\n\nconst SERVICE_TYPES = [\n\t'web_service',\n\t'private_service',\n\t'worker',\n\t'cron_job',\n\t'static_site',\n] as const;\n// The real service catalog, ascending — mirrors the server's\n// SERVICE_SIZE_ORDER. `pico↓xlarge` are shared-CPU; `pro_*` are dedicated-CPU.\n// Note: `starter` is a DATABASE/addon size, not a service size — do not add it.\nconst SERVICE_PLANS = [\n\t'pico',\n\t'nano',\n\t'micro',\n\t'small',\n\t'standard',\n\t'large',\n\t'xlarge',\n\t'pro_standard',\n\t'pro_large',\n] as const;\n\n// The OOM-safe floor for dev boxes — mirrors DEV_ENV_MIN_SIZE in\n// packages/shared/src/constants/pricing.ts. A coding agent + build OOMs on\n// anything below `standard` (2 GB). The server floors a sub-standard plan\n// too; we clamp here so the MCP tool never even requests an undersized box.\nconst DEV_ENV_MIN_SIZE = 'standard';\n\n/**\n * Clamp a requested service size up to the dev-env floor. Mirrors the\n * server-side `coerceDevEnvSize`: an unknown/omitted/sub-`standard` value\n * becomes `standard`; a known size at/above the floor is left untouched.\n * Duplicated (not imported) per the workspace constraint above.\n */\nfunction coerceDevEnvSize(value: string | undefined): (typeof SERVICE_PLANS)[number] {\n\tconst minIdx = SERVICE_PLANS.indexOf(DEV_ENV_MIN_SIZE);\n\tconst idx = value ? SERVICE_PLANS.indexOf(value as (typeof SERVICE_PLANS)[number]) : -1;\n\treturn idx >= minIdx ? (value as (typeof SERVICE_PLANS)[number]) : DEV_ENV_MIN_SIZE;\n}\n\ndefineTool({\n\tname: 'list_services',\n\tcategory: 'services',\n\tdescription: [\n\t\t'List services (web, worker, cron, private, static) in the active HostStack team.',\n\t\t'',\n\t\t'When to use: the agent needs to find a service by name, check what is deployed, or pick a target for a follow-up tool (logs, deploys, env vars). This is the canonical way to resolve a publicId from a human-friendly name.',\n\t\t'',\n\t\t'Note: agentic Dev Boxes (cloud dev environments) are EXCLUDED by default. Pass dev_environment:true to include them, or use list_dev_environments for the dedicated, annotated dev-box listing.',\n\t\t'',\n\t\t'Inputs (all optional):',\n\t\t' - project_id: narrow to one project (numeric id or publicId \"prj_…\").',\n\t\t' - environment_id: narrow to one environment (numeric id or publicId \"env_…\").',\n\t\t' - status: \"active\" | \"deploying\" | \"suspended\" | \"failed\" | \"not_deployed\".',\n\t\t' - type: \"web_service\" | \"private_service\" | \"worker\" | \"cron_job\" | \"static_site\".',\n\t\t' - dev_environment: include Dev Boxes in the results (excluded by default).',\n\t\t'',\n\t\t'Returns: { items: Service[] } — each service includes id, publicId, name, type, status, projectId, repoUrl, branch, runtime, createdAt.',\n\t\t'',\n\t\t'Example: list_services({ status: \"failed\" }) → only services that need attention.',\n\t].join('\\n'),\n\tinput: {\n\t\tproject_id: z\n\t\t\t.union([z.number().int().positive(), z.string()])\n\t\t\t.optional()\n\t\t\t.describe('Project filter — numeric id or publicId.'),\n\t\tenvironment_id: z\n\t\t\t.union([z.number().int().positive(), z.string()])\n\t\t\t.optional()\n\t\t\t.describe('Environment filter — numeric id or publicId.'),\n\t\tstatus: z\n\t\t\t.enum(['active', 'deploying', 'suspended', 'failed', 'not_deployed'])\n\t\t\t.optional()\n\t\t\t.describe('Filter by current runtime status.'),\n\t\ttype: z\n\t\t\t.enum(['web_service', 'private_service', 'worker', 'cron_job', 'static_site'])\n\t\t\t.optional()\n\t\t\t.describe('Filter by service type.'),\n\t\tdev_environment: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t'Include agentic Dev Boxes in the results (excluded by default; see list_dev_environments).',\n\t\t\t),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst filters: Parameters<typeof ctx.hoststack.services.list>[1] = {};\n\t\tif (args.dev_environment) filters.devEnvironment = true;\n\t\tif (args.project_id !== undefined) {\n\t\t\t// SDK accepts publicId or numeric id; let resolveId handle it.\n\t\t\tconst resolved = await ctx.hoststack.resolveId(args.project_id, {\n\t\t\t\tkind: 'project',\n\t\t\t\tteamId,\n\t\t\t});\n\t\t\tfilters.projectId = resolved;\n\t\t}\n\t\tif (args.environment_id !== undefined) {\n\t\t\tconst resolved = await ctx.hoststack.resolveId(args.environment_id, {\n\t\t\t\tkind: 'environment',\n\t\t\t\tteamId,\n\t\t\t});\n\t\t\tfilters.environmentId = resolved;\n\t\t}\n\t\tif (args.status) filters.status = args.status;\n\t\tif (args.type) filters.type = args.type;\n\n\t\tconst response = await ctx.hoststack.services.list(teamId, filters);\n\t\tconst data = shapeList(response, 'services', shapeService);\n\t\tconst filterDesc = [\n\t\t\targs.project_id !== undefined ? `project=${args.project_id}` : null,\n\t\t\targs.environment_id !== undefined ? `env=${args.environment_id}` : null,\n\t\t\targs.status ? `status=${args.status}` : null,\n\t\t\targs.type ? `type=${args.type}` : null,\n\t\t\targs.dev_environment ? 'devBoxes=included' : null,\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(', ');\n\t\tconst summary =\n\t\t\tdata.items.length === 0\n\t\t\t\t? filterDesc\n\t\t\t\t\t? `No services match the given filters (${filterDesc}).`\n\t\t\t\t\t: 'No services yet — create one with create_service (or create_dev_environment for an AI dev box), or via the dashboard.'\n\t\t\t\t: `Found ${data.items.length} service${data.items.length === 1 ? '' : 's'}${filterDesc ? ` matching ${filterDesc}` : ''}.`;\n\t\treturn respond({ summary, data });\n\t},\n});\n\ndefineTool({\n\tname: 'create_service',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Create a new service in a project. Source is either a connected git repo (github_repo_id) OR a pre-built docker_image — never both.',\n\t\t'',\n\t\t'When to use: the user wants to deploy something new. For a one-command AI dev environment specifically, prefer create_dev_environment (it also attaches the /workspace volume and sets the MCP keys).',\n\t\t'',\n\t\t'*** NOT for databases. *** If the user wants Postgres, Redis, MySQL, MariaDB or MongoDB, call create_database — do NOT create a service with docker_image \"postgres:16\" / \"redis:7\" / \"mongo\" / \"mysql\". A database deployed as a service is unmanaged: no backups, no version upgrades, no HA, no credential rotation, no metrics, no persistent volume, and nothing injects its URL into your app. `docker_image` here is for YOUR application images (or sidecars), not for datastores the platform already manages.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - project_id: numeric id or publicId (\"prj_…\") of the target project.',\n\t\t' - name: service name (1–100 chars).',\n\t\t' - type: \"web_service\" | \"private_service\" | \"worker\" | \"cron_job\" | \"static_site\".',\n\t\t' - docker_image (optional): pre-built image ref to deploy instead of building from source.',\n\t\t' - github_repo_id (optional): connect a previously-linked GitHub repo by numeric id.',\n\t\t' - branch (optional): git branch (default \"main\").',\n\t\t' - install_command / build_command / start_command (optional): build/run shell commands. start_command is required for web/private services without a docker_image.',\n\t\t' - cron_schedule (optional): cron expression — required for cron_job.',\n\t\t' - publish_path (optional): static-site output dir (e.g. \"dist\").',\n\t\t' - runtime (optional): \"node\" | \"bun\" | \"python\" | … (auto-detected from a repo when omitted).',\n\t\t' - plan (optional): service size (default \"micro\").',\n\t\t' - environment_id (optional): bind to a specific environment; defaults to the project Production env.',\n\t\t' - auto_deploy (optional, default true): trigger the first deploy immediately when a source is present.',\n\t\t'',\n\t\t'Returns: { service: Service, deployId: number | null }.',\n\t\t'',\n\t\t'Example: create_service({ project_id: \"prj_abc\", name: \"api\", type: \"web_service\", github_repo_id: 42 }) → { service: { publicId: \"svc_…\" }, deployId: 1234 }',\n\t].join('\\n'),\n\tinput: {\n\t\tproject_id: z\n\t\t\t.union([z.number().int().positive(), z.string()])\n\t\t\t.describe('Target project — numeric id or publicId.'),\n\t\tname: z.string().min(1).max(100).describe('Service name (1–100 chars).'),\n\t\ttype: z.enum(SERVICE_TYPES).describe('Service type.'),\n\t\tdocker_image: z\n\t\t\t.string()\n\t\t\t.max(500)\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t'Pre-built APPLICATION image ref. Mutually exclusive with github_repo_id. Not for databases — use create_database for postgres/redis/mysql/mariadb/mongodb.',\n\t\t\t),\n\t\tgithub_repo_id: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.positive()\n\t\t\t.optional()\n\t\t\t.describe('Linked GitHub repo numeric id. Mutually exclusive with docker_image.'),\n\t\tbranch: z.string().max(200).optional().describe('Git branch (default \"main\").'),\n\t\tinstall_command: z.string().max(1000).optional().describe('Install shell command.'),\n\t\tbuild_command: z.string().max(1000).optional().describe('Build shell command.'),\n\t\tstart_command: z\n\t\t\t.string()\n\t\t\t.max(1000)\n\t\t\t.optional()\n\t\t\t.describe('Start shell command (required for web/private services without an image).'),\n\t\tcron_schedule: z\n\t\t\t.string()\n\t\t\t.max(100)\n\t\t\t.optional()\n\t\t\t.describe('Cron expression — required for cron_job.'),\n\t\tpublish_path: z.string().max(500).optional().describe('Static-site output dir.'),\n\t\truntime: z.string().max(50).optional().describe('Runtime hint (node/bun/python/…).'),\n\t\tplan: z.enum(SERVICE_PLANS).optional().describe('Service size (default \"micro\").'),\n\t\tenvironment_id: z\n\t\t\t.union([z.number().int().positive(), z.string()])\n\t\t\t.optional()\n\t\t\t.describe('Bind to a specific environment; defaults to Production.'),\n\t\tauto_deploy: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe('Trigger the first deploy immediately (default true).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst projectId = await ctx.hoststack.resolveId(args.project_id, {\n\t\t\tkind: 'project',\n\t\t\tteamId,\n\t\t});\n\n\t\tconst input: Parameters<typeof ctx.hoststack.services.create>[1] = {\n\t\t\tname: args.name,\n\t\t\ttype: args.type,\n\t\t\tprojectId,\n\t\t};\n\t\tif (args.docker_image !== undefined) input.dockerImage = args.docker_image;\n\t\tif (args.github_repo_id !== undefined) input.githubRepoId = args.github_repo_id;\n\t\tif (args.branch !== undefined) input.branch = args.branch;\n\t\tif (args.install_command !== undefined) input.installCommand = args.install_command;\n\t\tif (args.build_command !== undefined) input.buildCommand = args.build_command;\n\t\tif (args.start_command !== undefined) input.startCommand = args.start_command;\n\t\tif (args.cron_schedule !== undefined) input.cronSchedule = args.cron_schedule;\n\t\tif (args.publish_path !== undefined) input.publishPath = args.publish_path;\n\t\tif (args.runtime !== undefined) input.runtime = args.runtime;\n\t\tif (args.plan !== undefined) input.plan = args.plan;\n\t\tif (args.auto_deploy !== undefined) input.autoDeploy = args.auto_deploy;\n\t\tif (args.environment_id !== undefined) {\n\t\t\tinput.environmentId = await ctx.hoststack.resolveId(args.environment_id, {\n\t\t\t\tkind: 'environment',\n\t\t\t\tteamId,\n\t\t\t});\n\t\t}\n\n\t\tconst response = await ctx.hoststack.services.create(teamId, input);\n\t\tconst data = {\n\t\t\tservice: shapeService(response.service),\n\t\t\tdeployId: (response as { deployId?: number | null }).deployId ?? null,\n\t\t};\n\t\tconst publicId =\n\t\t\tdata.service && 'publicId' in data.service\n\t\t\t\t? (data.service as { publicId: string }).publicId\n\t\t\t\t: 'unknown';\n\t\treturn respond({ summary: `Created service \"${args.name}\" (${publicId}).`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'create_dev_environment',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Spin up an AI Dev Box in one call: a cloud \"Dev Box\" (an agentic container from the dev-env image — Claude Code + Codex + OpenCode + MCPs preinstalled) inside a project, with a persistent /workspace volume and the MCP API keys set, then fire the first deploy.',\n\t\t'',\n\t\t'This makes a cloud Dev Box, NOT a project deploy environment. A project \"environment\" (create_environment → Production / Staging / Preview) is a deployment target; this is a workspace you code in. If you actually want a -dev deploy target, use create_environment instead.',\n\t\t'',\n\t\t'When to use: the user wants a cloud terminal / Dev Box they can drive coding agents in (from a desk or a phone). This mirrors the dashboard\\'s \"AI Dev Environment\" wizard preset — create (deploy deferred) → set keys → attach /workspace → deploy, so the first container boots with its volume and keys already in place.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - project_id: numeric id or publicId (\"prj_…\") of the target project.',\n\t\t' - name (optional): service name (default \"dev-environment\").',\n\t\t' - plan (optional): box size. Defaults to \"standard\" (2 GB) — the OOM-safe floor (DEV_ENV_MIN_SIZE); a coding agent + build OOMs below it. A smaller plan is clamped up to \"standard\".',\n\t\t' - disk_gb (optional): /workspace volume size in GB (default 10, 1–100).',\n\t\t' - hoststack_api_key (optional): sets HOSTSTACK_API_KEY so the hoststack MCP works inside the container.',\n\t\t' - poststack_api_key (optional): sets POSTSTACK_API_KEY so the poststack MCP works inside the container.',\n\t\t' - repo_url (optional): clone this git URL into /workspace on first boot (with optional branch).',\n\t\t'',\n\t\t'Returns: { service: Service, volumeAttached: boolean, deployId: number | null }. Open the Terminal tab on the service (dashboard or phone) once it is running; log in once with `claude /login` inside the container.',\n\t\t'',\n\t\t'Example: create_dev_environment({ project_id: \"prj_abc\", name: \"scratch\", hoststack_api_key: \"hs_live_…\" })',\n\t].join('\\n'),\n\tinput: {\n\t\tproject_id: z\n\t\t\t.union([z.number().int().positive(), z.string()])\n\t\t\t.describe('Target project — numeric id or publicId.'),\n\t\tname: z\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(100)\n\t\t\t.optional()\n\t\t\t.describe('Service name (default \"dev-environment\").'),\n\t\tplan: z\n\t\t\t.enum(SERVICE_PLANS)\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t'Box size (default \"standard\" — 2 GB, the OOM-safe floor; a smaller plan is clamped up to \"standard\").',\n\t\t\t),\n\t\tdisk_gb: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(1)\n\t\t\t.max(100)\n\t\t\t.optional()\n\t\t\t.describe('/workspace volume size in GB (default 10).'),\n\t\thoststack_api_key: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe('Value for HOSTSTACK_API_KEY (enables the hoststack MCP in-container).'),\n\t\tpoststack_api_key: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe('Value for POSTSTACK_API_KEY (enables the poststack MCP in-container).'),\n\t\trepo_url: z\n\t\t\t.string()\n\t\t\t.max(500)\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t'Clone this git URL into /workspace on first boot (HTTPS, or SSH once a key is set).',\n\t\t\t),\n\t\tbranch: z.string().max(200).optional().describe('Branch to clone (with repo_url).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst projectId = await ctx.hoststack.resolveId(args.project_id, {\n\t\t\tkind: 'project',\n\t\t\tteamId,\n\t\t});\n\t\tconst name = args.name ?? 'dev-environment';\n\t\tconst sizeGb = args.disk_gb ?? DEV_ENV_VOLUME.sizeGb;\n\t\t// Defence in depth: clamp the requested plan up to the OOM-safe dev-env\n\t\t// floor BEFORE asking the SDK to create the box. The server floors it\n\t\t// too, but this guarantees the tool never even requests a sub-`standard`\n\t\t// box that would OOM a coding agent on first boot.\n\t\tconst plan = coerceDevEnvSize(args.plan);\n\n\t\t// Defer the first deploy (autoDeploy:false) so we can set the MCP keys\n\t\t// and attach /workspace BEFORE the container boots — same ordering as\n\t\t// the dashboard wizard's use-new-service-form.\n\t\tconst createInput: Parameters<typeof ctx.hoststack.services.create>[1] = {\n\t\t\tname,\n\t\t\ttype: 'private_service',\n\t\t\tprojectId,\n\t\t\tdockerImage: DEV_ENV_IMAGE,\n\t\t\tautoDeploy: false,\n\t\t\tplan,\n\t\t};\n\t\tconst created = await ctx.hoststack.services.create(teamId, createInput);\n\t\tconst service = created.service;\n\n\t\t// From here on the service EXISTS and is billable. Any later failure\n\t\t// must tear it back down so we never orphan a half-provisioned,\n\t\t// non-persistent box — see rollback() below. (The server's own\n\t\t// rollbackPartialDevBox only covers the dedicated dev-env create path,\n\t\t// not this generic create-then-attach sequence.)\n\t\tconst rollback = async (): Promise<void> => {\n\t\t\ttry {\n\t\t\t\t// tearDownDevEnvironment cascades the box + volume + cloned DB;\n\t\t\t\t// it only accepts dev-env services, which this is (dev-env image).\n\t\t\t\tawait ctx.hoststack.services.tearDownDevEnvironment(teamId, service.id);\n\t\t\t} catch {\n\t\t\t\ttry {\n\t\t\t\t\tawait ctx.hoststack.services.delete(teamId, service.id);\n\t\t\t\t} catch {\n\t\t\t\t\t// Best-effort: surface the original failure to the caller\n\t\t\t\t\t// even if cleanup itself fails (orphan will need manual\n\t\t\t\t\t// removal via delete_dev_environment / the dashboard).\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\ttry {\n\t\t\tconst envVars: { key: string; value: string; isSecret: boolean }[] = [];\n\t\t\tif (args.hoststack_api_key)\n\t\t\t\tenvVars.push({\n\t\t\t\t\tkey: 'HOSTSTACK_API_KEY',\n\t\t\t\t\tvalue: args.hoststack_api_key,\n\t\t\t\t\tisSecret: true,\n\t\t\t\t});\n\t\t\tif (args.poststack_api_key)\n\t\t\t\tenvVars.push({\n\t\t\t\t\tkey: 'POSTSTACK_API_KEY',\n\t\t\t\t\tvalue: args.poststack_api_key,\n\t\t\t\t\tisSecret: true,\n\t\t\t\t});\n\t\t\t// Clone an arbitrary repo at boot (the image entrypoint reads these).\n\t\t\tif (args.repo_url) {\n\t\t\t\tenvVars.push({\n\t\t\t\t\tkey: 'HOSTSTACK_DEVENV_REPO_URL',\n\t\t\t\t\tvalue: args.repo_url,\n\t\t\t\t\tisSecret: false,\n\t\t\t\t});\n\t\t\t\tif (args.branch)\n\t\t\t\t\tenvVars.push({\n\t\t\t\t\t\tkey: 'HOSTSTACK_DEVENV_BRANCH',\n\t\t\t\t\t\tvalue: args.branch,\n\t\t\t\t\t\tisSecret: false,\n\t\t\t\t\t});\n\t\t\t}\n\t\t\tif (envVars.length > 0) {\n\t\t\t\tawait ctx.hoststack.envVars.bulkSet(teamId, service.id, { vars: envVars });\n\t\t\t}\n\n\t\t\t// A Dev Box without its /workspace volume silently loses all\n\t\t\t// out-of-image work on the next recreate. ABORT rather than deploy\n\t\t\t// a non-persistent box: a missing volume is a hard failure here.\n\t\t\ttry {\n\t\t\t\tawait ctx.hoststack.volumes.create(teamId, service.id, {\n\t\t\t\t\tname: DEV_ENV_VOLUME.name,\n\t\t\t\t\tmountPath: DEV_ENV_VOLUME.mountPath,\n\t\t\t\t\tsizeGb,\n\t\t\t\t});\n\t\t\t} catch (error: unknown) {\n\t\t\t\tconst reason = error instanceof Error ? error.message : String(error);\n\t\t\t\tawait rollback();\n\t\t\t\treturn respondError(\n\t\t\t\t\t`Failed to attach the /workspace volume for Dev Box \"${name}\" — aborted and rolled back rather than deploy a box that would lose all work on recreate. Volume error: ${reason}`,\n\t\t\t\t\t{ volumeError: reason, rolledBack: true },\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst deploy = await ctx.hoststack.deploys.trigger(teamId, service.id);\n\t\t\tconst deployId = deploy.deploy?.id ?? null;\n\n\t\t\treturn respond({\n\t\t\t\tsummary: `Created AI Dev Box \"${name}\" (${service.publicId}) with a /workspace volume — deploying. Open it in the dashboard's Dev Boxes section (or the service's Terminal tab) once running.`,\n\t\t\t\tdata: { service: shapeService(service), volumeAttached: true, deployId },\n\t\t\t});\n\t\t} catch (error: unknown) {\n\t\t\t// Any post-create failure (env-var set, deploy trigger, …) tears the\n\t\t\t// billable box back down so nothing is orphaned.\n\t\t\tconst reason = error instanceof Error ? error.message : String(error);\n\t\t\tawait rollback();\n\t\t\treturn respondError(\n\t\t\t\t`Failed to provision Dev Box \"${name}\" — rolled back the partially-created box. Error: ${reason}`,\n\t\t\t\t{ rolledBack: true },\n\t\t\t);\n\t\t}\n\t},\n});\n\ndefineTool({\n\tname: 'spin_up_dev_environment',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Spin up an agentic Dev Box FROM an existing service so you can reproduce a bug, fix it, view it, and ship it. Creates a cloud Dev Box (Claude/Codex/OpenCode + MCPs) that RUNS a clone of the app: the repo is auto-cloned into /workspace, the service env-vars are copied, and its linked database is cloned (so the box never touches the prod DB). The box gets an unguessable public dev URL and seamless `git push`.',\n\t\t'',\n\t\t'This makes a cloud Dev Box, NOT a project deploy environment — for a -dev/-staging deploy target use create_environment instead.',\n\t\t'',\n\t\t'When to use: \"spin up a dev environment for <service>\", \"I found a bug on <service>, give me a box to fix it\". Distinct from create_dev_environment, which makes a BARE box not tied to any app.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: the source service to debug — numeric id or publicId (\"svc_…\").',\n\t\t' - include_database_clone (optional): clone the linked database so the app runs on a copy of real data (default true).',\n\t\t' - name (optional): dev box name (default \"<source>-dev\").',\n\t\t'',\n\t\t'Returns: { service, devUrl, deployId }. Once it is live: open the Terminal tab, run `claude`, start the dev server (it must bind $PORT), and view the app at https://<devUrl>. Tear it all down later with delete_dev_environment.',\n\t\t'',\n\t\t'Example: spin_up_dev_environment({ service_id: \"svc_api\" }) → a dev box running a clone of the api service (repo + env-vars + cloned DB) with a public dev URL.',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z\n\t\t\t.union([z.number().int().positive(), z.string()])\n\t\t\t.describe('Source service to debug — numeric id or publicId.'),\n\t\tinclude_database_clone: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe('Clone the linked database so the app runs on copied data (default true).'),\n\t\tname: z\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(100)\n\t\t\t.optional()\n\t\t\t.describe('Dev box name (default \"<source>-dev\").'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst serviceId = await ctx.hoststack.resolveId(args.service_id, {\n\t\t\tkind: 'service',\n\t\t\tteamId,\n\t\t});\n\t\tconst opts: { includeDatabaseClone?: boolean; name?: string } = {};\n\t\tif (args.include_database_clone !== undefined)\n\t\t\topts.includeDatabaseClone = args.include_database_clone;\n\t\tif (args.name !== undefined) opts.name = args.name;\n\t\tconst result = await ctx.hoststack.services.spinUpDevEnvironment(teamId, serviceId, opts);\n\t\treturn respond({\n\t\t\tsummary: `Spun up dev environment \"${result.service.name}\" (${result.service.publicId}) — deploying. Once live: open the Terminal tab, run \\`claude\\`, start the dev server on $PORT, and view it at https://${result.devUrl}. \\`git push\\` works from inside.`,\n\t\t\tdata: {\n\t\t\t\tservice: shapeService(result.service),\n\t\t\t\tdevUrl: result.devUrl,\n\t\t\t\tdeployId: result.deployId,\n\t\t\t},\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'delete_dev_environment',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Tear down an agentic Dev Box in one call: removes the cloud Dev Box AND cascade-deletes its cloned database, its /workspace volume, and the auto-created `development` environment if it is now empty.',\n\t\t'',\n\t\t'This deletes a cloud Dev Box, NOT a project deploy environment — to remove a -dev/-staging deploy target use delete_environment instead.',\n\t\t'',\n\t\t'When to use: \"delete / tear down the dev environment\", once you have shipped the fix and no longer need the box.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: the dev box to tear down — numeric id or publicId.',\n\t\t'',\n\t\t'Returns: { ok: true }. Irreversible — the cloned database and workspace volume are deleted.',\n\t\t'',\n\t\t'Example: delete_dev_environment({ service_id: \"svc_api_dev\" }) → removes the dev box, its cloned database, and the /workspace volume.',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z\n\t\t\t.union([z.number().int().positive(), z.string()])\n\t\t\t.describe('The dev box to tear down — numeric id or publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst serviceId = await ctx.hoststack.resolveId(args.service_id, {\n\t\t\tkind: 'service',\n\t\t\tteamId,\n\t\t});\n\t\tawait ctx.hoststack.services.tearDownDevEnvironment(teamId, serviceId);\n\t\treturn respond({\n\t\t\tsummary:\n\t\t\t\t'Dev environment torn down — box, cloned database, /workspace volume, and empty development environment removed.',\n\t\t\tdata: { ok: true },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'resize_dev_environment',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Resize a cloud Dev Box (or any service) to a different size tier — the supported way to give it more memory/CPU/disk headroom (e.g. when ESLint/tsc OOMs).',\n\t\t'',\n\t\t'This resizes a cloud Dev Box, NOT a project deploy environment.',\n\t\t'',\n\t\t'When to use: a Dev Box OOM-killed (see exitReason/recommendedSize from list_dev_environments), or you just want more headroom. This changes the SIZE TIER — unlike per-config memory/CPU overrides, which are clamped to the current tier and so cannot grow a box past it.',\n\t\t'',\n\t\t\"How it applies: the new tier's memory + CPU take effect LIVE on the running container (no recreate, no dropped shell sessions); a larger disk takes effect on the next recreate (suspend→resume). Dev boxes are floored to the OOM-safe minimum size server-side.\",\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: the box to resize — numeric id or publicId.',\n\t\t' - size: target tier — one of the service catalog sizes (e.g. \"standard\", \"large\", \"xlarge\").',\n\t\t'',\n\t\t'Returns: { service } with the new plan.',\n\t\t'',\n\t\t'Example: resize_dev_environment({ service_id: \"svc_skyskraber_dev\", size: \"large\" }) → bumps the box to the large tier, applied live.',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z\n\t\t\t.union([z.number().int().positive(), z.string()])\n\t\t\t.describe('The box to resize — numeric id or publicId.'),\n\t\tsize: z\n\t\t\t.enum(SERVICE_PLANS)\n\t\t\t.describe(\n\t\t\t\t'Target size tier (service catalog size, e.g. \"standard\", \"large\", \"xlarge\").',\n\t\t\t),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst serviceId = await ctx.hoststack.resolveId(args.service_id, {\n\t\t\tkind: 'service',\n\t\t\tteamId,\n\t\t});\n\t\tconst { service } = await ctx.hoststack.services.resize(teamId, serviceId, args.size);\n\t\treturn respond({\n\t\t\tsummary: `Resized to ${service.plan} — memory/CPU applied live; disk grows on next recreate.`,\n\t\t\tdata: { service: shapeService(service) },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'list_dev_environments',\n\tcategory: 'services',\n\tdescription: [\n\t\t'List the team\\'s cloud Dev Boxes (the dashboard \"Dev Boxes\" / Development section), each annotated with the companion services attached to it.',\n\t\t'',\n\t\t\"These are cloud Dev Boxes, NOT project deploy environments — to list a project's deploy targets (Production / Staging / Preview) use list_environments instead.\",\n\t\t'',\n\t\t'When to use: \"show my dev environments\", before opening/tearing one down, to find a box\\'s id.',\n\t\t'',\n\t\t'Returns: { items: [{ ...service, devUrl, databases, exitReason, recommendedSize }] } where `databases` lists the companion engines wired into the box (e.g. [\"postgres\",\"redis\"]). `exitReason` is \"oom_killed\" / \"crashed\" / null for the box\\'s last container exit; when it is \"oom_killed\", `recommendedSize` is the next tier up to rescale to (use resize_dev_environment).',\n\t\t'',\n\t\t'Example: list_dev_environments() → every dev box for the active team.',\n\t].join('\\n'),\n\tinput: {},\n\thandler: async (_args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst { environments } = await ctx.hoststack.services.listDevEnvironments(teamId);\n\t\tconst oomCount = environments.filter((e) => e.exitReason === 'oom_killed').length;\n\t\treturn respond({\n\t\t\tsummary:\n\t\t\t\t`${environments.length} dev environment${environments.length === 1 ? '' : 's'}.` +\n\t\t\t\t(oomCount > 0\n\t\t\t\t\t? ` ${oomCount} recently OOM-killed — consider resize_dev_environment.`\n\t\t\t\t\t: ''),\n\t\t\tdata: {\n\t\t\t\titems: environments.map((env) => ({\n\t\t\t\t\t...shapeService(env),\n\t\t\t\t\tdevUrl: env.devUrl ?? null,\n\t\t\t\t\tdatabases: env.databases ?? [],\n\t\t\t\t\texitReason: env.exitReason ?? null,\n\t\t\t\t\trecommendedSize: env.recommendedSize ?? null,\n\t\t\t\t})),\n\t\t\t},\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'list_templates',\n\tcategory: 'services',\n\tdescription: [\n\t\t'List the canonical Dev Box (AI dev environment) preset so an agent can see, without guessing, what a `create_standalone_dev_environment` / `create_dev_environment` actually provisions: the container image, the persistent /workspace volume (mount + default size), the OOM-safe size floor, and the companion database options.',\n\t\t'',\n\t\t'When to use: before creating a Dev Box, to confirm the image, the default /workspace size, the minimum plan, or which companion engines can be attached — instead of hand-duplicating those constants.',\n\t\t'',\n\t\t'Returns: { templates: [{ id, name, image, volume: { name, mountPath, sizeGb }, minPlan, companions }] }. Today there is one preset (\"dev-environment\").',\n\t\t'',\n\t\t'Example: list_templates() → { templates: [{ id: \"dev-environment\", image: \"registry.hoststack.dev/hoststack/dev-env:latest\", volume: { mountPath: \"/workspace\", sizeGb: 10 }, minPlan: \"standard\", companions: [\"postgres\",\"redis\",\"meilisearch\"] }] }',\n\t].join('\\n'),\n\tinput: {},\n\thandler: async () => {\n\t\t// The canonical Dev Box preset, assembled from THIS package's own\n\t\t// constants (DEV_ENV_IMAGE / DEV_ENV_VOLUME / DEV_ENV_MIN_SIZE). Kept in\n\t\t// sync by review with packages/shared/src/templates.ts — NOT imported,\n\t\t// per the workspace constraint (the MCP package must not depend on the\n\t\t// private @hoststack/shared package). Duplicated intentionally.\n\t\tconst templates = [\n\t\t\t{\n\t\t\t\tid: 'dev-environment',\n\t\t\t\tname: 'AI Dev Environment',\n\t\t\t\timage: DEV_ENV_IMAGE,\n\t\t\t\tvolume: {\n\t\t\t\t\tname: DEV_ENV_VOLUME.name,\n\t\t\t\t\tmountPath: DEV_ENV_VOLUME.mountPath,\n\t\t\t\t\tsizeGb: DEV_ENV_VOLUME.sizeGb,\n\t\t\t\t},\n\t\t\t\t/** OOM-safe plan floor — a coding agent + build needs at least this. */\n\t\t\t\tminPlan: DEV_ENV_MIN_SIZE,\n\t\t\t\t/** Companion engines you can attach (fresh + empty), like local `make db-up`. */\n\t\t\t\tcompanions: ['postgres', 'redis', 'meilisearch'],\n\t\t\t},\n\t\t];\n\t\treturn respond({\n\t\t\tsummary: `${templates.length} Dev Box template${templates.length === 1 ? '' : 's'} available (image ${DEV_ENV_IMAGE}, /workspace ${DEV_ENV_VOLUME.sizeGb} GB, floor \"${DEV_ENV_MIN_SIZE}\").`,\n\t\t\tdata: { templates },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'create_standalone_dev_environment',\n\tcategory: 'services',\n\tdescription: [\n\t\t\"Create a STANDALONE Dev Box in one call: a cloud box (Claude Code + Codex + OpenCode + MCPs) on a persistent /workspace, from a connected GitHub repo, an arbitrary clone URL, or blank — with optional companion Postgres / Redis / Meilisearch wired into its env (mirrors a local `make db-up`). The box lives in the team's hidden Development home, NOT under a project.\",\n\t\t'',\n\t\t'This makes a cloud Dev Box, NOT a project deploy environment (create_environment → Production / Staging / Preview). It is a workspace you code in, not a deployment target.',\n\t\t'',\n\t\t'Every Dev Box — with or without companions — also ships NATIVE Postgres 17, Redis and Meilisearch INSIDE the box, started with `dev-services up` (postgres :5432 as user \"dev\" with trust auth, redis :6379, meilisearch :7700). That is the no-Docker replacement for `make db-up` and is the right answer for local development inside the box; there is no Docker daemon available in there. The `companions` option is different — it attaches SEPARATE managed databases to the box\\'s environment for when the box needs a real, persistent, backed-up datastore.',\n\t\t'',\n\t\t'When to use: \"create a dev environment for <repo>\", \"spin me up a cloud dev box with a Postgres\". Distinct from spin_up_dev_environment (which clones an EXISTING service) and create_dev_environment (a bare box in a chosen project).',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - name (optional): the Dev Box name. Omit it and the box is named after its source (the repo name, or \"dev-box\" when blank), with a numeric suffix if that name is taken — so \"give me a dev box\" needs no invented name.',\n\t\t' - source_kind: \"github_repo\" (clone a connected repo — needs github_repo_id), \"url\" (clone any http(s) git URL — needs clone_url), or \"blank\" (empty box).',\n\t\t' - github_repo_id (for github_repo): numeric id of a connected GitHub repo.',\n\t\t' - clone_url (for url): an http(s) git clone URL.',\n\t\t' - branch (optional): branch to clone.',\n\t\t' - databases (optional): companion services to attach — any of \"postgres\", \"redis\", \"meilisearch\".',\n\t\t' - plan (optional): box size. Defaults to \"standard\" (2 GB) — the OOM-safe floor (DEV_ENV_MIN_SIZE); a smaller plan is floored up to \"standard\" server-side.',\n\t\t\" - agent_accounts (optional): bind specific saved agent logins by account id per provider. OMIT to auto-inherit the box owner's default logins (claude/codex/opencode), so `claude` is already authenticated on first boot — no manual login.\",\n\t\t'',\n\t\t'Returns: { service, devUrl, deployId } — deploying. Once live: open the Terminal tab, run `claude`, start the dev server on $PORT, view at https://<devUrl>. Tear down with delete_dev_environment.',\n\t\t'',\n\t\t'Example: create_standalone_dev_environment({ name: \"app-dev\", source_kind: \"github_repo\", github_repo_id: 42, databases: [\"postgres\",\"redis\"] })',\n\t].join('\\n'),\n\tinput: {\n\t\tname: z\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(100)\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t'Dev Box name. Omit to have it named after the source (the repo name, or \"dev-box\" for a blank one), de-duplicated against existing boxes.',\n\t\t\t),\n\t\tsource_kind: z.enum(['github_repo', 'url', 'blank']).describe('Where the code comes from.'),\n\t\tgithub_repo_id: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.positive()\n\t\t\t.optional()\n\t\t\t.describe('Connected GitHub repo id (required when source_kind=\"github_repo\").'),\n\t\tclone_url: z\n\t\t\t.string()\n\t\t\t.url()\n\t\t\t.optional()\n\t\t\t.describe('http(s) git clone URL (required when source_kind=\"url\").'),\n\t\tbranch: z.string().min(1).max(255).optional().describe('Branch to clone.'),\n\t\tdatabases: z\n\t\t\t.array(z.enum(['postgres', 'redis', 'meilisearch']))\n\t\t\t.optional()\n\t\t\t.describe('Companion services to attach (fresh + empty).'),\n\t\tplan: z\n\t\t\t.enum(SERVICE_PLANS)\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t'Box size (default \"standard\" — 2 GB; a smaller plan is floored to \"standard\").',\n\t\t\t),\n\t\tagent_accounts: z\n\t\t\t.array(\n\t\t\t\tz.object({\n\t\t\t\t\tprovider: z.enum(['claude', 'codex', 'opencode']),\n\t\t\t\t\taccount_id: z.number().int().positive(),\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.max(3)\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t\"Bind saved agent logins by account id per provider. Omit to inherit the box owner's default logins automatically.\",\n\t\t\t),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tlet source: CreateDevEnvironmentInput['source'];\n\t\tif (args.source_kind === 'github_repo') {\n\t\t\tif (!args.github_repo_id) {\n\t\t\t\treturn respond({\n\t\t\t\t\tsummary: 'github_repo_id is required when source_kind is \"github_repo\".',\n\t\t\t\t\tdata: { ok: false },\n\t\t\t\t});\n\t\t\t}\n\t\t\tsource = {\n\t\t\t\tkind: 'github_repo',\n\t\t\t\tgithubRepoId: args.github_repo_id,\n\t\t\t\t...(args.branch ? { branch: args.branch } : {}),\n\t\t\t};\n\t\t} else if (args.source_kind === 'url') {\n\t\t\tif (!args.clone_url) {\n\t\t\t\treturn respond({\n\t\t\t\t\tsummary: 'clone_url is required when source_kind is \"url\".',\n\t\t\t\t\tdata: { ok: false },\n\t\t\t\t});\n\t\t\t}\n\t\t\tsource = {\n\t\t\t\tkind: 'url',\n\t\t\t\tcloneUrl: args.clone_url,\n\t\t\t\t...(args.branch ? { branch: args.branch } : {}),\n\t\t\t};\n\t\t} else {\n\t\t\tsource = { kind: 'blank' };\n\t\t}\n\t\tconst input: CreateDevEnvironmentInput = {\n\t\t\t...(args.name ? { name: args.name } : {}),\n\t\t\tsource,\n\t\t\t...(args.databases ? { databases: args.databases } : {}),\n\t\t\t...(args.plan ? { plan: args.plan } : {}),\n\t\t\t...(args.agent_accounts && args.agent_accounts.length > 0\n\t\t\t\t? {\n\t\t\t\t\t\tagentAccounts: args.agent_accounts.map((a) => ({\n\t\t\t\t\t\t\tprovider: a.provider,\n\t\t\t\t\t\t\taccountId: a.account_id,\n\t\t\t\t\t\t})),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t};\n\t\tconst result = await ctx.hoststack.services.createDevEnvironment(teamId, input);\n\t\treturn respond({\n\t\t\tsummary: `Created dev environment \"${result.service.name}\" (${result.service.publicId}) — deploying. Once live: open the Terminal tab, run \\`claude\\`, start the dev server on $PORT, and view it at https://${result.devUrl}.`,\n\t\t\tdata: {\n\t\t\t\tservice: shapeService(result.service),\n\t\t\t\tdevUrl: result.devUrl,\n\t\t\t\tdeployId: result.deployId,\n\t\t\t},\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'get_service',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Fetch a single service by ID with its current status AND its service_config row (resources, health-check tuning, scaling, restart policy).',\n\t\t'',\n\t\t'When to use: drilling into a service after list_services, checking deploy/runtime status, grabbing the repo+branch before triggering a deploy, or inspecting the health-check / autoscale knobs before tweaking them via update_service_config.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service (e.g. \"svc_abc123\").',\n\t\t'',\n\t\t'Returns: { service: Service, config: ServiceConfig } — service has type/status/runtime/repoUrl/branch/autoDeploy/region/plan/timestamps; config has memoryMb, cpuShares, diskSizeGb, port, protocol, healthCheckEnabled, healthCheckInterval, healthCheckTimeout, healthCheckGracePeriodSec, restartPolicy, deployStrategy (\"rolling\" | \"recreate\"), preDeployCommand, min/maxInstances, scale thresholds.',\n\t\t'',\n\t\t'Example: get_service({ service_id: \"svc_abc\" }) → { service: { type: \"web\", status: \"running\", … }, config: { healthCheckGracePeriodSec: 120, … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId (e.g. svc_abc123).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\t// Bundle service + config so a single call answers both \"how is it\n\t\t// running?\" and \"how is it tuned?\". Previously callers had to follow\n\t\t// up with a separate read for any of the health-check / scaling /\n\t\t// resource knobs, which lived only on the service_config row.\n\t\tconst [serviceResponse, configResponse] = await Promise.all([\n\t\t\tctx.hoststack.services.get(teamId, args.service_id),\n\t\t\tctx.hoststack.services.getConfig(teamId, args.service_id),\n\t\t]);\n\t\tconst data = {\n\t\t\tservice: shapeService(serviceResponse.service),\n\t\t\tconfig: shape(configResponse.config),\n\t\t};\n\t\tconst status =\n\t\t\tdata.service && 'status' in data.service\n\t\t\t\t? (data.service as { status: string }).status\n\t\t\t\t: 'unknown';\n\t\treturn respond({ summary: `Service ${args.service_id} is ${status}.`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'get_service_metrics',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Fetch the latest CPU, memory, network, and request-rate metrics for a service.',\n\t\t'',\n\t\t'When to use: a service is reportedly slow, you suspect resource pressure, or you want a quick health snapshot before scaling. Returns a single point-in-time sample. For a time series — \"is memory growing?\", \"did CPU spike during that deploy?\" — use get_service_metrics_history instead.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t'',\n\t\t'Returns: { metrics: { cpu, memory, network, requests } } — values are normalised utilisation/throughput numbers.',\n\t\t'',\n\t\t'Example: get_service_metrics({ service_id: \"svc_abc\" }) → { metrics: { cpu: 0.42, memory: 0.71, … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.services.getMetrics(teamId, args.service_id);\n\t\tconst data = { metrics: shape(response.metrics) };\n\t\treturn respond({ summary: `Metrics snapshot for service ${args.service_id}.`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'get_service_metrics_history',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Fetch a metrics time series (CPU, memory, network, disk) for a service.',\n\t\t'',\n\t\t'When to use: answering \"is memory growing over the last hour?\", \"did CPU spike during deploy X?\", or \"what does normal look like for this service?\". Pairs well with get_deploy to align spikes against deploy times.',\n\t\t'',\n\t\t'Inputs (all optional — omit both for the trailing hour):',\n\t\t' - service_id: publicId of the service.',\n\t\t' - from: ISO-8601 lower bound OR relative offset like \"-15m\" / \"-2h\" / \"-7d\".',\n\t\t' - to: ISO-8601 upper bound (or relative offset). Defaults to now.',\n\t\t'',\n\t\t'Resolution: ≤7d → raw samples (~minute granularity), ≤30d → hourly pre-aggregates, >30d → daily. Up to ~500 points returned.',\n\t\t'',\n\t\t'Returns: { history: Array<{ timestamp, cpuPercent, memoryUsedMb, memoryLimitMb, networkRxBytes, networkTxBytes, diskUsedMb }> }.',\n\t\t'',\n\t\t'Example: get_service_metrics_history({ service_id: \"svc_abc\", from: \"-1h\" }) → 60-ish points for the last hour.',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tfrom: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe('ISO-8601 lower bound or relative offset (e.g. \"-1h\", \"-2d\").'),\n\t\tto: z.string().optional().describe('ISO-8601 upper bound; defaults to now.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\t// Translate the same `-Nm/h/d` relative shorthand we accept in logs\n\t\t// so callers don't have to learn a second convention. The metrics\n\t\t// history endpoint expects ISO timestamps server-side; we resolve\n\t\t// relative offsets here for symmetry with get_service_logs.\n\t\tconst opts: { from?: string; to?: string } = {};\n\t\tconst resolveRel = (raw: string): string => {\n\t\t\tconst rel = /^-(\\d+)(s|m|h|d)$/.exec(raw.trim());\n\t\t\tif (!rel) return raw;\n\t\t\tconst amount = Number.parseInt(rel[1] as string, 10);\n\t\t\tconst unit = rel[2] as 's' | 'm' | 'h' | 'd';\n\t\t\tconst ms =\n\t\t\t\tunit === 's'\n\t\t\t\t\t? amount * 1000\n\t\t\t\t\t: unit === 'm'\n\t\t\t\t\t\t? amount * 60_000\n\t\t\t\t\t\t: unit === 'h'\n\t\t\t\t\t\t\t? amount * 3_600_000\n\t\t\t\t\t\t\t: amount * 86_400_000;\n\t\t\treturn new Date(Date.now() - ms).toISOString();\n\t\t};\n\t\tif (args.from) opts.from = resolveRel(args.from);\n\t\tif (args.to) opts.to = resolveRel(args.to);\n\n\t\tconst response = await ctx.hoststack.services.getMetricsHistory(\n\t\t\tteamId,\n\t\t\targs.service_id,\n\t\t\topts,\n\t\t);\n\t\tconst points = Array.isArray(response.history) ? response.history.length : 0;\n\t\treturn respond({\n\t\t\tsummary: `Returned ${points} metric point${points === 1 ? '' : 's'} for service ${args.service_id}.`,\n\t\t\tdata: { history: response.history },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'update_service',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Rename a service. Only the human-readable name changes — the publicId is permanent.',\n\t\t'',\n\t\t'When to use: the user wants to relabel a service in the dashboard. For deeper config edits (build command, branch, scale, plan), use update_service_config.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - name: new name (1–60 chars).',\n\t\t'',\n\t\t'Returns: { service: Service }.',\n\t\t'',\n\t\t'Example: update_service({ service_id: \"svc_abc\", name: \"api-prod\" }) → { service: { name: \"api-prod\", … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tname: z.string().min(1).max(60).describe('New service name (1–60 chars).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.services.update(teamId, args.service_id, {\n\t\t\tname: args.name,\n\t\t});\n\t\tconst data = { service: shapeService(response.service) };\n\t\treturn respond({ summary: `Renamed service ${args.service_id} to \"${args.name}\".`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'update_service_config',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Update build/runtime configuration for a service. All fields optional — pass only what you want to change.',\n\t\t'',\n\t\t'When to use: the user wants to tweak how a service builds, runs, scales, or health-checks. Build/runtime fields (branch, install/build/start command, root, dockerfile) take effect on the next deploy — call trigger_deploy after if you need them applied immediately. Instance_count, resource and health-check changes rescale or rewire without a redeploy.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - install_command, build_command, start_command (optional): shell commands. Pass null to clear.',\n\t\t' - branch (optional): git branch to track.',\n\t\t' - root_directory (optional): build context root inside the repo.',\n\t\t' - dockerfile_path (optional): path to Dockerfile relative to root_directory. Pass null to clear.',\n\t\t' - auto_deploy (optional): boolean — auto-deploy on git push.',\n\t\t' - health_check_path (optional): HTTP path the platform GETs to verify liveness (e.g. \"/health\"). Pass null for TCP-only check.',\n\t\t' - health_check_enabled (optional): boolean — toggle health checking on/off.',\n\t\t' - health_check_interval (optional): integer 5–300 seconds — how often the check runs.',\n\t\t' - health_check_timeout (optional): integer 1–60 seconds — single-attempt timeout.',\n\t\t' - health_check_grace_period_sec (optional): integer 1–1800 seconds — startup tolerance before failures count. RAISE THIS (e.g. 180) when the agent reports \"Health check timed out\" on a cold-boot app (Bun + Vite SSR typically need 90–180s).',\n\t\t' - memory_mb (optional): integer 128–16384 — container memory cap.',\n\t\t' - cpu_shares (optional): integer 128–4096 — relative CPU weight.',\n\t\t' - disk_size_gb (optional): integer 1–100 — ephemeral disk cap.',\n\t\t' - port (optional): integer 1–65535 — container port the platform forwards traffic to.',\n\t\t' - protocol (optional): \"http\" | \"tcp\".',\n\t\t' - restart_policy (optional): \"always\" | \"on-failure\" | \"no\".',\n\t\t' - deploy_strategy (optional): \"rolling\" (default) | \"recreate\". SET THIS TO \"recreate\" for any single-container service that holds an exclusive lock on a mounted volume — a database running inside the container, an embedded queue, anything with a lockfile or a fixed host port on shared storage. Under the default rolling strategy those services CANNOT deploy at all: the new container can\\'t open the datadir the outgoing container still holds, so it exits; because it never goes healthy the old one is never stopped; because the old one is never stopped the lock is never released. The deploy deadlocks for the whole grace period and then reports \"Health check timed out\". \"recreate\" stops the old container first, at the cost of a brief outage.',\n\t\t' - pre_deploy_command (optional): shell command run before the new release accepts traffic (typical use: migrations).',\n\t\t' - instance_count (optional): integer 1–50 — pin both min and max instances to this value.',\n\t\t' - min_instances, max_instances (optional): integers — autoscale bounds. Use instead of instance_count when you want a range.',\n\t\t' - scale_cpu_threshold, scale_memory_threshold (optional): integer 10–100 — autoscale trigger percentage.',\n\t\t' - log_filter_rules (optional): list of { pattern, action } rules applied to runtime logs at query time. Pattern matches the message by case-insensitive substring; action is \"drop\" (filter out) or \"downgrade\" (flip stderr → stdout so it stops looking like an error). Pass [] to clear all rules. Capped at 50 rules.',\n\t\t'',\n\t\t'Returns: { service?: Service, config?: ServiceConfig } — whichever rows were touched.',\n\t\t'',\n\t\t'Example: update_service_config({ service_id: \"svc_abc\", health_check_grace_period_sec: 180 }) → { config: { healthCheckGracePeriodSec: 180, … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tinstall_command: z\n\t\t\t.string()\n\t\t\t.nullable()\n\t\t\t.optional()\n\t\t\t.describe('Install shell command. Null clears.'),\n\t\tbuild_command: z\n\t\t\t.string()\n\t\t\t.nullable()\n\t\t\t.optional()\n\t\t\t.describe('Build shell command. Null clears.'),\n\t\tstart_command: z\n\t\t\t.string()\n\t\t\t.nullable()\n\t\t\t.optional()\n\t\t\t.describe('Start shell command. Null clears.'),\n\t\tbranch: z.string().optional().describe('Git branch to track.'),\n\t\troot_directory: z.string().optional().describe('Build context root.'),\n\t\tdockerfile_path: z\n\t\t\t.string()\n\t\t\t.nullable()\n\t\t\t.optional()\n\t\t\t.describe('Path to Dockerfile relative to root. Null clears.'),\n\t\tauto_deploy: z.boolean().optional().describe('Auto-deploy on push.'),\n\t\thealth_check_path: z\n\t\t\t.string()\n\t\t\t.nullable()\n\t\t\t.optional()\n\t\t\t.describe('HTTP health-check path (e.g. \"/health\"). Null = TCP-only check.'),\n\t\thealth_check_enabled: z.boolean().optional().describe('Toggle health checking on/off.'),\n\t\thealth_check_interval: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(5)\n\t\t\t.max(300)\n\t\t\t.optional()\n\t\t\t.describe('How often the check runs, in seconds (5–300).'),\n\t\thealth_check_timeout: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(1)\n\t\t\t.max(60)\n\t\t\t.optional()\n\t\t\t.describe('Single-attempt timeout in seconds (1–60).'),\n\t\thealth_check_grace_period_sec: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(1)\n\t\t\t.max(1800)\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t'Startup grace period in seconds (1–1800). Raise this if the app needs more time to boot before health checks start counting failures.',\n\t\t\t),\n\t\tmemory_mb: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(128)\n\t\t\t.max(16384)\n\t\t\t.optional()\n\t\t\t.describe('Container memory cap in MB (128–16384).'),\n\t\tcpu_shares: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(128)\n\t\t\t.max(4096)\n\t\t\t.optional()\n\t\t\t.describe('Relative CPU weight (128–4096).'),\n\t\tdisk_size_gb: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(1)\n\t\t\t.max(100)\n\t\t\t.optional()\n\t\t\t.describe('Ephemeral disk size in GB (1–100).'),\n\t\tport: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(1)\n\t\t\t.max(65535)\n\t\t\t.optional()\n\t\t\t.describe('Container port the platform forwards traffic to.'),\n\t\tprotocol: z.enum(['http', 'tcp']).optional().describe('Traffic protocol.'),\n\t\trestart_policy: z\n\t\t\t.enum(['always', 'on-failure', 'no'])\n\t\t\t.optional()\n\t\t\t.describe('Docker restart policy.'),\n\t\tdeploy_strategy: z\n\t\t\t.enum(['rolling', 'recreate'])\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t'How a deploy replaces the container. \"rolling\" (default) = start new, wait for healthy, switch traffic, stop old (zero downtime). \"recreate\" = stop old first, then start new (brief outage) — required for a container holding an exclusive lock on a mounted volume, which cannot deploy at all under rolling.',\n\t\t\t),\n\t\tpre_deploy_command: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe('Shell command run before the new release accepts traffic.'),\n\t\tinstance_count: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.positive()\n\t\t\t.max(50)\n\t\t\t.optional()\n\t\t\t.describe('Pin min and max instances to this value (1–50).'),\n\t\tmin_instances: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(0)\n\t\t\t.max(50)\n\t\t\t.optional()\n\t\t\t.describe('Autoscale lower bound. Use with max_instances for a range.'),\n\t\tmax_instances: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(1)\n\t\t\t.max(50)\n\t\t\t.optional()\n\t\t\t.describe('Autoscale upper bound. Use with min_instances for a range.'),\n\t\tscale_cpu_threshold: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(10)\n\t\t\t.max(100)\n\t\t\t.optional()\n\t\t\t.describe('Autoscale CPU trigger percentage (10–100).'),\n\t\tscale_memory_threshold: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(10)\n\t\t\t.max(100)\n\t\t\t.optional()\n\t\t\t.describe('Autoscale memory trigger percentage (10–100).'),\n\t\tlog_filter_rules: z\n\t\t\t.array(\n\t\t\t\tz.object({\n\t\t\t\t\tpattern: z.string().min(1).max(200),\n\t\t\t\t\taction: z.enum(['drop', 'downgrade']),\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.max(50)\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t'Runtime-log filter rules. Empty array [] clears all rules. Each pattern is case-insensitive substring match against the message.',\n\t\t\t),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\n\t\t// services-row fields (PATCH /services/:tid/:sid). Note: nullable\n\t\t// fields take `null` to clear, distinct from `undefined` which means\n\t\t// \"leave unchanged\" — passing `null` through to the underlying API\n\t\t// is what flips the column to NULL on the row.\n\t\tconst serviceUpdate: Record<string, unknown> = {};\n\t\tif (args.install_command !== undefined)\n\t\t\tserviceUpdate['installCommand'] = args.install_command;\n\t\tif (args.build_command !== undefined) serviceUpdate['buildCommand'] = args.build_command;\n\t\tif (args.start_command !== undefined) serviceUpdate['startCommand'] = args.start_command;\n\t\tif (args.dockerfile_path !== undefined)\n\t\t\tserviceUpdate['dockerfilePath'] = args.dockerfile_path;\n\t\tif (args.branch !== undefined) serviceUpdate['branch'] = args.branch;\n\t\tif (args.root_directory !== undefined) serviceUpdate['rootDirectory'] = args.root_directory;\n\t\tif (args.auto_deploy !== undefined) serviceUpdate['autoDeploy'] = args.auto_deploy;\n\t\tif (args.health_check_path !== undefined)\n\t\t\tserviceUpdate['healthCheckPath'] = args.health_check_path;\n\n\t\t// service_config-row fields (PATCH /services/:tid/:sid/config). The\n\t\t// schema expects min_instances/max_instances; \"pin to N\" means setting\n\t\t// both to the same value.\n\t\tconst configUpdate: Record<string, unknown> = {};\n\t\tif (args.health_check_enabled !== undefined)\n\t\t\tconfigUpdate['healthCheckEnabled'] = args.health_check_enabled;\n\t\tif (args.health_check_interval !== undefined)\n\t\t\tconfigUpdate['healthCheckInterval'] = args.health_check_interval;\n\t\tif (args.health_check_timeout !== undefined)\n\t\t\tconfigUpdate['healthCheckTimeout'] = args.health_check_timeout;\n\t\tif (args.health_check_grace_period_sec !== undefined)\n\t\t\tconfigUpdate['healthCheckGracePeriodSec'] = args.health_check_grace_period_sec;\n\t\tif (args.memory_mb !== undefined) configUpdate['memoryMb'] = args.memory_mb;\n\t\tif (args.cpu_shares !== undefined) configUpdate['cpuShares'] = args.cpu_shares;\n\t\tif (args.disk_size_gb !== undefined) configUpdate['diskSizeGb'] = args.disk_size_gb;\n\t\tif (args.port !== undefined) configUpdate['port'] = args.port;\n\t\tif (args.protocol !== undefined) configUpdate['protocol'] = args.protocol;\n\t\tif (args.restart_policy !== undefined) configUpdate['restartPolicy'] = args.restart_policy;\n\t\tif (args.deploy_strategy !== undefined)\n\t\t\tconfigUpdate['deployStrategy'] = args.deploy_strategy;\n\t\tif (args.pre_deploy_command !== undefined)\n\t\t\tconfigUpdate['preDeployCommand'] = args.pre_deploy_command;\n\t\tif (args.instance_count !== undefined) {\n\t\t\tconfigUpdate['minInstances'] = args.instance_count;\n\t\t\tconfigUpdate['maxInstances'] = args.instance_count;\n\t\t}\n\t\tif (args.min_instances !== undefined) configUpdate['minInstances'] = args.min_instances;\n\t\tif (args.max_instances !== undefined) configUpdate['maxInstances'] = args.max_instances;\n\t\tif (args.scale_cpu_threshold !== undefined)\n\t\t\tconfigUpdate['scaleCpuThreshold'] = args.scale_cpu_threshold;\n\t\tif (args.scale_memory_threshold !== undefined)\n\t\t\tconfigUpdate['scaleMemoryThreshold'] = args.scale_memory_threshold;\n\t\tif (args.log_filter_rules !== undefined) {\n\t\t\t// Empty array is a meaningful value (clears all rules);\n\t\t\t// undefined leaves rules unchanged. Don't short-circuit.\n\t\t\tconfigUpdate['logFilterRules'] = args.log_filter_rules;\n\t\t}\n\n\t\tif (Object.keys(serviceUpdate).length === 0 && Object.keys(configUpdate).length === 0) {\n\t\t\treturn respond({ summary: 'No fields to update.', data: {} });\n\t\t}\n\n\t\tconst data: Record<string, unknown> = {};\n\t\tconst touchedFields: string[] = [];\n\t\tif (Object.keys(serviceUpdate).length > 0) {\n\t\t\tconst serviceResponse = await ctx.hoststack.services.update(\n\t\t\t\tteamId,\n\t\t\t\targs.service_id,\n\t\t\t\tserviceUpdate,\n\t\t\t);\n\t\t\tdata['service'] = shape(serviceResponse.service);\n\t\t\ttouchedFields.push(...Object.keys(serviceUpdate));\n\t\t}\n\t\tif (Object.keys(configUpdate).length > 0) {\n\t\t\tconst configResponse = await ctx.hoststack.services.updateConfig(\n\t\t\t\tteamId,\n\t\t\t\targs.service_id,\n\t\t\t\tconfigUpdate,\n\t\t\t);\n\t\t\tdata['config'] = shape(configResponse.config);\n\t\t\ttouchedFields.push(...Object.keys(configUpdate));\n\t\t}\n\n\t\treturn respond({\n\t\t\tsummary: `Updated ${touchedFields.join(', ')} on service ${args.service_id}.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'suspend_service',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Suspend a service: stop all running instances and pause auto-deploys. The service stays configured and can be resumed later with resume_service.',\n\t\t'',\n\t\t'When to use: the user wants to temporarily stop traffic and billing without deleting the service (for example: dev environment overnight, debugging).',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t'',\n\t\t'Returns: { ok: true }.',\n\t\t'',\n\t\t'Example: suspend_service({ service_id: \"svc_dev\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.services.suspend(teamId, args.service_id);\n\t\treturn respond({ summary: `Suspended service ${args.service_id}.`, data: { ok: true } });\n\t},\n});\n\ndefineTool({\n\tname: 'resume_service',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Resume a previously suspended service: start instances back up and re-enable auto-deploys.',\n\t\t'',\n\t\t'When to use: the user wants to bring a suspended service back online. Pair with suspend_service.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t'',\n\t\t'Returns: { ok: true }.',\n\t\t'',\n\t\t'Example: resume_service({ service_id: \"svc_dev\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.services.resume(teamId, args.service_id);\n\t\treturn respond({ summary: `Resumed service ${args.service_id}.`, data: { ok: true } });\n\t},\n});\n\ndefineTool({\n\tname: 'delete_service',\n\tcategory: 'services',\n\tdescription: [\n\t\t'Permanently delete a service: stops and removes its containers, releases its hostname and routes, and cascade-deletes its attached volumes, env vars, domains and deploy history. Irreversible.',\n\t\t'',\n\t\t'When to use: the user explicitly asks to delete or remove a service, or you are cleaning up a service that was created by mistake or is no longer needed. Without this, a broken or abandoned service could only be removed from the dashboard — so a service that failed to come up had to be left in place and worked around by creating another one.',\n\t\t'',\n\t\t'ALWAYS confirm with the user before calling this on anything that has served traffic. To stop a service temporarily without losing it, use suspend_service instead. To tear down an agentic Dev Box (which also cascades its cloned database), use delete_dev_environment.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service to delete.',\n\t\t'',\n\t\t'Returns: { ok: true }.',\n\t\t'',\n\t\t'Example: delete_service({ service_id: \"svc_abandoned\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.services.delete(teamId, args.service_id);\n\t\treturn respond({\n\t\t\tsummary: `Deleted service ${args.service_id} and its attached resources. This cannot be undone.`,\n\t\t\tdata: { ok: true },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'get_service_logs',\n\tcategory: 'logs',\n\tdescription: [\n\t\t\"Fetch a snapshot of the running container's recent runtime logs (stdout/stderr). For *deploy* logs (build output), use get_deploy_logs instead.\",\n\t\t'',\n\t\t'When to use: a service is misbehaving in production and you need to read what it is currently logging. The tool returns a snapshot — there is no streaming over MCP. Re-call to get newer entries.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - lines (optional): tail size (default 200, max 1000).',\n\t\t' - since/until (optional): ISO-8601 timestamp OR a relative offset like \"-5m\", \"-1h\", \"-2d\".',\n\t\t' - stream (optional): \"stdout\" | \"stderr\". Omit to combine.',\n\t\t' - level (optional): real log level — trace/debug/info/warn/error/fatal. For structured JSON logs (pino, bunyan, OpenTelemetry severity) this filters on the parsed inner level field. For plain text logs it falls back to a stream-alias hint (info/debug → stdout, warn/error/fatal → stderr).',\n\t\t' - search (optional): case-insensitive substring grep, ≤100 chars.',\n\t\t' - count_only (optional): when true, returns { count } only — much cheaper for \"how many error lines in last 5m\" polling.',\n\t\t'',\n\t\t'Returns: { logs: LogEntry[] | string } when count_only is false. Each entry has { timestamp, level?, stream, message }. `level` is the parsed inner level when the message is a structured JSON envelope (pino numeric or string), and undefined for plain-text logs. `stream` is always one of stdout/stderr. Or { count: number } when count_only is true.',\n\t\t'',\n\t\t'Example: get_service_logs({ service_id: \"svc_abc\", search: \"OOM\", since: \"-15m\" }) → { logs: [...] }.',\n\t\t'',\n\t\t'More examples:',\n\t\t' - Last 50 stderr lines from the past hour: get_service_logs({ service_id: \"svc_abc\", lines: 50, stream: \"stderr\", since: \"-1h\" })',\n\t\t' - Just count error lines without fetching them: get_service_logs({ service_id: \"svc_abc\", level: \"error\", since: \"-5m\", count_only: true }) → { count: 47 }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tlines: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.positive()\n\t\t\t.max(1000)\n\t\t\t.optional()\n\t\t\t.describe('Tail size; default 200, hard cap 1000.'),\n\t\tsince: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe('ISO-8601 timestamp or relative offset (e.g. \"-5m\", \"-1h\").'),\n\t\tuntil: z.string().optional().describe('ISO-8601 timestamp or relative offset upper bound.'),\n\t\tstream: z.enum(['stdout', 'stderr']).optional().describe('Restrict to one stream.'),\n\t\tlevel: z\n\t\t\t.enum(['stdout', 'stderr', 'trace', 'debug', 'info', 'warn', 'error', 'fatal'])\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t'Filter by structured JSON log level (pino/bunyan/severity). Falls back to a stream-alias hint for plain-text logs (info/debug→stdout, warn/error/fatal→stderr).',\n\t\t\t),\n\t\tsearch: z.string().max(100).optional().describe('Case-insensitive substring filter.'),\n\t\tcount_only: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe('When true, return only { count } — skips the log payload.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst opts: {\n\t\t\tlines?: number;\n\t\t\tsince?: string;\n\t\t\tuntil?: string;\n\t\t\tstream?: 'stdout' | 'stderr';\n\t\t\tlevel?: 'stdout' | 'stderr' | 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';\n\t\t\tsearch?: string;\n\t\t\tcountOnly?: boolean;\n\t\t} = {\n\t\t\tlines: args.lines ?? 200,\n\t\t};\n\t\tif (args.since) opts.since = args.since;\n\t\tif (args.until) opts.until = args.until;\n\t\tif (args.stream) opts.stream = args.stream;\n\t\tif (args.level) opts.level = args.level;\n\t\tif (args.search) opts.search = args.search;\n\t\tif (args.count_only) opts.countOnly = args.count_only;\n\n\t\tconst response = await ctx.hoststack.services.getRuntimeLogs(teamId, args.service_id, opts);\n\t\tif ('count' in response) {\n\t\t\treturn respond({\n\t\t\t\tsummary: `${response.count} matching log line${response.count === 1 ? '' : 's'} for service ${args.service_id}.`,\n\t\t\t\tdata: { count: response.count },\n\t\t\t});\n\t\t}\n\t\tconst count = Array.isArray(response.logs)\n\t\t\t? response.logs.length\n\t\t\t: typeof response.logs === 'string'\n\t\t\t\t? response.logs.split('\\n').length\n\t\t\t\t: 0;\n\t\treturn respond({\n\t\t\tsummary: `Fetched ${count} log line${count === 1 ? '' : 's'} for service ${args.service_id}.`,\n\t\t\tdata: { logs: response.logs },\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'get_service_logs_bulk',\n\tcategory: 'logs',\n\tdescription: [\n\t\t'Fetch runtime logs for multiple services in parallel and return one response keyed by service_id. Single round-trip from the MCP client perspective.',\n\t\t'',\n\t\t'When to use: investigating something that spans a project — \"what does every service in the auth-fleet say about the OOM at 14:00?\", \"did anything log an error in the last 5 minutes across these 4 services?\". Pair with list_services (filter by project/status) to get the service_ids list first.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_ids: list of service publicIds (svc_…). Hard cap 10 to bound work — for larger fleets, partition the call.',\n\t\t' - lines_per_service (optional): tail size per service (default 100, max 500). Smaller default than get_service_logs since you are fanning out.',\n\t\t' - since/until (optional): same shape as get_service_logs (ISO-8601 or \"-5m\", \"-1h\").',\n\t\t' - stream (optional): \"stdout\" | \"stderr\".',\n\t\t' - level (optional): structured-log level filter (trace/debug/info/warn/error/fatal).',\n\t\t' - search (optional): case-insensitive substring filter applied to every service.',\n\t\t' - count_only (optional): when true, return { results: { [service_id]: { count } } } — much cheaper for \"how many error lines per service in the last 5m\" surveys.',\n\t\t'',\n\t\t'Returns: { results: { [service_id]: { logs?, count?, error? } } } — per-service result, with `error` populated when one service failed (the rest still succeed).',\n\t\t'',\n\t\t'Example: get_service_logs_bulk({ service_ids: [\"svc_api\", \"svc_worker\"], level: \"error\", since: \"-15m\", count_only: true }) → { results: { svc_api: { count: 0 }, svc_worker: { count: 12 } } }.',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_ids: z\n\t\t\t.array(z.string())\n\t\t\t.min(1)\n\t\t\t.max(10)\n\t\t\t.describe('Service publicIds (1–10). Hard cap 10 to bound parallel work.'),\n\t\tlines_per_service: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.positive()\n\t\t\t.max(500)\n\t\t\t.optional()\n\t\t\t.describe('Tail size per service; default 100, hard cap 500.'),\n\t\tsince: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe('ISO-8601 timestamp or relative offset (e.g. \"-5m\", \"-1h\").'),\n\t\tuntil: z.string().optional().describe('ISO-8601 timestamp or relative offset upper bound.'),\n\t\tstream: z.enum(['stdout', 'stderr']).optional().describe('Restrict to one stream.'),\n\t\tlevel: z\n\t\t\t.enum(['stdout', 'stderr', 'trace', 'debug', 'info', 'warn', 'error', 'fatal'])\n\t\t\t.optional()\n\t\t\t.describe('Structured log level filter (same as get_service_logs).'),\n\t\tsearch: z.string().max(100).optional().describe('Case-insensitive substring filter.'),\n\t\tcount_only: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe('When true, return only counts per service — skips the log payload.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst linesPerService = args.lines_per_service ?? 100;\n\n\t\t// Build a single options object reused across all fan-outs so we\n\t\t// don't reconstruct identical params in a loop.\n\t\tconst baseOpts: {\n\t\t\tlines: number;\n\t\t\tsince?: string;\n\t\t\tuntil?: string;\n\t\t\tstream?: 'stdout' | 'stderr';\n\t\t\tlevel?: 'stdout' | 'stderr' | 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';\n\t\t\tsearch?: string;\n\t\t\tcountOnly?: boolean;\n\t\t} = { lines: linesPerService };\n\t\tif (args.since) baseOpts.since = args.since;\n\t\tif (args.until) baseOpts.until = args.until;\n\t\tif (args.stream) baseOpts.stream = args.stream;\n\t\tif (args.level) baseOpts.level = args.level;\n\t\tif (args.search) baseOpts.search = args.search;\n\t\tif (args.count_only) baseOpts.countOnly = args.count_only;\n\n\t\t// Promise.allSettled so one failing service (e.g. deleted between\n\t\t// list_services and this call) doesn't void the rest.\n\t\tconst settled = await Promise.allSettled(\n\t\t\targs.service_ids.map(async (sid) => {\n\t\t\t\tconst response = await ctx.hoststack.services.getRuntimeLogs(teamId, sid, baseOpts);\n\t\t\t\treturn { sid, response };\n\t\t\t}),\n\t\t);\n\n\t\tconst results: Record<string, unknown> = {};\n\t\tlet okCount = 0;\n\t\tlet errorCount = 0;\n\t\tfor (let i = 0; i < settled.length; i += 1) {\n\t\t\tconst outcome = settled[i] as PromiseSettledResult<{\n\t\t\t\tsid: string;\n\t\t\t\tresponse: { logs?: unknown; count?: number };\n\t\t\t}>;\n\t\t\tconst sid = args.service_ids[i] as string;\n\t\t\tif (outcome.status === 'fulfilled') {\n\t\t\t\tconst { response } = outcome.value;\n\t\t\t\tif ('count' in response) {\n\t\t\t\t\tresults[sid] = { count: response.count };\n\t\t\t\t} else {\n\t\t\t\t\tresults[sid] = { logs: response.logs };\n\t\t\t\t}\n\t\t\t\tokCount += 1;\n\t\t\t} else {\n\t\t\t\tconst reason = outcome.reason as { message?: string } | string;\n\t\t\t\tresults[sid] = {\n\t\t\t\t\terror:\n\t\t\t\t\t\ttypeof reason === 'string' ? reason : (reason?.message ?? 'Unknown error'),\n\t\t\t\t};\n\t\t\t\terrorCount += 1;\n\t\t\t}\n\t\t}\n\n\t\tconst summary =\n\t\t\terrorCount === 0\n\t\t\t\t? `Fetched logs from ${okCount} service${okCount === 1 ? '' : 's'}.`\n\t\t\t\t: `Fetched logs from ${okCount} of ${args.service_ids.length} service${args.service_ids.length === 1 ? '' : 's'} (${errorCount} failed — see per-service .error field).`;\n\t\treturn respond({ summary, data: { results } });\n\t},\n});\n","import { z } from 'zod';\n\nimport { defineTool } from '../registry.js';\nimport { respond } from '../lib/respond.js';\nimport { shape, shapeList, shapeVolume } from '../lib/shape.js';\n\n/**\n * Platform minimum for a persistent disk, in GB.\n *\n * Inlined rather than imported: this package publishes to npm standalone and\n * must not depend on the `@hoststack/shared` workspace package. Kept in sync\n * with `HETZNER_BLOCK_VOLUME_MIN_GB` in\n * packages/shared/src/constants/pricing.ts — the API rejects anything below\n * it, so a lower bound here only converts a clean rejection into a failed\n * deploy.\n */\nconst MIN_VOLUME_SIZE_GB = 10;\n\ndefineTool({\n\tname: 'list_volumes',\n\tcategory: 'volumes',\n\tdescription: [\n\t\t'List persistent disks attached to a service. Volumes mount writable storage into the container at the path you choose, surviving redeploys and restarts.',\n\t\t'',\n\t\t'When to use: auditing what disks are attached, checking sizes before adding more, or confirming a volume took effect after creation. Note: storage is metered for billing — use this to spot oversized disks.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t'',\n\t\t'Returns: { items: Volume[] } — each entry has id, publicId, name, mountPath, sizeGb, status (pending|active|deleting), createdAt, updatedAt.',\n\t\t'',\n\t\t'Example: list_volumes({ service_id: \"svc_abc\" }) → { items: [{ name: \"data\", mountPath: \"/var/data\", sizeGb: 10, status: \"active\" }] }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId (e.g. svc_abc123).'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst response = await ctx.hoststack.volumes.list(teamId, args.service_id);\n\t\tconst data = shapeList(response, 'volumes', shapeVolume);\n\t\tconst summary =\n\t\t\tdata.items.length === 0\n\t\t\t\t? `No volumes attached to service ${args.service_id}.`\n\t\t\t\t: `Found ${data.items.length} volume${data.items.length === 1 ? '' : 's'} on service ${args.service_id}.`;\n\t\treturn respond({ summary, data });\n\t},\n});\n\ndefineTool({\n\tname: 'create_volume',\n\tcategory: 'volumes',\n\tdescription: [\n\t\t'Attach a new persistent disk to a service. The disk gets provisioned on the host and bind-mounted into the container at `mount_path` on the next deploy. Use this when an app needs writable persistent storage — uploads, caches, SQLite databases, anything that must survive container restarts.',\n\t\t'',\n\t\t'When to use: the user mentions storing files, uploads, or any data that needs to outlive a container restart. For purely ephemeral scratch space, point the app at /tmp instead (already tmpfs-mounted, free, no provisioning needed) — see HOSTSTACK_TMP_DIR.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service to attach to.',\n\t\t' - name: lowercase alphanumeric + hyphens, ≤64 chars (used as the docker volume identifier — change with care once data is written).',\n\t\t' - mount_path: in-container absolute path (e.g. \"/var/data\").',\n\t\t' - size_gb: optional, 10–100, default 10. 10 GB is the platform minimum (the underlying block storage cannot provision anything smaller) — a smaller value is rejected here rather than failing the next deploy. Metered for billing.',\n\t\t'',\n\t\t'Returns: { volume: Volume } — the created record. A durable volume comes back `status: \"pending\"`; the disk is created and attached on the next deploy, which flips it to \"active\". A deploy is required before the mount exists.',\n\t\t'',\n\t\t'Example: create_volume({ service_id: \"svc_abc\", name: \"data\", mount_path: \"/var/data\", size_gb: 10 }) → { volume: { name: \"data\", mountPath: \"/var/data\", sizeGb: 10, status: \"pending\" } }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tname: z\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(64)\n\t\t\t.regex(/^[a-z0-9-]+$/)\n\t\t\t.describe('Volume name (lowercase alphanumeric + hyphens).'),\n\t\tmount_path: z\n\t\t\t.string()\n\t\t\t.startsWith('/')\n\t\t\t.max(500)\n\t\t\t.describe('In-container mount path (absolute).'),\n\t\t// 10 GB is the real floor: the block-storage backend rejects anything\n\t\t// smaller. Advertising 1 GB here (and defaulting to it) meant taking the\n\t\t// defaults produced a volume that provisioned with `Hetzner API error:\n\t\t// 422` on the NEXT deploy, with nothing tying the failure back to the\n\t\t// size. Reject it at the call instead.\n\t\tsize_gb: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(MIN_VOLUME_SIZE_GB)\n\t\t\t.max(100)\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t`Disk size in GB (minimum ${MIN_VOLUME_SIZE_GB}, default ${MIN_VOLUME_SIZE_GB}, max 100 via MCP).`,\n\t\t\t),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst input: { name: string; mountPath: string; sizeGb?: number } = {\n\t\t\tname: args.name,\n\t\t\tmountPath: args.mount_path,\n\t\t};\n\t\tif (args.size_gb !== undefined) input.sizeGb = args.size_gb;\n\t\tconst response = await ctx.hoststack.volumes.create(teamId, args.service_id, input);\n\t\tconst data = { volume: shape(response.volume) };\n\t\treturn respond({\n\t\t\tsummary: `Attached volume \"${args.name}\" (${response.volume.sizeGb}GB) at ${args.mount_path} on service ${args.service_id}. Status is \"${response.volume.status}\" — deploy the service to provision and mount it.`,\n\t\t\tdata,\n\t\t});\n\t},\n});\n\ndefineTool({\n\tname: 'update_volume',\n\tcategory: 'volumes',\n\tdescription: [\n\t\t\"Update a volume's mountPath or sizeGb. Resizes take effect on the next deploy; shrinking is rejected at the storage layer (filesystems can't safely shrink under live data).\",\n\t\t'',\n\t\t'When to use: the user wants to grow the disk for an existing volume, or move where it mounts inside the container.',\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - volume_id: publicId of the volume to update.',\n\t\t' - mount_path (optional): new in-container mount path.',\n\t\t' - size_gb (optional): new size in GB (must be ≥ current).',\n\t\t'',\n\t\t'Returns: { volume: Volume } — the updated record.',\n\t\t'',\n\t\t'Example: update_volume({ service_id: \"svc_abc\", volume_id: \"vol_xyz\", size_gb: 20 }) → { volume: { sizeGb: 20, … } }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tvolume_id: z.string().describe('Volume publicId (e.g. vol_…).'),\n\t\tmount_path: z.string().startsWith('/').max(500).optional().describe('New mount path.'),\n\t\tsize_gb: z\n\t\t\t.number()\n\t\t\t.int()\n\t\t\t.min(MIN_VOLUME_SIZE_GB)\n\t\t\t.max(100)\n\t\t\t.optional()\n\t\t\t.describe(`New size in GB (minimum ${MIN_VOLUME_SIZE_GB}, grow-only).`),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tconst input: { mountPath?: string; sizeGb?: number } = {};\n\t\tif (args.mount_path !== undefined) input.mountPath = args.mount_path;\n\t\tif (args.size_gb !== undefined) input.sizeGb = args.size_gb;\n\t\tif (Object.keys(input).length === 0) {\n\t\t\treturn respond({ summary: 'No fields to update.', data: {} });\n\t\t}\n\t\tconst response = await ctx.hoststack.volumes.update(\n\t\t\tteamId,\n\t\t\targs.service_id,\n\t\t\targs.volume_id,\n\t\t\tinput,\n\t\t);\n\t\tconst data = { volume: shape(response.volume) };\n\t\tconst fields = Object.keys(input).join(', ');\n\t\treturn respond({ summary: `Updated ${fields} on volume ${args.volume_id}.`, data });\n\t},\n});\n\ndefineTool({\n\tname: 'delete_volume',\n\tcategory: 'volumes',\n\tdescription: [\n\t\t'Detach and deprovision a volume. The underlying disk is destroyed — back up any data first. Async: marks the row deleting, the host agent finalises removal once it acks. A periodic reaper retries if the agent was offline at delete time.',\n\t\t'',\n\t\t\"When to use: the user explicitly says to remove a volume, or you're cleaning up after retiring a service. Confirm before calling on production data.\",\n\t\t'',\n\t\t'Inputs:',\n\t\t' - service_id: publicId of the service.',\n\t\t' - volume_id: publicId of the volume.',\n\t\t'',\n\t\t'Returns: { ok: true }.',\n\t\t'',\n\t\t'Example: delete_volume({ service_id: \"svc_abc\", volume_id: \"vol_xyz\" }) → { ok: true }',\n\t].join('\\n'),\n\tinput: {\n\t\tservice_id: z.string().describe('Service publicId.'),\n\t\tvolume_id: z.string().describe('Volume publicId.'),\n\t},\n\thandler: async (args, ctx) => {\n\t\tconst teamId = await ctx.resolveTeamId();\n\t\tawait ctx.hoststack.volumes.delete(teamId, args.service_id, args.volume_id);\n\t\treturn respond({\n\t\t\tsummary: `Detached volume ${args.volume_id} from service ${args.service_id} (deprovisioning).`,\n\t\t\tdata: { ok: true },\n\t\t});\n\t},\n});\n"],"mappings":"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","names":["z","z","z","z","z","z","z","z","z","z","z","zones","z","z","z","z","z","response","data","z","z","z","z","z","z","z","z","z","z","z","z"]}