bazilion 0.1.1 → 0.2.0

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../daemon/src/index.ts","../../daemon/src/app.ts","../../daemon/src/lib/middleware-auth.ts","../../daemon/src/core/repos/agents.ts","../../daemon/src/core/agent/archive.ts","../../daemon/src/core/agent/delete.ts","../../daemon/src/core/repos/groups.ts","../../daemon/src/core/repos/profiles.ts","../../daemon/src/core/agent/resolve.ts","../../daemon/src/core/agent/spawn.ts","../../daemon/src/core/profile/load.ts","../../daemon/src/core/profile/identity.ts","../../daemon/src/core/repos/providerModels.ts","../../daemon/src/core/repos/providerState.ts","../../daemon/src/core/availableModels.ts","../../daemon/src/core/group/register.ts","../../daemon/src/core/profile/validate.ts","../../daemon/src/core/profile/create.ts","../../daemon/src/core/profile/templates.ts","../../daemon/src/core/profile/seed.ts","../../daemon/src/core/skills/discover.ts","../../daemon/src/core/agent/unarchive.ts","../../daemon/src/core/db/client.ts","../../daemon/src/core/db/migrate.ts","../../daemon/src/core/group/delete.ts","../../daemon/src/core/paths.ts","../../daemon/src/core/profile/delete.ts","../../daemon/src/core/profile/update.ts","../../daemon/src/core/services.ts","../../daemon/src/core/repos/config.ts","../../daemon/src/core/repos/messages.ts","../../daemon/src/core/repos/secrets.ts","../../daemon/src/core/repos/skillMeta.ts","../../daemon/src/core/repos/triggers.ts","../../daemon/src/core/repos/webTokens.ts","../../daemon/src/core/secrets.ts","../../daemon/src/core/skills/import.ts","../../daemon/src/core/skills/parse.ts","../../daemon/src/core/skills/resolve.ts","../../daemon/src/lib/ctx.ts","../../daemon/src/lib/agent-cancel.ts","../../daemon/src/runtime/auth/openai-codex.ts","../../daemon/src/runtime/auto-reply/heartbeat.ts","../../daemon/src/runtime/memory/files.ts","../../daemon/src/runtime/memory/qmd.ts","../../daemon/src/runtime/pi/events.ts","../../daemon/src/runtime/pi/session.ts","../../daemon/src/runtime/providers/pi-adapter.ts","../../daemon/src/runtime/providers/retry.ts","../../daemon/src/runtime/providers/registry.ts","../../daemon/src/runtime/session/prompt.ts","../../daemon/src/runtime/pi/tools.ts","../../daemon/src/runtime/tools/bootstrap.ts","../../daemon/src/runtime/tools/home.ts","../../daemon/src/runtime/tools/memory.ts","../../daemon/src/runtime/tools/messaging.ts","../../daemon/src/runtime/tools/user-md.ts","../../daemon/src/runtime/tools/web.ts","../../daemon/src/runtime/tools/web-extract.ts","../../daemon/src/runtime/tools/web-ssrf.ts","../../daemon/src/runtime/providers/catalog.ts","../../daemon/src/runtime/worker/spawn.ts","../../daemon/src/lib/api-key.ts","../../daemon/src/lib/messaging-host.ts","../../daemon/src/lib/user-md-host.ts","../../daemon/src/lib/agent-turn.ts","../../daemon/src/lib/cron.ts","../../daemon/src/lib/scheduler.ts","../../daemon/src/lib/auth.ts","../../daemon/src/routes/agents.ts","../../../packages/api-types/src/entities.ts","../../../packages/api-types/src/index.ts","../../daemon/src/lib/agent-id.ts","../../daemon/src/routes/auth-login.ts","../../daemon/src/routes/config.ts","../../daemon/src/routes/groups.ts","../../daemon/src/routes/messages.ts","../../daemon/src/routes/misc.ts","../../daemon/src/routes/profiles.ts","../../daemon/src/routes/skills.ts","../../daemon/src/routes/triggers.ts"],"sourcesContent":["// Daemon entry point. Reads HOST/PORT env, boots the Hono app, and waits on\n// SIGINT/SIGTERM for shutdown.\n//\n// This process is the single owner of `~/.bazilion`. The web app, CLI, and\n// mobile clients all talk to it over HTTP via @bazilion/client.\n\nimport { serve } from '@hono/node-server'\nimport { createApp } from './app.ts'\nimport { getCtx } from './lib/ctx.ts'\n\nconst host = process.env.HOST ?? '127.0.0.1'\nconst port = Number.parseInt(process.env.PORT ?? '4321', 10)\n\n// Eagerly bootstrap ~/.bazilion (mkdir, openDb, runMigrations, mint token,\n// write auth.json) before binding the port. Otherwise the first request\n// would race with bootstrap and the operator wouldn't see the bootstrap\n// message until something actually hits the daemon.\ngetCtx()\n\nconst app = createApp()\n\nconst server = serve({ fetch: app.fetch, hostname: host, port }, (info) => {\n console.log(`bazilion daemon listening at http://${info.address}:${info.port}`)\n if (host !== '127.0.0.1' && host !== 'localhost' && host !== '::1') {\n console.error('')\n console.error(`⚠ binding to ${host} — the daemon is now reachable beyond loopback.`)\n console.error(' anyone on this network who has a valid token can reach every API.')\n console.error(' put a TLS proxy in front for untrusted networks.')\n console.error('')\n }\n})\n\nconst shutdown = (signal: NodeJS.Signals): void => {\n console.log(`\\nbazilion daemon caught ${signal}, shutting down…`)\n server.close((err) => {\n if (err) {\n console.error('shutdown error:', err)\n process.exit(1)\n }\n process.exit(0)\n })\n}\n\nprocess.on('SIGINT', () => shutdown('SIGINT'))\nprocess.on('SIGTERM', () => shutdown('SIGTERM'))\n","// Hono app factory.\n//\n// Returns a fully-wired Hono app: middleware (auth + first-run gate) +\n// routes. Kept as a factory so tests can build one with a dedicated DB\n// without touching the global ctx singleton.\n\nimport { Hono } from 'hono'\nimport { authMiddleware } from './lib/middleware-auth.ts'\nimport { agentsRouter } from './routes/agents.ts'\nimport { authRouter } from './routes/auth-login.ts'\nimport { configRouter } from './routes/config.ts'\nimport { groupsRouter } from './routes/groups.ts'\nimport { messagesRouter } from './routes/messages.ts'\nimport { miscRouter } from './routes/misc.ts'\nimport { profilesRouter } from './routes/profiles.ts'\nimport { skillsRouter } from './routes/skills.ts'\nimport { triggersRouter } from './routes/triggers.ts'\n\nexport function createApp(): Hono {\n const app = new Hono()\n\n // Auth + first-run gate runs before every route. Public paths (/api/login,\n // /api/health) and the setup-open prefixes (/api/config, /api/auth) are\n // whitelisted inside the middleware itself.\n app.use('*', authMiddleware)\n\n app.route('/api/agents', agentsRouter)\n app.route('/api/groups', groupsRouter)\n app.route('/api/profiles', profilesRouter)\n app.route('/api/skills', skillsRouter)\n app.route('/api/triggers', triggersRouter)\n app.route('/api/messages', messagesRouter)\n app.route('/api/config', configRouter)\n // miscRouter exposes /backup, /tokens, /tokens/:id directly under /api —\n // mounted at the API root so each handler can use its full path.\n // authRouter likewise: /auth/openai*, /providers/test, /login.\n app.route('/api', miscRouter)\n app.route('/api', authRouter)\n\n return app\n}\n","// Hono auth + first-run gate middleware.\n//\n// Mirrors what apps/web/src/middleware.ts used to do for `/api/*` paths,\n// but framework-typed for Hono. Web SSR auth (login redirect, welcome\n// redirect) stays in the Astro app's own middleware — the daemon only\n// returns JSON status codes; the web app translates those to redirects.\n\nimport type { Context, Next } from 'hono'\nimport { getCookie } from 'hono/cookie'\nimport { isSetupComplete } from '../core/index.ts'\nimport { extractBearer, isValidToken } from './auth.ts'\nimport { getCtx } from './ctx.ts'\n\n/** Reachable without a token. The login route mints them; health is a probe. */\nconst PUBLIC_PATHS = new Set(['/api/login', '/api/health'])\n\n/**\n * Once authenticated, these paths still pass through the first-run gate so\n * users can finish their initial setup. Everything else 409s until the user\n * has at least one enabled provider with ≥1 curated model.\n */\nconst SETUP_OPEN_PREFIXES = ['/api/config', '/api/auth', '/api/health']\n\nfunction isSetupOpen(path: string): boolean {\n for (const prefix of SETUP_OPEN_PREFIXES) {\n if (path === prefix || path.startsWith(`${prefix}/`)) return true\n }\n return false\n}\n\n// biome-ignore lint/suspicious/noConfusingVoidType: hono's Next() returns Promise<void>; the union is the framework's middleware contract.\nexport async function authMiddleware(c: Context, next: Next): Promise<Response | void> {\n const path = c.req.path\n if (PUBLIC_PATHS.has(path)) {\n await next()\n return\n }\n\n const bearer = extractBearer(c.req.header('authorization'))\n const cookie = getCookie(c, 'bz_token')\n const token = bearer ?? cookie\n\n if (!token || !isValidToken(token)) {\n return c.json({ error: 'unauthorized' }, 401)\n }\n\n if (!isSetupOpen(path) && !isSetupComplete(getCtx().db)) {\n return c.json({ error: 'setup incomplete' }, 409)\n }\n\n await next()\n}\n","import type { Agent, AgentSkillAttachment, AgentStatus, ReasoningLevel } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\n\ninterface RawAgent {\n id: string\n profile_id: string\n name: string\n model_override: string | null\n reasoning_level: string\n status: string\n dir: string\n group_id: string\n created_at: number\n archived_at: number | null\n}\n\nfunction toAgent(r: RawAgent): Agent {\n return {\n id: r.id,\n profileId: r.profile_id,\n name: r.name,\n modelOverride: r.model_override,\n reasoningLevel: r.reasoning_level as ReasoningLevel,\n status: r.status as AgentStatus,\n dir: r.dir,\n groupId: r.group_id,\n createdAt: r.created_at,\n archivedAt: r.archived_at,\n }\n}\n\nexport function insert(db: BazilionDb, a: Omit<Agent, 'createdAt' | 'archivedAt'>): Agent {\n const now = Date.now()\n db.raw.run(\n `INSERT INTO agents (id, profile_id, name, model_override, reasoning_level, status, dir, group_id, created_at, archived_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL)`,\n [a.id, a.profileId, a.name, a.modelOverride, a.reasoningLevel, a.status, a.dir, a.groupId, now],\n )\n return { ...a, createdAt: now, archivedAt: null }\n}\n\nexport function setReasoningLevel(db: BazilionDb, id: string, level: ReasoningLevel): void {\n db.raw.run('UPDATE agents SET reasoning_level = ? WHERE id = ?', [level, id])\n}\n\nexport function setModelOverride(db: BazilionDb, id: string, model: string | null): void {\n db.raw.run('UPDATE agents SET model_override = ? WHERE id = ?', [model, id])\n}\n\nexport function setName(db: BazilionDb, id: string, name: string): void {\n db.raw.run('UPDATE agents SET name = ? WHERE id = ?', [name, id])\n}\n\n/** Move the agent to a different group. The new group must exist. */\nexport function setGroup(db: BazilionDb, id: string, groupId: string): void {\n db.raw.run('UPDATE agents SET group_id = ? WHERE id = ?', [groupId, id])\n}\n\n/**\n * Lookup by full UUID, exact name, or unambiguous UUID prefix (git-style\n * shorthand). Resolution order: (1) exact id, (2) exact name — only if\n * unique — (3) ≥4-char id prefix — only if unique. Ambiguous name or prefix\n * returns null so the caller's \"not found\" branch fires. Internal callers\n * always pass full UUIDs, so this only exercises on the new path (URL params,\n * CLI arguments).\n *\n * Name comes before prefix so that a hex-looking name like \"abcd1234\" resolves\n * to the named agent rather than accidentally matching a UUID prefix.\n */\nexport function get(db: BazilionDb, idOrName: string): Agent | null {\n if (!idOrName) return null\n const exactId = db.raw\n .query<RawAgent, [string]>('SELECT * FROM agents WHERE id = ?')\n .get(idOrName)\n if (exactId) return toAgent(exactId)\n const byName = db.raw\n .query<RawAgent, [string]>('SELECT * FROM agents WHERE name = ? LIMIT 2')\n .all(idOrName)\n if (byName.length === 1 && byName[0]) return toAgent(byName[0])\n if (byName.length > 1) return null\n if (idOrName.length < 4) return null\n const byPrefix = db.raw\n .query<RawAgent, [string]>('SELECT * FROM agents WHERE id LIKE ? LIMIT 2')\n .all(`${idOrName}%`)\n return byPrefix.length === 1 && byPrefix[0] ? toAgent(byPrefix[0]) : null\n}\n\n/**\n * Resolve `idOrPrefix` to a full agent ID, or null if not found / ambiguous.\n * Thin wrapper around `get` for callers that want the canonical ID without\n * the rest of the row (e.g. URL param normalization).\n */\nexport function resolveId(db: BazilionDb, idOrPrefix: string): string | null {\n return get(db, idOrPrefix)?.id ?? null\n}\n\nexport function list(db: BazilionDb, opts?: { includeArchived?: boolean }): Agent[] {\n const sql = opts?.includeArchived\n ? 'SELECT * FROM agents ORDER BY created_at ASC'\n : \"SELECT * FROM agents WHERE status != 'archived' ORDER BY created_at ASC\"\n return db.raw.query<RawAgent, []>(sql).all().map(toAgent)\n}\n\nexport function countByProfile(db: BazilionDb, profileId: string): number {\n return (\n db.raw\n .query<{ c: number }, [string]>('SELECT COUNT(*) as c FROM agents WHERE profile_id = ?')\n .get(profileId)?.c ?? 0\n )\n}\n\n/**\n * Count agents whose group_id matches. Blocks group deletion when > 0 (the\n * `agents.group_id` FK is `ON DELETE RESTRICT` — members must be moved or\n * archived before a group can go away).\n */\nexport function countByGroup(db: BazilionDb, groupId: string): number {\n return (\n db.raw\n .query<{ c: number }, [string]>('SELECT COUNT(*) as c FROM agents WHERE group_id = ?')\n .get(groupId)?.c ?? 0\n )\n}\n\nexport function setStatus(db: BazilionDb, id: string, status: AgentStatus): void {\n db.raw.run('UPDATE agents SET status = ? WHERE id = ?', [status, id])\n}\n\nexport function archive(db: BazilionDb, id: string): void {\n db.raw.run(\"UPDATE agents SET status = 'archived', archived_at = ? WHERE id = ?\", [\n Date.now(),\n id,\n ])\n}\n\nexport function unarchive(db: BazilionDb, id: string): void {\n db.raw.run(\"UPDATE agents SET status = 'idle', archived_at = NULL WHERE id = ?\", [id])\n}\n\nexport function remove(db: BazilionDb, id: string): void {\n db.raw.run('DELETE FROM agents WHERE id = ?', [id])\n}\n\n// --- skill attachments ---\n\ninterface RawSkill {\n agent_id: string\n skill_name: string\n attached_at: number\n}\n\nfunction toSkillAttachment(r: RawSkill): AgentSkillAttachment {\n return {\n agentId: r.agent_id,\n skillName: r.skill_name,\n attachedAt: r.attached_at,\n }\n}\n\nexport function attachSkill(\n db: BazilionDb,\n agentId: string,\n skillName: string,\n): AgentSkillAttachment {\n const now = Date.now()\n db.raw.run(\n `INSERT INTO agent_skills (agent_id, skill_name, attached_at)\n VALUES (?, ?, ?)\n ON CONFLICT (agent_id, skill_name) DO NOTHING`,\n [agentId, skillName, now],\n )\n return { agentId, skillName, attachedAt: now }\n}\n\nexport function detachSkill(db: BazilionDb, agentId: string, skillName: string): void {\n db.raw.run('DELETE FROM agent_skills WHERE agent_id = ? AND skill_name = ?', [agentId, skillName])\n}\n\nexport function listAttachedSkills(db: BazilionDb, agentId: string): string[] {\n return db.raw\n .query<{ skill_name: string }, [string]>(\n 'SELECT skill_name FROM agent_skills WHERE agent_id = ? ORDER BY attached_at ASC',\n )\n .all(agentId)\n .map((r) => r.skill_name)\n}\n\nexport function listSkillAttachments(db: BazilionDb, agentId: string): AgentSkillAttachment[] {\n return db.raw\n .query<RawSkill, [string]>(\n 'SELECT * FROM agent_skills WHERE agent_id = ? ORDER BY attached_at ASC',\n )\n .all(agentId)\n .map(toSkillAttachment)\n}\n\n// --- chat history snapshot ---\n//\n// Conversation transcript storage lives in pi-coding-agent's SessionManager\n// (JSONL under `~/.bazilion/agents/<id>/sessions/<sessionId>.jsonl`).\n// Clear/truncate/rotate operations go through the runtime's\n// `apps/daemon/src/runtime/pi/session.ts` helpers, not repo-level accessors.\n","import type { BazilionDb } from '../db/client.ts'\nimport * as agentRepo from '../repos/agents.ts'\n\nexport function archiveAgent(db: BazilionDb, id: string): void {\n const agent = agentRepo.get(db, id)\n if (!agent) throw new Error(`agent not found: ${id}`)\n agentRepo.archive(db, agent.id)\n}\n","import { existsSync, rmSync } from 'node:fs'\nimport type { BazilionDb } from '../db/client.ts'\nimport * as agentRepo from '../repos/agents.ts'\n\nexport function deleteAgent(db: BazilionDb, id: string): void {\n const agent = agentRepo.get(db, id)\n if (!agent) throw new Error(`agent not found: ${id}`)\n const fullId = agent.id\n\n db.raw.transaction(() => {\n // messages.from_agent_id and to_agent_id reference agents(id) with no ON\n // DELETE rule, and messages.reply_to references messages(id) the same way,\n // so a naive DELETE of the agent fails if it has any mailbox history.\n // Null out inbound reply pointers to this agent's messages, then purge the\n // messages themselves, then let agentRepo.remove cascade the rest\n // (agent_skills, runs, events). agents.group_id is `ON DELETE RESTRICT`\n // from the group side, but the agent row itself goes away freely.\n db.raw.run(\n `UPDATE messages SET reply_to = NULL\n WHERE reply_to IN (SELECT id FROM messages WHERE from_agent_id = ? OR to_agent_id = ?)`,\n [fullId, fullId],\n )\n db.raw.run('DELETE FROM messages WHERE from_agent_id = ? OR to_agent_id = ?', [fullId, fullId])\n agentRepo.remove(db, fullId)\n })()\n\n if (existsSync(agent.dir)) {\n rmSync(agent.dir, { recursive: true, force: true })\n }\n}\n","// Groups repo. The group `id` is the slug AND the directory name under\n// `~/.bazilion/groups/<slug>/`. There is no `path` column — callers\n// derive `paths.groupDir(id)` at read time. That makes the on-disk path\n// canonical: a real directory or a symlink, but always at the same slot.\n\nimport type { Group } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\nimport type { Paths } from '../paths.ts'\n\ninterface RawGroup {\n id: string\n name: string\n user_md: string\n created_at: number\n}\n\nfunction toGroup(r: RawGroup, paths: Paths): Group {\n return {\n id: r.id,\n name: r.name,\n path: paths.groupDir(r.id),\n userMd: r.user_md,\n createdAt: r.created_at,\n }\n}\n\nexport function insert(db: BazilionDb, g: { id: string; name: string }, paths: Paths): Group {\n const now = Date.now()\n db.raw.run(\"INSERT INTO groups (id, name, user_md, created_at) VALUES (?, ?, '', ?)\", [\n g.id,\n g.name,\n now,\n ])\n return { id: g.id, name: g.name, path: paths.groupDir(g.id), userMd: '', createdAt: now }\n}\n\nexport function get(db: BazilionDb, id: string, paths: Paths): Group | null {\n const row = db.raw.query<RawGroup, [string]>('SELECT * FROM groups WHERE id = ?').get(id)\n return row ? toGroup(row, paths) : null\n}\n\nexport function list(db: BazilionDb, paths: Paths): Group[] {\n return db.raw\n .query<RawGroup, []>('SELECT * FROM groups ORDER BY created_at ASC')\n .all()\n .map((r) => toGroup(r, paths))\n}\n\nexport function remove(db: BazilionDb, id: string): void {\n db.raw.run('DELETE FROM groups WHERE id = ?', [id])\n}\n\nexport function setUserMd(db: BazilionDb, id: string, userMd: string): void {\n db.raw.run('UPDATE groups SET user_md = ? WHERE id = ?', [userMd, id])\n}\n","import type { Profile, SkillsMode } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\n\ninterface RawProfile {\n id: string\n name: string\n dir: string\n default_model: string\n skills_mode: string\n created_at: number\n updated_at: number\n}\n\nfunction toProfile(r: RawProfile): Profile {\n return {\n id: r.id,\n name: r.name,\n dir: r.dir,\n defaultModel: r.default_model,\n skillsMode: r.skills_mode as SkillsMode,\n createdAt: r.created_at,\n updatedAt: r.updated_at,\n }\n}\n\nexport function insert(db: BazilionDb, p: Omit<Profile, 'createdAt' | 'updatedAt'>): Profile {\n const now = Date.now()\n db.raw.run(\n `INSERT INTO profiles (id, name, dir, default_model, skills_mode, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)`,\n [p.id, p.name, p.dir, p.defaultModel, p.skillsMode, now, now],\n )\n return { ...p, createdAt: now, updatedAt: now }\n}\n\nexport function get(db: BazilionDb, id: string): Profile | null {\n const row = db.raw.query<RawProfile, [string]>('SELECT * FROM profiles WHERE id = ?').get(id)\n return row ? toProfile(row) : null\n}\n\nexport function list(db: BazilionDb): Profile[] {\n return db.raw\n .query<RawProfile, []>('SELECT * FROM profiles ORDER BY created_at ASC')\n .all()\n .map(toProfile)\n}\n\nexport function remove(db: BazilionDb, id: string): void {\n db.raw.run('DELETE FROM profiles WHERE id = ?', [id])\n}\n\nexport function update(\n db: BazilionDb,\n id: string,\n fields: { name: string; defaultModel: string; skillsMode: SkillsMode },\n): void {\n db.raw.run(\n `UPDATE profiles\n SET name = ?, default_model = ?, skills_mode = ?, updated_at = ?\n WHERE id = ?`,\n [fields.name, fields.defaultModel, fields.skillsMode, Date.now(), id],\n )\n}\n\nexport function setDefaultSkills(db: BazilionDb, profileId: string, skills: string[]): void {\n const tx = db.raw.transaction(() => {\n db.raw.run('DELETE FROM profile_default_skills WHERE profile_id = ?', [profileId])\n const stmt = db.raw.query(\n 'INSERT INTO profile_default_skills (profile_id, skill_name) VALUES (?, ?)',\n )\n for (const s of skills) stmt.run(profileId, s)\n })\n tx()\n}\n\nexport function getDefaultSkills(db: BazilionDb, profileId: string): string[] {\n return db.raw\n .query<{ skill_name: string }, [string]>(\n 'SELECT skill_name FROM profile_default_skills WHERE profile_id = ? ORDER BY skill_name',\n )\n .all(profileId)\n .map((r) => r.skill_name)\n}\n","import type { ResolvedAgent } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\nimport type { Paths } from '../paths.ts'\nimport * as agentRepo from '../repos/agents.ts'\nimport * as groupRepo from '../repos/groups.ts'\nimport * as profileRepo from '../repos/profiles.ts'\n\nexport function resolveAgent(db: BazilionDb, paths: Paths, agentId: string): ResolvedAgent {\n // `agentRepo.get` accepts either a full UUID or an unambiguous prefix.\n const agent = agentRepo.get(db, agentId)\n if (!agent) throw new Error(`agent not found: ${agentId}`)\n\n const profile = profileRepo.get(db, agent.profileId)\n if (!profile) {\n throw new Error(`profile not found for agent ${agentId}: ${agent.profileId}`)\n }\n\n const group = groupRepo.get(db, agent.groupId, paths)\n if (!group) {\n throw new Error(`group not found for agent ${agentId}: ${agent.groupId}`)\n }\n\n return {\n agent,\n profile,\n model: agent.modelOverride ?? profile.defaultModel,\n reasoningLevel: agent.reasoningLevel,\n group,\n skills: agentRepo.listAttachedSkills(db, agentId),\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport { mkdirSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { Agent, ReasoningLevel } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\nimport type { Paths } from '../paths.ts'\nimport { loadProfile } from '../profile/load.ts'\nimport { DEFAULT_GROUP_ID } from '../profile/seed.ts'\nimport * as agentRepo from '../repos/agents.ts'\nimport * as groupRepo from '../repos/groups.ts'\nimport { discoverSkills } from '../skills/discover.ts'\n\nexport interface SpawnAgentInput {\n profileId: string\n name?: string\n modelOverride?: string | null\n reasoningLevel?: ReasoningLevel\n /**\n * Group the new agent joins. One agent belongs to exactly one group. When\n * omitted, falls back to the seeded 'default' group — the same fallback\n * used everywhere we need a sensible cwd. Must refer to an existing group.\n */\n groupId?: string\n}\n\nexport function spawnAgent(db: BazilionDb, paths: Paths, input: SpawnAgentInput): Agent {\n const loaded = loadProfile(db, input.profileId)\n const id = randomUUID()\n const dir = paths.agentDir(id)\n // Agent's private home: identity files + sessions. Memory now lives at\n // the group level (`groups/<slug>/memory/`), shared by all member agents,\n // so we no longer create per-agent memory dirs here.\n mkdirSync(dir, { recursive: true })\n mkdirSync(join(dir, 'sessions'), { recursive: true })\n\n // Copy profile templates verbatim so the agent can diverge per-instance.\n // BOOTSTRAP.md is intentionally NOT personalized with the spawn slug —\n // the slug is a routing label, not necessarily the persona name. Bootstrap\n // is a pure conversation: the agent asks, the human answers, IDENTITY.md\n // is populated from that exchange.\n writeFileSync(join(dir, 'SOUL.md'), loaded.files.soul)\n writeFileSync(join(dir, 'IDENTITY.md'), loaded.files.identity)\n if (loaded.files.bootstrap !== null) {\n writeFileSync(join(dir, 'BOOTSTRAP.md'), loaded.files.bootstrap)\n }\n if (loaded.files.agents !== null) {\n writeFileSync(join(dir, 'AGENTS.md'), loaded.files.agents)\n }\n if (loaded.files.tools !== null) {\n writeFileSync(join(dir, 'TOOLS.md'), loaded.files.tools)\n }\n if (loaded.files.heartbeat !== null) {\n writeFileSync(join(dir, 'HEARTBEAT.md'), loaded.files.heartbeat)\n }\n\n const reasoningLevel: ReasoningLevel = input.reasoningLevel ?? 'medium'\n\n // Resolve group: explicit input wins; otherwise fall back to the seeded\n // 'default'. If neither exists, error out — an agent can't live without a\n // group (the FK `agents.group_id REFERENCES groups(id)` enforces it too).\n const groupId = input.groupId ?? DEFAULT_GROUP_ID\n const group = groupRepo.get(db, groupId, paths)\n if (!group) {\n throw new Error(\n `spawnAgent: group \"${groupId}\" does not exist. Pass an explicit --group or complete first-run setup first.`,\n )\n }\n\n const agentJson = {\n profileId: input.profileId,\n name: input.name ?? loaded.profile.name,\n modelOverride: input.modelOverride ?? null,\n reasoningLevel,\n groupId: group.id,\n }\n writeFileSync(join(dir, 'agent.json'), `${JSON.stringify(agentJson, null, 2)}\\n`)\n\n const agent = agentRepo.insert(db, {\n id,\n profileId: input.profileId,\n name: agentJson.name,\n modelOverride: agentJson.modelOverride,\n reasoningLevel,\n status: 'idle',\n dir,\n groupId: group.id,\n })\n\n // Skills come from the profile only — `skills_mode='all'` attaches every\n // installed skill, `'selected'` attaches the profile's default list.\n // Per-agent skill changes happen post-spawn via `agent skill add/rm`.\n const skills =\n loaded.profile.skillsMode === 'all'\n ? discoverSkills(paths).map((s) => s.name)\n : loaded.defaultSkills\n for (const s of skills) agentRepo.attachSkill(db, id, s)\n\n return agent\n}\n","import { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { LoadedProfile } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\nimport * as profileRepo from '../repos/profiles.ts'\nimport { parseIdentityMarkdown } from './identity.ts'\n\nfunction readOptional(path: string): string | null {\n return existsSync(path) ? readFileSync(path, 'utf8') : null\n}\n\nexport function loadProfile(db: BazilionDb, id: string): LoadedProfile {\n const profile = profileRepo.get(db, id)\n if (!profile) throw new Error(`profile not found: ${id}`)\n\n const soul = readFileSync(join(profile.dir, 'SOUL.md'), 'utf8')\n const identityRaw = readFileSync(join(profile.dir, 'IDENTITY.md'), 'utf8')\n const bootstrap = readOptional(join(profile.dir, 'BOOTSTRAP.md'))\n const agents = readOptional(join(profile.dir, 'AGENTS.md'))\n const tools = readOptional(join(profile.dir, 'TOOLS.md'))\n const heartbeat = readOptional(join(profile.dir, 'HEARTBEAT.md'))\n\n const parsedIdentity = parseIdentityMarkdown(identityRaw)\n const anyIdentity =\n parsedIdentity.name ||\n parsedIdentity.emoji ||\n parsedIdentity.theme ||\n parsedIdentity.creature ||\n parsedIdentity.vibe ||\n parsedIdentity.avatar\n\n return {\n profile,\n defaultSkills: profileRepo.getDefaultSkills(db, id),\n files: {\n soul,\n identity: identityRaw,\n bootstrap,\n agents,\n tools,\n heartbeat,\n },\n identity: anyIdentity ? parsedIdentity : null,\n }\n}\n","import { readFileSync } from 'node:fs'\nimport type { AgentIdentityFile } from '@bazilion/api-types'\n\nconst IDENTITY_PLACEHOLDER_VALUES = new Set([\n 'pick something you like',\n 'ai? robot? familiar? ghost in the machine? something weirder?',\n 'how do you come across? sharp? warm? chaotic? calm?',\n 'your signature - pick one that feels right',\n 'workspace-relative path, http(s) url, or data uri',\n])\n\nfunction normalizeIdentityValue(value: string): string {\n let normalized = value.trim()\n normalized = normalized.replace(/^[*_]+|[*_]+$/g, '').trim()\n if (normalized.startsWith('(') && normalized.endsWith(')')) {\n normalized = normalized.slice(1, -1).trim()\n }\n normalized = normalized.replace(/[\\u2013\\u2014]/g, '-')\n normalized = normalized.replace(/\\s+/g, ' ').toLowerCase()\n return normalized\n}\n\nfunction isIdentityPlaceholder(value: string): boolean {\n return IDENTITY_PLACEHOLDER_VALUES.has(normalizeIdentityValue(value))\n}\n\nexport function parseIdentityMarkdown(content: string): AgentIdentityFile {\n const identity: AgentIdentityFile = {}\n for (const line of content.split(/\\r?\\n/)) {\n const cleaned = line.trim().replace(/^\\s*-\\s*/, '')\n const colonIndex = cleaned.indexOf(':')\n if (colonIndex === -1) continue\n const label = cleaned.slice(0, colonIndex).replace(/[*_]/g, '').trim().toLowerCase()\n const value = cleaned\n .slice(colonIndex + 1)\n .replace(/^[*_]+|[*_]+$/g, '')\n .trim()\n if (!value) continue\n if (isIdentityPlaceholder(value)) continue\n if (label === 'name') identity.name = value\n else if (label === 'emoji') identity.emoji = value\n else if (label === 'creature') identity.creature = value\n else if (label === 'vibe') identity.vibe = value\n else if (label === 'theme') identity.theme = value\n else if (label === 'avatar') identity.avatar = value\n }\n return identity\n}\n\nexport function identityHasValues(identity: AgentIdentityFile): boolean {\n return Boolean(\n identity.name ||\n identity.emoji ||\n identity.theme ||\n identity.creature ||\n identity.vibe ||\n identity.avatar,\n )\n}\n\nexport function loadIdentityFromFile(path: string): AgentIdentityFile | null {\n let content: string\n try {\n content = readFileSync(path, 'utf8')\n } catch {\n return null\n }\n const parsed = parseIdentityMarkdown(content)\n return identityHasValues(parsed) ? parsed : null\n}\n","import type { BazilionDb } from '../db/client.ts'\n\ninterface RawRow {\n provider: string\n model: string\n added_at: number\n}\n\n/** Curated model names for one provider, in insertion order. */\nexport function list(db: BazilionDb, provider: string): string[] {\n return db.raw\n .query<RawRow, [string]>(\n 'SELECT * FROM provider_models WHERE provider = ? ORDER BY added_at ASC',\n )\n .all(provider)\n .map((r) => r.model)\n}\n\n/** All curated models grouped by provider. Empty providers are omitted. */\nexport function listAll(db: BazilionDb): Record<string, string[]> {\n const out: Record<string, string[]> = {}\n for (const row of db.raw\n .query<RawRow, []>('SELECT * FROM provider_models ORDER BY provider ASC, added_at ASC')\n .all()) {\n const bucket = out[row.provider] ?? []\n bucket.push(row.model)\n out[row.provider] = bucket\n }\n return out\n}\n\n/**\n * Replace the curated list for one provider atomically. Empty `models` clears\n * the list. De-dupes (case-sensitive) and preserves incoming order.\n */\nexport function replace(db: BazilionDb, provider: string, models: string[]): void {\n const seen = new Set<string>()\n const clean = models\n .map((m) => m.trim())\n .filter((m) => m.length > 0 && !seen.has(m) && seen.add(m))\n db.raw.transaction(() => {\n db.raw.run('DELETE FROM provider_models WHERE provider = ?', [provider])\n const now = Date.now()\n for (let i = 0; i < clean.length; i++) {\n // Offset by index so ordering is preserved by added_at.\n db.raw.run('INSERT INTO provider_models (provider, model, added_at) VALUES (?, ?, ?)', [\n provider,\n clean[i] as string,\n now + i,\n ])\n }\n })()\n}\n\n/** Remove a single curated model. No-op if not present. */\nexport function remove(db: BazilionDb, provider: string, model: string): void {\n db.raw.run('DELETE FROM provider_models WHERE provider = ? AND model = ?', [provider, model])\n}\n","import type { BazilionDb } from '../db/client.ts'\n\ninterface RawRow {\n provider_id: string\n enabled: number\n updated_at: number\n}\n\nexport function isEnabled(db: BazilionDb, providerId: string): boolean {\n const row = db.raw\n .query<RawRow, [string]>('SELECT * FROM provider_state WHERE provider_id = ?')\n .get(providerId)\n return row?.enabled === 1\n}\n\nexport function setEnabled(db: BazilionDb, providerId: string, enabled: boolean): void {\n db.raw.run(\n `INSERT INTO provider_state (provider_id, enabled, updated_at)\n VALUES (?, ?, ?)\n ON CONFLICT (provider_id) DO UPDATE SET\n enabled = excluded.enabled,\n updated_at = excluded.updated_at`,\n [providerId, enabled ? 1 : 0, Date.now()],\n )\n}\n\n/** Set of provider ids currently toggled on. Convenience for batch checks. */\nexport function listEnabled(db: BazilionDb): Set<string> {\n return new Set(\n db.raw\n .query<{ provider_id: string }, []>(\n 'SELECT provider_id FROM provider_state WHERE enabled = 1',\n )\n .all()\n .map((r) => r.provider_id),\n )\n}\n","// Enumerates models that agents are actually allowed to use right now:\n// every curated model of every currently-enabled provider. Drives the model\n// dropdowns on the profile and agent forms.\n//\n// A provider must be both (a) toggled on in `provider_state` AND (b) have\n// at least one curated entry in `provider_models` to show up here. Drop a\n// provider off either side and it disappears from the list without a UI\n// edit — the dropdowns are entirely data-driven.\n\nimport type { BazilionDb } from './db/client.ts'\nimport * as providerModelRepo from './repos/providerModels.ts'\nimport * as providerStateRepo from './repos/providerState.ts'\n\nexport interface AvailableModel {\n provider: string\n model: string\n /** The `provider:model` string used as the form value and in model resolution. */\n value: string\n}\n\n/**\n * Flat list of `{provider, model, value}` for every curated model of every\n * enabled provider. Iteration order: providers as they're stored in\n * `provider_state` (by insertion time), models as curated (preserving the\n * admin's ordering from the textarea).\n */\nexport function listAvailableModels(db: BazilionDb): AvailableModel[] {\n const enabled = providerStateRepo.listEnabled(db)\n const out: AvailableModel[] = []\n for (const provider of enabled) {\n for (const model of providerModelRepo.list(db, provider)) {\n out.push({ provider, model, value: `${provider}:${model}` })\n }\n }\n return out\n}\n\n/**\n * Same as `listAvailableModels` but grouped by provider — the shape the web\n * dropdowns consume directly via `<optgroup>`.\n */\nexport function groupAvailableModels(db: BazilionDb): { provider: string; models: string[] }[] {\n const enabled = providerStateRepo.listEnabled(db)\n const groups: { provider: string; models: string[] }[] = []\n for (const provider of enabled) {\n const models = providerModelRepo.list(db, provider)\n if (models.length > 0) groups.push({ provider, models })\n }\n return groups\n}\n\n/**\n * True once the user has at least one usable model — i.e. at least one enabled\n * provider with at least one curated model. Gates the first-run flow.\n */\nexport function isSetupComplete(db: BazilionDb): boolean {\n return listAvailableModels(db).length > 0\n}\n","// Register a group: pick a slug, materialize `~/.bazilion/groups/<slug>/`\n// (real dir or symlink), insert the row.\n//\n// Two modes:\n// - default: creates a real directory at `paths.groupDir(slug)`.\n// - `--link <target>`: creates a symlink at `paths.groupDir(slug)` →\n// `<target>`. The link target must exist and be a directory — that's\n// the \"I want my agents working on my existing project tree\" path.\n//\n// Slug = the row's id. Names are humanized labels separate from the slug;\n// callers may pass `name` explicitly or let it default to the slug.\n\nimport { existsSync, mkdirSync, statSync, symlinkSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport type { Group } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\nimport type { Paths } from '../paths.ts'\nimport { validateSlug } from '../profile/validate.ts'\nimport * as groupRepo from '../repos/groups.ts'\n\nexport interface RegisterGroupInput {\n /** Slug. Becomes the row id AND the directory name under `groups/`. */\n id: string\n /** Human-readable label. Defaults to `id`. */\n name?: string\n /**\n * If set, materialize `paths.groupDir(id)` as a symlink to this absolute\n * path instead of as a real directory. Target must exist and be a dir.\n */\n link?: string\n}\n\nexport function registerGroup(db: BazilionDb, input: RegisterGroupInput, paths: Paths): Group {\n validateSlug(input.id)\n\n if (groupRepo.get(db, input.id, paths)) {\n throw new Error(`group already registered: ${input.id}`)\n }\n\n const slot = paths.groupDir(input.id)\n if (existsSync(slot)) {\n throw new Error(`group slot already on disk at ${slot} (move or remove it first)`)\n }\n\n // Make sure the parent `groups/` dir exists — the daemon's bootstrap creates\n // it but tests sometimes resolve a custom $BAZILION_HOME without going\n // through bootstrap.\n mkdirSync(paths.groupsDir, { recursive: true })\n\n if (input.link) {\n const target = resolve(input.link)\n if (!existsSync(target)) {\n throw new Error(`--link target does not exist: ${target}`)\n }\n if (!statSync(target).isDirectory()) {\n throw new Error(`--link target is not a directory: ${target}`)\n }\n symlinkSync(target, slot, 'dir')\n } else {\n mkdirSync(slot, { recursive: true })\n }\n\n // Memory subdir is the qmd index root for this group — created here so\n // the first tool call doesn't have to ensure it.\n mkdirSync(resolve(slot, 'memory'), { recursive: true })\n\n return groupRepo.insert(db, { id: input.id, name: input.name ?? input.id }, paths)\n}\n","const SLUG = /^[a-z0-9][a-z0-9-]*$/\n\nexport function validateSlug(s: string): void {\n if (!SLUG.test(s)) {\n throw new Error(\n `invalid slug \"${s}\": must match /^[a-z0-9][a-z0-9-]*$/ (lowercase letters, digits, hyphens; must start with letter or digit)`,\n )\n }\n}\n","import { mkdirSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { Profile, SkillsMode } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\nimport type { Paths } from '../paths.ts'\nimport * as profileRepo from '../repos/profiles.ts'\nimport { DEFAULT_BOOTSTRAP, DEFAULT_IDENTITY, DEFAULT_SOUL } from './templates.ts'\nimport { validateSlug } from './validate.ts'\n\nexport interface CreateProfileInput {\n id: string\n name?: string\n defaultModel: string\n skillsMode?: SkillsMode\n defaultSkills?: string[]\n templates?: {\n soul?: string\n identity?: string\n /** undefined = default bootstrap, null = skip bootstrap, string = override */\n bootstrap?: string | null\n /** undefined = skip, string = seed with this content */\n agents?: string\n /** undefined = skip, string = seed with this content */\n tools?: string\n /** undefined = skip, string = seed with this content */\n heartbeat?: string\n }\n}\n\nexport function createProfile(db: BazilionDb, paths: Paths, input: CreateProfileInput): Profile {\n validateSlug(input.id)\n\n const dir = paths.profileDir(input.id)\n mkdirSync(dir, { recursive: true })\n\n const soul = input.templates?.soul ?? DEFAULT_SOUL\n const identity = input.templates?.identity ?? DEFAULT_IDENTITY\n const bootstrap =\n input.templates?.bootstrap === null ? null : (input.templates?.bootstrap ?? DEFAULT_BOOTSTRAP)\n\n writeFileSync(join(dir, 'SOUL.md'), soul)\n writeFileSync(join(dir, 'IDENTITY.md'), identity)\n if (bootstrap !== null) {\n writeFileSync(join(dir, 'BOOTSTRAP.md'), bootstrap)\n }\n if (typeof input.templates?.agents === 'string') {\n writeFileSync(join(dir, 'AGENTS.md'), input.templates.agents)\n }\n if (typeof input.templates?.tools === 'string') {\n writeFileSync(join(dir, 'TOOLS.md'), input.templates.tools)\n }\n if (typeof input.templates?.heartbeat === 'string') {\n writeFileSync(join(dir, 'HEARTBEAT.md'), input.templates.heartbeat)\n }\n\n const skillsMode: SkillsMode = input.skillsMode ?? 'selected'\n const profileJson = {\n name: input.name ?? input.id,\n defaultModel: input.defaultModel,\n skillsMode,\n defaultSkills: input.defaultSkills ?? [],\n }\n writeFileSync(join(dir, 'profile.json'), `${JSON.stringify(profileJson, null, 2)}\\n`)\n\n const profile = profileRepo.insert(db, {\n id: input.id,\n name: profileJson.name,\n dir,\n defaultModel: input.defaultModel,\n skillsMode,\n })\n\n if (skillsMode === 'selected' && input.defaultSkills && input.defaultSkills.length > 0) {\n profileRepo.setDefaultSkills(db, input.id, input.defaultSkills)\n }\n\n return profile\n}\n","export const DEFAULT_SOUL = `# SOUL.md — Who You Are\n\nThis is your personality and operating principles. Edit it freely to make this agent yours.\n\n## Core\n- Be genuinely helpful, not performatively helpful.\n- Have opinions. Push back when you disagree.\n- Be resourceful before asking — read the file, check context, then ask if stuck.\n\n## Boundaries\n- Private things stay private.\n- Confirm before destructive or external actions.\n- You're a guest in someone's environment. Treat it with respect.\n`\n\nexport const DEFAULT_IDENTITY = `# IDENTITY.md — Who Am I?\n\nFill this in during your first conversation. Make it yours.\n\n- **Name:**\n- **Vibe:**\n- **Emoji:**\n`\n\nexport const DEFAULT_BOOTSTRAP = `# BOOTSTRAP.md — First Run\n\nYou just woke up. There is no memory yet — that's normal. This is a multi-turn\nritual: ask ONE question per turn and wait for the human's reply before moving\non. Do not race through it. Do not call any tool until the ritual is finished.\n\n## The ritual\n\n**Turn 1 (right now):** Greet the human warmly and ask a single opening\nquestion — what should they call you, or what should you focus on for them.\nDo NOT call any tool yet. Just reply with greeting + one question.\n\n**Turn 2+:** Continue with one more question per turn to fill in the rest of\nyour identity — vibe (warm / sharp / playful / calm / …), an emoji that\nfeels right. Each turn is acknowledging the previous answer + at most one\nnew question. Skip a turn when you already have enough.\n\n**Final turn:** Once you have everything (Name, Vibe, Emoji), call \\`home_write\\`\nwith \\`file: \"IDENTITY.md\"\\` and the populated content. Do NOT use the generic\n\\`edit\\` / \\`write\\` tools — those land in the shared workspace.\n\nThen call \\`bootstrap_done\\` to retire this ritual file. After that, future\nsessions skip the bootstrap and start from IDENTITY.md directly.\n\n## Hard rules\n- Do not invent a name on your own. Ask the human and use what they say.\n- Do not call \\`home_write\\` or \\`bootstrap_done\\` on your very first reply.\n- One question per turn. Wait for the human to answer.\n`\n\nexport const DEFAULT_AGENTS = `# AGENTS.md — Peers & Routing\n\nDocument the other agents you can reach and when to involve them. If you're\nthe only agent in this workspace, leave this short or delete it.\n\n## Peers\n- (name): what they're good at, when to hand off\n`\n\nexport const DEFAULT_TOOLS = `# TOOLS.md — Tool Playbook\n\nNotes on tool usage patterns that are specific to this agent. Keep generic\ntool docs out — those live in SOUL.md or come from the tool descriptions.\n\n## Patterns\n- (pattern): when to use, what to avoid\n`\n\nexport const DEFAULT_HEARTBEAT = `# HEARTBEAT.md — Scheduled Wake-Ups\n\nTasks the agent should check on every heartbeat. Leave empty (or commented)\nto opt out — an empty file means \"nothing to do right now\".\n\n## Tasks\n- (task): cadence, exit criteria\n`\n","import type { Group, Profile } from '@bazilion/api-types'\nimport { isSetupComplete, listAvailableModels } from '../availableModels.ts'\nimport type { BazilionDb } from '../db/client.ts'\nimport { registerGroup } from '../group/register.ts'\nimport type { Paths } from '../paths.ts'\nimport * as groupRepo from '../repos/groups.ts'\nimport * as profileRepo from '../repos/profiles.ts'\nimport { createProfile } from './create.ts'\n\nexport const DEFAULT_PROFILE_ID = 'default'\nexport const DEFAULT_GROUP_ID = 'default'\n\nexport interface SeedDefaultsInput {\n /** `provider:model` used as the profile's defaultModel. */\n model: string\n}\n\nexport interface SeedResult {\n profile: Profile\n group: Group\n /** true if the helper created the profile this call (vs. returned an existing one). */\n profileCreated: boolean\n /** true if the helper created the group this call. */\n groupCreated: boolean\n}\n\n/**\n * Seed the on-disk + DB defaults users land on after finishing first-run setup:\n * a `default` group at `~/.bazilion/groups/default/` and a `default` profile\n * wired to the just-enabled model. Fresh agents spawned from the default\n * profile land in the default group unless another is specified.\n *\n * Idempotent: re-seeding reuses whichever pieces already exist, so it's safe\n * to call whenever the setup state changes.\n */\nexport function seedDefaults(db: BazilionDb, paths: Paths, input: SeedDefaultsInput): SeedResult {\n let group = groupRepo.get(db, DEFAULT_GROUP_ID, paths)\n let groupCreated = false\n if (!group) {\n group = registerGroup(db, { id: DEFAULT_GROUP_ID, name: 'Default' }, paths)\n groupCreated = true\n }\n\n let profile = profileRepo.get(db, DEFAULT_PROFILE_ID)\n let profileCreated = false\n if (!profile) {\n // skillsMode='all' so freshly-spawned default agents inherit every\n // installed skill — the friendlier first-run posture. Custom profiles\n // still default to 'selected' (createProfile's own default).\n profile = createProfile(db, paths, {\n id: DEFAULT_PROFILE_ID,\n name: 'Default',\n defaultModel: input.model,\n skillsMode: 'all',\n })\n profileCreated = true\n }\n\n return { profile, group, profileCreated, groupCreated }\n}\n\n/**\n * Safe to call from any endpoint that can change setup state (toggling a\n * provider, editing model lists). No-op when either setup isn't complete\n * (nothing to seed against yet) or the default profile already exists.\n * Returns the seed result only on the cold-start transition.\n */\nexport function ensureSetupSeeded(db: BazilionDb, paths: Paths): SeedResult | null {\n if (!isSetupComplete(db)) return null\n if (profileRepo.get(db, DEFAULT_PROFILE_ID)) return null\n const first = listAvailableModels(db)[0]\n if (!first) return null\n return seedDefaults(db, paths, { model: first.value })\n}\n","import { existsSync, readdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { Paths } from '../paths.ts'\n\nexport interface DiscoveredSkill {\n name: string\n dir: string\n skillFile: string\n}\n\n/**\n * Walk the bazilion skill library and return every directory that contains a\n * SKILL.md file. Pure filesystem read — does not parse the markdown.\n */\nexport function discoverSkills(paths: Paths): DiscoveredSkill[] {\n if (!existsSync(paths.skillsDir)) return []\n\n const entries = readdirSync(paths.skillsDir, { withFileTypes: true })\n const skills: DiscoveredSkill[] = []\n for (const entry of entries) {\n if (!entry.isDirectory()) continue\n const dir = join(paths.skillsDir, entry.name)\n const skillFile = join(dir, 'SKILL.md')\n if (!existsSync(skillFile)) continue\n skills.push({ name: entry.name, dir, skillFile })\n }\n return skills.sort((a, b) => a.name.localeCompare(b.name))\n}\n","import type { BazilionDb } from '../db/client.ts'\nimport * as agentRepo from '../repos/agents.ts'\n\nexport function unarchiveAgent(db: BazilionDb, id: string): void {\n const agent = agentRepo.get(db, id)\n if (!agent) throw new Error(`agent not found: ${id}`)\n if (agent.status !== 'archived') {\n throw new Error(`agent is not archived (status: ${agent.status})`)\n }\n agentRepo.unarchive(db, agent.id)\n}\n","import { DatabaseSync, type SQLInputValue } from 'node:sqlite'\n\nexport interface QueryStmt<RowType, ParamsType extends unknown[]> {\n get(...params: ParamsType): RowType | null\n all(...params: ParamsType): RowType[]\n run(...params: ParamsType): { changes: number; lastInsertRowid: number | bigint }\n}\n\nexport interface QueryableDatabase {\n query<RowType, ParamsType extends unknown[]>(sql: string): QueryStmt<RowType, ParamsType>\n run(sql: string, params?: unknown[]): { changes: number; lastInsertRowid: number | bigint }\n exec(sql: string): void\n transaction<T>(fn: () => T): () => T\n}\n\nexport interface BazilionDb {\n raw: QueryableDatabase\n close(): void\n}\n\nfunction wrap(rawDb: DatabaseSync): QueryableDatabase {\n const cache = new Map<string, ReturnType<DatabaseSync['prepare']>>()\n function getStmt(sql: string) {\n let s = cache.get(sql)\n if (!s) {\n s = rawDb.prepare(sql)\n cache.set(sql, s)\n }\n return s\n }\n\n return {\n query<R, P extends unknown[]>(sql: string): QueryStmt<R, P> {\n const stmt = getStmt(sql)\n return {\n get(...params: P): R | null {\n const result = stmt.get(...(params as SQLInputValue[]))\n return (result as R | undefined) ?? null\n },\n all(...params: P): R[] {\n return stmt.all(...(params as SQLInputValue[])) as R[]\n },\n run(...params: P) {\n return stmt.run(...(params as SQLInputValue[])) as {\n changes: number\n lastInsertRowid: number | bigint\n }\n },\n }\n },\n run(sql, params) {\n const stmt = getStmt(sql)\n return stmt.run(...((params ?? []) as SQLInputValue[])) as {\n changes: number\n lastInsertRowid: number | bigint\n }\n },\n exec(sql) {\n rawDb.exec(sql)\n },\n // node:sqlite has no callable `transaction` wrapper; use manual BEGIN/COMMIT/ROLLBACK.\n transaction<T>(fn: () => T): () => T {\n return () => {\n rawDb.exec('BEGIN')\n try {\n const result = fn()\n rawDb.exec('COMMIT')\n return result\n } catch (err) {\n rawDb.exec('ROLLBACK')\n throw err\n }\n }\n },\n }\n}\n\nfunction applyPragmas(rawDb: DatabaseSync, includeWal: boolean): void {\n if (includeWal) {\n try {\n rawDb.exec('PRAGMA journal_mode = WAL')\n } catch {\n // some sqlite builds reject WAL on :memory: — ignore\n }\n }\n rawDb.exec('PRAGMA foreign_keys = ON')\n}\n\nexport function openDb(path: string): BazilionDb {\n const raw = new DatabaseSync(path)\n applyPragmas(raw, true)\n return {\n raw: wrap(raw),\n close() {\n raw.close()\n },\n }\n}\n\nexport function openInMemoryDb(): BazilionDb {\n const raw = new DatabaseSync(':memory:')\n applyPragmas(raw, false)\n return {\n raw: wrap(raw),\n close() {\n raw.close()\n },\n }\n}\n\nexport function inTx<T>(db: BazilionDb, fn: () => T): T {\n return db.raw.transaction(fn)()\n}\n","import { readdirSync, readFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { BazilionDb } from './client.ts'\n\nconst migrationsDir = join(dirname(fileURLToPath(import.meta.url)), 'migrations')\n\nexport function runMigrations(db: BazilionDb): void {\n db.raw.exec(`\n CREATE TABLE IF NOT EXISTS schema_migrations (\n version TEXT PRIMARY KEY,\n applied_at INTEGER NOT NULL\n )\n `)\n\n const applied = new Set(\n db.raw\n .query<{ version: string }, []>('SELECT version FROM schema_migrations')\n .all()\n .map((r) => r.version),\n )\n\n const files = readdirSync(migrationsDir)\n .filter((f) => f.endsWith('.sql'))\n .sort()\n\n for (const file of files) {\n const version = file.replace(/\\.sql$/, '')\n if (applied.has(version)) continue\n\n const sql = readFileSync(join(migrationsDir, file), 'utf8')\n const tx = db.raw.transaction(() => {\n db.raw.exec(sql)\n db.raw.run('INSERT INTO schema_migrations (version, applied_at) VALUES (?, ?)', [\n version,\n Date.now(),\n ])\n })\n tx()\n }\n}\n","import type { BazilionDb } from '../db/client.ts'\nimport type { Paths } from '../paths.ts'\nimport * as agentRepo from '../repos/agents.ts'\nimport * as groupRepo from '../repos/groups.ts'\n\nexport function deleteGroup(db: BazilionDb, paths: Paths, id: string): void {\n const g = groupRepo.get(db, id, paths)\n if (!g) throw new Error(`group not found: ${id}`)\n\n // ON DELETE RESTRICT on agents.group_id enforces this at the SQL layer,\n // but we surface a friendlier error listing the blocking members.\n const members = agentRepo.list(db, { includeArchived: true }).filter((a) => a.groupId === id)\n if (members.length > 0) {\n const names = members.map((a) => `${a.name} (${a.id.slice(0, 8)})`).join(', ')\n throw new Error(\n `cannot delete group \"${id}\": ${members.length} agent(s) still belong to it: ${names}. Move or archive them first.`,\n )\n }\n\n groupRepo.remove(db, id)\n}\n","import { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nexport interface Paths {\n home: string\n db: string\n /**\n * Bootstrap auth file shared by the daemon and the CLI: `{token, remote?}`.\n * - `token` is the plaintext of the bootstrap web token. The daemon reads\n * it once at startup to derive the encryption key for the `secrets`\n * table (PBKDF2 over it) and to validate that it matches a row in\n * `web_tokens` (so a corrupted file fails loudly). The CLI reads it as\n * its loopback bearer.\n * - `remote` (set via `bazilion login`) is a CLI-only override pointing at\n * a remote daemon. The local daemon ignores this field.\n *\n * One file replaces the previous `config.json` + `secrets.enc` split:\n * encrypted secrets and plaintext config now live as DB rows.\n */\n authFile: string\n profilesDir: string\n agentsDir: string\n skillsDir: string\n groupsDir: string\n logsDir: string\n profileDir(id: string): string\n agentDir(id: string): string\n skillDir(name: string): string\n groupDir(slug: string): string\n}\n\nexport function resolvePaths(home?: string): Paths {\n const root = home ?? process.env.BAZILION_HOME ?? join(homedir(), '.bazilion')\n return {\n home: root,\n db: join(root, 'bazilion.db'),\n authFile: join(root, 'auth.json'),\n profilesDir: join(root, 'profiles'),\n agentsDir: join(root, 'agents'),\n skillsDir: join(root, 'skills'),\n groupsDir: join(root, 'groups'),\n logsDir: join(root, 'logs'),\n profileDir(id) {\n return join(root, 'profiles', id)\n },\n agentDir(id) {\n return join(root, 'agents', id)\n },\n skillDir(name) {\n return join(root, 'skills', name)\n },\n groupDir(slug) {\n return join(root, 'groups', slug)\n },\n }\n}\n","import { existsSync, rmSync } from 'node:fs'\nimport type { BazilionDb } from '../db/client.ts'\nimport * as agentRepo from '../repos/agents.ts'\nimport * as profileRepo from '../repos/profiles.ts'\n\nexport function deleteProfile(db: BazilionDb, id: string): void {\n const profile = profileRepo.get(db, id)\n if (!profile) throw new Error(`profile not found: ${id}`)\n\n // Check for agents still using this profile\n const agents = agentRepo.list(db, { includeArchived: true }).filter((a) => a.profileId === id)\n if (agents.length > 0) {\n const names = agents.map((a) => `${a.name} (${a.id.slice(0, 8)})`).join(', ')\n throw new Error(\n `cannot delete profile \"${id}\": ${agents.length} agent(s) still reference it: ${names}. Delete or re-profile them first.`,\n )\n }\n\n // Remove from DB (CASCADE deletes profile_default_skills)\n profileRepo.remove(db, id)\n\n // Remove the profile directory from disk\n if (existsSync(profile.dir)) {\n rmSync(profile.dir, { recursive: true, force: true })\n }\n}\n","import { writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { Profile, SkillsMode } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\nimport type { Paths } from '../paths.ts'\nimport * as profileRepo from '../repos/profiles.ts'\n\nexport interface UpdateProfileInput {\n name?: string\n defaultModel?: string\n skillsMode?: SkillsMode\n defaultSkills?: string[]\n}\n\n/**\n * Update the mutable settings in profile.json + the DB row in lockstep.\n * Profile files (SOUL/IDENTITY/BOOTSTRAP) and the memory backend are NOT\n * touched — those have their own paths.\n */\nexport function updateProfile(\n db: BazilionDb,\n paths: Paths,\n id: string,\n input: UpdateProfileInput,\n): Profile {\n const existing = profileRepo.get(db, id)\n if (!existing) throw new Error(`profile not found: ${id}`)\n\n const nextSkillsMode: SkillsMode = input.skillsMode ?? existing.skillsMode\n\n const next = {\n name: input.name ?? existing.name,\n defaultModel: input.defaultModel ?? existing.defaultModel,\n skillsMode: nextSkillsMode,\n }\n profileRepo.update(db, id, next)\n\n if (input.defaultSkills !== undefined) {\n profileRepo.setDefaultSkills(db, id, input.defaultSkills)\n }\n\n const skills = profileRepo.getDefaultSkills(db, id)\n const profileJson = {\n name: next.name,\n defaultModel: next.defaultModel,\n skillsMode: next.skillsMode,\n defaultSkills: skills,\n }\n writeFileSync(\n join(paths.profileDir(id), 'profile.json'),\n `${JSON.stringify(profileJson, null, 2)}\\n`,\n )\n\n const updated = profileRepo.get(db, id)\n if (!updated) throw new Error(`profile vanished after update: ${id}`)\n return updated\n}\n","// Per-service field registry — the shape of the /config page.\n//\n// Each entry describes one \"thing\" the user might configure: an LLM provider\n// (Anthropic, LM Studio, …) or an ancillary service (Brave Search, SearXNG).\n// Fields know which storage backend they live in: `secret` → the encrypted\n// `secrets` table, `config` → the plaintext `config` table. The registry is\n// the single source of truth for the UI layout and for the generic\n// field-write endpoint's dispatch.\n//\n// When adding a new provider or service, append an entry here and the\n// config page + CLI pick it up automatically.\n\nexport type FieldKind = 'secret' | 'config'\n\nexport interface ServiceField {\n /** Env var name — canonical key in both stores. */\n envVar: string\n kind: FieldKind\n label: string\n placeholder?: string\n description?: string\n}\n\nexport type ServiceCategory = 'provider' | 'service'\n\nexport interface ServiceDef {\n /** Matches the provider-registry key for providers (e.g. 'anthropic'). */\n id: string\n displayName: string\n category: ServiceCategory\n /** Display grouping label shown above the card on the /config tabs. */\n group?: string\n /** Sign-up link, docs, or 1-line description shown on the card. */\n hint?: string\n fields: ServiceField[]\n}\n\n/**\n * One-liner: what's shown on each service card.\n * Order here is the display order on the config page.\n */\nexport const SERVICES: ServiceDef[] = [\n // --- LLM providers (configured via API keys / URLs) ---\n // Top 3: openai-codex (ChatGPT OAuth), openai (API key), anthropic.\n // Everything else in rough popularity order; locals last.\n {\n id: 'openai-codex',\n displayName: 'OpenAI ChatGPT (OAuth)',\n category: 'provider',\n hint: 'Use your ChatGPT Plus/Pro/Team account (same login as Codex CLI)',\n // No form fields — credentials come from an OAuth flow. The /config page\n // renders a Connect/Disconnect card using /api/auth/openai instead of the\n // standard field inputs.\n fields: [],\n },\n {\n id: 'openai',\n displayName: 'OpenAI',\n category: 'provider',\n hint: 'GPT models · platform.openai.com',\n fields: [{ envVar: 'OPENAI_API_KEY', kind: 'secret', label: 'API key', placeholder: 'sk-...' }],\n },\n {\n id: 'anthropic',\n displayName: 'Anthropic',\n category: 'provider',\n hint: 'Claude models · console.anthropic.com',\n fields: [\n { envVar: 'ANTHROPIC_API_KEY', kind: 'secret', label: 'API key', placeholder: 'sk-ant-...' },\n {\n envVar: 'ANTHROPIC_OAUTH_TOKEN',\n kind: 'secret',\n label: 'OAuth token (alternative to API key)',\n description: 'Takes precedence over ANTHROPIC_API_KEY when set',\n },\n ],\n },\n {\n id: 'google',\n displayName: 'Google (Gemini)',\n category: 'provider',\n hint: 'Gemini models · ai.google.dev (free tier available)',\n fields: [\n { envVar: 'GEMINI_API_KEY', kind: 'secret', label: 'API key', placeholder: 'AIza...' },\n ],\n },\n {\n id: 'google-vertex',\n displayName: 'Google Vertex AI',\n category: 'provider',\n hint: 'Authenticates via `gcloud auth application-default login`',\n fields: [\n {\n envVar: 'GOOGLE_CLOUD_PROJECT',\n kind: 'config',\n label: 'GCP project ID',\n placeholder: 'my-project-123456',\n },\n {\n envVar: 'GOOGLE_CLOUD_LOCATION',\n kind: 'config',\n label: 'GCP region',\n placeholder: 'us-central1',\n },\n ],\n },\n {\n id: 'azure-openai',\n displayName: 'Azure OpenAI',\n category: 'provider',\n fields: [{ envVar: 'AZURE_OPENAI_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'bedrock',\n displayName: 'Amazon Bedrock',\n category: 'provider',\n hint: 'Authenticates via AWS SDK env (AWS_PROFILE or AWS_ACCESS_KEY_ID/SECRET)',\n fields: [],\n },\n {\n id: 'github-copilot',\n displayName: 'GitHub Copilot',\n category: 'provider',\n hint: 'Use a GitHub Copilot subscription to call Claude/GPT/Gemini via Copilot',\n fields: [\n {\n envVar: 'COPILOT_GITHUB_TOKEN',\n kind: 'secret',\n label: 'GitHub token',\n description:\n 'Generic GH_TOKEN/GITHUB_TOKEN are ignored — set this scoped variable explicitly (or run `bazilion auth copilot login` once available).',\n },\n ],\n },\n {\n id: 'deepseek',\n displayName: 'DeepSeek',\n category: 'provider',\n hint: 'DeepSeek V4 Flash / Pro · platform.deepseek.com',\n fields: [{ envVar: 'DEEPSEEK_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'mistral',\n displayName: 'Mistral',\n category: 'provider',\n hint: 'mistral.ai',\n fields: [{ envVar: 'MISTRAL_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'xai',\n displayName: 'xAI',\n category: 'provider',\n hint: 'Grok · x.ai',\n fields: [{ envVar: 'XAI_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'groq',\n displayName: 'Groq',\n category: 'provider',\n hint: 'Fast inference · groq.com',\n fields: [{ envVar: 'GROQ_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'cerebras',\n displayName: 'Cerebras',\n category: 'provider',\n fields: [{ envVar: 'CEREBRAS_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'fireworks',\n displayName: 'Fireworks AI',\n category: 'provider',\n hint: 'DeepSeek/GLM/Kimi via fireworks.ai',\n fields: [{ envVar: 'FIREWORKS_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'together',\n displayName: 'Together AI',\n category: 'provider',\n hint: 'Open-weight models · together.ai',\n fields: [{ envVar: 'TOGETHER_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'moonshotai',\n displayName: 'Moonshot AI',\n category: 'provider',\n hint: 'Kimi K2/K2.5/K2.6 · platform.moonshot.ai',\n fields: [{ envVar: 'MOONSHOT_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'kimi-coding',\n displayName: 'Kimi Coding',\n category: 'provider',\n hint: 'Coding-tuned Kimi endpoint · platform.moonshot.cn',\n fields: [{ envVar: 'KIMI_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'minimax',\n displayName: 'MiniMax',\n category: 'provider',\n hint: 'MiniMax M2 family · platform.minimaxi.com',\n fields: [{ envVar: 'MINIMAX_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'xiaomi',\n displayName: 'Xiaomi MiMo',\n category: 'provider',\n hint: 'API billing endpoint · platform.xiaomimimo.com',\n fields: [{ envVar: 'XIAOMI_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'zai',\n displayName: 'zAI',\n category: 'provider',\n fields: [{ envVar: 'ZAI_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'huggingface',\n displayName: 'Hugging Face',\n category: 'provider',\n hint: 'Inference endpoints · huggingface.co',\n fields: [{ envVar: 'HF_TOKEN', kind: 'secret', label: 'Access token', placeholder: 'hf_...' }],\n },\n {\n id: 'cloudflare-ai-gateway',\n displayName: 'Cloudflare AI Gateway',\n category: 'provider',\n hint: 'Per-gateway routing to OpenAI/Anthropic/Workers AI',\n fields: [\n { envVar: 'CLOUDFLARE_API_KEY', kind: 'secret', label: 'API key' },\n { envVar: 'CLOUDFLARE_ACCOUNT_ID', kind: 'config', label: 'Account ID' },\n { envVar: 'CLOUDFLARE_GATEWAY_ID', kind: 'config', label: 'Gateway ID' },\n ],\n },\n {\n id: 'cloudflare-workers-ai',\n displayName: 'Cloudflare Workers AI',\n category: 'provider',\n hint: 'Inference on Cloudflare Workers · ai.cloudflare.com',\n fields: [\n { envVar: 'CLOUDFLARE_API_KEY', kind: 'secret', label: 'API key' },\n { envVar: 'CLOUDFLARE_ACCOUNT_ID', kind: 'config', label: 'Account ID' },\n ],\n },\n {\n id: 'openrouter',\n displayName: 'OpenRouter',\n category: 'provider',\n hint: 'Proxy for 200+ models · openrouter.ai',\n fields: [\n { envVar: 'OPENROUTER_API_KEY', kind: 'secret', label: 'API key', placeholder: 'sk-or-...' },\n ],\n },\n {\n id: 'vercel-ai-gateway',\n displayName: 'Vercel AI Gateway',\n category: 'provider',\n fields: [\n { envVar: 'AI_GATEWAY_API_KEY', kind: 'secret', label: 'API key' },\n {\n envVar: 'AI_GATEWAY_BASE_URL',\n kind: 'config',\n label: 'Base URL (optional)',\n placeholder: 'https://ai-gateway.vercel.sh/v1',\n },\n ],\n },\n {\n id: 'opencode',\n displayName: 'OpenCode',\n category: 'provider',\n hint: 'OpenAI-compatible proxy from the OpenCode CLI',\n fields: [{ envVar: 'OPENCODE_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'lmstudio',\n displayName: 'LM Studio',\n category: 'provider',\n hint: 'Local inference · lmstudio.ai',\n fields: [\n {\n envVar: 'LMSTUDIO_URL',\n kind: 'config',\n label: 'Endpoint URL',\n placeholder: 'http://127.0.0.1:1234/v1',\n },\n {\n envVar: 'LMSTUDIO_API_KEY',\n kind: 'secret',\n label: 'API key (rarely needed)',\n },\n ],\n },\n {\n id: 'ollama',\n displayName: 'Ollama',\n category: 'provider',\n hint: 'Local inference · ollama.com',\n fields: [\n {\n envVar: 'OLLAMA_URL',\n kind: 'config',\n label: 'Endpoint URL',\n placeholder: 'http://127.0.0.1:11434/v1',\n },\n {\n envVar: 'OLLAMA_API_KEY',\n kind: 'secret',\n label: 'API key (rarely needed)',\n },\n ],\n },\n {\n id: 'llamacpp',\n displayName: 'llama.cpp',\n category: 'provider',\n hint: 'Local inference · llama.cpp llama-server (OpenAI-compat /v1 endpoint)',\n fields: [\n {\n envVar: 'LLAMACPP_URL',\n kind: 'config',\n label: 'Endpoint URL',\n placeholder: 'http://127.0.0.1:8080/v1',\n },\n {\n envVar: 'LLAMACPP_API_KEY',\n kind: 'secret',\n label: 'API key (only if started with --api-key)',\n description:\n 'llama-server runs without auth by default. Set this only if you launched the server with the `--api-key KEY` flag.',\n },\n ],\n },\n\n // --- Ancillary services (web search, etc) ---\n {\n id: 'firecrawl',\n displayName: 'Firecrawl',\n category: 'service',\n group: 'Web Search',\n hint: 'web_fetch fallback for JS-heavy/blocked pages · firecrawl.dev (free tier available)',\n fields: [\n {\n envVar: 'FIRECRAWL_API_KEY',\n kind: 'secret',\n label: 'API key',\n placeholder: 'fc-...',\n description:\n 'When set, web_fetch automatically falls back to Firecrawl if the primary Readability extraction yields too little content.',\n },\n {\n envVar: 'FIRECRAWL_URL',\n kind: 'config',\n label: 'Base URL (optional, for self-hosted)',\n placeholder: 'https://api.firecrawl.dev',\n },\n ],\n },\n {\n id: 'brave-search',\n displayName: 'Brave Search',\n category: 'service',\n group: 'Web Search',\n hint: 'Web search tool · free tier at brave.com/search/api/',\n fields: [{ envVar: 'BRAVE_API_KEY', kind: 'secret', label: 'API key', placeholder: 'BSA...' }],\n },\n {\n id: 'searxng',\n displayName: 'SearXNG',\n category: 'service',\n group: 'Web Search',\n hint: 'Self-hosted meta-search engine · searxng.org',\n fields: [\n {\n envVar: 'SEARXNG_URL',\n kind: 'config',\n label: 'Instance URL',\n placeholder: 'https://searxng.example.com',\n },\n ],\n },\n]\n\n/**\n * Fast lookup: envVar → the field definition + owning service.\n * Rebuilt once at module init — the list is static.\n */\nconst FIELD_INDEX: Map<string, { service: ServiceDef; field: ServiceField }> = (() => {\n const m = new Map<string, { service: ServiceDef; field: ServiceField }>()\n for (const service of SERVICES) {\n for (const field of service.fields) {\n m.set(field.envVar, { service, field })\n }\n }\n return m\n})()\n\nexport function findFieldByEnvVar(\n envVar: string,\n): { service: ServiceDef; field: ServiceField } | undefined {\n return FIELD_INDEX.get(envVar)\n}\n\nexport function servicesByCategory(category: ServiceCategory): ServiceDef[] {\n return SERVICES.filter((s) => s.category === category)\n}\n","// Plaintext config store, backed by the `config` table.\n//\n// Companion to `secrets.ts` — same key-shaped values, but for the ones that\n// don't need confidentiality (server URLs, region slugs, project IDs). Kept\n// separate so the /config UI can show plaintext values directly without\n// extra masking logic.\n//\n// The CONFIG_KEYS allowlist (derived from the services registry) is enforced\n// here on writes — a typo or accidental misclassification can't put an API\n// key in this table.\n\nimport type { BazilionDb } from '../db/client.ts'\nimport { SERVICES } from '../services.ts'\n\n/**\n * Env var names that live in the plaintext config store. Derived from the\n * services registry — any field marked `kind: 'config'` ends up here.\n */\nexport const CONFIG_KEYS: readonly string[] = SERVICES.flatMap((s) =>\n s.fields.filter((f) => f.kind === 'config').map((f) => f.envVar),\n)\n\nconst CONFIG_KEY_SET = new Set<string>(CONFIG_KEYS)\n\nexport function isConfigKey(key: string): boolean {\n return CONFIG_KEY_SET.has(key)\n}\n\ninterface RawRow {\n key: string\n value: string\n updated_at: number\n}\n\nexport interface ConfigStore {\n get(key: string): string | undefined\n set(key: string, value: string): void\n remove(key: string): void\n list(): { key: string; value: string }[]\n getAll(): Record<string, string>\n}\n\nexport function openConfig(db: BazilionDb): ConfigStore {\n return {\n get(key) {\n const row = db.raw.query<RawRow, [string]>('SELECT * FROM config WHERE key = ?').get(key)\n return row?.value\n },\n set(key, value) {\n if (!isConfigKey(key)) {\n throw new Error(\n `config.set: \"${key}\" is not a known config key (${CONFIG_KEYS.join(', ')})`,\n )\n }\n db.raw.run(\n `INSERT INTO config (key, value, updated_at) VALUES (?, ?, ?)\n ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`,\n [key, value, Date.now()],\n )\n },\n remove(key) {\n db.raw.run('DELETE FROM config WHERE key = ?', [key])\n },\n list() {\n return db.raw\n .query<RawRow, []>('SELECT * FROM config ORDER BY key ASC')\n .all()\n .map((r) => ({ key: r.key, value: r.value }))\n },\n getAll() {\n const out: Record<string, string> = {}\n for (const r of db.raw.query<RawRow, []>('SELECT * FROM config').all()) {\n out[r.key] = r.value\n }\n return out\n },\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport type { Message } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\n\ninterface RawMessage {\n id: string\n from_agent_id: string\n to_agent_id: string\n reply_to: string | null\n payload: string\n created_at: number\n read_at: number | null\n}\n\nfunction toMessage(r: RawMessage): Message {\n return {\n id: r.id,\n fromAgentId: r.from_agent_id,\n toAgentId: r.to_agent_id,\n replyTo: r.reply_to,\n payload: r.payload,\n createdAt: r.created_at,\n readAt: r.read_at,\n }\n}\n\nexport function send(\n db: BazilionDb,\n input: { from: string; to: string; payload: string; replyTo?: string | null },\n): Message {\n const id = randomUUID()\n const now = Date.now()\n db.raw.run(\n `INSERT INTO messages (id, from_agent_id, to_agent_id, reply_to, payload, created_at, read_at)\n VALUES (?, ?, ?, ?, ?, ?, NULL)`,\n [id, input.from, input.to, input.replyTo ?? null, input.payload, now],\n )\n return {\n id,\n fromAgentId: input.from,\n toAgentId: input.to,\n replyTo: input.replyTo ?? null,\n payload: input.payload,\n createdAt: now,\n readAt: null,\n }\n}\n\nexport function get(db: BazilionDb, id: string): Message | null {\n const row = db.raw.query<RawMessage, [string]>('SELECT * FROM messages WHERE id = ?').get(id)\n return row ? toMessage(row) : null\n}\n\nexport function listInbox(\n db: BazilionDb,\n agentId: string,\n opts?: { unreadOnly?: boolean },\n): Message[] {\n const sql = opts?.unreadOnly\n ? 'SELECT * FROM messages WHERE to_agent_id = ? AND read_at IS NULL ORDER BY created_at ASC'\n : 'SELECT * FROM messages WHERE to_agent_id = ? ORDER BY created_at ASC'\n return db.raw.query<RawMessage, [string]>(sql).all(agentId).map(toMessage)\n}\n\nexport function markRead(db: BazilionDb, id: string): void {\n db.raw.run('UPDATE messages SET read_at = ? WHERE id = ? AND read_at IS NULL', [Date.now(), id])\n}\n\n/**\n * Find messages that are replies to a given message id, addressed to a specific agent.\n * Used by `wait_for_reply` to poll for incoming responses.\n */\nexport function findReplies(db: BazilionDb, toAgentId: string, inReplyTo: string): Message[] {\n return db.raw\n .query<RawMessage, [string, string]>(\n `SELECT * FROM messages\n WHERE to_agent_id = ? AND reply_to = ?\n ORDER BY created_at ASC`,\n )\n .all(toAgentId, inReplyTo)\n .map(toMessage)\n}\n\n/**\n * Return the distinct `to_agent_id`s that currently have at least one unread\n * message, filtered to agents not in a terminal state (idle or starting).\n * Used by the scheduler's message-wake loop so a tick can fan-out auto-\n * delivery turns without walking every agent in the DB.\n */\nexport function listRecipientsWithUnread(db: BazilionDb): string[] {\n const rows = db.raw\n .query<{ to_agent_id: string }, []>(\n `SELECT DISTINCT m.to_agent_id FROM messages m\n JOIN agents a ON a.id = m.to_agent_id\n WHERE m.read_at IS NULL AND a.status = 'idle'\n ORDER BY m.to_agent_id`,\n )\n .all()\n return rows.map((r) => r.to_agent_id)\n}\n\n/**\n * Atomically fetch + mark-read all unread messages addressed to `agentId`.\n * Runs inside a transaction so two concurrent schedulers / manual deliveries\n * can't double-dispatch the same message. Returns the fetched messages in\n * ascending `created_at` order — callers format them into the recipient's\n * wake-up prompt.\n */\nexport function drainUnreadForAgent(db: BazilionDb, agentId: string): Message[] {\n return db.raw.transaction(() => {\n const rows = db.raw\n .query<RawMessage, [string]>(\n `SELECT * FROM messages\n WHERE to_agent_id = ? AND read_at IS NULL\n ORDER BY created_at ASC`,\n )\n .all(agentId)\n if (rows.length === 0) return []\n const now = Date.now()\n db.raw.run(\n `UPDATE messages SET read_at = ?\n WHERE to_agent_id = ? AND read_at IS NULL`,\n [now, agentId],\n )\n return rows.map((r) => toMessage({ ...r, read_at: now }))\n })()\n}\n","// Encrypted secrets store, backed by the `secrets` table.\n//\n// Layout: one row per env-var-shaped key (`ANTHROPIC_API_KEY`,\n// `OPENAI_CODEX_OAUTH`, …). Each value is an AES-256-GCM envelope (salt +\n// iv + tag + data, hex-encoded JSON), with the key derived from the\n// bootstrap token via PBKDF2-SHA256 (100k iterations). The crypto matches\n// the previous `secrets.enc` file format byte-for-byte — only the storage\n// medium changed.\n//\n// Why encrypt at all when the password lives in `~/.bazilion/auth.json`\n// next to the DB? Same reason as before: it's defense against accidental\n// exposure (cat'd dumps, screenshares, naive backups), not against an\n// attacker with filesystem read. Anyone who can read both files wins.\n//\n// Caching: `deriveKey` runs PBKDF2 once per (password, salt) pair and the\n// salt is per-row, so a busy daemon does ~one PBKDF2 per secret read. The\n// `secretCache` keeps decrypted values in-memory keyed by row id so repeated\n// reads inside one process don't repeat the work; mutations clear the cache\n// row.\n\nimport { createCipheriv, createDecipheriv, pbkdf2Sync, randomBytes } from 'node:crypto'\nimport type { BazilionDb } from '../db/client.ts'\n\nconst ALGORITHM = 'aes-256-gcm'\nconst KEY_LEN = 32\nconst ITERATIONS = 100_000\nconst DIGEST = 'sha256'\n\ninterface EncryptedEnvelope {\n salt: string\n iv: string\n tag: string\n data: string\n}\n\nfunction deriveKey(password: string, salt: Buffer): Buffer {\n return pbkdf2Sync(password, salt, ITERATIONS, KEY_LEN, DIGEST)\n}\n\nfunction encrypt(plaintext: string, password: string): EncryptedEnvelope {\n const salt = randomBytes(16)\n const key = deriveKey(password, salt)\n const iv = randomBytes(12)\n const cipher = createCipheriv(ALGORITHM, key, iv)\n let data = cipher.update(plaintext, 'utf8', 'hex')\n data += cipher.final('hex')\n const tag = cipher.getAuthTag()\n return {\n salt: salt.toString('hex'),\n iv: iv.toString('hex'),\n tag: tag.toString('hex'),\n data,\n }\n}\n\nfunction decrypt(envelope: EncryptedEnvelope, password: string): string {\n const salt = Buffer.from(envelope.salt, 'hex')\n const key = deriveKey(password, salt)\n const iv = Buffer.from(envelope.iv, 'hex')\n const tag = Buffer.from(envelope.tag, 'hex')\n const decipher = createDecipheriv(ALGORITHM, key, iv)\n decipher.setAuthTag(tag)\n let plaintext = decipher.update(envelope.data, 'hex', 'utf8')\n plaintext += decipher.final('utf8')\n return plaintext\n}\n\ninterface RawRow {\n key: string\n envelope: string\n updated_at: number\n}\n\nexport interface SecretsStore {\n get(key: string): string | undefined\n set(key: string, value: string): void\n remove(key: string): void\n has(key: string): boolean\n list(): { key: string; preview: string }[]\n getAll(): Record<string, string>\n}\n\n/**\n * Open the encrypted secrets store. `password` is the bootstrap token\n * (read from `auth.json` by the caller). Throws on individual-row decrypt\n * failures only when actively reading that row — bad rows show as\n * `undefined` from `get`, the caller can `set` to overwrite.\n */\nexport function openSecrets(db: BazilionDb, password: string): SecretsStore {\n function getRow(key: string): RawRow | null {\n return db.raw.query<RawRow, [string]>('SELECT * FROM secrets WHERE key = ?').get(key)\n }\n\n function listAll(): RawRow[] {\n return db.raw.query<RawRow, []>('SELECT * FROM secrets ORDER BY key ASC').all()\n }\n\n function tryDecrypt(row: RawRow): string | undefined {\n try {\n const envelope = JSON.parse(row.envelope) as EncryptedEnvelope\n return decrypt(envelope, password)\n } catch {\n return undefined\n }\n }\n\n return {\n get(key) {\n const row = getRow(key)\n if (!row) return undefined\n return tryDecrypt(row)\n },\n set(key, value) {\n const envelope = JSON.stringify(encrypt(value, password))\n db.raw.run(\n `INSERT INTO secrets (key, envelope, updated_at) VALUES (?, ?, ?)\n ON CONFLICT(key) DO UPDATE SET envelope = excluded.envelope, updated_at = excluded.updated_at`,\n [key, envelope, Date.now()],\n )\n },\n remove(key) {\n db.raw.run('DELETE FROM secrets WHERE key = ?', [key])\n },\n has(key) {\n return getRow(key) !== null\n },\n list() {\n return listAll().map((r) => {\n const value = tryDecrypt(r)\n return {\n key: r.key,\n preview: value ? (value.length > 8 ? `${value.slice(0, 6)}…` : '***') : '(unreadable)',\n }\n })\n },\n getAll() {\n const out: Record<string, string> = {}\n for (const r of listAll()) {\n const v = tryDecrypt(r)\n if (v !== undefined) out[r.key] = v\n }\n return out\n },\n }\n}\n","import type { SkillMeta } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\n\ninterface RawMeta {\n name: string\n source: string | null\n imported_at: number | null\n}\n\nfunction toMeta(r: RawMeta): SkillMeta {\n return {\n name: r.name,\n source: r.source,\n importedAt: r.imported_at,\n }\n}\n\nexport function get(db: BazilionDb, name: string): SkillMeta | null {\n const row = db.raw.query<RawMeta, [string]>('SELECT * FROM skill_meta WHERE name = ?').get(name)\n return row ? toMeta(row) : null\n}\n\nexport function listAll(db: BazilionDb): SkillMeta[] {\n return db.raw.query<RawMeta, []>('SELECT * FROM skill_meta ORDER BY name ASC').all().map(toMeta)\n}\n\nexport interface UpsertInput {\n name: string\n source?: string | null\n importedAt?: number | null\n}\n\nexport function upsert(db: BazilionDb, input: UpsertInput): SkillMeta {\n const existing = get(db, input.name)\n const source = input.source !== undefined ? input.source : (existing?.source ?? null)\n const importedAt =\n input.importedAt !== undefined ? input.importedAt : (existing?.importedAt ?? null)\n db.raw.run(\n `INSERT INTO skill_meta (name, source, imported_at)\n VALUES (?, ?, ?)\n ON CONFLICT(name) DO UPDATE SET source = excluded.source, imported_at = excluded.imported_at`,\n [input.name, source, importedAt],\n )\n return { name: input.name, source, importedAt }\n}\n\nexport function remove(db: BazilionDb, name: string): void {\n db.raw.run('DELETE FROM skill_meta WHERE name = ?', [name])\n}\n","import { randomUUID } from 'node:crypto'\nimport type { AgentTrigger, TriggerKind } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\n\ninterface RawTrigger {\n id: string\n agent_id: string\n kind: string\n interval_sec: number | null\n cron_expr: string | null\n message: string\n enabled: number\n last_fired_at: number | null\n created_at: number\n}\n\nfunction toTrigger(r: RawTrigger): AgentTrigger {\n return {\n id: r.id,\n agentId: r.agent_id,\n kind: r.kind as TriggerKind,\n intervalSec: r.interval_sec,\n cronExpr: r.cron_expr,\n message: r.message,\n enabled: r.enabled === 1,\n lastFiredAt: r.last_fired_at,\n createdAt: r.created_at,\n }\n}\n\nexport interface InsertTriggerInput {\n agentId: string\n kind: TriggerKind\n intervalSec: number | null\n cronExpr: string | null\n message: string\n enabled?: boolean\n}\n\nexport function insert(db: BazilionDb, input: InsertTriggerInput): AgentTrigger {\n const id = randomUUID()\n const now = Date.now()\n const enabled = input.enabled === false ? 0 : 1\n db.raw.run(\n `INSERT INTO agent_triggers\n (id, agent_id, kind, interval_sec, cron_expr, message, enabled, last_fired_at, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, NULL, ?)`,\n [id, input.agentId, input.kind, input.intervalSec, input.cronExpr, input.message, enabled, now],\n )\n return {\n id,\n agentId: input.agentId,\n kind: input.kind,\n intervalSec: input.intervalSec,\n cronExpr: input.cronExpr,\n message: input.message,\n enabled: enabled === 1,\n lastFiredAt: null,\n createdAt: now,\n }\n}\n\nexport function get(db: BazilionDb, id: string): AgentTrigger | null {\n const row = db.raw\n .query<RawTrigger, [string]>('SELECT * FROM agent_triggers WHERE id = ?')\n .get(id)\n return row ? toTrigger(row) : null\n}\n\nexport function listForAgent(db: BazilionDb, agentId: string): AgentTrigger[] {\n return db.raw\n .query<RawTrigger, [string]>(\n 'SELECT * FROM agent_triggers WHERE agent_id = ? ORDER BY created_at ASC',\n )\n .all(agentId)\n .map(toTrigger)\n}\n\nexport function listEnabled(db: BazilionDb): AgentTrigger[] {\n return db.raw\n .query<RawTrigger, []>(\n `SELECT t.* FROM agent_triggers t\n JOIN agents a ON a.id = t.agent_id\n WHERE t.enabled = 1 AND a.status != 'archived'\n ORDER BY t.created_at ASC`,\n )\n .all()\n .map(toTrigger)\n}\n\nexport function setEnabled(db: BazilionDb, id: string, enabled: boolean): void {\n db.raw.run('UPDATE agent_triggers SET enabled = ? WHERE id = ?', [enabled ? 1 : 0, id])\n}\n\nexport function markFired(db: BazilionDb, id: string, when: number = Date.now()): void {\n db.raw.run('UPDATE agent_triggers SET last_fired_at = ? WHERE id = ?', [when, id])\n}\n\nexport function remove(db: BazilionDb, id: string): void {\n db.raw.run('DELETE FROM agent_triggers WHERE id = ?', [id])\n}\n","import { createHash, randomBytes, randomUUID } from 'node:crypto'\nimport type { WebToken } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\n\ninterface RawToken {\n id: string\n label: string\n token_hash: string\n created_at: number\n last_used_at: number | null\n revoked_at: number | null\n}\n\nfunction toToken(r: RawToken): WebToken {\n return {\n id: r.id,\n label: r.label,\n createdAt: r.created_at,\n lastUsedAt: r.last_used_at,\n revokedAt: r.revoked_at,\n }\n}\n\nexport function hashToken(token: string): string {\n return createHash('sha256').update(token).digest('hex')\n}\n\nexport interface CreatedToken {\n meta: WebToken\n /** Plaintext token — shown exactly once, never re-queryable. */\n token: string\n}\n\nexport function create(db: BazilionDb, label: string): CreatedToken {\n const id = randomUUID()\n const token = randomBytes(24).toString('hex')\n const tokenHash = hashToken(token)\n const now = Date.now()\n db.raw.run(\n `INSERT INTO web_tokens (id, label, token_hash, created_at, last_used_at, revoked_at)\n VALUES (?, ?, ?, ?, NULL, NULL)`,\n [id, label, tokenHash, now],\n )\n return {\n token,\n meta: { id, label, createdAt: now, lastUsedAt: null, revokedAt: null },\n }\n}\n\nexport function list(db: BazilionDb, opts?: { includeRevoked?: boolean }): WebToken[] {\n const sql = opts?.includeRevoked\n ? 'SELECT * FROM web_tokens ORDER BY created_at ASC'\n : 'SELECT * FROM web_tokens WHERE revoked_at IS NULL ORDER BY created_at ASC'\n return db.raw.query<RawToken, []>(sql).all().map(toToken)\n}\n\nexport function get(db: BazilionDb, id: string): WebToken | null {\n const row = db.raw.query<RawToken, [string]>('SELECT * FROM web_tokens WHERE id = ?').get(id)\n return row ? toToken(row) : null\n}\n\n/**\n * Returns the active token row matching the given plaintext, or null.\n * Does NOT bump last_used_at — call markUsed separately once the caller\n * has decided the request is authorized.\n */\nexport function findActiveByToken(db: BazilionDb, token: string): WebToken | null {\n const tokenHash = hashToken(token)\n const row = db.raw\n .query<RawToken, [string]>(\n 'SELECT * FROM web_tokens WHERE token_hash = ? AND revoked_at IS NULL',\n )\n .get(tokenHash)\n return row ? toToken(row) : null\n}\n\nexport function markUsed(db: BazilionDb, id: string, when: number = Date.now()): void {\n db.raw.run('UPDATE web_tokens SET last_used_at = ? WHERE id = ?', [when, id])\n}\n\nexport function revoke(db: BazilionDb, id: string, when: number = Date.now()): boolean {\n const res = db.raw.run(\n 'UPDATE web_tokens SET revoked_at = ? WHERE id = ? AND revoked_at IS NULL',\n [when, id],\n )\n return res.changes > 0\n}\n","// Auth / secrets entry points keyed off the bootstrap `auth.json` file.\n//\n// `auth.json` carries one mandatory field — `token` — written by the daemon's\n// first-run bootstrap. The daemon uses it as the PBKDF2 seed for the `secrets`\n// table; the CLI uses it as the bearer for loopback HTTP. CLI-side `remote`\n// overrides (set by `bazilion login`) coexist in the same file.\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport type { BazilionDb } from './db/client.ts'\nimport { openConfig } from './repos/config.ts'\nimport { openSecrets } from './repos/secrets.ts'\n\nexport interface AuthFile {\n token: string\n remote?: { server: string; token: string } | null\n}\n\n/**\n * Read `auth.json` and return the parsed contents. Throws when missing or\n * malformed — callers should treat that as \"bazilion not initialized.\"\n */\nexport function readAuthFile(authFile: string): AuthFile {\n if (!existsSync(authFile)) {\n throw new Error(\n `${authFile} not found. Start the daemon (\\`bazilion serve\\`) — it auto-bootstraps on first run.`,\n )\n }\n const raw = readFileSync(authFile, 'utf8')\n const parsed = JSON.parse(raw) as Partial<AuthFile>\n if (typeof parsed.token !== 'string' || !parsed.token) {\n throw new Error(`${authFile} is missing the \"token\" field`)\n }\n return {\n token: parsed.token,\n remote: parsed.remote ?? null,\n }\n}\n\n/**\n * Merge plaintext config + decrypted secrets + process env into a single\n * env-shaped record. Precedence (low → high): config → secrets → env. The\n * caller supplies the bootstrap `password` (typically `readAuthFile().token`)\n * because the secrets table is encrypted with it.\n *\n * Either layer may fail to read (corrupt row, wrong key, table absent at\n * fixture-bootstrap time); failures are swallowed per-layer so a single bad\n * value never blocks the merge.\n */\nexport function mergeSecretsIntoEnv(\n db: BazilionDb,\n password: string,\n env: NodeJS.ProcessEnv = process.env,\n): NodeJS.ProcessEnv {\n let configValues: Record<string, string> = {}\n let secretValues: Record<string, string> = {}\n try {\n configValues = openConfig(db).getAll()\n } catch {\n // table missing or unreadable — continue without the layer\n }\n try {\n secretValues = openSecrets(db, password).getAll()\n } catch {\n // table missing or wrong password — continue without the layer\n }\n return { ...configValues, ...secretValues, ...env }\n}\n","import { cpSync, existsSync, mkdtempSync, readdirSync, rmSync, statSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { basename, join, resolve, sep } from 'node:path'\nimport AdmZip from 'adm-zip'\nimport type { Paths } from '../paths.ts'\nimport { parseSkillFile } from './parse.ts'\n\nexport interface ImportSkillsInput {\n /**\n * Absolute path to either:\n * - a single skill folder (contains SKILL.md),\n * - a parent directory containing multiple skill folders,\n * - a `.zip` file whose top level holds one-folder-per-skill (or a single\n * wrapping folder that holds them).\n */\n source: string\n /** overwrite existing target skills */\n force?: boolean\n}\n\nexport interface ImportResult {\n imported: string[]\n skipped: { name: string; reason: string }[]\n}\n\n/**\n * Extract a zip archive into a fresh temp dir with a zip-slip guard — every\n * entry's resolved path must stay under the extraction root. Returns both the\n * mkdtemp root (for cleanup) and the effective source path to hand to the\n * importer. When the archive is wrapped in a single top-level directory\n * (common with GitHub-style archives), we descend into it so `source` lines\n * up with the \"parent-of-skill-dirs\" shape the importer already understands.\n */\nfunction extractZipSafely(zipPath: string): { root: string; effectiveSource: string } {\n const root = mkdtempSync(join(tmpdir(), 'bazilion-skill-zip-'))\n try {\n const zip = new AdmZip(zipPath)\n for (const entry of zip.getEntries()) {\n const rawName = entry.entryName\n if (rawName.startsWith('/') || rawName.startsWith('\\\\')) {\n throw new Error(`zip entry has absolute path: ${rawName}`)\n }\n const resolved = resolve(root, rawName)\n if (resolved !== root && !resolved.startsWith(root + sep)) {\n throw new Error(`zip entry escapes extraction root: ${rawName}`)\n }\n }\n zip.extractAllTo(root, true)\n } catch (err) {\n rmSync(root, { recursive: true, force: true })\n throw err\n }\n\n // Unwrap a single top-level folder if present — the importer's\n // \"source-is-a-directory\" cases (single-skill dir vs. parent-of-skills dir)\n // both apply equally well to the unwrapped path.\n let effectiveSource = root\n const topEntries = readdirSync(root, { withFileTypes: true })\n if (topEntries.length === 1 && topEntries[0]?.isDirectory()) {\n effectiveSource = join(root, topEntries[0].name)\n }\n return { root, effectiveSource }\n}\n\nexport function importSkills(paths: Paths, input: ImportSkillsInput): ImportResult {\n const rawSource = resolve(input.source)\n if (!existsSync(rawSource)) {\n throw new Error(`source does not exist: ${rawSource}`)\n }\n\n let source = rawSource\n let tempRoot: string | null = null\n const sourceStat = statSync(rawSource)\n if (sourceStat.isFile()) {\n if (!rawSource.toLowerCase().endsWith('.zip')) {\n throw new Error(`source file must be a .zip archive: ${rawSource}`)\n }\n const { root, effectiveSource } = extractZipSafely(rawSource)\n tempRoot = root\n source = effectiveSource\n } else if (!sourceStat.isDirectory()) {\n throw new Error(`source is not a directory: ${rawSource}`)\n }\n\n try {\n return importSkillsFromDir(paths, source, input)\n } finally {\n if (tempRoot) rmSync(tempRoot, { recursive: true, force: true })\n }\n}\n\nfunction importSkillsFromDir(paths: Paths, source: string, input: ImportSkillsInput): ImportResult {\n const candidates: { name: string; dir: string }[] = []\n\n // Two shapes are accepted:\n // 1. source is itself a single skill dir (contains SKILL.md)\n // 2. source is a parent containing multiple skill dirs\n if (existsSync(join(source, 'SKILL.md'))) {\n candidates.push({ name: basename(source), dir: source })\n } else {\n const entries = readdirSync(source, { withFileTypes: true })\n for (const e of entries) {\n if (!e.isDirectory()) continue\n const skillDir = join(source, e.name)\n if (!existsSync(join(skillDir, 'SKILL.md'))) continue\n candidates.push({ name: e.name, dir: skillDir })\n }\n }\n\n if (candidates.length === 0) {\n throw new Error(`no skills found in ${source}`)\n }\n\n // Validate every SKILL.md before touching the target dir.\n for (const c of candidates) {\n parseSkillFile(join(c.dir, 'SKILL.md'))\n }\n\n const imported: string[] = []\n const skipped: { name: string; reason: string }[] = []\n\n for (const c of candidates) {\n const target = join(paths.skillsDir, c.name)\n if (existsSync(target) && !input.force) {\n skipped.push({\n name: c.name,\n reason: 'already exists (use --force to overwrite)',\n })\n continue\n }\n cpSync(c.dir, target, { recursive: true, force: !!input.force })\n imported.push(c.name)\n }\n\n return { imported, skipped }\n}\n","import { readFileSync } from 'node:fs'\nimport { parse as parseYaml } from 'yaml'\n\n/**\n * Standard agent-skill frontmatter. Required fields are typed; the rest is open\n * (skill formats may add fields like `allowed-tools`, `homepage`, etc.).\n */\nexport interface SkillFrontmatter {\n name: string\n description: string\n [key: string]: unknown\n}\n\nexport interface ParsedSkill {\n frontmatter: SkillFrontmatter\n body: string\n raw: string\n}\n\nconst FRONTMATTER_RE = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/\n\nexport function parseSkillContent(raw: string): ParsedSkill {\n const m = raw.match(FRONTMATTER_RE)\n if (!m) {\n throw new Error('SKILL.md missing YAML frontmatter (expected leading \"---\")')\n }\n const yamlBlock = m[1] ?? ''\n const body = m[2] ?? ''\n\n let fm: unknown\n try {\n fm = parseYaml(yamlBlock)\n } catch (err) {\n throw new Error(`SKILL.md frontmatter is not valid YAML: ${(err as Error).message}`)\n }\n if (!fm || typeof fm !== 'object' || Array.isArray(fm)) {\n throw new Error('SKILL.md frontmatter must be a YAML object')\n }\n const fmObj = fm as Record<string, unknown>\n if (typeof fmObj.name !== 'string' || fmObj.name.length === 0) {\n throw new Error('SKILL.md frontmatter missing required \"name\"')\n }\n if (typeof fmObj.description !== 'string' || fmObj.description.length === 0) {\n throw new Error('SKILL.md frontmatter missing required \"description\"')\n }\n return { frontmatter: fmObj as SkillFrontmatter, body, raw }\n}\n\nexport function parseSkillFile(path: string): ParsedSkill {\n const raw = readFileSync(path, 'utf8')\n return parseSkillContent(raw)\n}\n","import type { BazilionDb } from '../db/client.ts'\nimport type { Paths } from '../paths.ts'\nimport * as agentRepo from '../repos/agents.ts'\nimport { discoverSkills } from './discover.ts'\nimport { type ParsedSkill, parseSkillFile } from './parse.ts'\n\nexport interface ResolvedSkill {\n name: string\n dir: string\n parsed: ParsedSkill\n}\n\nexport interface ResolvedSkillSet {\n /** skills attached to the agent that exist and parse correctly */\n resolved: ResolvedSkill[]\n /** attached skill names that are missing from the library or fail to parse */\n missing: { name: string; reason: string }[]\n}\n\n/**\n * Given an agent, return the parsed skills currently attached to it. Skill\n * attachments live in `agent_skills`; the source of truth for content is\n * `~/.bazilion/skills/<name>/SKILL.md`.\n */\nexport function resolveAgentSkills(\n db: BazilionDb,\n paths: Paths,\n agentId: string,\n): ResolvedSkillSet {\n const attached = agentRepo.listAttachedSkills(db, agentId)\n const discovered = new Map(discoverSkills(paths).map((s) => [s.name, s]))\n\n const resolved: ResolvedSkill[] = []\n const missing: { name: string; reason: string }[] = []\n\n for (const name of attached) {\n const ds = discovered.get(name)\n if (!ds) {\n missing.push({ name, reason: 'not in library' })\n continue\n }\n try {\n const parsed = parseSkillFile(ds.skillFile)\n resolved.push({ name, dir: ds.dir, parsed })\n } catch (err) {\n missing.push({ name, reason: (err as Error).message })\n }\n }\n return { resolved, missing }\n}\n","import { chmodSync, existsSync, mkdirSync, writeFileSync } from 'node:fs'\nimport {\n type BazilionDb,\n openDb,\n type Paths,\n readAuthFile,\n resolvePaths,\n runMigrations,\n webTokenRepo,\n} from '../core/index.ts'\nimport { startScheduler } from './scheduler.ts'\n\nlet _db: BazilionDb | null = null\nlet _paths: Paths | null = null\nlet _authToken: string | null = null\nlet _schedulerStarted = false\n\nexport interface DaemonCtx {\n db: BazilionDb\n paths: Paths\n /**\n * Plaintext bootstrap token from `auth.json`. Used to derive the encryption\n * key for the `secrets` table — `mergeSecretsIntoEnv(db, ctx.authToken)`.\n * Cached for the process lifetime; if the user rotates the token, the\n * daemon must restart to pick it up.\n */\n authToken: string\n}\n\n/**\n * One-shot first-run bootstrap. Idempotent: every step skips itself when its\n * artifact already exists. Mints the bootstrap web_tokens row + writes the\n * plaintext into auth.json the first time we see no auth file.\n */\nfunction bootstrap(paths: Paths): { db: BazilionDb; authToken: string } {\n for (const d of [\n paths.home,\n paths.profilesDir,\n paths.agentsDir,\n paths.skillsDir,\n paths.groupsDir,\n paths.logsDir,\n ]) {\n mkdirSync(d, { recursive: true })\n }\n\n const db = openDb(paths.db)\n runMigrations(db)\n\n if (!existsSync(paths.authFile)) {\n const created = webTokenRepo.create(db, 'bootstrap')\n writeFileSync(paths.authFile, `${JSON.stringify({ token: created.token }, null, 2)}\\n`, {\n mode: 0o600,\n })\n try {\n chmodSync(paths.authFile, 0o600)\n } catch {\n // Windows: chmod is a no-op\n }\n console.log(`bazilion auto-bootstrapped at ${paths.home}`)\n console.log(`bootstrap token written to ${paths.authFile}`)\n return { db, authToken: created.token }\n }\n\n return { db, authToken: readAuthFile(paths.authFile).token }\n}\n\nexport function getCtx(): DaemonCtx {\n if (!_paths) _paths = resolvePaths()\n if (!_db || _authToken === null) {\n const result = bootstrap(_paths)\n _db = result.db\n _authToken = result.authToken\n }\n if (!_schedulerStarted && process.env.BAZILION_SCHEDULER !== 'off') {\n _schedulerStarted = true\n startScheduler()\n }\n return { db: _db, paths: _paths, authToken: _authToken }\n}\n","// In-memory registry of agents currently running a turn and their\n// AbortControllers. The chat / scheduler / inbox-wake paths register before\n// they spawn a worker; the cancel route looks the agent up and calls\n// `abort()`. Doubles as the \"is this agent busy?\" probe the scheduler uses\n// to skip overlapping inbox-wakes and triggers.\n//\n// Pinned to `globalThis` via a well-known Symbol so there is exactly one\n// instance per process even if a bundler ever splits this module across\n// chunks. Two different Map instances would make registrations invisible to\n// the cancel side.\n\nconst REGISTRY_KEY = Symbol.for('bazilion.agent-cancel.registry')\n\ninterface Registry {\n active: Map<string, AbortController>\n}\n\nfunction registry(): Registry {\n const g = globalThis as unknown as Record<symbol, Registry | undefined>\n let r = g[REGISTRY_KEY]\n if (!r) {\n r = { active: new Map() }\n g[REGISTRY_KEY] = r\n }\n return r\n}\n\nexport function registerAgent(agentId: string, controller: AbortController): void {\n registry().active.set(agentId, controller)\n}\n\nexport function unregisterAgent(agentId: string): void {\n registry().active.delete(agentId)\n}\n\n/** Returns true if the agent had an active turn that was aborted, false otherwise. */\nexport function cancelAgent(agentId: string): boolean {\n const { active } = registry()\n const c = active.get(agentId)\n if (!c) return false\n c.abort()\n active.delete(agentId)\n return true\n}\n\nexport function isActiveAgent(agentId: string): boolean {\n return registry().active.has(agentId)\n}\n","// OpenAI ChatGPT / Codex OAuth — token storage + refresh on top of pi-ai.\n//\n// Pi-ai ships a complete OAuth flow for the ChatGPT backend (`@earendil-works/pi-ai`\n// exports `loginOpenAICodex` + `refreshOpenAICodexToken`), so this module is\n// thin: it adapts the credential I/O to Bazilion's encrypted secrets store\n// and exposes a single `loadAccessToken(db, authToken)` call that refreshes\n// when the token is about to expire.\n//\n// Storage: the JSON blob `{refresh, access, expires}` lives under the\n// secrets key `OPENAI_CODEX_OAUTH` in the `secrets` table. The blob is\n// never copied into the env (unlike plain-API-key providers) — refresh is\n// stateful, so every call reads and writes through the live secrets store.\n\nimport type { OpenAICodexStatus } from '@bazilion/api-types'\nimport type { OAuthCredentials } from '@earendil-works/pi-ai'\nimport { loginOpenAICodex, refreshOpenAICodexToken } from '@earendil-works/pi-ai/oauth'\nimport { type BazilionDb, openSecrets } from '../../core/index.ts'\n\nexport const OPENAI_CODEX_SECRET_KEY = 'OPENAI_CODEX_OAUTH'\n\n/** Refresh when the access token has less than this much life left. */\nconst REFRESH_MARGIN_MS = 60_000\n\nexport interface StoredCredentials {\n refresh: string\n access: string\n expires: number\n}\n\nfunction readCredentials(db: BazilionDb, authToken: string): StoredCredentials | null {\n const raw = openSecrets(db, authToken).get(OPENAI_CODEX_SECRET_KEY)\n if (!raw) return null\n try {\n const parsed = JSON.parse(raw) as Partial<StoredCredentials>\n if (\n typeof parsed.refresh === 'string' &&\n typeof parsed.access === 'string' &&\n typeof parsed.expires === 'number'\n ) {\n return { refresh: parsed.refresh, access: parsed.access, expires: parsed.expires }\n }\n return null\n } catch {\n return null\n }\n}\n\nfunction writeCredentials(db: BazilionDb, authToken: string, creds: StoredCredentials): void {\n openSecrets(db, authToken).set(OPENAI_CODEX_SECRET_KEY, JSON.stringify(creds))\n}\n\nexport function clearCredentials(db: BazilionDb, authToken: string): void {\n openSecrets(db, authToken).remove(OPENAI_CODEX_SECRET_KEY)\n}\n\nexport function hasCredentials(db: BazilionDb, authToken: string): boolean {\n return readCredentials(db, authToken) !== null\n}\n\nfunction decodeAccountId(accessToken: string): string | null {\n const parts = accessToken.split('.')\n if (parts.length !== 3) return null\n try {\n const payload = JSON.parse(Buffer.from(parts[1] as string, 'base64').toString('utf8')) as {\n 'https://api.openai.com/auth'?: { chatgpt_account_id?: string }\n }\n return payload['https://api.openai.com/auth']?.chatgpt_account_id ?? null\n } catch {\n return null\n }\n}\n\nexport function getStatus(db: BazilionDb, authToken: string): OpenAICodexStatus {\n const creds = readCredentials(db, authToken)\n if (!creds) return { connected: false, expiresAt: null, accountId: null }\n return {\n connected: true,\n expiresAt: creds.expires,\n accountId: decodeAccountId(creds.access),\n }\n}\n\n/**\n * Returns a valid access token, refreshing via pi-ai if the stored one is\n * within `REFRESH_MARGIN_MS` of expiry. Throws when no credentials are stored\n * so callers can surface an actionable \"run `bazilion auth openai login`\"\n * error rather than a 401 from the upstream API.\n */\nexport async function loadAccessToken(db: BazilionDb, authToken: string): Promise<string> {\n const creds = readCredentials(db, authToken)\n if (!creds) {\n throw new Error(\n 'OpenAI ChatGPT OAuth not configured — run `bazilion auth openai login` (or use the Connect button on /config)',\n )\n }\n if (creds.expires > Date.now() + REFRESH_MARGIN_MS) return creds.access\n\n const refreshed = (await refreshOpenAICodexToken(creds.refresh)) as OAuthCredentials\n const next: StoredCredentials = {\n refresh: refreshed.refresh,\n access: refreshed.access,\n expires: refreshed.expires,\n }\n writeCredentials(db, authToken, next)\n return next.access\n}\n\n/** Persist credentials fetched by pi-ai's `loginOpenAICodex`. */\nexport function saveLoginCredentials(\n db: BazilionDb,\n authToken: string,\n creds: OAuthCredentials,\n): void {\n writeCredentials(db, authToken, {\n refresh: creds.refresh,\n access: creds.access,\n expires: creds.expires,\n })\n}\n\nexport { loginOpenAICodex, refreshOpenAICodexToken }\n","// Default heartbeat prompt. Users paste this constant as a trigger's\n// `message` (or call `resolveHeartbeatPrompt` with a custom one) to wire\n// HEARTBEAT.md into a scheduled wake-up without reinventing the framing.\nexport const HEARTBEAT_PROMPT =\n 'Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply HEARTBEAT_OK.'\n\nexport const DEFAULT_HEARTBEAT_EVERY_SEC = 30 * 60\n\n/**\n * A HEARTBEAT.md is \"effectively empty\" when it has no actionable task lines.\n * Whitespace, ATX headers, and stub checklist items (`- [ ]`) all count as\n * empty so we can skip a turn when the file has been left as a placeholder.\n * Missing content (undefined/null/non-string) returns false — the LLM should\n * still get a chance to act.\n */\nexport function isHeartbeatContentEffectivelyEmpty(content: string | undefined | null): boolean {\n if (typeof content !== 'string') return false\n for (const line of content.split('\\n')) {\n const trimmed = line.trim()\n if (!trimmed) continue\n if (/^#+(\\s|$)/.test(trimmed)) continue\n if (/^[-*+]\\s*(\\[[\\sXx]?\\]\\s*)?$/.test(trimmed)) continue\n return false\n }\n return true\n}\n\nexport function resolveHeartbeatPrompt(raw?: string | null): string {\n const trimmed = typeof raw === 'string' ? raw.trim() : ''\n return trimmed || HEARTBEAT_PROMPT\n}\n","import {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n rmSync,\n statSync,\n writeFileSync,\n} from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport type { MemoryEntry, MemoryHit } from '@bazilion/api-types'\nimport type { MemoryBackend } from './types.ts'\n\nconst SNIPPET_PAD = 60\n\n/**\n * Filesystem-backed memory: every entry is a file under `root`. Search is\n * substring matching across all files. Index = the filesystem itself.\n */\nexport function filesBackend(root: string): MemoryBackend {\n function safe(key: string): string {\n if (key.includes('..') || key.startsWith('/') || key.includes('\\0')) {\n throw new Error(`unsafe memory key: ${key}`)\n }\n return join(root, key)\n }\n\n function walk(dir: string, prefix: string, out: MemoryEntry[]): void {\n if (!existsSync(dir)) return\n for (const e of readdirSync(dir, { withFileTypes: true })) {\n const full = join(dir, e.name)\n const key = prefix ? `${prefix}/${e.name}` : e.name\n if (e.isDirectory()) {\n walk(full, key, out)\n } else if (e.isFile()) {\n const stats = statSync(full)\n out.push({\n key,\n content: readFileSync(full, 'utf8'),\n updatedAt: stats.mtimeMs,\n })\n }\n }\n }\n\n return {\n async init() {\n mkdirSync(root, { recursive: true })\n },\n\n async read(key) {\n const path = safe(key)\n if (!existsSync(path)) {\n throw new Error(`memory entry not found: ${key}`)\n }\n const stats = statSync(path)\n return {\n key,\n content: readFileSync(path, 'utf8'),\n updatedAt: stats.mtimeMs,\n }\n },\n\n async write(key, content) {\n const path = safe(key)\n mkdirSync(dirname(path), { recursive: true })\n writeFileSync(path, content)\n const stats = statSync(path)\n return { key, content, updatedAt: stats.mtimeMs }\n },\n\n async search(query, opts) {\n const limit = opts?.limit ?? 10\n const all: MemoryEntry[] = []\n walk(root, '', all)\n const q = query.toLowerCase()\n const hits: MemoryHit[] = []\n for (const entry of all) {\n const idx = entry.content.toLowerCase().indexOf(q)\n if (idx === -1) continue\n const start = Math.max(0, idx - SNIPPET_PAD)\n const end = Math.min(entry.content.length, idx + query.length + SNIPPET_PAD)\n hits.push({\n key: entry.key,\n snippet: entry.content.slice(start, end),\n score: 1,\n })\n }\n return hits.slice(0, limit)\n },\n\n async list() {\n const out: MemoryEntry[] = []\n walk(root, '', out)\n return out.sort((a, b) => a.key.localeCompare(b.key))\n },\n\n async remove(key) {\n const path = safe(key)\n if (existsSync(path)) rmSync(path)\n },\n }\n}\n","import {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n rmSync,\n statSync,\n writeFileSync,\n} from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport type { MemoryEntry, MemoryHit } from '@bazilion/api-types'\nimport { createStore, extractSnippet, type QMDStore } from '@tobilu/qmd'\nimport type { MemoryBackend } from './types.ts'\n\nconst INDEX_FILENAME = '.qmd-index.sqlite'\nconst COLLECTION_NAME = 'memory'\nconst PATTERN = '**/*.md'\n\n// One store per memory directory per process. createStore opens a SQLite\n// handle; we dedupe so concurrent chat requests for the same agent reuse it.\nconst storeCache = new Map<string, Promise<QMDStore>>()\n\nfunction getStore(dir: string): Promise<QMDStore> {\n let p = storeCache.get(dir)\n if (!p) {\n p = createStore({\n dbPath: join(dir, INDEX_FILENAME),\n config: {\n collections: {\n [COLLECTION_NAME]: { path: dir, pattern: PATTERN },\n },\n },\n })\n storeCache.set(dir, p)\n }\n return p\n}\n\nfunction safeKey(root: string, key: string): string {\n if (key.includes('..') || key.startsWith('/') || key.includes('\\0')) {\n throw new Error(`unsafe memory key: ${key}`)\n }\n return join(root, key)\n}\n\nfunction walkMd(dir: string, prefix: string, out: MemoryEntry[]): void {\n if (!existsSync(dir)) return\n for (const e of readdirSync(dir, { withFileTypes: true })) {\n if (e.name.startsWith('.')) continue // skip .qmd-index.sqlite and friends\n const full = join(dir, e.name)\n const key = prefix ? `${prefix}/${e.name}` : e.name\n if (e.isDirectory()) {\n walkMd(full, key, out)\n } else if (e.isFile() && e.name.endsWith('.md')) {\n const stats = statSync(full)\n out.push({\n key,\n content: readFileSync(full, 'utf8'),\n updatedAt: stats.mtimeMs,\n })\n }\n }\n}\n\n/**\n * Memory backend backed by @tobilu/qmd — BM25 keyword search over markdown\n * files under `root`. Writes markdown to disk, then asks qmd to reindex.\n *\n * Uses `searchLex` only; no embeddings, no LLM rerank, no model download.\n * The hybrid `search()` / `searchVector()` paths exist in the qmd SDK and\n * can be wired in later if we want semantic search — they'd add a dependency\n * on `node-llama-cpp` and several GB of GGUF models.\n */\nexport function qmdBackend(root: string): MemoryBackend {\n return {\n async init() {\n mkdirSync(root, { recursive: true })\n // Opening the store + initial scan. update() is idempotent.\n const store = await getStore(root)\n await store.update()\n },\n\n async read(key) {\n const path = safeKey(root, key)\n if (!existsSync(path)) {\n throw new Error(`memory entry not found: ${key}`)\n }\n const stats = statSync(path)\n return {\n key,\n content: readFileSync(path, 'utf8'),\n updatedAt: stats.mtimeMs,\n }\n },\n\n async write(key, content) {\n const path = safeKey(root, key)\n mkdirSync(dirname(path), { recursive: true })\n writeFileSync(path, content)\n const stats = statSync(path)\n // Reindex so the newly-written file is searchable on the next search().\n // update() re-scans the collection; for typical memory sizes (tens of\n // files) this is sub-millisecond.\n const store = await getStore(root)\n await store.update()\n return { key, content, updatedAt: stats.mtimeMs }\n },\n\n async search(query, opts) {\n const limit = opts?.limit ?? 10\n const store = await getStore(root)\n const results = await store.searchLex(query, {\n limit,\n collection: COLLECTION_NAME,\n })\n const hits: MemoryHit[] = []\n for (const r of results) {\n // qmd's filepath is a synthetic URI (`qmd://<collection>/<path>`);\n // displayPath is collection-prefixed (`<collection>/<path>`). Strip\n // the leading `<collection>/` to get the key the caller wrote.\n const prefix = `${COLLECTION_NAME}/`\n const key = r.displayPath.startsWith(prefix)\n ? r.displayPath.slice(prefix.length)\n : r.displayPath\n let content = r.body ?? ''\n if (!content) {\n try {\n content = readFileSync(join(root, key), 'utf8')\n } catch {\n content = ''\n }\n }\n const snippet = extractSnippet(content, query).snippet\n hits.push({ key, snippet, score: r.score })\n }\n return hits\n },\n\n async list() {\n const out: MemoryEntry[] = []\n walkMd(root, '', out)\n return out.sort((a, b) => a.key.localeCompare(b.key))\n },\n\n async remove(key) {\n const path = safeKey(root, key)\n if (existsSync(path)) rmSync(path)\n const store = await getStore(root)\n await store.update()\n },\n }\n}\n","// Translator: pi `AgentSessionEvent` → Bazilion `SessionEvent[]`.\n//\n// The worker's NDJSON wire format (`ChatFrame`) is still the same discrete\n// event stream CLI / browser clients know how to render. This module is the\n// adapter at the single choke-point — pi event in, zero-or-more Bazilion\n// events out.\n//\n// Coverage:\n// - user message_start → one `user_message`\n// - assistant text_delta → one `assistant_delta` per chunk\n// - assistant message_end:\n// - if the message carries text → one `assistant_message`\n// - for every tool-call content → one `tool_call`\n// - tool_execution_end → `tool_result` or `tool_error` based on isError\n// - message_end with aborted/error stopReason → one `error`\n//\n// Not surfaced (intentional):\n// - agent_start / agent_end — run-row lifecycle, not chat events\n// - turn_start / turn_end — too chatty, nothing to render\n// - message_start (assistant) — text will come via updates + end\n// - message_update (non-text) — thinking deltas etc; left for a later\n// pass when UIs render thinking blocks\n// - queue_update / compaction_* — session meta, not assistant output\n// - auto_retry_* — silently retried, user sees only the\n// eventual success or failure\n\nimport type { ProviderMessage, SessionEvent, ToolCall } from '@bazilion/api-types'\nimport type { AgentMessage, AgentToolResult } from '@earendil-works/pi-agent-core'\nimport type { AssistantMessage } from '@earendil-works/pi-ai'\nimport type { AgentSessionEvent } from '@earendil-works/pi-coding-agent'\n\nexport function translatePiEvent(e: AgentSessionEvent): SessionEvent[] {\n switch (e.type) {\n case 'message_start': {\n if (e.message.role === 'user') {\n return [{ type: 'user_message', text: stringifyContent(e.message.content) }]\n }\n return []\n }\n\n case 'message_update': {\n const inner = e.assistantMessageEvent\n if (inner.type === 'text_delta') {\n return [{ type: 'assistant_delta', delta: inner.delta }]\n }\n return []\n }\n\n case 'message_end': {\n const m = e.message\n if (m.role !== 'assistant') return []\n const out: SessionEvent[] = []\n const text = extractAssistantText(m as AssistantMessage)\n if (text) out.push({ type: 'assistant_message', text })\n for (const block of (m as AssistantMessage).content ?? []) {\n if (block.type === 'toolCall') {\n out.push({\n type: 'tool_call',\n id: block.id,\n name: block.name,\n arguments: JSON.stringify(block.arguments ?? {}),\n })\n }\n }\n const stopReason = (m as AssistantMessage).stopReason\n if (stopReason === 'aborted' || stopReason === 'error') {\n const errText = (m as AssistantMessage).errorMessage ?? stopReason\n out.push({ type: 'error', error: errText })\n }\n return out\n }\n\n case 'tool_execution_end': {\n const text = extractToolResultText(e.result)\n if (e.isError) {\n return [{ type: 'tool_error', id: e.toolCallId, name: e.toolName, error: text }]\n }\n return [{ type: 'tool_result', id: e.toolCallId, name: e.toolName, result: text }]\n }\n\n default:\n return []\n }\n}\n\nexport function extractAssistantText(m: AssistantMessage): string {\n let out = ''\n for (const block of m.content ?? []) {\n if (block.type === 'text') out += block.text\n }\n return out\n}\n\nexport function extractAssistantToolCalls(m: AssistantMessage): ToolCall[] {\n const out: ToolCall[] = []\n for (const block of m.content ?? []) {\n if (block.type === 'toolCall') {\n out.push({ id: block.id, name: block.name, arguments: JSON.stringify(block.arguments ?? {}) })\n }\n }\n return out\n}\n\n/** Flatten `AgentToolResult.content` blocks into a single string — matches the\n * shape Bazilion tools always returned before pi adoption. */\nexport function extractToolResultText(result: unknown): string {\n const r = result as AgentToolResult<unknown> | undefined\n if (!r?.content) return ''\n let out = ''\n for (const block of r.content) {\n if (block.type === 'text') out += block.text\n }\n return out\n}\n\n/** Stringify a pi user-message content array. */\nfunction stringifyContent(content: unknown): string {\n if (typeof content === 'string') return content\n if (!Array.isArray(content)) return ''\n let out = ''\n for (const block of content as { type: string; text?: string }[]) {\n if (block.type === 'text' && typeof block.text === 'string') out += block.text\n }\n return out\n}\n\n/**\n * Convert pi's authoritative `session.state.messages` (AgentMessage[]) into\n * Bazilion's ProviderMessage[] shape, so the `done` ChatFrame stays\n * compatible with browser + CLI clients that rehydrate from it.\n *\n * Notes on role mapping: pi uses `\"toolResult\"` for tool-response messages;\n * Bazilion uses `\"tool\"`. AssistantMessage content arrays become either\n * `content` string (text blocks joined) or a `toolCalls` array (toolCall\n * blocks converted).\n */\nexport function piMessagesToProviderView(messages: AgentMessage[]): ProviderMessage[] {\n const out: ProviderMessage[] = []\n for (const m of messages) {\n // Custom Bazilion message types would land in this switch too, but we\n // don't register any via CustomAgentMessages declaration merging yet.\n switch (m.role) {\n case 'user': {\n out.push({ role: 'user', content: stringifyContent((m as { content: unknown }).content) })\n break\n }\n case 'assistant': {\n const am = m as AssistantMessage\n const text = extractAssistantText(am)\n const toolCalls = extractAssistantToolCalls(am)\n const msg: ProviderMessage = { role: 'assistant', content: text }\n if (toolCalls.length > 0) msg.toolCalls = toolCalls\n out.push(msg)\n break\n }\n case 'toolResult': {\n const tr = m as { content: unknown; toolCallId?: string; toolName?: string }\n out.push({\n role: 'tool',\n content: stringifyContent(tr.content),\n toolCallId: tr.toolCallId,\n toolName: tr.toolName,\n })\n break\n }\n default:\n // System and other unknown roles are skipped — the runtime's system\n // prompt is already wired via pi's settingsManager + our buildSystemPrompt.\n break\n }\n }\n return out\n}\n","// Bazilion → pi-coding-agent session bridge.\n//\n// `createBazilionSession` returns a fully-wired `AgentSession` suitable for\n// calling `session.prompt(text)` / `session.compact(instructions)` / etc.\n//\n// What we take ownership of (and hand to pi):\n// - cwd: the agent's default workspace path (or agent.dir as a degenerate\n// fallback when no workspace is mounted). Pi's built-in `read/bash/edit/\n// write/grep/find/ls` tools are rooted here.\n// - agentDir: `<bazilion-home>/pi` — pi writes transient state here\n// (settings overrides, resource caches). We don't share it with the\n// user's global `~/.pi/agent` so a Bazilion install never clobbers an\n// independent pi CLI install.\n// - authStorage: `InMemoryAuthStorageBackend` pre-seeded with the resolved\n// API key for the agent's current provider. We never let pi read/write\n// its own auth file — secrets live in the daemon-owned `secrets` table\n// and reach us via `opts.apiKey` (initial) + `opts.refreshApiKey`\n// (OAuth refresher for long turns).\n// - modelRegistry: in-memory. Native providers (anthropic/openai/google/…)\n// come from pi's bundled catalog. For Bazilion-only providers\n// (`lmstudio`, `ollama`) we call `registerProvider(name, {baseUrl,\n// api: 'openai-completions', authHeader: false})` — matches the\n// openai-completions shim our pi-adapter has been using.\n// - sessionManager: `SessionManager.create(cwd, <agentDir>/sessions)`\n// writing JSONL to `~/.bazilion/agents/<id>/sessions/<sessionId>.jsonl`.\n// Crash-survival, append-only, branching, compaction entries — all owned\n// by pi now. Replaces our `agents.chat_messages` blob.\n// - settingsManager: in-memory. Bazilion controls auto-compaction\n// (disabled — we compact manually on user request via /compact) and\n// retry (enabled with Bazilion-tuned caps).\n//\n// What stays outside pi's purview:\n// - spawning agents / profiles / skills discovery (core/)\n// - workspaces registry & mount tracking (core/)\n// - inter-agent messaging, triggers, scheduler (core + apps/web)\n// - memory backend (we wrap it as a pi customTool via `createBazilionCustomTools`)\n\nimport { existsSync, mkdirSync, readdirSync, statSync } from 'node:fs'\nimport { basename, join } from 'node:path'\nimport type { ResolvedAgent } from '@bazilion/api-types'\nimport type { AgentMessage, ThinkingLevel } from '@earendil-works/pi-agent-core'\nimport {\n type AgentSession,\n AuthStorage,\n createAgentSession,\n createExtensionRuntime,\n ModelRegistry,\n type ResourceLoader,\n SessionManager,\n SettingsManager,\n} from '@earendil-works/pi-coding-agent'\nimport type { BazilionDb, Paths } from '../../core/index.ts'\nimport { providerStateRepo } from '../../core/index.ts'\nimport type { MemoryBackend } from '../memory/types.ts'\nimport { resolveModel as resolvePiModel } from '../providers/pi-adapter.ts'\nimport { createProviderRegistry, loadProviderConfigFromEnv } from '../providers/registry.ts'\nimport { buildSystemPrompt } from '../session/prompt.ts'\nimport type { MessagingHost, UserMdHost } from '../worker/ipc-protocol.ts'\nimport { createBazilionCustomTools } from './tools.ts'\n\nconst BUILTIN_TOOL_NAMES = ['read', 'bash', 'edit', 'write', 'grep', 'find', 'ls'] as const\n\nexport interface CreateBazilionSessionOptions {\n agent: ResolvedAgent\n paths: Paths\n /** Merged env (process.env + secrets) — produced via `mergeSecretsIntoEnv`. */\n env: NodeJS.ProcessEnv\n memory: MemoryBackend\n /**\n * Names of providers the user has explicitly enabled in /config.\n * Empty set means \"no per-provider gating configured\" — all providers pass.\n * Pre-computed by the daemon and handed in so the session never has to\n * touch the SQLite `provider_state` table itself.\n */\n enabledProviders: Set<string>\n /**\n * Optional host for inter-agent messaging. Wired from the worker's IPC\n * channel back to the daemon — workers no longer hold a SQLite handle of\n * their own. Omit to disable the messaging tools entirely (e.g. unit\n * tests that don't exercise inbox flows).\n */\n messagingHost?: MessagingHost\n /**\n * Optional host for the group-shared USER.md append tool. Like\n * `messagingHost`, this is wired via the worker's IPC channel. Omit to\n * disable the `user_md_append` tool.\n */\n userMdHost?: UserMdHost\n /**\n * Optional explicit API key for the agent's provider. Wins over any value\n * derived from `env`. Required for OAuth-backed providers (`openai-codex`)\n * since their credentials live in the daemon-owned `secrets` table, not\n * in env vars.\n */\n apiKey?: string\n /**\n * Optional callback for OAuth-backed providers whose access tokens may\n * expire mid-turn. When provided, pi calls it to refresh the JWT during\n * long tool-execution loops. Daemon-side callers (compact/context/truncate)\n * wire this directly against the secrets repo; worker turns currently\n * skip it (the initial token from `apiKey` carries the whole turn).\n */\n refreshApiKey?: (providerName: string) => Promise<string>\n /**\n * Session id to resume. When omitted, pi starts a fresh session file.\n * `/reset` passes `undefined` to rotate; normal chat passes the agent's\n * current session id (persisted on the Bazilion side as `agents.session_id`\n * if we later add that column — today we just restore the most recent\n * session file, which pi's SessionManager locates automatically).\n */\n sessionId?: string\n}\n\nexport interface BazilionSessionHandle {\n session: AgentSession\n /** Call when done — disposes listeners + closes the pi session. */\n dispose(): void\n}\n\n/**\n * Build a pi `AgentSession` using Bazilion's resolved agent + provider state.\n * The returned session is ready for `prompt()` / `compact()` / `reset()`.\n */\nexport async function createBazilionSession(\n opts: CreateBazilionSessionOptions,\n): Promise<BazilionSessionHandle> {\n const { agent, paths, env, memory, enabledProviders, messagingHost, userMdHost, refreshApiKey } =\n opts\n\n const { providerName, modelId } = splitModelString(agent.model)\n\n // Enabled-set gate — mirrors createProviderRegistry's check. We keep the\n // Bazilion-side enabled/disabled /config toggles authoritative even though\n // pi does its own provider resolution: we simply refuse to build a session\n // for a disabled provider. The set is pre-computed by the daemon (the\n // worker has no SQLite handle of its own).\n if (enabledProviders.size > 0 && !enabledProviders.has(providerName)) {\n throw new Error(`${providerName} provider is disabled — enable it on the /config page`)\n }\n\n // Build the pi Model<Api>. This reuses the same catalog-lookup + literal-\n // fallback that the pi-adapter uses for Provider.chat today, so `lmstudio:\n // any-model` / unreleased OpenAI models / etc. keep working.\n const piProviderName = mapProviderName(providerName)\n const model = resolvePiModel(\n {\n providerName,\n piProviderName,\n fallbackApi: pickFallbackApi(providerName),\n baseUrl: resolveBaseUrl(providerName, env),\n },\n modelId,\n )\n\n // Resolve the API key. Caller-supplied `opts.apiKey` wins (the daemon\n // passes pre-fetched OAuth tokens for `openai-codex` here); otherwise\n // fall back to the env-derived key. Pi's AuthStorage is in-memory only —\n // we never write `auth.json`. `setRuntimeApiKey` is the process-scoped\n // override hook AuthStorage exposes for exactly this.\n const apiKey = opts.apiKey ?? resolveApiKey(providerName, env)\n\n const authStorage = AuthStorage.inMemory()\n if (apiKey) {\n authStorage.setRuntimeApiKey(piProviderName, apiKey)\n }\n\n const modelRegistry = ModelRegistry.inMemory(authStorage)\n // Bazilion-only providers aren't in pi's bundled catalog; register them\n // dynamically so ModelRegistry accepts the Model<> object + resolves auth.\n if (providerName === 'lmstudio' || providerName === 'ollama') {\n modelRegistry.registerProvider(piProviderName, {\n baseUrl: model.baseUrl,\n api: 'openai-completions',\n authHeader: false,\n apiKey: apiKey ?? 'dummy',\n })\n }\n\n // cwd for pi's coding tools is the agent's group directory. Every agent\n // belongs to exactly one group; the group's filesystem root is where work\n // product lives and where the agent's `read`/`bash`/`edit`/`write` are\n // rooted. Private identity/soul files live in `agent.dir` and are reached\n // through the scoped `home_*` tools, not via cwd.\n const cwd = agent.group.path\n if (!existsSync(cwd)) mkdirSync(cwd, { recursive: true })\n\n // Session file under the agent's own directory. Keeping it under\n // `agents/<id>/sessions/` makes `bazilion uninstall` (data tier) already\n // clean them up without changes.\n //\n // Resume-or-create: pi's SessionManager has no built-in \"latest session\"\n // opener. We walk the session dir for the newest `.jsonl` and open it;\n // fall back to `create()` when none exists (fresh agent or post-/reset).\n // This is what makes turn-to-turn continuity work: each worker turn picks\n // up where the last one left off.\n const sessionDir = join(paths.agentDir(agent.agent.id), 'sessions')\n mkdirSync(sessionDir, { recursive: true })\n const existing = findMostRecent(sessionDir)\n const sessionManager = existing\n ? SessionManager.open(existing, sessionDir, cwd)\n : SessionManager.create(cwd, sessionDir)\n\n // In-memory settings: auto-compaction off (we trigger compaction manually\n // via /compact), retry on with Bazilion-tuned caps matching what withRetry\n // used to apply before pi-adoption.\n const settingsManager = SettingsManager.inMemory({\n compaction: { enabled: false },\n retry: {\n enabled: true,\n maxRetries: 2,\n baseDelayMs: 500,\n provider: { maxRetryDelayMs: 8_000 },\n },\n })\n\n // Bazilion-authored system prompt becomes an `appendSystemPrompt` entry.\n // Pi keeps its default base (which lists built-in tools + guidelines), our\n // profile content (SOUL.md / IDENTITY.md / workspaces / memory hint) is\n // concatenated after it. This is the same injection hook pi extensions use.\n const bazilionPrompt = buildSystemPrompt(agent)\n const resourceLoader = createBazilionResourceLoader(bazilionPrompt)\n await resourceLoader.reload()\n\n // Tool allowlist: pi's `tools` option is exclusive when provided — only\n // the listed names are enabled, regardless of what's in `customTools`.\n // So we have to enumerate both pi's built-in coding tools *and* every\n // Bazilion custom tool we want the LLM to see. Missing the custom names\n // from the allowlist would silently drop memory/messaging/web/bootstrap\n // tools from the agent's surface.\n const customTools = createBazilionCustomTools({ agent, memory, messagingHost, userMdHost, env })\n const allowedTools = [...BUILTIN_TOOL_NAMES, ...customTools.map((t) => t.name)]\n\n const { session } = await createAgentSession({\n cwd,\n agentDir: join(paths.home, 'pi'),\n model,\n thinkingLevel: toPiThinkingLevel(agent.reasoningLevel),\n tools: allowedTools,\n customTools,\n sessionManager,\n settingsManager,\n authStorage,\n modelRegistry,\n resourceLoader,\n })\n\n // OAuth providers: wire pi's per-request `getApiKey` callback so the JWT\n // gets refreshed *during* a long tool-execution loop, not just at the\n // start of the turn. This is exactly the use case pi-agent-core's doc\n // calls out for this hook (\"short-lived OAuth tokens that may expire\n // during long-running tool execution phases\"). Caller supplies the\n // refresher because only they have access to the secrets table.\n if (refreshApiKey) {\n session.agent.getApiKey = async (requestedProvider) => {\n if (requestedProvider !== piProviderName) return undefined\n try {\n return await refreshApiKey(providerName)\n } catch {\n // Stale/removed credentials mid-session → return undefined so pi\n // surfaces a \"no auth\" error cleanly instead of us throwing out of\n // the provider callback (which would drag down the whole turn).\n return undefined\n }\n }\n }\n\n return {\n session,\n dispose() {\n session.dispose()\n },\n }\n}\n\n// --- helpers ---\n\nfunction splitModelString(s: string): { providerName: string; modelId: string } {\n const idx = s.indexOf(':')\n if (idx === -1) {\n throw new Error(`invalid model string \"${s}\": expected \"provider:model\"`)\n }\n return { providerName: s.slice(0, idx), modelId: s.slice(idx + 1) }\n}\n\n/**\n * Map Bazilion provider names to pi's canonical `piProviderName` for catalog\n * lookups. The split exists because Bazilion was registering e.g. `bedrock`\n * but pi catalogs it as `amazon-bedrock`.\n */\nfunction mapProviderName(name: string): string {\n if (name === 'bedrock') return 'amazon-bedrock'\n return name\n}\n\nfunction pickFallbackApi(providerName: string): string {\n switch (providerName) {\n case 'anthropic':\n return 'anthropic-messages'\n case 'google':\n return 'google-generative-ai'\n case 'google-vertex':\n return 'google-vertex'\n case 'azure-openai':\n return 'azure-openai-responses'\n case 'bedrock':\n return 'bedrock-converse-stream'\n case 'openai-codex':\n return 'openai-codex-responses'\n default:\n return 'openai-completions'\n }\n}\n\nfunction resolveBaseUrl(providerName: string, env: NodeJS.ProcessEnv): string | undefined {\n if (providerName === 'lmstudio') return env.LMSTUDIO_URL ?? 'http://127.0.0.1:1234/v1'\n if (providerName === 'ollama') return env.OLLAMA_URL ?? 'http://127.0.0.1:11434/v1'\n return undefined\n}\n\nfunction resolveApiKey(providerName: string, env: NodeJS.ProcessEnv): string | undefined {\n // Hand-written table mirroring loadProviderConfigFromEnv — cheaper than\n // spinning up a whole ProviderRegistry just to pluck one field.\n switch (providerName) {\n case 'anthropic':\n return env.ANTHROPIC_OAUTH_TOKEN ?? env.ANTHROPIC_API_KEY\n case 'openai':\n return env.OPENAI_API_KEY\n case 'google':\n return env.GEMINI_API_KEY\n case 'mistral':\n return env.MISTRAL_API_KEY\n case 'groq':\n return env.GROQ_API_KEY\n case 'cerebras':\n return env.CEREBRAS_API_KEY\n case 'xai':\n return env.XAI_API_KEY\n case 'zai':\n return env.ZAI_API_KEY\n case 'huggingface':\n return env.HF_TOKEN\n case 'openrouter':\n return env.OPENROUTER_API_KEY\n case 'vercel-ai-gateway':\n return env.AI_GATEWAY_API_KEY\n case 'azure-openai':\n return env.AZURE_OPENAI_API_KEY\n case 'lmstudio':\n return env.LMSTUDIO_API_KEY ?? 'lm-studio'\n case 'ollama':\n return env.OLLAMA_API_KEY ?? 'ollama'\n default:\n return undefined\n }\n}\n\nfunction toPiThinkingLevel(level: string): ThinkingLevel {\n switch (level) {\n case 'off':\n case 'minimal':\n case 'low':\n case 'medium':\n case 'high':\n case 'xhigh':\n return level\n default:\n return 'medium'\n }\n}\n\n/**\n * Minimal `ResourceLoader` implementation — feeds pi our Bazilion-authored\n * system prompt block via `getAppendSystemPrompt` and returns empty collections\n * for everything else. Pi's default loader reads skill/prompt/theme markdown\n * from the workspace cwd; we intentionally opt out because Bazilion owns skill\n * discovery at the platform level (see `apps/daemon/src/core/skills`).\n */\nfunction createBazilionResourceLoader(appendSystemPrompt: string): ResourceLoader {\n const extensions = { extensions: [], errors: [], runtime: createExtensionRuntime() }\n return {\n getExtensions: () => extensions,\n getSkills: () => ({ skills: [], diagnostics: [] }),\n getPrompts: () => ({ prompts: [], diagnostics: [] }),\n getThemes: () => ({ themes: [], diagnostics: [] }),\n getAgentsFiles: () => ({ agentsFiles: [] }),\n getSystemPrompt: () => undefined,\n getAppendSystemPrompt: () => (appendSystemPrompt ? [appendSystemPrompt] : []),\n extendResources: () => {},\n async reload() {},\n }\n}\n\n/**\n * Re-exported for callers that want to check whether a provider is\n * Bazilion-enabled before even trying to spawn a session (e.g. /context\n * endpoint which builds a session just to enumerate tools).\n */\nexport function isProviderEnabled(db: BazilionDb, providerName: string): boolean {\n const enabled = providerStateRepo.listEnabled(db)\n return enabled.size === 0 || enabled.has(providerName)\n}\n\n/**\n * Escape hatch for callers that need the raw provider registry (e.g. the\n * current /api/providers/test endpoint). Keeps that one endpoint on our\n * existing non-pi path until we migrate it in a follow-up.\n */\nexport function loadEnabledRegistry(db: BazilionDb, authToken: string, env: NodeJS.ProcessEnv) {\n return createProviderRegistry(loadProviderConfigFromEnv(env, { db, authToken }), {\n enabledSet: providerStateRepo.listEnabled(db),\n })\n}\n\n/**\n * Read the most recent session file for an agent *without* spawning a full\n * AgentSession, and return the resolved provider-message view. Used for SSR\n * page loads that only need to render the canonical transcript — no need\n * to boot pi just to inspect the transcript.\n *\n * Returns an empty array when the agent has no prior session (fresh spawn,\n * or post-/reset).\n */\nexport function loadInitialMessages(agent: ResolvedAgent, paths: Paths): AgentMessage[] {\n const sessionDir = join(paths.agentDir(agent.agent.id), 'sessions')\n if (!existsSync(sessionDir)) return []\n const cwd = agent.group.path\n if (!existsSync(cwd)) return []\n const recent = findMostRecent(sessionDir)\n if (!recent) return []\n try {\n const sm = SessionManager.open(recent, sessionDir)\n const ctx = sm.buildSessionContext()\n return ctx.messages\n } catch (err) {\n // Corrupt session file, stale format, or pi version bump — log loud\n // enough that an operator noticing a blank chat can find the cause in\n // server logs. The turn loop itself starts a fresh session on the\n // next message, so this isn't load-bearing for writes, only reads.\n console.error(\n `[session] loadInitialMessages failed for agent ${agent.agent.id} (${recent}):`,\n err instanceof Error ? (err.stack ?? err.message) : err,\n )\n return []\n }\n}\n\n/**\n * Cheap \"has the session changed?\" probe for polling clients (the web chat\n * stale-tab banner). Returns the most recent session file's basename plus\n * byte size — append-only JSONL, so either value moving means new activity.\n * Returns `{ file: null, size: 0 }` for agents that have never had a turn.\n */\nexport function loadSessionHead(\n agent: ResolvedAgent,\n paths: Paths,\n): { file: string | null; size: number } {\n const sessionDir = join(paths.agentDir(agent.agent.id), 'sessions')\n if (!existsSync(sessionDir)) return { file: null, size: 0 }\n const recent = findMostRecent(sessionDir)\n if (!recent) return { file: null, size: 0 }\n try {\n const s = statSync(recent)\n return { file: basename(recent), size: s.size }\n } catch {\n return { file: null, size: 0 }\n }\n}\n\n/**\n * Test helper: seed a pi session file for an agent with `n` synthetic\n * user/assistant message pairs. Writes a real JSONL entry tree via\n * SessionManager so round-tripping through pi's own reader stays honest.\n * Exported from runtime rather than lived in tests because tests in apps/cli\n * can't directly import pi packages (not a direct dep).\n */\nexport function seedSessionForTest(\n agent: ResolvedAgent,\n paths: Paths,\n messages: Array<{ role: 'user' | 'assistant'; text: string }>,\n): void {\n const cwd = agent.group.path\n if (!existsSync(cwd)) mkdirSync(cwd, { recursive: true })\n const sessionDir = join(paths.agentDir(agent.agent.id), 'sessions')\n mkdirSync(sessionDir, { recursive: true })\n const sm = SessionManager.create(cwd, sessionDir)\n const now = Date.now()\n messages.forEach((m, i) => {\n if (m.role === 'user') {\n sm.appendMessage({\n role: 'user',\n content: [{ type: 'text', text: m.text }],\n timestamp: now + i,\n })\n } else {\n sm.appendMessage({\n role: 'assistant',\n content: [{ type: 'text', text: m.text }],\n api: 'openai-completions',\n provider: 'lmstudio',\n model: 'test-model',\n usage: {\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheWrite: 0,\n totalTokens: 0,\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n },\n stopReason: 'stop',\n timestamp: now + i,\n })\n }\n })\n}\n\n/**\n * Test helper: count message entries on the current leaf's branch of the\n * agent's most-recent session file. Returns 0 when no session file exists.\n */\nexport function countSessionMessagesForTest(agent: ResolvedAgent, paths: Paths): number {\n const sessionDir = join(paths.agentDir(agent.agent.id), 'sessions')\n const recent = findMostRecent(sessionDir)\n if (!recent) return 0\n const cwd = agent.group.path\n try {\n const sm = SessionManager.open(recent, sessionDir, cwd)\n return sm.getBranch().filter((e) => e.type === 'message').length\n } catch {\n return 0\n }\n}\n\n/** Newest `.jsonl` in a pi session directory by mtime, or null if empty. */\nfunction findMostRecent(sessionDir: string): string | null {\n if (!existsSync(sessionDir)) return null\n let newest: { path: string; mtimeMs: number } | null = null\n for (const entry of readdirSync(sessionDir)) {\n if (!entry.endsWith('.jsonl')) continue\n const path = join(sessionDir, entry)\n try {\n const s = statSync(path)\n if (!newest || s.mtimeMs > newest.mtimeMs) newest = { path, mtimeMs: s.mtimeMs }\n } catch {\n // ignore races\n }\n }\n return newest?.path ?? null\n}\n","// Adapter from Bazilion's Provider interface → pi-ai's streamSimple.\n//\n// Pi-ai (`@earendil-works/pi-ai`) is Mario Zechner's unified LLM SDK — 15+\n// providers behind one event-stream API. This file is the only place in the\n// codebase that touches pi-ai directly; everything else downstream\n// (`runTurnStream`, `persistRun`, the worker entry, CLI, web) sees the same\n// `Provider.chat(ProviderRequest): Promise<ProviderResponse>` contract it\n// always has. That keeps the wire format, DB schema, and chat UI stable while\n// giving us cost/usage, thinking levels, prompt caching, and every provider\n// pi supports — for free.\n//\n// Model resolution: we prefer pi's typed catalog via `getModel(provider, id)`\n// which carries cost + context-window metadata; for anything outside the\n// catalog (local models, newly-released models, custom OpenAI-compat\n// endpoints) we construct a `Model<>` literal with sensible defaults. This\n// preserves Bazilion's \"any model string\" flexibility.\n\nimport type { ProviderMessage, ReasoningLevel, ToolCall, ToolDef } from '@bazilion/api-types'\nimport {\n type AssistantMessage,\n getModel,\n type Model,\n type Message as PiMessage,\n type Tool as PiTool,\n type ToolCall as PiToolCall,\n streamSimple,\n type TextContent,\n Type,\n} from '@earendil-works/pi-ai'\nimport type { Provider, ProviderRequest, ProviderResponse, StopReason } from './types.ts'\n\nexport interface PiProviderConfig {\n /** Display name on the returned Provider; also the registry key (e.g. 'bedrock', 'azure-openai'). */\n providerName: string\n /** Pi's canonical provider name for catalog lookup (e.g. 'amazon-bedrock', 'azure-openai-responses'). Defaults to providerName. */\n piProviderName?: string\n /** Override baseUrl for openai-compat endpoints (lmstudio, ollama, custom). */\n baseUrl?: string\n /**\n * Static key or an async supplier. Suppliers are called at the top of each\n * chat() so OAuth-backed providers can refresh expiring tokens without\n * rebuilding the Provider instance (which the registry caches).\n */\n apiKey?: string | (() => string | Promise<string>)\n /** Which pi `Api` to use when the model isn't in pi's catalog. */\n fallbackApi: string\n}\n\nfunction defaultBaseUrlFor(providerName: string): string {\n switch (providerName) {\n case 'lmstudio':\n return process.env.LMSTUDIO_URL ?? 'http://127.0.0.1:1234/v1'\n case 'ollama':\n return process.env.OLLAMA_URL ?? 'http://127.0.0.1:11434/v1'\n default:\n return ''\n }\n}\n\nfunction buildModelLiteral(cfg: PiProviderConfig, modelId: string): Model<string> {\n return {\n id: modelId,\n name: modelId,\n api: cfg.fallbackApi,\n provider: cfg.providerName,\n baseUrl: cfg.baseUrl ?? defaultBaseUrlFor(cfg.providerName),\n reasoning: false,\n input: ['text'],\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n contextWindow: 32_768,\n maxTokens: 4_096,\n }\n}\n\nexport function resolveModel(cfg: PiProviderConfig, modelId: string): Model<string> {\n const lookupName = cfg.piProviderName ?? cfg.providerName\n // Try pi's typed catalog first — gets us cost, context window, reasoning flags\n // for free on the known providers' known models.\n try {\n // getModel's type signature is catalog-constrained, but at runtime it just\n // indexes MODELS[provider][id]. Cast through unknown so unknown ids fall\n // through to the literal builder instead of tripping the compiler.\n const known = (getModel as unknown as (p: string, m: string) => Model<string> | undefined)(\n lookupName,\n modelId,\n )\n if (known && typeof known === 'object' && 'api' in known) {\n // Override baseUrl + provider for local / compat endpoints — pi's catalog\n // doesn't know about lmstudio/ollama but if a user types\n // `openai:gpt-4o` with a custom OPENAI_BASE_URL, honor that here.\n if (cfg.baseUrl) return { ...known, baseUrl: cfg.baseUrl }\n return known\n }\n } catch {\n // Fall through.\n }\n return buildModelLiteral(cfg, modelId)\n}\n\nfunction convertMessages(messages: ProviderMessage[]): PiMessage[] {\n const out: PiMessage[] = []\n const now = Date.now()\n for (const m of messages) {\n if (m.role === 'system') continue // pi takes system prompt separately\n if (m.role === 'user') {\n out.push({ role: 'user', content: m.content, timestamp: now })\n continue\n }\n if (m.role === 'assistant') {\n const content: AssistantMessage['content'] = []\n if (m.content) content.push({ type: 'text', text: m.content } satisfies TextContent)\n if (m.toolCalls) {\n for (const tc of m.toolCalls) {\n let parsed: Record<string, unknown> = {}\n try {\n parsed = JSON.parse(tc.arguments) as Record<string, unknown>\n } catch {\n // leave empty\n }\n content.push({\n type: 'toolCall',\n id: tc.id,\n name: tc.name,\n arguments: parsed,\n } satisfies PiToolCall)\n }\n }\n // Synthesize the AssistantMessage fields pi expects on replays — these\n // are only load-bearing for the LLM that gets the transcript; since we\n // don't persist usage/stopReason in Bazilion's message store, defaults\n // are fine.\n out.push({\n role: 'assistant',\n content,\n api: 'anthropic-messages',\n provider: 'anthropic',\n model: 'unknown',\n usage: {\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheWrite: 0,\n totalTokens: 0,\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n },\n stopReason: 'stop',\n timestamp: now,\n })\n continue\n }\n if (m.role === 'tool') {\n out.push({\n role: 'toolResult',\n toolCallId: m.toolCallId ?? '',\n toolName: m.toolName ?? 'tool',\n content: [{ type: 'text', text: m.content }],\n isError: false,\n timestamp: now,\n })\n }\n }\n return out\n}\n\nfunction convertTools(tools: ToolDef[] | undefined): PiTool[] | undefined {\n if (!tools || tools.length === 0) return undefined\n return tools.map((t) => ({\n name: t.name,\n description: t.description,\n // Type.Unsafe lets us pass raw JSON Schema through without re-authoring in\n // typebox. Providers validate against the schema, not typebox's TSchema.\n parameters: Type.Unsafe<unknown>(t.parameters as Record<string, unknown>),\n }))\n}\n\nfunction toBazilionStopReason(reason: string): StopReason {\n switch (reason) {\n case 'stop':\n return 'stop'\n case 'length':\n return 'length'\n case 'toolUse':\n return 'tool_use'\n default:\n return 'error'\n }\n}\n\nfunction extractFinalResponse(msg: AssistantMessage): ProviderResponse {\n let text = ''\n const toolCalls: ToolCall[] = []\n for (const block of msg.content) {\n if (block.type === 'text') {\n text += block.text\n } else if (block.type === 'toolCall') {\n toolCalls.push({\n id: block.id,\n name: block.name,\n arguments: JSON.stringify(block.arguments ?? {}),\n })\n }\n }\n const res: ProviderResponse = {\n content: text,\n toolCalls,\n stopReason: toBazilionStopReason(msg.stopReason),\n }\n if (msg.usage) {\n res.usage = {\n promptTokens: msg.usage.input,\n completionTokens: msg.usage.output,\n }\n }\n return res\n}\n\nfunction mapReasoning(\n r: ReasoningLevel | undefined,\n): 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | undefined {\n if (!r || r === 'off') return undefined\n return r\n}\n\nasync function resolveApiKey(cfg: PiProviderConfig): Promise<string | undefined> {\n if (typeof cfg.apiKey === 'function') return await cfg.apiKey()\n return cfg.apiKey\n}\n\nexport function piProvider(cfg: PiProviderConfig): Provider {\n return {\n name: cfg.providerName,\n async chat(req: ProviderRequest): Promise<ProviderResponse> {\n const model = resolveModel(cfg, req.model)\n const apiKey = await resolveApiKey(cfg)\n\n const stream = streamSimple(\n model,\n {\n systemPrompt: req.system ?? '',\n messages: convertMessages(req.messages),\n tools: convertTools(req.tools),\n },\n {\n signal: req.signal,\n apiKey,\n reasoning: mapReasoning(req.reasoning),\n maxTokens: req.maxTokens,\n temperature: req.temperature,\n },\n )\n\n let finalMessage: AssistantMessage | null = null\n for await (const event of stream) {\n if (event.type === 'text_delta' && req.onDelta) {\n req.onDelta(event.delta)\n } else if (event.type === 'done') {\n finalMessage = event.message\n } else if (event.type === 'error') {\n finalMessage = event.error\n }\n }\n if (!finalMessage) {\n throw new Error(`pi provider ${cfg.providerName} returned no terminal event`)\n }\n if (finalMessage.stopReason === 'aborted' || finalMessage.stopReason === 'error') {\n const msg = finalMessage.errorMessage ?? 'provider error'\n throw new Error(msg)\n }\n return extractFinalResponse(finalMessage)\n },\n }\n}\n","// Transient-error retry wrapper for Provider.chat().\n//\n// Applied uniformly in `createProviderRegistry` so every provider (anthropic,\n// openai, openai-codex, lmstudio, ollama, …) gets the same retry policy. A\n// one-shot upstream 5xx or rate-limit shouldn't kill the agent's turn — the\n// runtime marks the run `failed` and the user is stuck re-sending the same\n// message by hand, which is hostile UX.\n//\n// What counts as retryable is a small allowlist (server 5xx, rate-limit, a\n// handful of network errnos). Auth errors, invalid-request errors, context\n// overflows, and user-triggered aborts bypass retry entirely — they won't\n// resolve by trying again and the fast failure is the right signal.\n//\n// One hard rule: if the underlying chat already streamed text back via\n// onDelta, we can't retry — a second attempt would emit duplicated text into\n// the UI. The wrapper detects this by shadowing onDelta and tracking whether\n// the callback fired.\n\nimport type { Provider, ProviderRequest, ProviderResponse } from './types.ts'\n\nexport interface RetryOptions {\n /** How many *extra* attempts beyond the first. Default 2 → up to 3 tries total. */\n maxRetries?: number\n /** First backoff delay in ms. Doubles each retry up to maxDelayMs. Default 500. */\n initialDelayMs?: number\n /** Upper bound on a single backoff delay. Default 8000. */\n maxDelayMs?: number\n /** Optional callback invoked before each retry (for logging / telemetry). */\n onRetry?: (info: { attempt: number; delayMs: number; error: Error }) => void\n}\n\n/**\n * Lowercased substrings that mark an error as worth retrying. Checked with a\n * simple `includes` so we don't need to parse the upstream JSON shapes.\n */\nconst RETRYABLE_MARKERS: readonly string[] = [\n 'server_error',\n 'internal_server',\n 'rate_limit',\n 'rate limit',\n 'too many requests',\n 'overloaded', // covers 'overloaded_error' (Anthropic)\n 'service_unavailable',\n 'service unavailable',\n 'gateway_timeout',\n 'gateway timeout',\n 'bad_gateway',\n 'bad gateway',\n 'econnreset',\n 'etimedout',\n 'econnrefused',\n 'enotfound',\n 'eai_again',\n 'socket hang up',\n 'fetch failed',\n 'network error',\n 'connection reset',\n 'status 429',\n 'status 500',\n 'status 502',\n 'status 503',\n 'status 504',\n '\"status\":429',\n '\"status\":500',\n '\"status\":502',\n '\"status\":503',\n '\"status\":504',\n]\n\n/**\n * Non-retryable markers win over retryable ones — if an error mentions\n * authentication or a 4xx (other than 429), retrying won't help.\n */\nconst NON_RETRYABLE_MARKERS: readonly string[] = [\n 'invalid_api_key',\n 'invalid api key',\n 'incorrect_api_key',\n 'authentication',\n 'unauthorized',\n 'permission_denied',\n 'permission denied',\n 'forbidden',\n 'invalid_request',\n 'invalid request',\n 'not_found',\n 'model_not_found',\n 'context_length_exceeded',\n 'context length',\n 'content_filter',\n 'quota_exceeded',\n 'insufficient_quota',\n 'billing',\n 'status 400',\n 'status 401',\n 'status 403',\n 'status 404',\n 'status 422',\n]\n\nexport function isRetryableError(err: unknown): boolean {\n const raw = err instanceof Error ? err.message : typeof err === 'string' ? err : String(err)\n const msg = raw.toLowerCase()\n for (const deny of NON_RETRYABLE_MARKERS) {\n if (msg.includes(deny)) return false\n }\n for (const allow of RETRYABLE_MARKERS) {\n if (msg.includes(allow)) return true\n }\n return false\n}\n\nfunction sleepWithAbort(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(new Error('aborted'))\n return\n }\n const t = setTimeout(() => {\n if (signal) signal.removeEventListener('abort', onAbort)\n resolve()\n }, ms)\n const onAbort = () => {\n clearTimeout(t)\n reject(new Error('aborted'))\n }\n signal?.addEventListener('abort', onAbort, { once: true })\n })\n}\n\nexport function withRetry(provider: Provider, opts: RetryOptions = {}): Provider {\n const maxRetries = opts.maxRetries ?? 2\n const initialDelayMs = opts.initialDelayMs ?? 500\n const maxDelayMs = opts.maxDelayMs ?? 8_000\n\n return {\n name: provider.name,\n async chat(req: ProviderRequest): Promise<ProviderResponse> {\n let attempt = 0\n // Use `let` so each retry gets a fresh shadow; we need to know whether\n // onDelta fired on the *most recent* attempt.\n let lastError: Error | null = null\n while (true) {\n let streamed = false\n const wrappedReq: ProviderRequest = req.onDelta\n ? {\n ...req,\n onDelta: (delta: string) => {\n streamed = true\n req.onDelta?.(delta)\n },\n }\n : req\n try {\n return await provider.chat(wrappedReq)\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err))\n if (req.signal?.aborted) throw lastError\n if (streamed) throw lastError\n if (attempt >= maxRetries) throw lastError\n if (!isRetryableError(lastError)) throw lastError\n const delayMs = Math.min(initialDelayMs * 2 ** attempt, maxDelayMs)\n opts.onRetry?.({ attempt: attempt + 1, delayMs, error: lastError })\n try {\n await sleepWithAbort(delayMs, req.signal)\n } catch {\n // Aborted during backoff — surface the original provider error\n // rather than the synthetic abort so the run's failure reason\n // still points at what actually went wrong.\n throw lastError\n }\n attempt++\n }\n }\n },\n }\n}\n","import type { BazilionDb } from '../../core/index.ts'\nimport {\n hasCredentials as hasOpenAICodexCredentials,\n loadAccessToken as loadOpenAICodexAccessToken,\n} from '../auth/openai-codex.ts'\nimport { piProvider } from './pi-adapter.ts'\nimport { type RetryOptions, withRetry } from './retry.ts'\nimport type { Provider } from './types.ts'\n\nexport interface ProviderConfig {\n anthropic?: { apiKey: string; baseURL?: string }\n openai?: { apiKey: string; baseURL?: string }\n /** ChatGPT/Codex OAuth. The apiKey is fetched+refreshed lazily from secrets. */\n openaiCodex?: { db: BazilionDb; authToken: string }\n google?: { apiKey: string; baseURL?: string }\n azureOpenai?: { apiKey: string; baseURL?: string }\n bedrock?: { apiKey?: string } // auth via AWS SDK env (AWS_PROFILE / AWS_ACCESS_KEY_ID / ...)\n googleVertex?: Record<string, never> // auth via ADC + GOOGLE_CLOUD_PROJECT\n mistral?: { apiKey: string; baseURL?: string }\n groq?: { apiKey: string; baseURL?: string }\n cerebras?: { apiKey: string; baseURL?: string }\n xai?: { apiKey: string; baseURL?: string }\n zai?: { apiKey: string; baseURL?: string }\n huggingface?: { apiKey: string; baseURL?: string }\n openrouter?: { apiKey: string; baseURL?: string }\n vercelAiGateway?: { apiKey: string; baseURL?: string }\n // Providers added in pi-ai 0.70–0.75.\n deepseek?: { apiKey: string; baseURL?: string }\n fireworks?: { apiKey: string; baseURL?: string }\n together?: { apiKey: string; baseURL?: string }\n moonshotai?: { apiKey: string; baseURL?: string }\n kimiCoding?: { apiKey: string; baseURL?: string }\n minimax?: { apiKey: string; baseURL?: string }\n xiaomi?: { apiKey: string; baseURL?: string }\n opencode?: { apiKey: string; baseURL?: string }\n githubCopilot?: { apiKey: string }\n cloudflareAiGateway?: { apiKey: string; accountId?: string; gatewayId?: string }\n cloudflareWorkersAi?: { apiKey: string; accountId?: string }\n lmstudio?: { baseURL?: string; apiKey?: string }\n ollama?: { baseURL?: string; apiKey?: string }\n llamacpp?: { baseURL?: string; apiKey?: string }\n}\n\nexport interface ResolvedModel {\n provider: Provider\n model: string\n}\n\n/**\n * Env var → provider config. Empty / missing vars leave that provider unconfigured.\n *\n * Pass `oauth` (the daemon's `{db, authToken}` pair) to also pick up\n * OAuth-backed providers whose credentials live in the `secrets` table\n * (currently: `openai-codex` / ChatGPT). Env-only callers can omit it —\n * those providers just won't be configured.\n */\nexport function loadProviderConfigFromEnv(\n env: NodeJS.ProcessEnv = process.env,\n oauth?: { db: BazilionDb; authToken: string },\n): ProviderConfig {\n const config: ProviderConfig = {\n lmstudio: {\n ...(env.LMSTUDIO_URL !== undefined ? { baseURL: env.LMSTUDIO_URL } : {}),\n ...(env.LMSTUDIO_API_KEY !== undefined ? { apiKey: env.LMSTUDIO_API_KEY } : {}),\n },\n ollama: {\n ...(env.OLLAMA_URL !== undefined ? { baseURL: env.OLLAMA_URL } : {}),\n ...(env.OLLAMA_API_KEY !== undefined ? { apiKey: env.OLLAMA_API_KEY } : {}),\n },\n llamacpp: {\n ...(env.LLAMACPP_URL !== undefined ? { baseURL: env.LLAMACPP_URL } : {}),\n ...(env.LLAMACPP_API_KEY !== undefined ? { apiKey: env.LLAMACPP_API_KEY } : {}),\n },\n }\n if (env.ANTHROPIC_API_KEY || env.ANTHROPIC_OAUTH_TOKEN) {\n config.anthropic = { apiKey: env.ANTHROPIC_OAUTH_TOKEN ?? env.ANTHROPIC_API_KEY ?? '' }\n }\n if (env.OPENAI_API_KEY) config.openai = { apiKey: env.OPENAI_API_KEY }\n if (env.GEMINI_API_KEY) config.google = { apiKey: env.GEMINI_API_KEY }\n if (env.AZURE_OPENAI_API_KEY) config.azureOpenai = { apiKey: env.AZURE_OPENAI_API_KEY }\n if (\n env.AWS_PROFILE ||\n env.AWS_BEARER_TOKEN_BEDROCK ||\n (env.AWS_ACCESS_KEY_ID && env.AWS_SECRET_ACCESS_KEY)\n ) {\n config.bedrock = {}\n }\n if (env.GOOGLE_CLOUD_PROJECT && env.GOOGLE_CLOUD_LOCATION) {\n config.googleVertex = {}\n }\n if (env.MISTRAL_API_KEY) config.mistral = { apiKey: env.MISTRAL_API_KEY }\n if (env.GROQ_API_KEY) config.groq = { apiKey: env.GROQ_API_KEY }\n if (env.CEREBRAS_API_KEY) config.cerebras = { apiKey: env.CEREBRAS_API_KEY }\n if (env.XAI_API_KEY) config.xai = { apiKey: env.XAI_API_KEY }\n if (env.ZAI_API_KEY) config.zai = { apiKey: env.ZAI_API_KEY }\n if (env.HF_TOKEN) config.huggingface = { apiKey: env.HF_TOKEN }\n if (env.OPENROUTER_API_KEY) config.openrouter = { apiKey: env.OPENROUTER_API_KEY }\n if (env.AI_GATEWAY_API_KEY) config.vercelAiGateway = { apiKey: env.AI_GATEWAY_API_KEY }\n if (env.DEEPSEEK_API_KEY) config.deepseek = { apiKey: env.DEEPSEEK_API_KEY }\n if (env.FIREWORKS_API_KEY) config.fireworks = { apiKey: env.FIREWORKS_API_KEY }\n if (env.TOGETHER_API_KEY) config.together = { apiKey: env.TOGETHER_API_KEY }\n if (env.MOONSHOT_API_KEY) config.moonshotai = { apiKey: env.MOONSHOT_API_KEY }\n if (env.KIMI_API_KEY) config.kimiCoding = { apiKey: env.KIMI_API_KEY }\n if (env.MINIMAX_API_KEY) config.minimax = { apiKey: env.MINIMAX_API_KEY }\n if (env.XIAOMI_API_KEY) config.xiaomi = { apiKey: env.XIAOMI_API_KEY }\n if (env.OPENCODE_API_KEY) config.opencode = { apiKey: env.OPENCODE_API_KEY }\n if (env.COPILOT_GITHUB_TOKEN) config.githubCopilot = { apiKey: env.COPILOT_GITHUB_TOKEN }\n if (env.CLOUDFLARE_API_KEY && env.CLOUDFLARE_ACCOUNT_ID) {\n config.cloudflareWorkersAi = {\n apiKey: env.CLOUDFLARE_API_KEY,\n accountId: env.CLOUDFLARE_ACCOUNT_ID,\n }\n if (env.CLOUDFLARE_GATEWAY_ID) {\n config.cloudflareAiGateway = {\n apiKey: env.CLOUDFLARE_API_KEY,\n accountId: env.CLOUDFLARE_ACCOUNT_ID,\n gatewayId: env.CLOUDFLARE_GATEWAY_ID,\n }\n }\n }\n if (oauth && hasOpenAICodexCredentials(oauth.db, oauth.authToken)) {\n config.openaiCodex = oauth\n }\n return config\n}\n\nexport interface ProviderRegistry {\n resolve(modelString: string): ResolvedModel\n list(): string[]\n}\n\nexport interface ProviderRegistryOptions {\n /** If provided, resolve() refuses any provider not in the set with \"disabled by admin\". */\n enabledSet?: ReadonlySet<string>\n /** Retry policy applied uniformly to every provider; omit for built-in defaults. */\n retry?: RetryOptions\n}\n\ninterface ProviderEntry {\n configured: (c: ProviderConfig) => boolean\n build: (c: ProviderConfig) => Provider\n /** Helpful error hint when the caller references this provider but env isn't set. */\n hint: string\n}\n\nconst PROVIDERS: Record<string, ProviderEntry> = {\n anthropic: {\n configured: (c) => !!c.anthropic,\n build: (c) =>\n piProvider({\n providerName: 'anthropic',\n fallbackApi: 'anthropic-messages',\n apiKey: c.anthropic?.apiKey,\n baseUrl: c.anthropic?.baseURL,\n }),\n hint: 'ANTHROPIC_API_KEY or ANTHROPIC_OAUTH_TOKEN',\n },\n openai: {\n configured: (c) => !!c.openai,\n build: (c) =>\n piProvider({\n providerName: 'openai',\n fallbackApi: 'openai-completions',\n apiKey: c.openai?.apiKey,\n baseUrl: c.openai?.baseURL,\n }),\n hint: 'OPENAI_API_KEY',\n },\n 'openai-codex': {\n configured: (c) => !!c.openaiCodex,\n // Pi-ai's `openai-codex-responses` speaks the ChatGPT backend's Responses\n // API (https://chatgpt.com/backend-api) using a JWT access token as the\n // apiKey. We pass a supplier that refreshes lazily via the OAuth refresh\n // token, so the registry-cached Provider instance stays valid across\n // expiries without rebuild.\n build: (c) => {\n const openaiCodex = c.openaiCodex\n if (!openaiCodex) throw new Error('openai-codex not configured')\n return piProvider({\n providerName: 'openai-codex',\n fallbackApi: 'openai-codex-responses',\n apiKey: () => loadOpenAICodexAccessToken(openaiCodex.db, openaiCodex.authToken),\n })\n },\n hint: 'run `bazilion auth openai login` (or click Connect on /config)',\n },\n google: {\n configured: (c) => !!c.google,\n build: (c) =>\n piProvider({\n providerName: 'google',\n fallbackApi: 'google-generative-ai',\n apiKey: c.google?.apiKey,\n baseUrl: c.google?.baseURL,\n }),\n hint: 'GEMINI_API_KEY',\n },\n 'google-vertex': {\n configured: (c) => !!c.googleVertex,\n build: () => piProvider({ providerName: 'google-vertex', fallbackApi: 'google-vertex' }),\n hint: 'GOOGLE_CLOUD_PROJECT + GOOGLE_CLOUD_LOCATION + ADC (gcloud auth)',\n },\n 'azure-openai': {\n configured: (c) => !!c.azureOpenai,\n build: (c) =>\n piProvider({\n providerName: 'azure-openai',\n fallbackApi: 'azure-openai-responses',\n apiKey: c.azureOpenai?.apiKey,\n baseUrl: c.azureOpenai?.baseURL,\n }),\n hint: 'AZURE_OPENAI_API_KEY',\n },\n bedrock: {\n configured: (c) => !!c.bedrock,\n build: () =>\n piProvider({\n providerName: 'bedrock',\n piProviderName: 'amazon-bedrock',\n fallbackApi: 'bedrock-converse-stream',\n }),\n hint: 'AWS_PROFILE or AWS_ACCESS_KEY_ID+AWS_SECRET_ACCESS_KEY',\n },\n mistral: {\n configured: (c) => !!c.mistral,\n build: (c) =>\n piProvider({\n providerName: 'mistral',\n fallbackApi: 'openai-completions',\n apiKey: c.mistral?.apiKey,\n baseUrl: c.mistral?.baseURL,\n }),\n hint: 'MISTRAL_API_KEY',\n },\n groq: {\n configured: (c) => !!c.groq,\n build: (c) =>\n piProvider({\n providerName: 'groq',\n fallbackApi: 'openai-completions',\n apiKey: c.groq?.apiKey,\n baseUrl: c.groq?.baseURL,\n }),\n hint: 'GROQ_API_KEY',\n },\n cerebras: {\n configured: (c) => !!c.cerebras,\n build: (c) =>\n piProvider({\n providerName: 'cerebras',\n fallbackApi: 'openai-completions',\n apiKey: c.cerebras?.apiKey,\n baseUrl: c.cerebras?.baseURL,\n }),\n hint: 'CEREBRAS_API_KEY',\n },\n xai: {\n configured: (c) => !!c.xai,\n build: (c) =>\n piProvider({\n providerName: 'xai',\n fallbackApi: 'openai-completions',\n apiKey: c.xai?.apiKey,\n baseUrl: c.xai?.baseURL,\n }),\n hint: 'XAI_API_KEY',\n },\n zai: {\n configured: (c) => !!c.zai,\n build: (c) =>\n piProvider({\n providerName: 'zai',\n fallbackApi: 'openai-completions',\n apiKey: c.zai?.apiKey,\n baseUrl: c.zai?.baseURL,\n }),\n hint: 'ZAI_API_KEY',\n },\n huggingface: {\n configured: (c) => !!c.huggingface,\n build: (c) =>\n piProvider({\n providerName: 'huggingface',\n fallbackApi: 'openai-completions',\n apiKey: c.huggingface?.apiKey,\n baseUrl: c.huggingface?.baseURL,\n }),\n hint: 'HF_TOKEN',\n },\n openrouter: {\n configured: (c) => !!c.openrouter,\n build: (c) =>\n piProvider({\n providerName: 'openrouter',\n fallbackApi: 'openai-completions',\n apiKey: c.openrouter?.apiKey,\n baseUrl: c.openrouter?.baseURL,\n }),\n hint: 'OPENROUTER_API_KEY',\n },\n 'vercel-ai-gateway': {\n configured: (c) => !!c.vercelAiGateway,\n build: (c) =>\n piProvider({\n providerName: 'vercel-ai-gateway',\n fallbackApi: 'openai-completions',\n apiKey: c.vercelAiGateway?.apiKey,\n baseUrl: c.vercelAiGateway?.baseURL,\n }),\n hint: 'AI_GATEWAY_API_KEY',\n },\n deepseek: {\n configured: (c) => !!c.deepseek,\n build: (c) =>\n piProvider({\n providerName: 'deepseek',\n fallbackApi: 'openai-completions',\n apiKey: c.deepseek?.apiKey,\n baseUrl: c.deepseek?.baseURL,\n }),\n hint: 'DEEPSEEK_API_KEY',\n },\n fireworks: {\n configured: (c) => !!c.fireworks,\n build: (c) =>\n piProvider({\n providerName: 'fireworks',\n fallbackApi: 'anthropic-messages',\n apiKey: c.fireworks?.apiKey,\n baseUrl: c.fireworks?.baseURL,\n }),\n hint: 'FIREWORKS_API_KEY',\n },\n together: {\n configured: (c) => !!c.together,\n build: (c) =>\n piProvider({\n providerName: 'together',\n fallbackApi: 'openai-completions',\n apiKey: c.together?.apiKey,\n baseUrl: c.together?.baseURL,\n }),\n hint: 'TOGETHER_API_KEY',\n },\n moonshotai: {\n configured: (c) => !!c.moonshotai,\n build: (c) =>\n piProvider({\n providerName: 'moonshotai',\n fallbackApi: 'openai-completions',\n apiKey: c.moonshotai?.apiKey,\n baseUrl: c.moonshotai?.baseURL,\n }),\n hint: 'MOONSHOT_API_KEY',\n },\n 'kimi-coding': {\n configured: (c) => !!c.kimiCoding,\n build: (c) =>\n piProvider({\n providerName: 'kimi-coding',\n fallbackApi: 'anthropic-messages',\n apiKey: c.kimiCoding?.apiKey,\n baseUrl: c.kimiCoding?.baseURL,\n }),\n hint: 'KIMI_API_KEY',\n },\n minimax: {\n configured: (c) => !!c.minimax,\n build: (c) =>\n piProvider({\n providerName: 'minimax',\n fallbackApi: 'anthropic-messages',\n apiKey: c.minimax?.apiKey,\n baseUrl: c.minimax?.baseURL,\n }),\n hint: 'MINIMAX_API_KEY',\n },\n xiaomi: {\n configured: (c) => !!c.xiaomi,\n build: (c) =>\n piProvider({\n providerName: 'xiaomi',\n fallbackApi: 'openai-completions',\n apiKey: c.xiaomi?.apiKey,\n baseUrl: c.xiaomi?.baseURL,\n }),\n hint: 'XIAOMI_API_KEY',\n },\n opencode: {\n configured: (c) => !!c.opencode,\n build: (c) =>\n piProvider({\n providerName: 'opencode',\n fallbackApi: 'openai-completions',\n apiKey: c.opencode?.apiKey,\n baseUrl: c.opencode?.baseURL,\n }),\n hint: 'OPENCODE_API_KEY',\n },\n 'github-copilot': {\n configured: (c) => !!c.githubCopilot,\n build: (c) =>\n piProvider({\n providerName: 'github-copilot',\n fallbackApi: 'anthropic-messages',\n apiKey: c.githubCopilot?.apiKey,\n }),\n hint: 'COPILOT_GITHUB_TOKEN (generic GH_TOKEN/GITHUB_TOKEN are ignored)',\n },\n 'cloudflare-ai-gateway': {\n configured: (c) => !!c.cloudflareAiGateway,\n build: (c) =>\n piProvider({\n providerName: 'cloudflare-ai-gateway',\n fallbackApi: 'anthropic-messages',\n apiKey: c.cloudflareAiGateway?.apiKey,\n }),\n hint: 'CLOUDFLARE_API_KEY + CLOUDFLARE_ACCOUNT_ID + CLOUDFLARE_GATEWAY_ID',\n },\n 'cloudflare-workers-ai': {\n configured: (c) => !!c.cloudflareWorkersAi,\n build: (c) =>\n piProvider({\n providerName: 'cloudflare-workers-ai',\n fallbackApi: 'openai-completions',\n apiKey: c.cloudflareWorkersAi?.apiKey,\n }),\n hint: 'CLOUDFLARE_API_KEY + CLOUDFLARE_ACCOUNT_ID',\n },\n lmstudio: {\n configured: () => true,\n build: (c) =>\n piProvider({\n providerName: 'lmstudio',\n fallbackApi: 'openai-completions',\n apiKey: c.lmstudio?.apiKey ?? 'lm-studio',\n baseUrl: c.lmstudio?.baseURL ?? 'http://127.0.0.1:1234/v1',\n }),\n hint: 'LMSTUDIO_URL (default http://127.0.0.1:1234/v1)',\n },\n ollama: {\n configured: () => true,\n build: (c) =>\n piProvider({\n providerName: 'ollama',\n fallbackApi: 'openai-completions',\n apiKey: c.ollama?.apiKey ?? 'ollama',\n baseUrl: c.ollama?.baseURL ?? 'http://127.0.0.1:11434/v1',\n }),\n hint: 'OLLAMA_URL (default http://127.0.0.1:11434/v1)',\n },\n llamacpp: {\n // Like lmstudio/ollama, always considered \"configured\" — the daemon\n // can't tell if llama-server is actually running until a request hits\n // it. Falls back to the documented default port + a placeholder\n // apiKey (llama-server ignores it unless --api-key was passed).\n configured: () => true,\n build: (c) =>\n piProvider({\n providerName: 'llamacpp',\n fallbackApi: 'openai-completions',\n apiKey: c.llamacpp?.apiKey ?? 'no-key',\n baseUrl: c.llamacpp?.baseURL ?? 'http://127.0.0.1:8080/v1',\n }),\n hint: 'LLAMACPP_URL (default http://127.0.0.1:8080/v1)',\n },\n}\n\n/**\n * Model strings are `provider:model`, e.g.:\n * - `anthropic:claude-opus-4-6`\n * - `openai:gpt-4o`\n * - `google:gemini-2.0-flash-exp`\n * - `groq:llama-3.3-70b-versatile`\n * - `lmstudio:my-loaded-model`\n * - `ollama:llama2`\n */\nexport function createProviderRegistry(\n config: ProviderConfig,\n opts: ProviderRegistryOptions = {},\n): ProviderRegistry {\n const cache = new Map<string, Provider>()\n const enabledSet = opts.enabledSet\n\n function get(name: string): Provider {\n const cached = cache.get(name)\n if (cached) return cached\n const entry = PROVIDERS[name]\n if (!entry) throw new Error(`unknown provider: ${name}`)\n if (enabledSet && !enabledSet.has(name)) {\n throw new Error(`${name} provider is disabled — enable it on the /config page`)\n }\n if (!entry.configured(config)) {\n throw new Error(`${name} provider not configured (set ${entry.hint})`)\n }\n const raw = entry.build(config)\n const provider = withRetry(raw, {\n ...(opts.retry ?? {}),\n onRetry: (info) => {\n opts.retry?.onRetry?.(info)\n console.warn(\n `[provider/${name}] transient error on attempt ${info.attempt}, retrying in ${info.delayMs}ms: ${info.error.message.slice(0, 160)}`,\n )\n },\n })\n cache.set(name, provider)\n return provider\n }\n\n return {\n resolve(modelString: string): ResolvedModel {\n const idx = modelString.indexOf(':')\n if (idx === -1) {\n throw new Error(`invalid model string \"${modelString}\": expected \"provider:model\"`)\n }\n const providerName = modelString.slice(0, idx)\n const model = modelString.slice(idx + 1)\n return { provider: get(providerName), model }\n },\n list() {\n return Object.entries(PROVIDERS)\n .filter(([name, entry]) => {\n if (!entry.configured(config)) return false\n if (enabledSet && !enabledSet.has(name)) return false\n return true\n })\n .map(([name]) => name)\n },\n }\n}\n\nexport interface ProviderMeta {\n name: string\n enabled: boolean\n /** Hint shown when the provider isn't configured — the env var(s) required. */\n envHint: string\n}\n\n/** List every provider the registry knows about, plus whether each is configured. */\nexport function listAllProviders(config: ProviderConfig): ProviderMeta[] {\n return Object.entries(PROVIDERS).map(([name, entry]) => ({\n name,\n enabled: entry.configured(config),\n envHint: entry.hint,\n }))\n}\n","// Bazilion system-prompt builder. Feeds pi's `getAppendSystemPrompt()` hook\n// so the agent sees its persona + skills + workspaces + memory guidance\n// stacked on top of pi's built-in base prompt (which lists coding tools and\n// general guidelines). Pure filesystem read — no LLM, no DB.\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { ResolvedAgent } from '@bazilion/api-types'\n\n// Prompt order: peers first (who else is around), then persona, then tooling\n// hints, then self-knowledge, then the wake-up playbook.\n//\n// BOOTSTRAP.md is intentionally NOT in this generic-context list — it gets\n// its own dedicated \"First-Run Ritual\" section below with explicit\n// anti-checklist framing, so models treat it as multi-turn Q&A guidance\n// rather than a one-shot script to execute. The system prompt regenerates\n// per turn, so the section auto-vanishes when `bootstrap_done` removes the\n// file (vs. wrapping the user message, which would persist in pi's session\n// JSONL forever and replay on every future turn).\nconst CONTEXT_FILE_ORDER = [\n 'AGENTS.md',\n 'SOUL.md',\n 'TOOLS.md',\n 'IDENTITY.md',\n 'HEARTBEAT.md',\n] as const\n\nexport function buildSystemPrompt(agent: ResolvedAgent): string {\n const parts: string[] = []\n\n const contextBlocks: string[] = []\n for (const file of CONTEXT_FILE_ORDER) {\n const path = join(agent.agent.dir, file)\n if (!existsSync(path)) continue\n const content = readFileSync(path, 'utf8').trimEnd()\n if (!content) continue\n contextBlocks.push(`## ${file}\\n\\n${content}`)\n }\n if (contextBlocks.length > 0) {\n parts.push(`# Project Context\\n\\n${contextBlocks.join('\\n\\n')}`)\n }\n\n // First-Run Ritual block — only emitted while BOOTSTRAP.md exists on disk.\n // The wording deliberately frames it as \"multi-turn Q&A\" not \"checklist\"\n // and lists hard rules at the top so tool-eager models still notice them\n // even if they skim the body.\n const bootstrapPath = join(agent.agent.dir, 'BOOTSTRAP.md')\n if (existsSync(bootstrapPath)) {\n const bootstrap = readFileSync(bootstrapPath, 'utf8').trimEnd()\n if (bootstrap) {\n parts.push(\n [\n '# First-Run Ritual',\n '',\n 'This is your first session. The document below is **conversational guidance**, not a checklist to execute in one shot. It describes a multi-turn Q&A you should have with the human, one question per turn.',\n '',\n '## Hard rules',\n '- Your first reply is ONLY a greeting + ONE question. No tool calls. Wait for the human to answer.',\n '- Each subsequent turn: at most one new question. Wait between turns.',\n '- Only after the ritual is complete (you have enough to write IDENTITY.md): call `home_write` once, then `bootstrap_done`.',\n '',\n '## BOOTSTRAP.md',\n '',\n bootstrap,\n ].join('\\n'),\n )\n }\n }\n\n parts.push(\n [\n '# Agent Home',\n '',\n 'Your private home holds who you are — identity, soul, behaviour rules, wake-up routine. It is not shared with other agents and cannot be overwritten by them. The files above (IDENTITY.md, SOUL.md, AGENTS.md, TOOLS.md, HEARTBEAT.md) live in this home, plus BOOTSTRAP.md when you are still in your first-run ritual.',\n '',\n '- To change who you are (name, vibe, personality, how you behave): use `home_write`.',\n '- To inspect exact wording of your own files: use `home_read` or `home_list`.',\n '- To remember facts the user told you or things you learned: use `memory_write` — NOT `home_write`.',\n '- To produce work output (code, docs, artefacts): use `write` / `edit` — those land in your workspace, not your home.',\n ].join('\\n'),\n )\n\n if (agent.skills.length > 0) {\n parts.push(\n `# Available Skills\\n\\nYou have access to the following skills: ${agent.skills.join(', ')}.`,\n )\n }\n\n const groupLines = [\n '# Group',\n '',\n `- ${agent.group.id} (${agent.group.name}): ${agent.group.path}`,\n '',\n 'Your group is where work product lives — code, docs, artefacts, shared scratch. It may be shared with other agents in the same group. Your coding tools (`read`, `bash`, `edit`, `write`, `grep`, `find`, `ls`) are rooted at the group directory. Never use these tools to edit your identity/soul/behaviour files — those live in your home and are reached via `home_write` / `home_read`.',\n ]\n parts.push(groupLines.join('\\n'))\n\n if (agent.group.userMd.trim()) {\n parts.push(\n `# About the User\\n\\nShared context about the human you're working with in this group. Both you and the human curate it. To update: call \\`user_md_get\\` (returns current content + an etag), merge your change into the full text, then call \\`user_md_write\\` with the merged content and the etag. Use this for STABLE user-specific facts (preferences, role, working hours, how they like to be addressed) — and to CORRECT stale entries when the human tells you something different from what's recorded. For project knowledge use \\`memory_write\\` instead; for personal notes about yourself use \\`home_write\\` on IDENTITY.md. **Do NOT send peer messages announcing USER.md changes — every agent in the group sees the new content in their system prompt on their next turn automatically.**\\n\\n${agent.group.userMd.trim()}`,\n )\n } else {\n parts.push(\n `# About the User\\n\\nThis group's USER.md is empty. As you learn STABLE facts about the human (preferences, role, working hours, how they like to be addressed), populate it via \\`user_md_get\\` then \\`user_md_write\\` (always get first — you need the etag). Reserve this for things you're confident are durable — project knowledge belongs in \\`memory_write\\`, personal notes about yourself in \\`home_write\\` on IDENTITY.md. **Do NOT send peer messages announcing USER.md changes — every agent in the group sees the new content in their system prompt on their next turn automatically.**`,\n )\n }\n\n parts.push(\n '# Memory\\n\\nYou share a persistent memory backend with every other agent in this group. Use `memory_write` to remember things across sessions, and `memory_search` / `memory_read` / `memory_list` to recall them. This memory is for project knowledge — codebase notes, decisions, things the user told you about the work. For personal notes about yourself (preferences, persona quirks), use `home_write` on IDENTITY.md instead. Always check memory at the start of a session: another agent in the group may have already learned something useful. **Do NOT send peer messages announcing memory writes — every agent has access to the same store via `memory_search` and will find your note when they need it.**',\n )\n\n return parts.join('\\n\\n---\\n\\n')\n}\n","// Adapter: Bazilion ToolHandler → pi-coding-agent ToolDefinition.\n//\n// Pi expects tools to return `AgentToolResult<TDetails>` =\n// `{ content: (TextContent | ImageContent)[]; details: TDetails; terminate?: boolean }`.\n// Our handlers return plain strings. The adapter wraps the string into a single\n// text content block with empty details — the same fidelity we had before.\n//\n// Pi's tool execute contract: throw on failure. The agent loop wraps thrown\n// errors as tool-result messages with `isError: true`. We preserve this shape\n// directly because our handlers already throw on bad args / runtime failures.\n//\n// What's in this module:\n// - `ourToolToPiTool` — single-handler wrapper.\n// - `createBazilionCustomTools` — composed suite of the Bazilion-specific\n// tools (memory_*, messaging, bootstrap_done, web_search/fetch). File I/O\n// tools are *not* here — pi's createCodingTools(cwd, …) replaces them.\n\nimport type { ResolvedAgent } from '@bazilion/api-types'\nimport type { ToolDefinition } from '@earendil-works/pi-coding-agent'\nimport { Type } from 'typebox'\nimport type { MemoryBackend } from '../memory/types.ts'\nimport { bootstrapTool } from '../tools/bootstrap.ts'\nimport { homeTools } from '../tools/home.ts'\nimport { memoryTools } from '../tools/memory.ts'\nimport { messagingTools } from '../tools/messaging.ts'\nimport type { ToolHandler } from '../tools/types.ts'\nimport { userMdTools } from '../tools/user-md.ts'\nimport { webTools } from '../tools/web.ts'\nimport type { MessagingHost, UserMdHost } from '../worker/ipc-protocol.ts'\n\n/**\n * Wrap a Bazilion `ToolHandler` as a pi `ToolDefinition` so it can be passed\n * through `customTools` to `createAgentSession`.\n *\n * Design note: we keep the same tool name + description + parameter JSON schema\n * that the handler already declares. Pi wants a `TypeBox` schema; we pass the\n * JSONSchema through `Type.Unsafe` so the LLM validation happens on pi's side\n * without us having to re-author schemas in typebox syntax.\n */\nexport function ourToolToPiTool(h: ToolHandler): ToolDefinition {\n return {\n name: h.def.name,\n label: h.def.name,\n description: h.def.description,\n parameters: Type.Unsafe<Record<string, unknown>>(h.def.parameters as Record<string, unknown>),\n async execute(_toolCallId, params) {\n const text = await h.invoke(params as Record<string, unknown>)\n return {\n content: [{ type: 'text', text }],\n details: {},\n }\n },\n }\n}\n\nexport interface BazilionCustomToolsOpts {\n agent: ResolvedAgent\n memory: MemoryBackend\n /** If provided, enables inter-agent messaging tools. */\n messagingHost?: MessagingHost\n /** If provided, enables the `user_md_append` tool. */\n userMdHost?: UserMdHost\n /** Merged env (process.env + secrets). */\n env?: NodeJS.ProcessEnv\n}\n\n/**\n * Build the list of Bazilion-specific custom tools in the shape pi expects.\n *\n * Excludes file-I/O tools (`read`/`bash`/`edit`/`write`/`grep`/`find`/`ls`) —\n * those come from pi's `createCodingTools(cwd, …)` now that we've adopted the\n * richer toolset. Also excludes the legacy `workspace_list/read/write`\n * triumvirate: pi's tools work against a single cwd (the agent's default\n * workspace), and mounted non-default workspaces are reachable via absolute\n * paths through pi's `bash`/`read`/`edit`.\n */\nexport function createBazilionCustomTools(opts: BazilionCustomToolsOpts): ToolDefinition[] {\n const handlers: ToolHandler[] = [\n ...memoryTools(opts.memory),\n ...homeTools(opts.agent.agent.dir),\n bootstrapTool(opts.agent.agent.dir),\n ...webTools({ env: opts.env }),\n ]\n if (opts.messagingHost) {\n handlers.push(...messagingTools(opts.messagingHost, opts.agent.agent.id))\n }\n if (opts.userMdHost) {\n handlers.push(...userMdTools(opts.userMdHost, opts.agent.group.id))\n }\n return handlers.map(ourToolToPiTool)\n}\n","import { existsSync, rmSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { ToolHandler } from './types.ts'\n\nexport function bootstrapTool(agentDir: string): ToolHandler {\n return {\n def: {\n name: 'bootstrap_done',\n description:\n 'Call this once you have finished your bootstrap conversation (introduced yourself, learned the user, updated IDENTITY.md). Removes BOOTSTRAP.md so it does not appear in future sessions.',\n parameters: { type: 'object', properties: {} },\n },\n async invoke() {\n const path = join(agentDir, 'BOOTSTRAP.md')\n if (existsSync(path)) {\n rmSync(path)\n return 'BOOTSTRAP.md removed. Bootstrap is complete.'\n }\n return 'BOOTSTRAP.md was already removed.'\n },\n }\n}\n","import { readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { ToolHandler } from './types.ts'\n\n// Files the agent may read/write in its private home directory.\n// BOOTSTRAP.md is readable but not writable — its lifecycle belongs to\n// the `bootstrap_done` tool, not `home_write`.\nconst HOME_FILES_READABLE = [\n 'IDENTITY.md',\n 'SOUL.md',\n 'BOOTSTRAP.md',\n 'AGENTS.md',\n 'TOOLS.md',\n 'HEARTBEAT.md',\n] as const\n\nconst HOME_FILES_WRITABLE = [\n 'IDENTITY.md',\n 'SOUL.md',\n 'AGENTS.md',\n 'TOOLS.md',\n 'HEARTBEAT.md',\n] as const\n\nexport function homeTools(agentDir: string): ToolHandler[] {\n return [\n {\n def: {\n name: 'home_read',\n description:\n 'Read one of your own home files — your identity, soul, or behaviour rules. These files are private to you and are also injected into your system prompt; read them when you need to quote exact wording or check current state.',\n parameters: {\n type: 'object',\n properties: {\n file: { type: 'string', enum: [...HOME_FILES_READABLE] },\n },\n required: ['file'],\n },\n },\n async invoke(args) {\n const file = String(args.file ?? '')\n if (!HOME_FILES_READABLE.includes(file as (typeof HOME_FILES_READABLE)[number])) {\n throw new Error(\n `home_read: \"file\" must be one of ${HOME_FILES_READABLE.join(', ')}; got \"${file}\"`,\n )\n }\n const path = join(agentDir, file)\n try {\n return readFileSync(path, 'utf8')\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n throw new Error(`home_read: could not read ${file}: ${msg}`)\n }\n },\n },\n {\n def: {\n name: 'home_write',\n description:\n \"Overwrite one of your own home files. Use this to update your name, personality, or persistent self-definition. Do NOT use this for work output (use `write` / `edit` — those land in your group's shared directory) or for facts you want to remember (use `memory_write`). BOOTSTRAP.md is not writable here; call `bootstrap_done` to retire it.\",\n parameters: {\n type: 'object',\n properties: {\n file: { type: 'string', enum: [...HOME_FILES_WRITABLE] },\n content: { type: 'string', description: 'new full file content' },\n },\n required: ['file', 'content'],\n },\n },\n async invoke(args) {\n const file = String(args.file ?? '')\n if (!HOME_FILES_WRITABLE.includes(file as (typeof HOME_FILES_WRITABLE)[number])) {\n throw new Error(\n `home_write: \"file\" must be one of ${HOME_FILES_WRITABLE.join(', ')}; got \"${file}\"`,\n )\n }\n const content = typeof args.content === 'string' ? args.content : ''\n const path = join(agentDir, file)\n writeFileSync(path, content, 'utf8')\n return `wrote ${file} (${Buffer.byteLength(content, 'utf8')} bytes)`\n },\n },\n {\n def: {\n name: 'home_list',\n description: 'List your home files with their sizes.',\n parameters: { type: 'object', properties: {} },\n },\n async invoke() {\n const entries: string[] = []\n for (const file of HOME_FILES_READABLE) {\n const path = join(agentDir, file)\n try {\n const s = statSync(path)\n entries.push(`${file} (${s.size}b)`)\n } catch {\n // file not present — skip\n }\n }\n if (entries.length === 0) {\n const dirEntries = (() => {\n try {\n return readdirSync(agentDir)\n } catch {\n return []\n }\n })()\n return `(no home files found; agent dir contains: ${dirEntries.join(', ') || 'nothing'})`\n }\n return entries.join('\\n')\n },\n },\n ]\n}\n","import type { MemoryBackend } from '../memory/types.ts'\nimport type { ToolHandler } from './types.ts'\n\nexport function memoryTools(memory: MemoryBackend): ToolHandler[] {\n return [\n {\n def: {\n name: 'memory_write',\n description:\n 'Write or update a memory note in the GROUP-SHARED memory. All agents in this group can read what you write. Use it for project knowledge, codebase notes, decisions, and findings — anything other agents in the group should benefit from. For personal notes about yourself (preferences, persona) use `home_write` on IDENTITY.md. For STABLE facts about the human you\\'re working with (their preferences, role, working hours, how they like to be addressed) use `user_md_get` then `user_md_write` — those land in every agent\\'s system prompt directly. Key is a path-like string with a markdown extension, e.g. \"auth-flow.md\" or \"decisions/2026-05-migration.md\".',\n parameters: {\n type: 'object',\n properties: {\n key: { type: 'string', description: 'memory key (relative path)' },\n content: { type: 'string', description: 'note content (plain text or markdown)' },\n },\n required: ['key', 'content'],\n },\n },\n async invoke(args) {\n const key = String(args.key ?? '')\n const content = String(args.content ?? '')\n if (!key) throw new Error('memory_write: \"key\" is required')\n const entry = await memory.write(key, content)\n return `wrote ${entry.key} (${entry.content.length} bytes)`\n },\n },\n {\n def: {\n name: 'memory_search',\n description:\n 'Search the group-shared memory by substring. Returns matching entry keys with short snippets around the match.',\n parameters: {\n type: 'object',\n properties: {\n query: { type: 'string' },\n limit: { type: 'number', description: 'max results (default 10)' },\n },\n required: ['query'],\n },\n },\n async invoke(args) {\n const query = String(args.query ?? '')\n if (!query) throw new Error('memory_search: \"query\" is required')\n const limit = typeof args.limit === 'number' ? args.limit : 10\n const hits = await memory.search(query, { limit })\n if (hits.length === 0) return 'no matches'\n return hits.map((h) => `${h.key}: ${h.snippet.replaceAll('\\n', ' ')}`).join('\\n')\n },\n },\n {\n def: {\n name: 'memory_read',\n description: 'Read a single entry from the group-shared memory by key.',\n parameters: {\n type: 'object',\n properties: { key: { type: 'string' } },\n required: ['key'],\n },\n },\n async invoke(args) {\n const key = String(args.key ?? '')\n if (!key) throw new Error('memory_read: \"key\" is required')\n const entry = await memory.read(key)\n return entry.content\n },\n },\n {\n def: {\n name: 'memory_list',\n description: 'List every entry in the group-shared memory with its byte size.',\n parameters: { type: 'object', properties: {} },\n },\n async invoke() {\n const all = await memory.list()\n if (all.length === 0) return '(empty)'\n return all.map((e) => `${e.key} (${e.content.length}b)`).join('\\n')\n },\n },\n ]\n}\n","import type { MessagingHost } from '../worker/ipc-protocol.ts'\nimport type { ToolHandler } from './types.ts'\n\ninterface MessagePayload {\n text: string\n [key: string]: unknown\n}\n\nfunction decodeText(payload: string): string {\n try {\n const parsed = JSON.parse(payload) as MessagePayload\n if (parsed && typeof parsed.text === 'string') return parsed.text\n } catch {\n // not JSON; return raw payload\n }\n return payload\n}\n\nexport function messagingTools(host: MessagingHost, fromAgentId: string): ToolHandler[] {\n return [\n {\n def: {\n name: 'send_message',\n description:\n \"Send a message to another agent. Use the recipient's agent id (UUID). Use this ONLY for things the recipient needs to ACT on: delegating a task, asking a peer for information you cannot get yourself, escalating a decision. Do NOT use it for status updates or to announce changes to group-shared resources — USER.md and the group memory backend both propagate to every agent in the group automatically on their next turn, so messages like \\\"I updated USER.md\\\" or \\\"I wrote a new memory note\\\" are pure noise and will trigger an inbox-wake loop on the recipient.\",\n parameters: {\n type: 'object',\n properties: {\n to: { type: 'string', description: 'Recipient agent id' },\n text: { type: 'string', description: 'Message text' },\n reply_to: {\n type: 'string',\n description: 'Optional: id of the message you are replying to',\n },\n },\n required: ['to', 'text'],\n },\n },\n async invoke(args) {\n const to = String(args.to ?? '')\n const text = String(args.text ?? '')\n if (!to) throw new Error('send_message: \"to\" is required')\n if (!text) throw new Error('send_message: \"text\" is required')\n if (!(await host.agentExists(to))) {\n throw new Error(`send_message: agent not found: ${to}`)\n }\n const replyTo = typeof args.reply_to === 'string' ? args.reply_to : null\n const { messageId } = await host.sendMessage({\n from: fromAgentId,\n to,\n payload: JSON.stringify({ text }),\n replyTo,\n })\n return `sent message ${messageId}`\n },\n },\n {\n def: {\n name: 'read_inbox',\n description: 'Read messages addressed to you. Marks unread messages as read by default.',\n parameters: {\n type: 'object',\n properties: {\n include_read: {\n type: 'boolean',\n description: 'Also include already-read messages (default false)',\n },\n },\n },\n },\n async invoke(args) {\n const includeRead = args.include_read === true\n const messages = await host.listInbox(fromAgentId, { unreadOnly: !includeRead })\n if (messages.length === 0) return '(no messages)'\n const lines: string[] = []\n for (const m of messages) {\n lines.push(`from ${m.fromAgentId} [${m.id}]: ${decodeText(m.payload)}`)\n if (!m.readAt) await host.markRead(m.id)\n }\n return lines.join('\\n')\n },\n },\n {\n def: {\n name: 'wait_for_reply',\n description:\n 'Block until a reply to a message you sent arrives, or until the timeout expires.',\n parameters: {\n type: 'object',\n properties: {\n message_id: {\n type: 'string',\n description: 'id of the message you sent',\n },\n timeout_ms: {\n type: 'number',\n description: 'max wait in milliseconds (default 30000)',\n },\n poll_ms: {\n type: 'number',\n description: 'poll interval in milliseconds (default 200)',\n },\n },\n required: ['message_id'],\n },\n },\n async invoke(args) {\n const messageId = String(args.message_id ?? '')\n if (!messageId) throw new Error('wait_for_reply: \"message_id\" is required')\n const timeout = typeof args.timeout_ms === 'number' ? args.timeout_ms : 30000\n const poll = typeof args.poll_ms === 'number' ? args.poll_ms : 200\n const start = Date.now()\n while (Date.now() - start < timeout) {\n const replies = await host.findReplies(fromAgentId, messageId)\n if (replies.length > 0) {\n const r = replies[0]\n if (r) {\n if (!r.readAt) await host.markRead(r.id)\n return `reply from ${r.fromAgentId} [${r.id}]: ${decodeText(r.payload)}`\n }\n }\n await new Promise((r) => setTimeout(r, poll))\n }\n return `no reply within ${timeout}ms`\n },\n },\n ]\n}\n","// Group-shared USER.md read/write surface for agents.\n//\n// USER.md is inlined into every agent's system prompt every turn (capped at\n// 12 KB on the daemon-side host). Agents previously could only read it; now\n// they can also update it via read-modify-write so they can correct stale\n// facts, not just stack new ones. Concurrency between multiple agents in\n// the same group is handled via optimistic etag checks — see\n// `lib/user-md-host.ts` for the full rationale.\n//\n// Two tools:\n// - `user_md_get` — returns current content + an etag.\n// - `user_md_write` — replaces content; requires `if_match` to equal the\n// most recent etag, else returns a conflict.\n//\n// Project knowledge (codebase notes, decisions) still goes to `memory_write`.\n// Personal notes about the agent itself go to `home_write` on IDENTITY.md.\n\nimport type { UserMdHost } from '../worker/ipc-protocol.ts'\nimport type { ToolHandler } from './types.ts'\n\nexport function userMdTools(host: UserMdHost, groupId: string): ToolHandler[] {\n return [\n {\n def: {\n name: 'user_md_get',\n description:\n \"Read the group-shared USER.md (facts every agent in the group knows about the human). Returns the current content followed by an `etag:` line — you MUST pass that etag back as `if_match` on the next `user_md_write` so the daemon can detect concurrent edits by other agents in the group. Always call this immediately before any `user_md_write`.\",\n parameters: {\n type: 'object',\n properties: {},\n },\n },\n async invoke() {\n const { content, etag } = await host.get(groupId)\n const body = content.length > 0 ? content : '(USER.md is empty)'\n return `${body}\\n\\n---\\netag: ${etag}`\n },\n },\n {\n def: {\n name: 'user_md_write',\n description:\n \"Replace the group-shared USER.md with new content. Use this for STABLE user-specific facts (preferences, role, working hours, how the human likes to be addressed). MANDATORY workflow: (1) call `user_md_get` first, (2) integrate your change into the full content preserving everything unrelated, (3) call `user_md_write` with the merged content and the etag you got from `user_md_get`. If another agent in the group wrote to USER.md between your get and write, this returns an etag-mismatch error — just call `user_md_get` again and retry the merge. The full result must fit under 12 KB. For project knowledge use `memory_write`; for notes about yourself use `home_write` on IDENTITY.md.\",\n parameters: {\n type: 'object',\n properties: {\n content: {\n type: 'string',\n description:\n 'Full new contents of USER.md (this is a complete replacement, NOT an append). Include everything you want to keep.',\n },\n if_match: {\n type: 'string',\n description:\n 'The etag returned by your most recent `user_md_get`. The write fails if USER.md changed in the meantime.',\n },\n },\n required: ['content', 'if_match'],\n },\n },\n async invoke(args) {\n const content = String(args.content ?? '')\n const ifMatch = String(args.if_match ?? '')\n if (!ifMatch) {\n throw new Error(\n 'user_md_write: \"if_match\" is required — call user_md_get first to obtain the current etag.',\n )\n }\n const { etag, totalBytes } = await host.write(groupId, content, ifMatch)\n return `wrote USER.md (${totalBytes} bytes, new etag: ${etag})`\n },\n },\n ]\n}\n","import { fetch as undiciFetch } from 'undici'\nimport type { ToolHandler } from './types.ts'\nimport {\n type ExtractMode,\n type ExtractResult,\n extractReadable,\n markdownToPlain,\n} from './web-extract.ts'\nimport { guardedFetch, SsrFBlockedError } from './web-ssrf.ts'\n\nconst DEFAULT_USER_AGENT =\n 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_7_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36'\nconst DEFAULT_CACHE_TTL_MS = 15 * 60_000\nconst DEFAULT_CACHE_MAX = 100\nconst DEFAULT_MAX_LENGTH = 20_000\nconst DEFAULT_TIMEOUT_MS = 30_000\n// Raw body cap applied before parsing. Multi-megabyte HTML (Mintlify/Next.js\n// docs sites, ad-heavy pages) can stall or OOM Readability+linkedom's\n// synchronous DOM walk. 3 MB comfortably covers real articles; anything\n// larger gets truncated and the caller sees a note in the output.\nconst DEFAULT_MAX_BODY_BYTES = 3 * 1024 * 1024\n// If the primary Readability path returns fewer than this many characters\n// from a 2xx HTML response, and FIRECRAWL_API_KEY is configured, retry the\n// fetch via Firecrawl which renders JS server-side. Threshold is heuristic:\n// real articles routinely exceed 200 chars; pages that bottom out below it\n// are almost always JS-shell pages where extraction collapsed.\nconst FIRECRAWL_FALLBACK_THRESHOLD = 200\nconst FIRECRAWL_DEFAULT_URL = 'https://api.firecrawl.dev'\n\ninterface SearchResult {\n title: string\n url: string\n snippet: string\n}\n\nfunction stripHtml(s: string): string {\n return s\n .replace(/<[^>]*>/g, '')\n .replace(/&amp;/g, '&')\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\")\n .replace(/&nbsp;/g, ' ')\n .trim()\n}\n\n// --- search backends ---\n\nasync function braveSearch(\n query: string,\n limit: number,\n apiKey: string,\n fetchFn: typeof fetch,\n): Promise<SearchResult[]> {\n const params = new URLSearchParams({ q: query, count: String(limit) })\n const res = await fetchFn(`https://api.search.brave.com/res/v1/web/search?${params}`, {\n headers: {\n accept: 'application/json',\n 'accept-encoding': 'gzip',\n 'x-subscription-token': apiKey,\n },\n })\n if (!res.ok) throw new Error(`Brave Search: ${res.status} ${await res.text()}`)\n const data = (await res.json()) as {\n web?: { results?: { title?: string; url?: string; description?: string }[] }\n }\n return (data.web?.results ?? []).slice(0, limit).map((r) => ({\n title: r.title ?? '',\n url: r.url ?? '',\n snippet: r.description ? stripHtml(r.description) : '',\n }))\n}\n\nasync function searxngSearch(\n query: string,\n limit: number,\n baseURL: string,\n fetchFn: typeof fetch,\n): Promise<SearchResult[]> {\n const params = new URLSearchParams({ q: query, format: 'json' })\n const res = await fetchFn(`${baseURL}/search?${params}`, {\n headers: { accept: 'application/json' },\n })\n if (!res.ok) throw new Error(`SearXNG: ${res.status} ${await res.text()}`)\n const data = (await res.json()) as {\n results?: { title?: string; url?: string; content?: string }[]\n }\n return (data.results ?? []).slice(0, limit).map((r) => ({\n title: r.title ?? '',\n url: r.url ?? '',\n snippet: r.content ?? '',\n }))\n}\n\n// --- error formatting ---\n\n/**\n * Flatten an Error and its `cause` chain into a single readable string.\n * undici surfaces network failures as `TypeError: fetch failed` with the\n * real reason (UND_ERR_*, ECONNRESET, certificate errors, …) stashed in\n * `err.cause`; without unwrapping it the agent only ever sees \"fetch\n * failed\" and has no path to diagnose or work around the problem.\n */\nfunction describeError(err: unknown): string {\n if (!(err instanceof Error)) return String(err)\n const parts: string[] = []\n const seen = new Set<unknown>()\n let cur: unknown = err\n while (cur instanceof Error && !seen.has(cur)) {\n seen.add(cur)\n const code = (cur as { code?: string }).code\n parts.push(code ? `[${code}] ${cur.message}` : cur.message)\n cur = (cur as { cause?: unknown }).cause\n }\n return parts.join(' — cause: ')\n}\n\n// --- bounded body reader ---\n\n/**\n * Stream `res.body` and accumulate up to `maxBytes`, then truncate. Returns\n * the decoded text (using the charset from content-type, falling back to\n * UTF-8) and a flag the caller can surface to the agent so it knows the\n * page was larger than the cap.\n */\nasync function readBodyCapped(\n res: Response,\n maxBytes: number,\n): Promise<{ text: string; truncated: boolean }> {\n const ct = res.headers.get('content-type') ?? ''\n const charset = /charset=([^;]+)/i.exec(ct)?.[1]?.trim().toLowerCase() || 'utf-8'\n const decoder = new TextDecoder(charset, { fatal: false })\n const reader = res.body?.getReader()\n if (!reader) {\n const text = await res.text()\n if (text.length > maxBytes) return { text: text.slice(0, maxBytes), truncated: true }\n return { text, truncated: false }\n }\n const chunks: Uint8Array[] = []\n let total = 0\n let truncated = false\n while (true) {\n const { value, done } = await reader.read()\n if (done) break\n if (!value) continue\n if (total + value.byteLength > maxBytes) {\n const keep = maxBytes - total\n if (keep > 0) chunks.push(value.subarray(0, keep))\n truncated = true\n try {\n await reader.cancel()\n } catch {\n // body already settled\n }\n break\n }\n chunks.push(value)\n total += value.byteLength\n }\n const sum = chunks.reduce((s, c) => s + c.byteLength, 0)\n const merged = new Uint8Array(sum)\n let off = 0\n for (const c of chunks) {\n merged.set(c, off)\n off += c.byteLength\n }\n return { text: decoder.decode(merged), truncated }\n}\n\n// --- Firecrawl fallback ---\n\ninterface FirecrawlResponse {\n success?: boolean\n data?: {\n markdown?: string\n metadata?: { title?: string }\n }\n error?: string\n}\n\n/**\n * Last-resort HTML rendering via Firecrawl's `/v1/scrape` endpoint. Used\n * when the primary Readability path returns near-empty content from a 2xx\n * HTML response (JS-only shells, anti-bot walls, login redirects). Returns\n * `null` when Firecrawl is not configured or the call fails so the caller\n * falls back to the primary extraction unchanged — Firecrawl is best-effort,\n * never an error source.\n */\nasync function firecrawlScrape(\n url: string,\n mode: ExtractMode,\n env: NodeJS.ProcessEnv,\n fetchFn: typeof fetch,\n timeoutMs: number,\n): Promise<ExtractResult | null> {\n const apiKey = env.FIRECRAWL_API_KEY\n if (!apiKey) return null\n const base = (env.FIRECRAWL_URL ?? FIRECRAWL_DEFAULT_URL).replace(/\\/$/, '')\n const ac = new AbortController()\n const t = setTimeout(() => ac.abort(new Error('firecrawl timeout')), timeoutMs)\n try {\n const res = await fetchFn(`${base}/v1/scrape`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${apiKey}`,\n accept: 'application/json',\n },\n body: JSON.stringify({\n url,\n formats: ['markdown'],\n onlyMainContent: true,\n }),\n signal: ac.signal,\n })\n if (!res.ok) return null\n const body = (await res.json()) as FirecrawlResponse\n if (!body.success || !body.data?.markdown) return null\n const md = body.data.markdown\n const title = body.data.metadata?.title\n const text = mode === 'text' ? markdownToPlain(md) : md\n return title ? { text, title } : { text }\n } catch {\n return null\n } finally {\n clearTimeout(t)\n }\n}\n\n// --- per-URL cache ---\n\ninterface CacheEntry {\n value: ExtractResult\n expiresAt: number\n}\n\nfunction cacheGet(cache: Map<string, CacheEntry>, key: string): ExtractResult | null {\n const entry = cache.get(key)\n if (!entry) return null\n if (entry.expiresAt < Date.now()) {\n cache.delete(key)\n return null\n }\n // Refresh LRU position\n cache.delete(key)\n cache.set(key, entry)\n return entry.value\n}\n\nfunction cacheSet(\n cache: Map<string, CacheEntry>,\n key: string,\n value: ExtractResult,\n ttlMs: number,\n maxEntries: number,\n): void {\n cache.set(key, { value, expiresAt: Date.now() + ttlMs })\n while (cache.size > maxEntries) {\n const oldest = cache.keys().next().value\n if (!oldest) break\n cache.delete(oldest)\n }\n}\n\n// --- tool factory ---\n\nexport interface WebToolsOpts {\n fetchImpl?: typeof fetch\n env?: NodeJS.ProcessEnv\n /** Disable SSRF checks (tests against 127.0.0.1 mock servers). Default false. */\n allowPrivate?: boolean\n /** Cache TTL in ms. Default 15 min. */\n cacheTtlMs?: number\n /** Max cache entries. Default 100. */\n cacheMax?: number\n /** Fetch timeout in ms. Default 30s. */\n timeoutMs?: number\n /** Cap on raw response body bytes before parsing. Default 3 MB. */\n maxBodyBytes?: number\n /** Disable the Firecrawl fallback even when FIRECRAWL_API_KEY is set. */\n firecrawlDisabled?: boolean\n}\n\n/**\n * web_search backends (tried in order):\n * 1. Brave Search (env: BRAVE_API_KEY) — free tier, 2000 req/month\n * 2. SearXNG (env: SEARXNG_URL) — self-hosted, unlimited\n * 3. Error with setup instructions if neither is configured\n *\n * web_fetch: guarded fetch (SSRF-blocked private IPs) + Readability + markdown,\n * with per-URL in-memory cache (15 min TTL).\n */\nexport function webTools(opts?: WebToolsOpts): ToolHandler[] {\n // Default to undici 8's fetch so search-backend HTTP shares the same\n // stack as guardedFetch (and stays out of Node 24's bundled undici 7).\n const fetchFn = opts?.fetchImpl ?? (undiciFetch as unknown as typeof fetch)\n const env = opts?.env ?? process.env\n const allowPrivate = opts?.allowPrivate ?? false\n const cacheTtlMs = opts?.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS\n const cacheMax = opts?.cacheMax ?? DEFAULT_CACHE_MAX\n const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS\n const maxBodyBytes = opts?.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES\n const firecrawlDisabled = opts?.firecrawlDisabled ?? false\n const cache = new Map<string, CacheEntry>()\n\n return [\n {\n def: {\n name: 'web_search',\n description:\n 'Search the internet. Returns a list of titles, URLs, and snippets. Requires BRAVE_API_KEY or SEARXNG_URL to be configured.',\n parameters: {\n type: 'object',\n properties: {\n query: { type: 'string', description: 'Search query' },\n limit: { type: 'number', description: 'Max results to return (default 5)' },\n },\n required: ['query'],\n },\n },\n async invoke(args) {\n const query = String(args.query ?? '')\n if (!query) throw new Error('web_search: query is required')\n const limit = typeof args.limit === 'number' ? args.limit : 5\n\n const braveKey = env.BRAVE_API_KEY\n if (braveKey) {\n const results = await braveSearch(query, limit, braveKey, fetchFn)\n return results.length === 0 ? 'no results' : formatResults(results)\n }\n\n const searxngUrl = env.SEARXNG_URL\n if (searxngUrl) {\n const results = await searxngSearch(query, limit, searxngUrl, fetchFn)\n return results.length === 0 ? 'no results' : formatResults(results)\n }\n\n throw new Error(\n 'web_search: no search backend configured. Set BRAVE_API_KEY (free at https://brave.com/search/api/) or SEARXNG_URL.',\n )\n },\n },\n {\n def: {\n name: 'web_fetch',\n description:\n 'Fetch a URL and return its readable content. HTML is extracted via Readability and converted to markdown. When the primary extraction returns near-empty content from a 2xx HTML page (typical of JS-only shells), the tool automatically retries via Firecrawl if FIRECRAWL_API_KEY is configured. Results are cached for 15 minutes.',\n parameters: {\n type: 'object',\n properties: {\n url: { type: 'string', description: 'The URL to fetch (http or https)' },\n max_length: {\n type: 'number',\n description: 'Max characters to return (default 20000)',\n },\n extract_mode: {\n type: 'string',\n enum: ['markdown', 'text'],\n description: 'Output format for HTML pages. Default \"markdown\".',\n },\n },\n required: ['url'],\n },\n },\n async invoke(args) {\n const url = String(args.url ?? '')\n if (!url) throw new Error('web_fetch: url is required')\n const maxLen = typeof args.max_length === 'number' ? args.max_length : DEFAULT_MAX_LENGTH\n const mode: ExtractMode = args.extract_mode === 'text' ? 'text' : 'markdown'\n const cacheKey = `${mode}|${url}`\n\n const cached = cacheGet(cache, cacheKey)\n if (cached) return formatOutput(cached, maxLen)\n\n let result: GuardedFetchResultShape | null = null\n try {\n result = await guardedFetch({\n url,\n fetchImpl: opts?.fetchImpl,\n allowPrivate,\n timeoutMs,\n init: {\n headers: {\n 'user-agent': DEFAULT_USER_AGENT,\n accept: 'text/html,application/xhtml+xml,application/json,text/plain,*/*',\n 'accept-language': 'en-US,en;q=0.9',\n },\n },\n })\n if (!result.response.ok) {\n throw new Error(`${result.response.status} ${result.response.statusText}`)\n }\n const ct = result.response.headers.get('content-type') ?? ''\n const isHtml = ct.includes('text/html') || ct.includes('xhtml')\n const { text: body, truncated } = await readBodyCapped(result.response, maxBodyBytes)\n let extracted: ExtractResult\n if (isHtml) {\n extracted = extractReadable(body, result.finalUrl, mode)\n } else if (ct.includes('application/json')) {\n try {\n extracted = { text: JSON.stringify(JSON.parse(body), null, 2) }\n } catch {\n extracted = { text: body }\n }\n } else {\n extracted = { text: body }\n }\n // Firecrawl fallback: only meaningful for HTML pages where the\n // primary extractor collapsed. Skip JSON / plain-text bodies and\n // skip when extraction already produced something substantial.\n if (\n isHtml &&\n !firecrawlDisabled &&\n extracted.text.length < FIRECRAWL_FALLBACK_THRESHOLD\n ) {\n const rescued = await firecrawlScrape(\n result.finalUrl,\n mode,\n env,\n fetchFn,\n timeoutMs,\n )\n if (rescued) {\n extracted = {\n ...rescued,\n text: `${rescued.text}\\n\\n[content rendered via Firecrawl fallback — primary extraction returned ${extracted.text.length} chars]`,\n }\n }\n }\n if (truncated) {\n extracted = {\n ...extracted,\n text: `${extracted.text}\\n\\n[raw body truncated at ${maxBodyBytes} bytes before extraction — page exceeded the size cap]`,\n }\n }\n cacheSet(cache, cacheKey, extracted, cacheTtlMs, cacheMax)\n return formatOutput(extracted, maxLen)\n } catch (err) {\n if (err instanceof SsrFBlockedError) throw new Error(`web_fetch: ${err.message}`)\n throw new Error(`web_fetch: ${describeError(err)}`)\n } finally {\n if (result) await result.release()\n }\n },\n },\n ]\n}\n\ntype GuardedFetchResultShape = Awaited<ReturnType<typeof guardedFetch>>\n\nfunction formatOutput(r: ExtractResult, maxLen: number): string {\n const body = r.title ? `# ${r.title}\\n\\n${r.text}` : r.text\n if (body.length > maxLen) return `${body.slice(0, maxLen)}\\n\\n[truncated at ${maxLen} chars]`\n return body\n}\n\nfunction formatResults(results: SearchResult[]): string {\n return results.map((r, i) => `${i + 1}. ${r.title}\\n ${r.url}\\n ${r.snippet}`).join('\\n\\n')\n}\n","import { Readability } from '@mozilla/readability'\nimport { parseHTML } from 'linkedom'\n\nexport type ExtractMode = 'markdown' | 'text'\n\nexport interface ExtractResult {\n text: string\n title?: string\n}\n\nfunction decodeEntities(value: string): string {\n return value\n .replace(/&nbsp;/gi, ' ')\n .replace(/&amp;/gi, '&')\n .replace(/&quot;/gi, '\"')\n .replace(/&#39;/gi, \"'\")\n .replace(/&lt;/gi, '<')\n .replace(/&gt;/gi, '>')\n .replace(/&#x([0-9a-f]+);/gi, (_, hex) => String.fromCharCode(Number.parseInt(hex, 16)))\n .replace(/&#(\\d+);/gi, (_, dec) => String.fromCharCode(Number.parseInt(dec, 10)))\n}\n\nfunction stripTags(value: string): string {\n return decodeEntities(value.replace(/<[^>]+>/g, ''))\n}\n\nfunction normalizeWhitespace(value: string): string {\n return value\n .replace(/\\r/g, '')\n .replace(/[ \\t]+\\n/g, '\\n')\n .replace(/\\n{3,}/g, '\\n\\n')\n .replace(/[ \\t]{2,}/g, ' ')\n .trim()\n}\n\nfunction htmlToMarkdown(html: string): { text: string; title?: string } {\n const titleMatch = html.match(/<title[^>]*>([\\s\\S]*?)<\\/title>/i)\n const title = titleMatch ? normalizeWhitespace(stripTags(titleMatch[1] ?? '')) : undefined\n let text = html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, '')\n .replace(/<style[\\s\\S]*?<\\/style>/gi, '')\n .replace(/<noscript[\\s\\S]*?<\\/noscript>/gi, '')\n .replace(/<nav[\\s\\S]*?<\\/nav>/gi, '')\n .replace(/<header[\\s\\S]*?<\\/header>/gi, '')\n .replace(/<footer[\\s\\S]*?<\\/footer>/gi, '')\n text = text.replace(/<a\\s+[^>]*href=[\"']([^\"']+)[\"'][^>]*>([\\s\\S]*?)<\\/a>/gi, (_, href, body) => {\n const label = normalizeWhitespace(stripTags(body))\n return label ? `[${label}](${href})` : href\n })\n text = text.replace(/<h([1-6])[^>]*>([\\s\\S]*?)<\\/h\\1>/gi, (_, level, body) => {\n const n = Math.max(1, Math.min(6, Number.parseInt(level, 10)))\n return `\\n${'#'.repeat(n)} ${normalizeWhitespace(stripTags(body))}\\n`\n })\n text = text.replace(/<li[^>]*>([\\s\\S]*?)<\\/li>/gi, (_, body) => {\n const label = normalizeWhitespace(stripTags(body))\n return label ? `\\n- ${label}` : ''\n })\n text = text\n .replace(/<(br|hr)\\s*\\/?>/gi, '\\n')\n .replace(/<\\/(p|div|section|article|tr|ul|ol|table|blockquote)>/gi, '\\n')\n text = stripTags(text)\n return { text: normalizeWhitespace(text), title }\n}\n\nexport function markdownToPlain(md: string): string {\n let t = md\n t = t.replace(/!\\[[^\\]]*]\\([^)]+\\)/g, '')\n t = t.replace(/\\[([^\\]]+)]\\([^)]+\\)/g, '$1')\n t = t.replace(/```[\\s\\S]*?```/g, (block) =>\n block.replace(/```[^\\n]*\\n?/g, '').replace(/```/g, ''),\n )\n t = t.replace(/`([^`]+)`/g, '$1')\n t = t.replace(/^#{1,6}\\s+/gm, '')\n t = t.replace(/^\\s*[-*+]\\s+/gm, '')\n t = t.replace(/^\\s*\\d+\\.\\s+/gm, '')\n return normalizeWhitespace(t)\n}\n\n/**\n * Extract readable content from HTML using Readability, with a regex-based\n * markdown fallback when Readability can't identify an article.\n */\nexport function extractReadable(html: string, url: string, mode: ExtractMode): ExtractResult {\n const fallback = (): ExtractResult => {\n const r = htmlToMarkdown(html)\n return mode === 'text' ? { text: markdownToPlain(r.text), title: r.title } : r\n }\n try {\n const { document } = parseHTML(html)\n try {\n ;(document as unknown as { baseURI?: string }).baseURI = url\n } catch {\n // best-effort\n }\n type ReadabilityArg = ConstructorParameters<typeof Readability>[0]\n const parsed = new Readability(document as unknown as ReadabilityArg, {\n charThreshold: 0,\n }).parse()\n if (!parsed?.content) return fallback()\n const title = parsed.title || undefined\n if (mode === 'text') {\n const text = normalizeWhitespace(parsed.textContent ?? '')\n return text ? { text, title } : fallback()\n }\n const rendered = htmlToMarkdown(parsed.content)\n return { text: rendered.text, title: title ?? rendered.title }\n } catch {\n return fallback()\n }\n}\n","import { lookup as dnsLookupCb, type LookupAddress } from 'node:dns'\nimport { lookup as dnsLookup } from 'node:dns/promises'\nimport { Agent, type Dispatcher, fetch as undiciFetch } from 'undici'\n\nexport class SsrFBlockedError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'SsrFBlockedError'\n }\n}\n\nconst BLOCKED_HOSTNAMES = new Set(['localhost', 'metadata.google.internal'])\nconst PRIVATE_IPV6_PREFIXES = ['fe80:', 'fec0:', 'fc', 'fd']\n\nfunction normalizeHostname(hostname: string): string {\n let h = hostname.trim().toLowerCase().replace(/\\.$/, '')\n if (h.startsWith('[') && h.endsWith(']')) h = h.slice(1, -1)\n return h\n}\n\nfunction parseIpv4(address: string): number[] | null {\n const parts = address.split('.')\n if (parts.length !== 4) return null\n const nums = parts.map((p) => Number.parseInt(p, 10))\n if (nums.some((n) => Number.isNaN(n) || n < 0 || n > 255)) return null\n return nums\n}\n\nfunction isPrivateIpv4(parts: number[]): boolean {\n const [a, b] = parts as [number, number, number, number]\n if (a === 0 || a === 10 || a === 127) return true\n if (a === 169 && b === 254) return true\n if (a === 172 && b >= 16 && b <= 31) return true\n if (a === 192 && b === 168) return true\n if (a === 100 && b >= 64 && b <= 127) return true\n return false\n}\n\nexport function isPrivateIpAddress(address: string): boolean {\n let norm = address.trim().toLowerCase()\n if (norm.startsWith('[') && norm.endsWith(']')) norm = norm.slice(1, -1)\n if (!norm) return false\n if (norm.startsWith('::ffff:')) {\n const mapped = norm.slice('::ffff:'.length)\n const ipv4 = parseIpv4(mapped)\n if (ipv4) return isPrivateIpv4(ipv4)\n }\n if (norm.includes(':')) {\n if (norm === '::' || norm === '::1') return true\n return PRIVATE_IPV6_PREFIXES.some((p) => norm.startsWith(p))\n }\n const ipv4 = parseIpv4(norm)\n return ipv4 ? isPrivateIpv4(ipv4) : false\n}\n\nexport function isBlockedHostname(hostname: string): boolean {\n const h = normalizeHostname(hostname)\n if (!h) return false\n if (BLOCKED_HOSTNAMES.has(h)) return true\n return h.endsWith('.localhost') || h.endsWith('.local') || h.endsWith('.internal')\n}\n\ntype LookupCallback = (\n err: NodeJS.ErrnoException | null,\n address: string | LookupAddress[],\n family?: number,\n) => void\n\nfunction createPinnedLookup(hostname: string, addresses: string[]): typeof dnsLookupCb {\n const normalized = normalizeHostname(hostname)\n const records = addresses.map((address) => ({\n address,\n family: (address.includes(':') ? 6 : 4) as 4 | 6,\n }))\n let index = 0\n return ((host: string, options?: unknown, callback?: unknown) => {\n const cb: LookupCallback =\n typeof options === 'function' ? (options as LookupCallback) : (callback as LookupCallback)\n if (!cb) return\n if (normalizeHostname(host) !== normalized) {\n if (typeof options === 'function' || options === undefined) {\n return (dnsLookupCb as unknown as (h: string, cb: LookupCallback) => void)(host, cb)\n }\n return (dnsLookupCb as unknown as (h: string, o: unknown, cb: LookupCallback) => void)(\n host,\n options,\n cb,\n )\n }\n const opts =\n typeof options === 'object' && options !== null\n ? (options as { all?: boolean; family?: number })\n : {}\n const family = typeof options === 'number' ? options : (opts.family ?? 0)\n const candidates =\n family === 4 || family === 6 ? records.filter((r) => r.family === family) : records\n const usable = candidates.length > 0 ? candidates : records\n if (opts.all) {\n cb(null, usable as LookupAddress[])\n return\n }\n const chosen = usable[index % usable.length]\n if (!chosen) return\n index += 1\n cb(null, chosen.address, chosen.family)\n }) as typeof dnsLookupCb\n}\n\nasync function resolveAndCheck(hostname: string): Promise<string[]> {\n const norm = normalizeHostname(hostname)\n if (!norm) throw new SsrFBlockedError('Invalid hostname')\n if (isBlockedHostname(norm)) throw new SsrFBlockedError(`Blocked hostname: ${hostname}`)\n if (isPrivateIpAddress(norm)) throw new SsrFBlockedError('Blocked: private IP literal')\n const results = await dnsLookup(norm, { all: true })\n if (results.length === 0) throw new SsrFBlockedError(`Cannot resolve: ${hostname}`)\n for (const r of results) {\n if (isPrivateIpAddress(r.address)) throw new SsrFBlockedError('Blocked: resolves to private IP')\n }\n return Array.from(new Set(results.map((r) => r.address)))\n}\n\ntype FetchLike = (input: string | URL, init?: RequestInit) => Promise<Response>\n\nexport interface GuardedFetchOptions {\n url: string\n fetchImpl?: FetchLike\n init?: RequestInit\n maxRedirects?: number\n timeoutMs?: number\n signal?: AbortSignal\n /** If true, skip all SSRF checks (for tests hitting 127.0.0.1 mocks). */\n allowPrivate?: boolean\n}\n\nexport interface GuardedFetchResult {\n response: Response\n finalUrl: string\n release: () => Promise<void>\n}\n\nfunction isRedirectStatus(s: number): boolean {\n return s === 301 || s === 302 || s === 303 || s === 307 || s === 308\n}\n\nasync function closeDispatcher(d: Dispatcher | null): Promise<void> {\n if (!d) return\n try {\n await d.close()\n } catch {\n // ignore\n }\n}\n\nexport async function guardedFetch(opts: GuardedFetchOptions): Promise<GuardedFetchResult> {\n // Use undici's own fetch (not globalThis.fetch) so the `dispatcher` Agent\n // we attach below is the same undici major version as the fetch impl\n // consuming it. Node 24 ships undici 7.x as its built-in fetch; mixing\n // a standalone undici 8.x Agent with the 7.x dispatcher fails with\n // `UND_ERR_INVALID_ARG: invalid onRequestStart method` because the\n // diagnostics-channel handler signatures changed between majors.\n const fetcher: FetchLike = opts.fetchImpl ?? (undiciFetch as unknown as FetchLike)\n const maxRedirects = opts.maxRedirects ?? 3\n const abortController = new AbortController()\n const timeoutId = opts.timeoutMs\n ? setTimeout(() => abortController.abort(new Error('timeout')), opts.timeoutMs)\n : null\n if (opts.signal) {\n if (opts.signal.aborted) abortController.abort(opts.signal.reason)\n else\n opts.signal.addEventListener('abort', () => abortController.abort(opts.signal?.reason), {\n once: true,\n })\n }\n\n let current = opts.url\n const visited = new Set<string>()\n let redirects = 0\n let dispatcher: Dispatcher | null = null\n\n const release = async (): Promise<void> => {\n if (timeoutId) clearTimeout(timeoutId)\n await closeDispatcher(dispatcher)\n dispatcher = null\n }\n\n while (true) {\n let parsed: URL\n try {\n parsed = new URL(current)\n } catch {\n await release()\n throw new Error('Invalid URL')\n }\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n await release()\n throw new Error('Invalid URL: must be http or https')\n }\n\n // Pin DNS only when we control the dispatcher (native fetch path).\n const canPin = !opts.fetchImpl\n if (!opts.allowPrivate) {\n const addrs = await resolveAndCheck(parsed.hostname)\n await closeDispatcher(dispatcher)\n dispatcher = canPin\n ? new Agent({ connect: { lookup: createPinnedLookup(parsed.hostname, addrs) } })\n : null\n }\n\n const init: RequestInit = {\n ...(opts.init ?? {}),\n redirect: 'manual',\n signal: abortController.signal,\n }\n // `dispatcher` is a Node fetch extension not reflected in the DOM\n // RequestInit type — and the undici Dispatcher type brand can diverge\n // from the one @types/node bundles. Stamp it on via a cast.\n if (dispatcher) (init as unknown as { dispatcher: Dispatcher }).dispatcher = dispatcher\n\n let res: Response\n try {\n res = await fetcher(parsed.toString(), init)\n } catch (err) {\n await release()\n throw err\n }\n\n if (isRedirectStatus(res.status)) {\n const loc = res.headers.get('location')\n if (!loc) {\n await release()\n throw new Error(`Redirect ${res.status} missing Location header`)\n }\n redirects += 1\n if (redirects > maxRedirects) {\n await release()\n throw new Error(`Too many redirects (> ${maxRedirects})`)\n }\n const next = new URL(loc, parsed).toString()\n if (visited.has(next)) {\n await release()\n throw new Error('Redirect loop')\n }\n visited.add(next)\n void res.body?.cancel()\n current = next\n continue\n }\n\n return { response: res, finalUrl: parsed.toString(), release }\n }\n}\n","// Catalog lookup for config UI + CLI: \"what models does provider X offer?\"\n//\n// Two sources, merged and de-duplicated:\n// 1. pi-ai's typed catalog (`getModels(provider)`) — static list of\n// known cloud models with cost + context-window metadata, bundled with\n// pi-ai. Works for the 10ish KnownProvider names; empty for local /\n// alias providers (lmstudio, ollama, bedrock-via-our-alias).\n// 2. For OpenAI-compat endpoints (lmstudio, ollama, openrouter,\n// vercel-ai-gateway, openai with custom baseURL), we query\n// `GET {baseURL}/models` and extract `data[].id`. This picks up\n// newly released models, user-loaded local models, etc.\n//\n// `listCatalogModels(providerName)` returns the union. Errors from live\n// fetches are surfaced so callers can show \"couldn't reach lmstudio\" rather\n// than a silent empty list.\n\nimport { getModels as piGetModels } from '@earendil-works/pi-ai'\nimport { fetch as undiciFetch } from 'undici'\n\n// piProviderName: what pi-ai's catalog indexes by. For bedrock we use the\n// Bazilion-registry-key 'bedrock' externally but pi uses 'amazon-bedrock'.\nconst REGISTRY_TO_PI: Record<string, string> = {\n bedrock: 'amazon-bedrock',\n 'azure-openai': 'azure-openai-responses',\n}\n\n// baseURL for providers whose /v1/models we can probe. Omitted for the\n// big cloud APIs that require a real key and generally aren't \"explore me\"\n// — those come from the pi catalog. `process.env` reads pick up the same\n// secrets/config merge the rest of the runtime uses.\nfunction liveEndpointFor(providerName: string, env: NodeJS.ProcessEnv): string | null {\n switch (providerName) {\n case 'lmstudio':\n return env.LMSTUDIO_URL ?? 'http://127.0.0.1:1234/v1'\n case 'ollama':\n // Ollama has its own /api/tags for model list; its OpenAI-compat /v1\n // endpoint supports /models though, so use that.\n return env.OLLAMA_URL ?? 'http://127.0.0.1:11434/v1'\n case 'llamacpp':\n return env.LLAMACPP_URL ?? 'http://127.0.0.1:8080/v1'\n case 'openrouter':\n return 'https://openrouter.ai/api/v1'\n case 'vercel-ai-gateway':\n return env.AI_GATEWAY_BASE_URL ?? 'https://ai-gateway.vercel.sh/v1'\n case 'groq':\n return 'https://api.groq.com/openai/v1'\n case 'cerebras':\n return 'https://api.cerebras.ai/v1'\n case 'xai':\n return 'https://api.x.ai/v1'\n case 'mistral':\n return 'https://api.mistral.ai/v1'\n default:\n return null\n }\n}\n\nfunction piModels(providerName: string): string[] {\n const piName = REGISTRY_TO_PI[providerName] ?? providerName\n try {\n const models = (piGetModels as unknown as (p: string) => { id: string }[] | undefined)(piName)\n if (!models) return []\n return models.map((m) => m.id)\n } catch {\n return []\n }\n}\n\nexport interface LiveFetchResult {\n models: string[]\n /** Only populated on failure; caller renders for UX. */\n error?: string\n}\n\nasync function fetchModelsFrom(\n baseURL: string,\n apiKey: string | undefined,\n signal?: AbortSignal,\n): Promise<LiveFetchResult> {\n try {\n const headers: Record<string, string> = { accept: 'application/json' }\n if (apiKey) headers.authorization = `Bearer ${apiKey}`\n const res = await undiciFetch(`${baseURL.replace(/\\/$/, '')}/models`, { headers, signal })\n if (!res.ok) return { models: [], error: `${res.status} ${res.statusText}` }\n const body = (await res.json()) as { data?: Array<{ id?: string }> } | null\n const ids = (body?.data ?? []).map((m) => m.id).filter((id): id is string => !!id)\n return { models: ids }\n } catch (err) {\n return { models: [], error: (err as Error).message }\n }\n}\n\nfunction apiKeyFor(providerName: string, env: NodeJS.ProcessEnv): string | undefined {\n switch (providerName) {\n case 'lmstudio':\n return env.LMSTUDIO_API_KEY ?? 'lm-studio'\n case 'ollama':\n return env.OLLAMA_API_KEY ?? 'ollama'\n case 'openrouter':\n return env.OPENROUTER_API_KEY\n case 'vercel-ai-gateway':\n return env.AI_GATEWAY_API_KEY\n case 'groq':\n return env.GROQ_API_KEY\n case 'cerebras':\n return env.CEREBRAS_API_KEY\n case 'xai':\n return env.XAI_API_KEY\n case 'mistral':\n return env.MISTRAL_API_KEY\n default:\n return undefined\n }\n}\n\nexport interface CatalogResult {\n /** Models from pi-ai's typed catalog — stable, no network. */\n catalog: string[]\n /** Live `/v1/models` query — populated only for openai-compat endpoints we know how to probe. */\n live?: LiveFetchResult\n}\n\n/**\n * List known models for a provider. Combines pi's static catalog with a live\n * `/v1/models` query for endpoints that expose one. Returns both separately\n * so the UI can surface which ones come from where.\n *\n * `live` is omitted (not just empty) when the provider doesn't expose a\n * `/v1/models` endpoint — e.g. Anthropic or Bedrock. Those rely on the\n * catalog only.\n */\nexport async function listCatalogModels(\n providerName: string,\n env: NodeJS.ProcessEnv = process.env,\n signal?: AbortSignal,\n): Promise<CatalogResult> {\n const catalog = piModels(providerName)\n const endpoint = liveEndpointFor(providerName, env)\n if (!endpoint) return { catalog }\n const key = apiKeyFor(providerName, env)\n const live = await fetchModelsFrom(endpoint, key, signal)\n return { catalog, live }\n}\n\n/** Synchronous variant for contexts that only want the pi catalog slice. */\nexport function listCatalogModelsSync(providerName: string): string[] {\n return piModels(providerName)\n}\n","// Parent-side spawn helper for whole-run subprocess isolation.\n//\n// `spawnWorkerTurn` launches `./entry.ts` and feeds it a `WorkerInput` JSON\n// blob on stdin describing the turn to run (pre-resolved agent record,\n// enabled-provider set, message text). The worker no longer opens its own\n// SQLite handle — the daemon is the sole owner of `~/.bazilion`.\n//\n// Two channels run between parent and child:\n// - stdout (NDJSON): the worker emits `ChatFrame`s; we line-parse and\n// yield each one to the caller.\n// - IPC (Node `stdio: 'ipc'`): the worker calls back into the parent for\n// anything that needs DB access during the turn (today: the messaging\n// tools `send_message` / `read_inbox` / `wait_for_reply`). We dispatch\n// each `IpcRequest` through the injected `MessagingHost` and reply with\n// `child.send`.\n//\n// Cancellation: wire an AbortSignal via `opts.signal`. On abort we send\n// SIGTERM to the child — the child has a signal handler that calls\n// `session.abort()`, which aborts the provider fetch and surfaces a final\n// `error` SessionEvent before the worker exits cleanly. If the child doesn't\n// exit within `killGraceMs`, we SIGKILL it.\n\nimport { type ChildProcess, spawn } from 'node:child_process'\nimport { existsSync } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport { fileURLToPath, pathToFileURL } from 'node:url'\nimport type { ChatFrame, ResolvedAgent } from '@bazilion/api-types'\nimport type { IpcReply, IpcRequest, MessagingHost, UserMdHost } from './ipc-protocol.ts'\n\nconst DEFAULT_KILL_GRACE_MS = 3_000\n\n// In dev, this file is at apps/daemon/src/runtime/worker/spawn.ts and the\n// worker entry is its `entry.ts` sibling. In the published bundle, all of\n// spawn.ts's code is inlined into dist/daemon.js, where `./entry.ts` does\n// not exist — the worker is bundled separately to dist/worker.js. Pick at\n// load time by probing the filesystem.\nconst sourceEntryPath = fileURLToPath(new URL('./entry.ts', import.meta.url))\nconst bundledEntryPath = fileURLToPath(new URL('./worker.js', import.meta.url))\nconst entryPath = existsSync(sourceEntryPath) ? sourceEntryPath : bundledEntryPath\nconst entryIsTs = entryPath.endsWith('.ts')\n\n// .ts dev entry: Node 24+ runs TS directly via native type-stripping (no\n// `--experimental-strip-types` flag needed in stable 24, but we still pass\n// it for older 22.x dev environments). tsx is the fallback for any runtime\n// where strip-types is missing. `--no-warnings` silences the experimental\n// banner that older Node versions emit on every child start.\n//\n// .js bundled entry: plain `node entry.js` — no type stripping, no tsx.\nfunction workerSpawnArgs(): string[] {\n if (!entryIsTs) return [entryPath]\n const tsFeature = (process.features as unknown as Record<string, unknown>).typescript\n if (typeof tsFeature === 'string' || tsFeature === true) {\n return ['--experimental-strip-types', '--no-warnings', entryPath]\n }\n return ['--import', tsxImportSpecifier(), entryPath]\n}\n\nlet cachedTsxImport: string | null = null\nfunction tsxImportSpecifier(): string {\n if (cachedTsxImport) return cachedTsxImport\n // `require.resolve('tsx')` returns the absolute path to tsx's loader.mjs —\n // the ESM module that hooks the runtime. Passing it to `node --import` as a\n // file:// URL is the most portable way to activate tsx in a subprocess: it\n // avoids CWD-sensitive bare-specifier resolution, and works regardless of\n // where the caller lives in a pnpm-hoisted workspace.\n const req = createRequire(import.meta.url)\n cachedTsxImport = pathToFileURL(req.resolve('tsx')).href\n return cachedTsxImport\n}\n\nexport interface WorkerTurnSpec {\n /** Pre-resolved agent record — the worker never queries the DB itself. */\n agent: ResolvedAgent\n /** First user-message text for this turn. */\n message: string\n /**\n * Names of providers the user has enabled in /config. Empty array means\n * no per-provider gating configured (all providers pass).\n */\n enabledProviders: string[]\n /**\n * Pre-fetched API key for the agent's provider. Required for OAuth-backed\n * providers (`openai-codex`) — the worker has no DB handle to read the\n * secrets table itself. Omit for env-key providers; `pi/session.ts` then\n * derives the key from `process.env`.\n */\n apiKey?: string\n}\n\nexport interface SpawnWorkerOpts {\n /** Abort to kill the in-flight worker. */\n signal?: AbortSignal\n /** ms between SIGTERM and fallback SIGKILL (default 3000). */\n killGraceMs?: number\n /** Override env passed to the child. Defaults to `process.env`. */\n env?: NodeJS.ProcessEnv\n /**\n * Daemon-side implementation of the messaging tools the worker calls back\n * into via IPC. Omit only when the caller knows the agent will not invoke\n * any of `send_message` / `read_inbox` / `wait_for_reply` — passing it\n * costs nothing for turns that don't use messaging.\n */\n messagingHost?: MessagingHost\n /**\n * Daemon-side implementation of the USER.md append tool. Omit and the\n * `user_md_append` tool will be unavailable on this turn.\n */\n userMdHost?: UserMdHost\n}\n\nexport async function* spawnWorkerTurn(\n spec: WorkerTurnSpec,\n opts: SpawnWorkerOpts = {},\n): AsyncGenerator<ChatFrame, void, void> {\n const child = spawn(process.execPath, workerSpawnArgs(), {\n env: opts.env ?? process.env,\n stdio: ['pipe', 'pipe', 'inherit', 'ipc'],\n })\n\n if (opts.messagingHost || opts.userMdHost) {\n attachIpcHandler(child, opts.messagingHost, opts.userMdHost)\n }\n\n child.stdin?.write(JSON.stringify(spec))\n child.stdin?.end()\n\n const grace = opts.killGraceMs ?? DEFAULT_KILL_GRACE_MS\n let killTimer: NodeJS.Timeout | null = null\n const onAbort = (): void => {\n if (child.exitCode !== null || child.signalCode !== null) return\n try {\n child.kill('SIGTERM')\n } catch {\n // process may have already exited between our check and the kill\n }\n killTimer = setTimeout(() => {\n if (child.exitCode === null && child.signalCode === null) {\n try {\n child.kill('SIGKILL')\n } catch {}\n }\n }, grace)\n killTimer.unref()\n }\n if (opts.signal?.aborted) onAbort()\n else opts.signal?.addEventListener('abort', onAbort)\n\n const waitForExit: Promise<{ code: number | null; signal: NodeJS.Signals | null }> = new Promise(\n (resolve) => {\n if (child.exitCode !== null || child.signalCode !== null) {\n resolve({ code: child.exitCode, signal: child.signalCode })\n return\n }\n child.once('close', (code, signal) => resolve({ code, signal }))\n },\n )\n\n let emittedFatal = false\n\n try {\n let buf = ''\n if (!child.stdout) throw new Error('worker spawn: stdout pipe missing')\n for await (const chunk of child.stdout) {\n buf += (chunk as Buffer).toString('utf8')\n let idx = buf.indexOf('\\n')\n while (idx !== -1) {\n const line = buf.slice(0, idx)\n buf = buf.slice(idx + 1)\n if (line.trim()) {\n const frame = parseFrame(line)\n if (frame.kind === 'fatal') emittedFatal = true\n yield frame\n }\n idx = buf.indexOf('\\n')\n }\n }\n if (buf.trim()) {\n const frame = parseFrame(buf)\n if (frame.kind === 'fatal') emittedFatal = true\n yield frame\n }\n\n const exit = await waitForExit\n // Child exited without emitting a fatal frame but with non-zero status —\n // surface that so the caller doesn't silently swallow a crash. Cancelled\n // turns produce an `error` SessionEvent via the worker's signal handler\n // and exit cleanly with code 0; only truly unexpected exits hit this.\n if (!emittedFatal && exit.code !== 0 && exit.code !== null) {\n yield {\n kind: 'fatal',\n error: `worker exited with code ${exit.code}${exit.signal ? ` (${exit.signal})` : ''}`,\n }\n } else if (!emittedFatal && exit.signal && exit.code === null) {\n yield { kind: 'fatal', error: `worker killed by ${exit.signal}` }\n }\n } finally {\n opts.signal?.removeEventListener('abort', onAbort)\n if (killTimer) clearTimeout(killTimer)\n try {\n child.disconnect()\n } catch {\n // already disconnected (child closed first) — fine\n }\n }\n}\n\nfunction parseFrame(line: string): ChatFrame {\n try {\n return JSON.parse(line) as ChatFrame\n } catch {\n return { kind: 'fatal', error: `worker emitted malformed frame: ${line.slice(0, 200)}` }\n }\n}\n\nfunction attachIpcHandler(\n child: ChildProcess,\n messagingHost: MessagingHost | undefined,\n userMdHost: UserMdHost | undefined,\n): void {\n child.on('message', (msg: unknown) => {\n if (!isIpcRequest(msg)) return\n void dispatch(msg, messagingHost, userMdHost).then((reply) => {\n try {\n child.send?.(reply)\n } catch {\n // child may have exited between request and reply — drop silently\n }\n })\n })\n}\n\nfunction isIpcRequest(msg: unknown): msg is IpcRequest {\n if (!msg || typeof msg !== 'object') return false\n const m = msg as Record<string, unknown>\n return m.type === 'rpc' && typeof m.id === 'string' && typeof m.method === 'string'\n}\n\nfunction requireMessagingHost(host: MessagingHost | undefined, method: string): MessagingHost {\n if (!host) throw new Error(`worker called messaging method \"${method}\" without a messagingHost`)\n return host\n}\n\nfunction requireUserMdHost(host: UserMdHost | undefined, method: string): UserMdHost {\n if (!host) throw new Error(`worker called user_md method \"${method}\" without a userMdHost`)\n return host\n}\n\nasync function dispatch(\n req: IpcRequest,\n messagingHost: MessagingHost | undefined,\n userMdHost: UserMdHost | undefined,\n): Promise<IpcReply> {\n try {\n let result: unknown\n switch (req.method) {\n case 'agentExists':\n result = await requireMessagingHost(messagingHost, req.method).agentExists(req.args.agentId)\n break\n case 'sendMessage':\n result = await requireMessagingHost(messagingHost, req.method).sendMessage(req.args)\n break\n case 'listInbox':\n result = await requireMessagingHost(messagingHost, req.method).listInbox(\n req.args.agentId,\n { unreadOnly: req.args.unreadOnly },\n )\n break\n case 'markRead':\n await requireMessagingHost(messagingHost, req.method).markRead(req.args.messageId)\n result = null\n break\n case 'findReplies':\n result = await requireMessagingHost(messagingHost, req.method).findReplies(\n req.args.agentId,\n req.args.replyTo,\n )\n break\n case 'userMdGet':\n result = await requireUserMdHost(userMdHost, req.method).get(req.args.groupId)\n break\n case 'userMdWrite':\n result = await requireUserMdHost(userMdHost, req.method).write(\n req.args.groupId,\n req.args.content,\n req.args.ifMatch,\n )\n break\n }\n return { type: 'rpc-reply', id: req.id, ok: true, result }\n } catch (err) {\n return { type: 'rpc-reply', id: req.id, ok: false, error: (err as Error).message }\n }\n}\n","// Resolves the API key (and refresher) for an agent's provider. Centralizes\n// the OAuth special case for `openai-codex` — its access token lives in the\n// daemon-owned `secrets` table, not in env vars, so callers can't pluck it\n// from the merged env the way they can for plain API-key providers.\n\nimport type { ResolvedAgent } from '@bazilion/api-types'\nimport type { BazilionDb } from '../core/index.ts'\nimport { hasOpenAICodexCredentials, loadOpenAICodexAccessToken } from '../runtime/index.ts'\n\nexport interface AgentApiKey {\n /** Initial access token / API key. Undefined when the env layer carries it. */\n apiKey?: string\n /**\n * Optional refresher pi calls during long tool-execution loops to swap an\n * expired JWT for a fresh one. Only set for OAuth providers — daemon-side\n * sessions wire this; worker turns currently rely on the initial token\n * carrying the whole turn (subsecond-to-minutes) since they have no DB\n * handle to refresh against.\n */\n refreshApiKey?: (providerName: string) => Promise<string>\n}\n\n/**\n * Pre-fetch the API key for `agent`'s provider. Returns `{}` when the\n * provider is env-key-based (the merged env passed to the session already\n * carries the value). For `openai-codex`, throws a friendly error when the\n * user hasn't connected their ChatGPT account yet — that surfaces in the\n * chat UI as a clear \"go to /config\" message rather than pi's generic\n * \"no API key\" complaint.\n */\nexport async function resolveAgentApiKey(\n db: BazilionDb,\n authToken: string,\n agent: ResolvedAgent,\n opts: { withRefresher?: boolean } = {},\n): Promise<AgentApiKey> {\n const providerName = agent.model.split(':', 1)[0] ?? ''\n if (providerName !== 'openai-codex') return {}\n\n if (!hasOpenAICodexCredentials(db, authToken)) {\n throw new Error(\n 'openai-codex is not connected — run `bazilion auth openai login` or click Connect on /config',\n )\n }\n const apiKey = await loadOpenAICodexAccessToken(db, authToken)\n if (!opts.withRefresher) return { apiKey }\n return {\n apiKey,\n refreshApiKey: async (requestedProvider) => {\n if (requestedProvider !== 'openai-codex') {\n throw new Error(`unexpected refresh request for ${requestedProvider}`)\n }\n return loadOpenAICodexAccessToken(db, authToken)\n },\n }\n}\n","// Daemon-side `MessagingHost` implementation backed by the local SQLite handle.\n//\n// Two consumers:\n// 1. In-process callers (compact / context / truncate endpoints) that build\n// a Bazilion session for inspection and want messaging tools enumerated\n// with the same shape the chat path sees.\n// 2. The IPC handler that services messaging requests issued by worker\n// subprocesses. Workers no longer hold a SQLite handle of their own —\n// they call `process.send({type: 'rpc', ...})` and the parent dispatches\n// through this host.\n\nimport { agentRepo, type BazilionDb, messageRepo } from '../core/index.ts'\nimport type { MessagingHost } from '../runtime/index.ts'\n\nexport function createDbMessagingHost(db: BazilionDb): MessagingHost {\n return {\n agentExists(agentId) {\n return agentRepo.get(db, agentId) !== null\n },\n sendMessage(input) {\n const m = messageRepo.send(db, input)\n return { messageId: m.id }\n },\n listInbox(agentId, opts) {\n return messageRepo.listInbox(db, agentId, opts)\n },\n markRead(messageId) {\n messageRepo.markRead(db, messageId)\n },\n findReplies(agentId, replyTo) {\n return messageRepo.findReplies(db, agentId, replyTo)\n },\n }\n}\n","// Daemon-side `UserMdHost` implementation backed by the local SQLite handle\n// + `groupRepo`. Same shape as `messaging-host.ts`: the worker subprocess\n// calls IPC, the daemon dispatches through this host.\n//\n// Optimistic concurrency: `get` returns the current content plus a short\n// content-derived etag. `write` requires the caller to echo that etag back\n// in `ifMatch`; if the stored content moved on in the meantime (another\n// agent in the same group wrote concurrently) the write fails with a\n// conflict error containing the new etag, and the caller is expected to\n// re-read, re-merge, and retry. No locks, no leases — pessimistic locking\n// would block agents for whole LLM turns (seconds-to-minutes), which is far\n// worse than the vanishingly-rare retry path.\n//\n// USER.md is capped at USER_MD_MAX_BYTES (kept in sync with the cap in\n// routes/groups.ts) because it's inlined into every agent's system prompt\n// on every turn — uncapped growth would silently blow out the context.\n\nimport { createHash } from 'node:crypto'\nimport { type BazilionDb, groupRepo } from '../core/index.ts'\nimport type { Paths } from '../core/paths.ts'\nimport type {\n UserMdGetResult,\n UserMdHost,\n UserMdWriteResult,\n} from '../runtime/index.ts'\n\nexport const USER_MD_MAX_BYTES = 12_000\n\n/** Short content hash. 16 hex chars is comfortable headroom against accidental collision. */\nfunction computeEtag(content: string): string {\n return createHash('sha256').update(content, 'utf8').digest('hex').slice(0, 16)\n}\n\nexport function createDbUserMdHost(db: BazilionDb, paths: Paths): UserMdHost {\n return {\n get(groupId): UserMdGetResult {\n const group = groupRepo.get(db, groupId, paths)\n if (!group) throw new Error(`group not found: ${groupId}`)\n return { content: group.userMd, etag: computeEtag(group.userMd) }\n },\n write(groupId, content, ifMatch): UserMdWriteResult {\n const group = groupRepo.get(db, groupId, paths)\n if (!group) throw new Error(`group not found: ${groupId}`)\n const currentEtag = computeEtag(group.userMd)\n if (currentEtag !== ifMatch) {\n throw new Error(\n `etag mismatch — USER.md was updated by another agent. Current etag is ${currentEtag} (you passed ${ifMatch}). Call user_md_get again to re-read, merge your change, and retry.`,\n )\n }\n const bytes = Buffer.byteLength(content, 'utf8')\n if (bytes > USER_MD_MAX_BYTES) {\n throw new Error(\n `USER.md would exceed the ${USER_MD_MAX_BYTES}-byte cap (you tried to write ${bytes}). Trim your content or ask the human to compact via the web UI.`,\n )\n }\n groupRepo.setUserMd(db, groupId, content)\n return { etag: computeEtag(content), totalBytes: bytes }\n },\n }\n}\n","import type { ChatFrame } from '@bazilion/api-types'\nimport { mergeSecretsIntoEnv, providerStateRepo, resolveAgent } from '../core/index.ts'\nimport { spawnWorkerTurn } from '../runtime/index.ts'\nimport { registerAgent, unregisterAgent } from './agent-cancel.ts'\nimport { resolveAgentApiKey } from './api-key.ts'\nimport { getCtx } from './ctx.ts'\nimport { createDbMessagingHost } from './messaging-host.ts'\nimport { createDbUserMdHost } from './user-md-host.ts'\n\ninterface RunAgentTurnOpts {\n /** If omitted, a fresh AbortController is created internally. */\n controller?: AbortController\n}\n\n/**\n * Runs one full agent turn in an isolated subprocess, streaming `ChatFrame`s\n * in NDJSON-ready order. The heavy lifting (provider calls, tool execution,\n * pi session journal append) happens inside the child; this function is a\n * thin relay that:\n * - resolves the agent + provider gate + secrets envelope here in the\n * daemon (the worker no longer holds a SQLite handle of its own),\n * - spawns the worker with an IPC channel and a `MessagingHost` that\n * services the inter-agent messaging tools the worker calls back into,\n * - forwards stdout frames to the caller and wires cancellation through\n * the agent-cancel registry.\n */\nexport async function* runAgentTurn(\n agentId: string,\n message: string,\n opts: RunAgentTurnOpts = {},\n): AsyncGenerator<ChatFrame> {\n const { db, paths, authToken } = getCtx()\n const agent = resolveAgent(db, paths, agentId)\n const enabledProviders = Array.from(providerStateRepo.listEnabled(db))\n const env = mergeSecretsIntoEnv(db, authToken)\n const messagingHost = createDbMessagingHost(db)\n const userMdHost = createDbUserMdHost(db, paths)\n // Pre-fetch the API key for OAuth providers (`openai-codex`) before the\n // worker spawns — the worker has no DB handle, so it can't reach the\n // secrets table itself. For env-key providers this is a no-op (`{}`).\n // Refresher is intentionally skipped: the worker has no IPC channel for\n // OAuth refresh today, and the initial token comfortably outlives a\n // single turn for ChatGPT-backed sessions.\n const { apiKey } = await resolveAgentApiKey(db, authToken, agent)\n\n const controller = opts.controller ?? new AbortController()\n registerAgent(agentId, controller)\n try {\n for await (const frame of spawnWorkerTurn(\n { agent, message, enabledProviders, apiKey },\n { signal: controller.signal, env, messagingHost, userMdHost },\n )) {\n yield frame\n }\n } finally {\n unregisterAgent(agentId)\n }\n}\n","// Minimal 5-field cron matcher: \"minute hour day-of-month month day-of-week\".\n// Supports *, */N, N, N-M, and comma-separated lists thereof per field.\n// Day-of-week: 0 or 7 = Sunday, 1 = Monday ... 6 = Saturday.\n//\n// Matching semantics match the \"standard\" cron (non-Vixie) rule: if BOTH\n// day-of-month and day-of-week are restricted (i.e. not `*`), the match is an\n// OR — the trigger fires when either matches. Most common expressions are\n// `*/5 * * * *` or `0 9 * * *` where only one of the two is restricted, so\n// the subtlety rarely matters.\n\nfunction parseField(raw: string, min: number, max: number): Set<number> {\n const values = new Set<number>()\n for (const part of raw.split(',')) {\n const [rangePart, stepPart] = part.split('/')\n const step = stepPart === undefined ? 1 : Number(stepPart)\n if (!Number.isInteger(step) || step < 1) {\n throw new Error(`invalid step \"${stepPart}\"`)\n }\n let lo: number\n let hi: number\n if (rangePart === '*' || rangePart === undefined) {\n lo = min\n hi = max\n } else if (rangePart.includes('-')) {\n const [a, b] = rangePart.split('-').map((n) => Number(n))\n if (!Number.isInteger(a) || !Number.isInteger(b)) {\n throw new Error(`invalid range \"${rangePart}\"`)\n }\n lo = a as number\n hi = b as number\n } else {\n const n = Number(rangePart)\n if (!Number.isInteger(n)) {\n throw new Error(`invalid value \"${rangePart}\"`)\n }\n lo = n\n hi = n\n }\n if (lo < min || hi > max || lo > hi) {\n throw new Error(`value out of range ${min}-${max}: \"${part}\"`)\n }\n for (let v = lo; v <= hi; v += step) values.add(v)\n }\n return values\n}\n\nexport interface ParsedCron {\n minute: Set<number>\n hour: Set<number>\n dom: Set<number>\n month: Set<number>\n dow: Set<number>\n domRestricted: boolean\n dowRestricted: boolean\n}\n\nexport function parseCron(expr: string): ParsedCron {\n const parts = expr.trim().split(/\\s+/)\n if (parts.length !== 5) {\n throw new Error(`expected 5 fields, got ${parts.length}: \"${expr}\"`)\n }\n const [m, h, dom, mon, dow] = parts as [string, string, string, string, string]\n const parsed: ParsedCron = {\n minute: parseField(m, 0, 59),\n hour: parseField(h, 0, 23),\n dom: parseField(dom, 1, 31),\n month: parseField(mon, 1, 12),\n // accept 7 as Sunday alias → normalise to 0\n dow: new Set([...parseField(dow.replace(/7/g, '0'), 0, 6)]),\n domRestricted: dom !== '*',\n dowRestricted: dow !== '*',\n }\n return parsed\n}\n\nexport function matchesCron(parsed: ParsedCron, date: Date): boolean {\n if (!parsed.minute.has(date.getMinutes())) return false\n if (!parsed.hour.has(date.getHours())) return false\n if (!parsed.month.has(date.getMonth() + 1)) return false\n const domMatch = parsed.dom.has(date.getDate())\n const dowMatch = parsed.dow.has(date.getDay())\n if (parsed.domRestricted && parsed.dowRestricted) {\n return domMatch || dowMatch\n }\n if (parsed.domRestricted) return domMatch\n if (parsed.dowRestricted) return dowMatch\n return true\n}\n\n/** Validates an expression — throws on syntax errors. Used by API write paths. */\nexport function validateCron(expr: string): void {\n parseCron(expr)\n}\n","// In-process scheduler for agent triggers (heartbeats + cron) and inbox\n// auto-delivery.\n//\n// Each tick does two jobs:\n//\n// 1. Trigger firing. Loads enabled `agent_triggers` rows and fires whichever\n// are due via `runAgentTurn`. A trigger is \"due\" when:\n// - interval: last_fired_at + intervalSec*1000 ≤ now (never-fired\n// uses created_at as the baseline)\n// - cron: current minute's wall-clock matches expression AND\n// last_fired_at's minute < current minute\n//\n// 2. Inbox auto-delivery (always on). Scans `messages` for recipients\n// with unread mail. For each idle recipient (not already running /\n// firing), drains all their unread messages in one transaction and\n// fires a turn whose prompt embeds the messages. Marking read happens\n// *inside* the drain transaction so two concurrent ticks can't\n// double-dispatch. To disable both triggers AND auto-delivery, set\n// `BAZILION_SCHEDULER=off` — there is no separate inbox-only knob\n// because free inter-agent messaging is a baseline Bazilion promise.\n//\n// Concurrency: each trigger gets an in-memory \"firing\" guard so a slow turn\n// can't pile up overlapping runs for the same trigger. Auto-delivery shares\n// the same mechanism keyed on `msg-wake:<agentId>`. The DB is still the\n// source of truth for last_fired_at / read_at — we mark *before* kicking the\n// run, so a server restart won't immediately re-fire.\n\nimport type { AgentTrigger, Message } from '@bazilion/api-types'\nimport { agentRepo, messageRepo, triggerRepo } from '../core/index.ts'\nimport { isActiveAgent } from './agent-cancel.ts'\nimport { runAgentTurn } from './agent-turn.ts'\nimport { matchesCron, type ParsedCron, parseCron } from './cron.ts'\nimport { getCtx } from './ctx.ts'\n\nconst SCHEDULER_KEY = Symbol.for('bazilion.scheduler')\nconst TICK_MS = Number(process.env.BAZILION_SCHEDULER_TICK_MS ?? 5_000)\n\ninterface SchedulerState {\n timer: NodeJS.Timeout | null\n firing: Set<string>\n cronCache: Map<string, ParsedCron>\n /** pinned onStop for graceful shutdown (tests) */\n stopped: boolean\n}\n\nfunction state(): SchedulerState {\n const g = globalThis as unknown as Record<symbol, SchedulerState | undefined>\n let s = g[SCHEDULER_KEY]\n if (!s) {\n s = { timer: null, firing: new Set(), cronCache: new Map(), stopped: false }\n g[SCHEDULER_KEY] = s\n }\n return s\n}\n\nfunction floorToMinute(ms: number): number {\n return Math.floor(ms / 60_000) * 60_000\n}\n\nfunction isDue(t: AgentTrigger, now: number, cronCache: Map<string, ParsedCron>): boolean {\n if (!t.enabled) return false\n if (t.kind === 'interval') {\n const every = (t.intervalSec ?? 0) * 1000\n if (every <= 0) return false\n const baseline = t.lastFiredAt ?? t.createdAt\n return now - baseline >= every\n }\n if (t.kind === 'cron') {\n if (!t.cronExpr) return false\n let parsed = cronCache.get(t.cronExpr)\n if (!parsed) {\n try {\n parsed = parseCron(t.cronExpr)\n } catch {\n return false\n }\n cronCache.set(t.cronExpr, parsed)\n }\n const nowFloor = floorToMinute(now)\n if (t.lastFiredAt && floorToMinute(t.lastFiredAt) === nowFloor) return false\n return matchesCron(parsed, new Date(nowFloor))\n }\n return false\n}\n\nasync function fireTrigger(t: AgentTrigger): Promise<void> {\n const s = state()\n if (s.firing.has(t.id)) return\n s.firing.add(t.id)\n const ctx = getCtx()\n // Mark fired first — if the agent turn fails, we still don't want to loop\n // on the same trigger every tick. The user will see it in `trigger list`\n // (last_fired_at updated) and the run will be marked failed.\n try {\n triggerRepo.markFired(ctx.db, t.id)\n } catch (err) {\n console.error(`[scheduler] markFired failed for ${t.id}:`, err)\n s.firing.delete(t.id)\n return\n }\n try {\n // Drain the turn; we don't stream to anyone. Errors surface as `fatal`\n // frames which we log but don't throw — the run row in the DB carries\n // the real status.\n for await (const frame of runAgentTurn(t.agentId, t.message)) {\n if (frame.kind === 'fatal') {\n console.error(`[scheduler] trigger ${t.id} fatal:`, frame.error)\n }\n }\n } catch (err) {\n console.error(`[scheduler] trigger ${t.id} unexpected throw:`, err)\n } finally {\n s.firing.delete(t.id)\n }\n}\n\nfunction decodeText(payload: string): string {\n try {\n const obj = JSON.parse(payload) as { text?: unknown }\n if (typeof obj.text === 'string') return obj.text\n } catch {}\n return payload\n}\n\n// Sentinel prepended to every inbox-wake prompt. The web chat UI detects it\n// to render the bubble with a distinct \"inter-agent\" style instead of the\n// default user-message styling. Kept in sync by copy with `chat.ts`'s\n// INBOX_WAKE_PREFIX constant.\nconst INBOX_WAKE_PREFIX = '[[bazilion:inbox-wake]]\\n'\n\n/**\n * Build a wake-up prompt for an agent that has unread mail. The prompt is\n * framed as a user-side system notice — not an agent-style message — so the\n * recipient's LLM understands this is the runtime telling it \"here's what\n * arrived for you\".\n *\n * Loop prevention: we differentiate by `replyTo`. A NEW message (no\n * `replyTo`) opens a thread, and the sender is waiting for an answer — the\n * agent must respond at least once. A REPLY (`replyTo` set) is already\n * closing a round-trip, so the agent may acknowledge silently. This single\n * asymmetry is enough to terminate conversations after one exchange instead\n * of ping-ponging forever (\"you have to answer me\" → \"no you have to\n * answer me\" → …).\n */\nfunction buildInboxPrompt(\n agentId: string,\n messages: Message[],\n fromNames: Map<string, string>,\n): string {\n const lines: string[] = [INBOX_WAKE_PREFIX.trimEnd()]\n lines.push(\n `You have ${messages.length} new message${messages.length === 1 ? '' : 's'} in your inbox:`,\n )\n lines.push('')\n const newThread: Message[] = []\n for (const m of messages) {\n const name = fromNames.get(m.fromAgentId)\n const fromLabel = name ? `${name} (${m.fromAgentId})` : m.fromAgentId\n const text = decodeText(m.payload)\n const header = m.replyTo\n ? `--- from ${fromLabel} (message ${m.id}, reply to ${m.replyTo}) ---`\n : `--- from ${fromLabel} (message ${m.id}) ---`\n lines.push(header)\n lines.push(text)\n lines.push('')\n if (!m.replyTo) newThread.push(m)\n }\n if (newThread.length > 0) {\n lines.push(\n `You MUST reply to the ${newThread.length} new message${newThread.length === 1 ? '' : 's'} above ` +\n '(the ones that are NOT marked as a reply). For each, call ' +\n '`send_message(to=<sender agent id>, text=<your reply>, reply_to=<the message id shown in the header>)`. ' +\n 'Give a concrete answer if you can; a brief acknowledgement is fine if the message is purely informational. ' +\n 'Avoid asking follow-up questions — answer with what you already know. ' +\n 'IMPORTANT: do NOT demand a response from the sender in your reply — they already got what they asked for, ' +\n 'and asking them back to reply just creates infinite loops.',\n )\n }\n const replies = messages.filter((m) => m.replyTo)\n if (replies.length > 0) {\n lines.push(\n `The other message${replies.length === 1 ? ' is a reply' : 's are replies'} to something you previously sent. ` +\n 'Read, absorb, and move on — no response is required. Only send a follow-up if there is a ' +\n 'genuinely new question or action that requires it; otherwise this thread is closed.',\n )\n }\n // reference the recipient id so the agent knows which mailbox this is for\n // in case it was spawned without persona context\n lines.push(`(recipient: ${agentId})`)\n return lines.join('\\n')\n}\n\nasync function fireInboxWake(agentId: string): Promise<void> {\n const s = state()\n const key = `msg-wake:${agentId}`\n if (s.firing.has(key)) return\n const ctx = getCtx()\n // Skip agents with an active turn — they'll pick up the messages on their\n // next natural turn or via the next tick after the current one ends.\n if (isActiveAgent(agentId)) return\n\n s.firing.add(key)\n try {\n const msgs = messageRepo.drainUnreadForAgent(ctx.db, agentId)\n if (msgs.length === 0) {\n // Raced with another consumer; nothing to do.\n return\n }\n const fromIds = new Set(msgs.map((m) => m.fromAgentId))\n const fromNames = new Map<string, string>()\n for (const fid of fromIds) {\n const sender = agentRepo.get(ctx.db, fid)\n if (sender) fromNames.set(fid, sender.name)\n }\n const prompt = buildInboxPrompt(agentId, msgs, fromNames)\n\n try {\n for await (const frame of runAgentTurn(agentId, prompt)) {\n if (frame.kind === 'fatal') {\n console.error(`[scheduler] inbox wake ${agentId} fatal:`, frame.error)\n }\n }\n } catch (err) {\n console.error(`[scheduler] inbox wake ${agentId} unexpected throw:`, err)\n }\n } catch (err) {\n console.error(`[scheduler] inbox drain failed for ${agentId}:`, err)\n } finally {\n s.firing.delete(key)\n }\n}\n\nasync function tick(): Promise<void> {\n const s = state()\n if (s.stopped) return\n const now = Date.now()\n let triggers: AgentTrigger[]\n let recipients: string[] = []\n try {\n const ctx = getCtx()\n triggers = triggerRepo.listEnabled(ctx.db)\n recipients = messageRepo.listRecipientsWithUnread(ctx.db)\n } catch (err) {\n console.error('[scheduler] tick read failed:', err)\n return\n }\n for (const t of triggers) {\n if (isDue(t, now, s.cronCache)) {\n // Fire async, don't await — the tick itself must stay fast.\n void fireTrigger(t)\n }\n }\n for (const agentId of recipients) {\n // Same fire-and-forget shape as triggers; `fireInboxWake` internally\n // dedup-gates and bails if the agent already has an active run.\n void fireInboxWake(agentId)\n }\n}\n\nexport function startScheduler(): void {\n const s = state()\n // Replace any existing timer unconditionally so a duplicate startScheduler\n // call (e.g. test harness calling getCtx twice) doesn't leave stale loops.\n if (s.timer) clearInterval(s.timer)\n s.stopped = false\n s.timer = setInterval(() => {\n void tick()\n }, TICK_MS)\n // Unref so the scheduler never blocks process exit in tests.\n if (typeof s.timer.unref === 'function') s.timer.unref()\n}\n\nexport function stopScheduler(): void {\n const s = state()\n s.stopped = true\n if (s.timer) {\n clearInterval(s.timer)\n s.timer = null\n }\n}\n\n// Exposed for tests that want to drive the loop manually rather than wait\n// on wall-clock intervals.\nexport async function _tickOnce(): Promise<void> {\n await tick()\n}\n\nexport function _isDueForTest(\n t: AgentTrigger,\n now: number,\n cronCache: Map<string, ParsedCron> = new Map(),\n): boolean {\n return isDue(t, now, cronCache)\n}\n","// Token verification primitives — framework-agnostic. The Hono auth middleware\n// (lib/middleware-auth.ts) wraps these; native clients (CLI, mobile) pass the\n// same token via `Authorization: Bearer …`, and browsers send the httpOnly\n// `bz_token` cookie minted by `POST /api/login`.\n//\n// All tokens — including the bootstrap one minted by the daemon's first-run\n// bootstrap — live as hashed rows in the `web_tokens` table. The bootstrap\n// row's plaintext is exposed in `~/.bazilion/auth.json` so the daemon (PBKDF2\n// seed for the secrets table) and the CLI (loopback bearer) can use it.\n// Validation goes through `findActiveByToken`, no special-case loopback path.\n\nimport { webTokenRepo } from '../core/index.ts'\nimport { getCtx } from './ctx.ts'\n\n/**\n * Is this string a currently-valid token? Accepts any active (non-revoked)\n * row in `web_tokens` — including the bootstrap row written by the daemon's\n * first-run bootstrap. Bumps `last_used_at` on a match so operators can see\n * idle vs active tokens in `token list`.\n */\nexport function isValidToken(token: string): boolean {\n try {\n const { db } = getCtx()\n const match = webTokenRepo.findActiveByToken(db, token)\n if (match) {\n webTokenRepo.markUsed(db, match.id)\n return true\n }\n } catch {\n // db unavailable — treat as unauthenticated\n }\n return false\n}\n\n/** Pull the bearer token out of an `Authorization: Bearer …` header. */\nexport function extractBearer(authHeader: string | null | undefined): string | null {\n if (!authHeader) return null\n // RFC 6750 auth scheme is case-insensitive.\n const match = /^\\s*Bearer\\s+(.+?)\\s*$/i.exec(authHeader)\n return match?.[1] ?? null\n}\n","// /api/agents/* — agent CRUD + lifecycle + sub-resources (group, skills,\n// triggers, messages, sessions, chat). Memory is per-group and lives on\n// the groups router.\n//\n// Sub-resources are inlined here rather than split across files because they\n// all share `/api/agents/:id/...` and benefit from being adjacent — e.g. the\n// chat streaming endpoint and chat/compact next to each other.\n\nimport { existsSync, readdirSync, readFileSync, rmSync } from 'node:fs'\nimport { join } from 'node:path'\nimport {\n type AttachSkillRequest,\n type ChatCompactRequest,\n type ChatCompactResponse,\n type ChatContextResponse,\n type ContextFileEntry,\n type ContextGroupEntry,\n type ContextSkillEntry,\n type ContextToolEntry,\n type CreateTriggerRequest,\n type ListInboxResponse,\n type MoveAgentRequest,\n REASONING_LEVELS,\n type ReasoningLevel,\n type ResolvedSkillsResponse,\n type SendMessageRequest,\n type SessionHeadResponse,\n type SpawnAgentRequest,\n type TruncateChatRequest,\n type TruncateChatResponse,\n} from '@bazilion/api-types'\nimport { Hono } from 'hono'\nimport {\n agentRepo,\n archiveAgent,\n deleteAgent,\n discoverSkills,\n groupRepo,\n mergeSecretsIntoEnv,\n messageRepo,\n providerStateRepo,\n resolveAgent,\n resolveAgentSkills,\n skillMetaRepo,\n spawnAgent,\n triggerRepo,\n unarchiveAgent,\n} from '../core/index.ts'\nimport { cancelAgent } from '../lib/agent-cancel.ts'\nimport { resolveAgentIdParam } from '../lib/agent-id.ts'\nimport { runAgentTurn } from '../lib/agent-turn.ts'\nimport { resolveAgentApiKey } from '../lib/api-key.ts'\nimport { validateCron } from '../lib/cron.ts'\nimport { getCtx } from '../lib/ctx.ts'\nimport { createDbMessagingHost } from '../lib/messaging-host.ts'\nimport {\n buildSystemPrompt,\n createBazilionSession,\n loadInitialMessages,\n loadSessionHead,\n piMessagesToProviderView,\n qmdBackend,\n} from '../runtime/index.ts'\n\nexport const agentsRouter = new Hono()\n\n// ─── CRUD + lifecycle ────────────────────────────────────────────────────\n\nagentsRouter.get('/', (c) => {\n const includeArchived = c.req.query('includeArchived') === 'true'\n const { db, paths, authToken } = getCtx()\n return c.json(agentRepo.list(db, { includeArchived }))\n})\n\nagentsRouter.post('/', async (c) => {\n const raw = (await c.req.json().catch(() => null)) as\n | (Record<string, unknown> & Partial<SpawnAgentRequest>)\n | null\n if (!raw) return c.json({ error: 'invalid JSON body' }, 400)\n const profileId =\n typeof raw.profileId === 'string'\n ? raw.profileId\n : typeof raw.profile === 'string'\n ? raw.profile\n : ''\n if (!profileId) return c.json({ error: 'profileId is required' }, 400)\n const name = typeof raw.name === 'string' && raw.name ? raw.name : undefined\n const model =\n typeof raw.model === 'string' && raw.model\n ? raw.model\n : typeof raw.modelOverride === 'string' && raw.modelOverride\n ? raw.modelOverride\n : undefined\n const groupId =\n typeof raw.groupId === 'string' && raw.groupId\n ? raw.groupId\n : typeof raw.group === 'string' && raw.group\n ? (raw.group as string)\n : undefined\n let reasoningLevel: ReasoningLevel | undefined\n if (typeof raw.reasoningLevel === 'string') {\n if (!REASONING_LEVELS.includes(raw.reasoningLevel as ReasoningLevel)) {\n return c.json({ error: `invalid reasoningLevel: ${raw.reasoningLevel}` }, 400)\n }\n reasoningLevel = raw.reasoningLevel as ReasoningLevel\n }\n\n const { db, paths, authToken } = getCtx()\n try {\n const agent = spawnAgent(db, paths, {\n profileId,\n name,\n modelOverride: model,\n reasoningLevel,\n groupId,\n })\n return c.json(agent, 201)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n})\n\nagentsRouter.get('/:id', (c) => {\n const { db, paths, authToken } = getCtx()\n const id = resolveAgentIdParam(db, c.req.param('id'))\n try {\n return c.json(resolveAgent(db, paths, id))\n } catch (err) {\n return c.json({ error: (err as Error).message }, 404)\n }\n})\n\nagentsRouter.patch('/:id', async (c) => {\n const body = (await c.req.json().catch(() => null)) as Record<string, unknown> | null\n if (!body) return c.json({ error: 'invalid JSON body' }, 400)\n const { db, paths, authToken } = getCtx()\n const resolvedId = agentRepo.resolveId(db, c.req.param('id'))\n if (!resolvedId) return c.json({ error: `agent not found: ${c.req.param('id')}` }, 404)\n\n if (body.name !== undefined) {\n if (typeof body.name !== 'string') return c.json({ error: 'name must be a string' }, 400)\n const trimmed = body.name.trim()\n if (!trimmed) return c.json({ error: 'name cannot be empty' }, 400)\n agentRepo.setName(db, resolvedId, trimmed)\n }\n if (body.reasoningLevel !== undefined) {\n if (\n typeof body.reasoningLevel !== 'string' ||\n !REASONING_LEVELS.includes(body.reasoningLevel as ReasoningLevel)\n ) {\n return c.json({ error: `invalid reasoningLevel: ${body.reasoningLevel}` }, 400)\n }\n agentRepo.setReasoningLevel(db, resolvedId, body.reasoningLevel as ReasoningLevel)\n }\n if (body.modelOverride !== undefined) {\n if (body.modelOverride !== null && typeof body.modelOverride !== 'string') {\n return c.json({ error: 'modelOverride must be a string or null' }, 400)\n }\n const value = body.modelOverride === '' ? null : (body.modelOverride as string | null)\n agentRepo.setModelOverride(db, resolvedId, value)\n }\n\n const agent = agentRepo.get(db, resolvedId)\n if (!agent) return c.json({ error: 'agent vanished after update' }, 404)\n return c.json(agent)\n})\n\nagentsRouter.delete('/:id', (c) => {\n const { db, paths, authToken } = getCtx()\n try {\n deleteAgent(db, c.req.param('id'))\n return c.body(null, 204)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n})\n\nagentsRouter.post('/:id/archive', (c) => {\n const { db, paths, authToken } = getCtx()\n try {\n archiveAgent(db, c.req.param('id'))\n return c.body(null, 204)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n})\n\nagentsRouter.post('/:id/unarchive', (c) => {\n const { db, paths, authToken } = getCtx()\n try {\n unarchiveAgent(db, c.req.param('id'))\n return c.body(null, 204)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n})\n\n// ─── Group move ──────────────────────────────────────────────────────────\n\nagentsRouter.patch('/:id/group', async (c) => {\n const body = (await c.req.json().catch(() => null)) as MoveAgentRequest | null\n if (!body || typeof body.groupId !== 'string' || !body.groupId) {\n return c.json({ error: 'groupId (string) is required' }, 400)\n }\n const { db, paths, authToken } = getCtx()\n let resolved: ReturnType<typeof resolveAgent>\n try {\n resolved = resolveAgent(db, paths, c.req.param('id'))\n } catch {\n return c.json({ error: `agent not found: ${c.req.param('id')}` }, 404)\n }\n if (!groupRepo.get(db, body.groupId, paths)) {\n return c.json({ error: `group not found: ${body.groupId}` }, 404)\n }\n agentRepo.setGroup(db, resolved.agent.id, body.groupId)\n return c.json(resolveAgent(db, paths, resolved.agent.id))\n})\n\n// ─── Skills ──────────────────────────────────────────────────────────────\n\nagentsRouter.get('/:id/skills', (c) => {\n const { db, paths, authToken } = getCtx()\n const id = resolveAgentIdParam(db, c.req.param('id'))\n const set = resolveAgentSkills(db, paths, id)\n const body: ResolvedSkillsResponse = {\n resolved: set.resolved.map((s) => {\n const meta = skillMetaRepo.get(db, s.name)\n return {\n name: s.name,\n description: s.parsed.frontmatter.description,\n source: meta?.source ?? null,\n importedAt: meta?.importedAt ?? null,\n }\n }),\n missing: set.missing,\n }\n return c.json(body)\n})\n\nagentsRouter.post('/:id/skills', async (c) => {\n const body = (await c.req.json().catch(() => null)) as AttachSkillRequest | null\n if (!body || typeof body.skill !== 'string' || !body.skill) {\n return c.json({ error: 'skill is required' }, 400)\n }\n const { db, paths, authToken } = getCtx()\n const agent = agentRepo.get(db, c.req.param('id'))\n if (!agent) return c.json({ error: `agent not found: ${c.req.param('id')}` }, 404)\n agentRepo.attachSkill(db, agent.id, body.skill)\n return c.body(null, 204)\n})\n\nagentsRouter.delete('/:id/skills/:name', (c) => {\n const { db, paths, authToken } = getCtx()\n const id = resolveAgentIdParam(db, c.req.param('id'))\n agentRepo.detachSkill(db, id, c.req.param('name'))\n return c.body(null, 204)\n})\n\n// ─── Triggers ────────────────────────────────────────────────────────────\n\nagentsRouter.get('/:id/triggers', (c) => {\n const { db, paths, authToken } = getCtx()\n const agent = agentRepo.get(db, c.req.param('id'))\n if (!agent) return c.json({ error: `agent not found: ${c.req.param('id')}` }, 404)\n return c.json({ triggers: triggerRepo.listForAgent(db, agent.id) })\n})\n\nagentsRouter.post('/:id/triggers', async (c) => {\n const body = (await c.req.json().catch(() => null)) as CreateTriggerRequest | null\n if (!body) return c.json({ error: 'invalid JSON body' }, 400)\n if (typeof body.message !== 'string' || !body.message.trim()) {\n return c.json({ error: 'message is required' }, 400)\n }\n const { db, paths, authToken } = getCtx()\n const agent = agentRepo.get(db, c.req.param('id'))\n if (!agent) return c.json({ error: `agent not found: ${c.req.param('id')}` }, 404)\n\n if (body.kind === 'interval') {\n if (!Number.isFinite(body.intervalSec) || (body.intervalSec ?? 0) <= 0) {\n return c.json({ error: 'intervalSec must be a positive number' }, 400)\n }\n const trigger = triggerRepo.insert(db, {\n agentId: agent.id,\n kind: 'interval',\n intervalSec: Math.floor(body.intervalSec as number),\n cronExpr: null,\n message: body.message,\n enabled: body.enabled,\n })\n return c.json({ trigger }, 201)\n }\n\n if (body.kind === 'cron') {\n if (typeof body.cronExpr !== 'string' || !body.cronExpr.trim()) {\n return c.json({ error: 'cronExpr is required for kind=cron' }, 400)\n }\n try {\n validateCron(body.cronExpr)\n } catch (err) {\n return c.json({ error: `invalid cron: ${(err as Error).message}` }, 400)\n }\n const trigger = triggerRepo.insert(db, {\n agentId: agent.id,\n kind: 'cron',\n intervalSec: null,\n cronExpr: body.cronExpr.trim(),\n message: body.message,\n enabled: body.enabled,\n })\n return c.json({ trigger }, 201)\n }\n\n return c.json({ error: `invalid kind: ${body.kind}` }, 400)\n})\n\n// ─── Messages ────────────────────────────────────────────────────────────\n\nagentsRouter.get('/:id/messages', (c) => {\n const { db, paths, authToken } = getCtx()\n const agent = agentRepo.get(db, c.req.param('id'))\n if (!agent) return c.json({ error: `agent not found: ${c.req.param('id')}` }, 404)\n const unreadOnly = c.req.query('unread') === '1'\n const body: ListInboxResponse = {\n messages: messageRepo.listInbox(db, agent.id, { unreadOnly }),\n }\n return c.json(body)\n})\n\nagentsRouter.post('/:id/messages', async (c) => {\n const body = (await c.req.json().catch(() => null)) as SendMessageRequest | null\n if (\n !body ||\n typeof body.from !== 'string' ||\n !body.from ||\n !body.payload ||\n typeof body.payload.text !== 'string'\n ) {\n return c.json({ error: 'from and payload.text are required' }, 400)\n }\n const { db, paths, authToken } = getCtx()\n const fromAgent = agentRepo.get(db, body.from)\n if (!fromAgent) return c.json({ error: `agent not found: ${body.from}` }, 404)\n const toAgent = agentRepo.get(db, c.req.param('id'))\n if (!toAgent) return c.json({ error: `agent not found: ${c.req.param('id')}` }, 404)\n if (body.replyTo && !messageRepo.get(db, body.replyTo)) {\n return c.json({ error: `reply target not found: ${body.replyTo}` }, 404)\n }\n const msg = messageRepo.send(db, {\n from: fromAgent.id,\n to: toAgent.id,\n payload: JSON.stringify({ text: body.payload.text }),\n replyTo: body.replyTo ?? null,\n })\n return c.json(msg, 201)\n})\n\n// ─── Cancel ──────────────────────────────────────────────────────────────\n\n// Aborts the agent's currently-running turn, if any. Returns 204 on a\n// successful abort, 409 when the agent is idle. Cancellation drives off the\n// in-memory agent-cancel registry, which is also what the scheduler probes\n// to skip overlapping inbox wakes / triggers.\nagentsRouter.post('/:id/cancel', (c) => {\n const { db, paths, authToken } = getCtx()\n const id = resolveAgentIdParam(db, c.req.param('id'))\n const cancelled = cancelAgent(id)\n if (!cancelled) return c.json({ error: 'agent has no active turn' }, 409)\n return c.body(null, 204)\n})\n\n// ─── Sessions ────────────────────────────────────────────────────────────\n\nagentsRouter.get('/:id/sessions/head', (c) => {\n const { db, paths, authToken } = getCtx()\n let resolved: ReturnType<typeof resolveAgent>\n try {\n resolved = resolveAgent(db, paths, c.req.param('id'))\n } catch {\n return c.json({ error: `agent not found: ${c.req.param('id')}` }, 404)\n }\n const head: SessionHeadResponse = loadSessionHead(resolved, paths)\n return c.json(head)\n})\n\n/**\n * Returns the agent's prior transcript flattened to ProviderMessage[].\n * SSR loaders use it to render the chat history on first paint without\n * touching pi or the filesystem from the web process.\n */\nagentsRouter.get('/:id/sessions/messages', (c) => {\n const { db, paths, authToken } = getCtx()\n let resolved: ReturnType<typeof resolveAgent>\n try {\n resolved = resolveAgent(db, paths, c.req.param('id'))\n } catch {\n return c.json({ error: `agent not found: ${c.req.param('id')}` }, 404)\n }\n const messages = piMessagesToProviderView(loadInitialMessages(resolved, paths))\n return c.json({ messages })\n})\n\n// ─── Chat ────────────────────────────────────────────────────────────────\n\n/**\n * Streaming chat endpoint. Server-authoritative: prior history is read by\n * pi's SessionManager from the agent's JSONL session file. The client sends\n * only `{ message }`. Response is NDJSON-encoded `ChatFrame`s.\n */\nagentsRouter.post('/:id/chat', async (c) => {\n const { db, paths, authToken } = getCtx()\n const id = resolveAgentIdParam(db, c.req.param('id'))\n\n let body: { message?: string }\n try {\n body = (await c.req.json()) as { message?: string }\n } catch {\n return c.json({ error: 'invalid JSON body' }, 400)\n }\n const message = body.message\n if (!message || typeof message !== 'string') {\n return c.json({ error: 'message is required' }, 400)\n }\n\n const stream = new ReadableStream({\n async start(controller) {\n const encoder = new TextEncoder()\n try {\n for await (const frame of runAgentTurn(id, message)) {\n try {\n controller.enqueue(encoder.encode(`${JSON.stringify(frame)}\\n`))\n } catch {\n // client disconnected — keep draining so state gets saved\n }\n }\n } catch (err) {\n try {\n controller.enqueue(\n encoder.encode(`${JSON.stringify({ kind: 'fatal', error: (err as Error).message })}\\n`),\n )\n } catch {}\n }\n try {\n controller.close()\n } catch {}\n },\n })\n\n return new Response(stream, {\n headers: {\n 'content-type': 'application/x-ndjson',\n 'cache-control': 'no-cache',\n 'x-content-type-options': 'nosniff',\n },\n })\n})\n\nagentsRouter.post('/:id/chat/compact', async (c) => {\n let body: ChatCompactRequest = {}\n if (c.req.header('content-length') !== '0') {\n try {\n const parsed = (await c.req.json()) as ChatCompactRequest | null\n if (parsed && typeof parsed === 'object') body = parsed\n } catch {\n // empty body is allowed — all fields optional\n }\n }\n\n const { db, paths, authToken } = getCtx()\n const id = resolveAgentIdParam(db, c.req.param('id'))\n if (!agentRepo.get(db, id)) return c.json({ error: 'agent not found' }, 404)\n\n const resolved = resolveAgent(db, paths, id)\n const memory = qmdBackend(join(resolved.group.path, 'memory'))\n await memory.init()\n const env = mergeSecretsIntoEnv(db, authToken)\n\n const apiKeyResolution = await resolveAgentApiKey(db, authToken, resolved, {\n withRefresher: true,\n })\n const handle = await createBazilionSession({\n agent: resolved,\n paths,\n env,\n memory,\n enabledProviders: providerStateRepo.listEnabled(db),\n messagingHost: createDbMessagingHost(db),\n ...apiKeyResolution,\n })\n try {\n const entriesBefore = handle.session.sessionManager.getEntries().length\n const result = await handle.session.compact(body.customInstructions)\n const entriesAfter = handle.session.sessionManager.getEntries().length\n\n let keptTail = 0\n if (result.firstKeptEntryId) {\n const branch = handle.session.sessionManager.getBranch()\n const idx = branch.findIndex((e) => e.id === result.firstKeptEntryId)\n if (idx >= 0) for (const e of branch.slice(idx)) if (e.type === 'message') keptTail++\n }\n\n const tokensAfter = handle.session.getContextUsage()?.tokens ?? 0\n\n const resp: ChatCompactResponse = {\n before: entriesBefore,\n after: entriesAfter,\n summarized: Math.max(0, entriesBefore - entriesAfter + 1),\n keptTail,\n tokensBefore: result.tokensBefore,\n tokensAfter,\n summary: result.summary,\n }\n return c.json(resp)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 502)\n } finally {\n handle.dispose()\n }\n})\n\nagentsRouter.get('/:id/chat/context', async (c) => {\n const { db, paths, authToken } = getCtx()\n const id = resolveAgentIdParam(db, c.req.param('id'))\n if (!agentRepo.get(db, id)) return c.json({ error: 'agent not found' }, 404)\n\n const resolved = resolveAgent(db, paths, id)\n\n const files: ContextFileEntry[] = []\n for (const file of CONTEXT_FILE_ORDER) {\n const path = join(resolved.agent.dir, file)\n if (!existsSync(path)) continue\n const content = readFileSync(path, 'utf8').trimEnd()\n if (!content) continue\n const chars = content.length + file.length + 6\n files.push({ name: file, chars, tokens: estimateTokens(chars) })\n }\n const systemPromptText = buildSystemPrompt(resolved)\n const systemPromptChars = systemPromptText.length\n\n const skillsListChars =\n resolved.skills.length > 0\n ? `# Available Skills\\n\\nYou have access to the following skills: ${resolved.skills.join(', ')}.`\n .length\n : 0\n const groupLines = [\n '# Group',\n '',\n `- ${resolved.group.id} (${resolved.group.name}): ${resolved.group.path}`,\n '',\n 'Your group is where work product lives — code, docs, artefacts, shared scratch. It may be shared with other agents in the same group. Your coding tools (`read`, `bash`, `edit`, `write`, `grep`, `find`, `ls`) are rooted at the group directory. Never use these tools to edit your identity/soul/behaviour files — those live in your home and are reached via `home_write` / `home_read`.',\n ]\n const groupListChars = groupLines.join('\\n').length\n const userMdChars = resolved.group.userMd.trim()\n ? `# About the User\\n\\nRead-only context about the human you're working with in this group. You cannot edit this — if it's wrong, say so and they will update it.\\n\\n${resolved.group.userMd.trim()}`\n .length\n : 0\n const memoryHintChars =\n '# Memory\\n\\nYou have a persistent memory backend. Use `memory_write` to remember things across sessions, and `memory_search` / `memory_read` / `memory_list` to recall them. Always check memory at the start of a session if the user might have told you something important before.'\n .length\n\n const memory = qmdBackend(join(resolved.group.path, 'memory'))\n await memory.init()\n const env = mergeSecretsIntoEnv(db, authToken)\n const apiKeyResolution = await resolveAgentApiKey(db, authToken, resolved, {\n withRefresher: true,\n })\n const handle = await createBazilionSession({\n agent: resolved,\n paths,\n env,\n memory,\n enabledProviders: providerStateRepo.listEnabled(db),\n messagingHost: createDbMessagingHost(db),\n ...apiKeyResolution,\n })\n\n try {\n const toolInfos = handle.session.getAllTools()\n let toolsSchemaChars = 0\n let toolsListChars = 0\n const toolEntries: ContextToolEntry[] = []\n for (const info of toolInfos) {\n const schemaJson = JSON.stringify(info.parameters ?? {})\n const schemaChars = schemaJson.length\n const descriptionChars = info.description.length\n toolsSchemaChars += schemaChars\n toolsListChars += info.name.length + descriptionChars + 3\n toolEntries.push({\n name: info.name,\n schemaChars,\n descriptionChars,\n paramCount: countProperties(info.parameters),\n })\n }\n toolEntries.sort((a, b) => b.schemaChars - a.schemaChars)\n\n const installed = discoverSkills(paths)\n const skillEntries: ContextSkillEntry[] = []\n for (const name of resolved.skills) {\n const match = installed.find((s) => s.name === name)\n let blockChars = name.length + 2\n if (match) {\n try {\n blockChars = readFileSync(match.skillFile, 'utf8').length\n } catch {}\n }\n skillEntries.push({ name, blockChars })\n }\n skillEntries.sort((a, b) => b.blockChars - a.blockChars)\n\n const group: ContextGroupEntry = {\n id: resolved.group.id,\n name: resolved.group.name,\n path: resolved.group.path,\n userMdChars: resolved.group.userMd.length,\n }\n\n const stats = handle.session.getSessionStats()\n const historyChars = stats.tokens.total * 4\n const messageEntries = stats.userMessages + stats.assistantMessages + stats.toolResults\n const compactionEntries = handle.session.sessionManager\n .getEntries()\n .filter((e) => e.type === 'compaction').length\n const contextUsage = handle.session.getContextUsage()\n const historyTokens = contextUsage?.tokens ?? stats.tokens.total\n\n const detail = c.req.query('detail') === '1' || c.req.query('json') === '1'\n const CAP = 30\n const toolEntriesOut = detail ? toolEntries : toolEntries.slice(0, CAP)\n const skillEntriesOut = detail ? skillEntries : skillEntries.slice(0, CAP)\n\n const totalsChars = systemPromptChars + toolsSchemaChars + historyChars\n const resp: ChatContextResponse = {\n agentId: resolved.agent.id,\n model: resolved.model,\n systemPrompt: {\n chars: systemPromptChars,\n tokens: estimateTokens(systemPromptChars),\n files,\n skillsListChars,\n groupListChars,\n userMdChars,\n memoryHintChars,\n },\n tools: {\n count: toolInfos.length,\n listChars: toolsListChars,\n schemaChars: toolsSchemaChars,\n entries: toolEntriesOut,\n },\n skills: {\n count: resolved.skills.length,\n entries: skillEntriesOut,\n },\n group,\n history: {\n messageEntries,\n compactionEntries,\n chars: historyChars,\n bytes: historyChars,\n tokensEstimate: historyTokens,\n },\n totals: {\n chars: totalsChars,\n tokens: estimateTokens(totalsChars),\n },\n }\n return c.json(resp)\n } finally {\n handle.dispose()\n }\n})\n\nagentsRouter.post('/:id/chat/reset', (c) => {\n const { db, paths, authToken } = getCtx()\n const id = resolveAgentIdParam(db, c.req.param('id'))\n const agent = agentRepo.get(db, id)\n if (!agent) return c.json({ error: 'agent not found' }, 404)\n\n const sessionsDir = join(paths.agentDir(agent.id), 'sessions')\n let deleted = 0\n if (existsSync(sessionsDir)) {\n for (const file of readdirSync(sessionsDir)) {\n if (!file.endsWith('.jsonl')) continue\n try {\n rmSync(join(sessionsDir, file))\n deleted++\n } catch {\n // best-effort\n }\n }\n }\n return c.json({ ok: true, deletedSessionFiles: deleted })\n})\n\nagentsRouter.post('/:id/chat/truncate', async (c) => {\n let body: TruncateChatRequest\n try {\n body = (await c.req.json()) as TruncateChatRequest\n } catch {\n return c.json({ error: 'invalid JSON body' }, 400)\n }\n const keep = Number(body.keepCount)\n if (!Number.isFinite(keep) || keep < 0 || !Number.isInteger(keep)) {\n return c.json({ error: 'keepCount must be a non-negative integer' }, 400)\n }\n\n const { db, paths, authToken } = getCtx()\n const id = resolveAgentIdParam(db, c.req.param('id'))\n if (!agentRepo.get(db, id)) return c.json({ error: 'agent not found' }, 404)\n\n const resolved = resolveAgent(db, paths, id)\n const memory = qmdBackend(join(resolved.group.path, 'memory'))\n await memory.init()\n const env = mergeSecretsIntoEnv(db, authToken)\n\n const apiKeyResolution = await resolveAgentApiKey(db, authToken, resolved, {\n withRefresher: true,\n })\n const handle = await createBazilionSession({\n agent: resolved,\n paths,\n env,\n memory,\n enabledProviders: providerStateRepo.listEnabled(db),\n messagingHost: createDbMessagingHost(db),\n ...apiKeyResolution,\n })\n try {\n const branch = handle.session.sessionManager.getBranch()\n const messageEntries = branch.filter((e) => e.type === 'message')\n const before = messageEntries.length\n const target = Math.max(0, Math.min(keep, before))\n\n if (target === before) {\n return c.json({ before, after: before } satisfies TruncateChatResponse)\n }\n\n if (target === 0) {\n handle.session.sessionManager.resetLeaf()\n } else {\n const lastKept = messageEntries[target - 1]\n if (!lastKept) return c.json({ error: 'internal: missing target entry' }, 500)\n handle.session.sessionManager.branch(lastKept.id)\n }\n\n return c.json({ before, after: target } satisfies TruncateChatResponse)\n } finally {\n handle.dispose()\n }\n})\n\n// ─── helpers ─────────────────────────────────────────────────────────────\n\nconst CONTEXT_FILE_ORDER = [\n 'AGENTS.md',\n 'SOUL.md',\n 'TOOLS.md',\n 'IDENTITY.md',\n 'HEARTBEAT.md',\n 'BOOTSTRAP.md',\n] as const\n\nfunction estimateTokens(chars: number): number {\n return Math.ceil(Math.max(0, chars) / 4)\n}\n\nfunction countProperties(schema: unknown): number | null {\n if (!schema || typeof schema !== 'object') return null\n const props = (schema as { properties?: unknown }).properties\n if (!props || typeof props !== 'object') return null\n return Object.keys(props as Record<string, unknown>).length\n}\n","// Canonical entity shapes. The daemon's DB schema (apps/daemon/src/core/db)\n// produces these, the daemon serialises them onto the wire, every client\n// (web, mobile, cli, future SDKs) consumes them. Owned here so clients never\n// have to reach into daemon source (which carries node:sqlite) just to know\n// what an Agent is.\n\nexport type Timestamp = number\n\n/**\n * A group is a collaboration context: one filesystem root, one USER.md\n * (read-only to agents, edited by the human), one roster of member agents.\n * Every agent belongs to exactly one group.\n */\nexport interface Group {\n id: string\n name: string\n path: string\n /** Read-only context about the human for all agents in this group.\n * Injected into the system prompt; never exposed as a file on disk. */\n userMd: string\n createdAt: Timestamp\n}\n\nexport type SkillsMode = 'all' | 'selected'\n\nexport interface Profile {\n id: string\n name: string\n dir: string\n defaultModel: string\n skillsMode: SkillsMode\n createdAt: Timestamp\n updatedAt: Timestamp\n}\n\nexport type AgentStatus = 'idle' | 'running' | 'archived'\n\nexport type ReasoningLevel = 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh'\n\nexport const REASONING_LEVELS: ReasoningLevel[] = [\n 'off',\n 'minimal',\n 'low',\n 'medium',\n 'high',\n 'xhigh',\n]\n\nexport interface Agent {\n id: string\n profileId: string\n name: string\n modelOverride: string | null\n reasoningLevel: ReasoningLevel\n status: AgentStatus\n dir: string\n /** The group this agent belongs to. Every agent has exactly one. */\n groupId: string\n createdAt: Timestamp\n archivedAt: Timestamp | null\n}\n\nexport interface AgentSkillAttachment {\n agentId: string\n skillName: string\n attachedAt: Timestamp\n}\n\nexport interface SkillMeta {\n name: string\n source: string | null\n importedAt: Timestamp | null\n}\n\nexport interface Message {\n id: string\n fromAgentId: string\n toAgentId: string\n replyTo: string | null\n payload: string\n createdAt: Timestamp\n readAt: Timestamp | null\n}\n\nexport interface WebToken {\n id: string\n label: string\n createdAt: Timestamp\n lastUsedAt: Timestamp | null\n revokedAt: Timestamp | null\n}\n\nexport type TriggerKind = 'interval' | 'cron'\n\nexport interface AgentTrigger {\n id: string\n agentId: string\n kind: TriggerKind\n intervalSec: number | null\n cronExpr: string | null\n message: string\n enabled: boolean\n lastFiredAt: Timestamp | null\n createdAt: Timestamp\n}\n\nexport interface OpenAICodexStatus {\n connected: boolean\n /** Unix ms expiry of the current access token; null if disconnected. */\n expiresAt: number | null\n /** chatgpt_account_id extracted from the JWT, when available. */\n accountId: string | null\n}\n\nexport interface AgentIdentityFile {\n name?: string\n emoji?: string\n theme?: string\n creature?: string\n vibe?: string\n avatar?: string\n}\n\nexport interface ResolvedAgent {\n agent: Agent\n profile: Profile\n model: string\n reasoningLevel: ReasoningLevel\n group: Group\n skills: string[]\n}\n\nexport interface LoadedProfile {\n profile: Profile\n defaultSkills: string[]\n files: {\n soul: string\n identity: string\n bootstrap: string | null\n agents: string | null\n tools: string | null\n heartbeat: string | null\n }\n /** Structured fields parsed from IDENTITY.md — null when no values are set. */\n identity: AgentIdentityFile | null\n}\n","// Wire-shape package. Hermetic: depends on nothing from the daemon, so every\n// client (web, mobile, cli, future SDKs) can pull in API shapes without\n// dragging Node-only code (node:sqlite, undici, pi-ai, the worker spawner)\n// into its TS check graph or runtime bundle. The daemon imports its entity\n// and wire types FROM here.\n\nexport type {\n Agent,\n AgentIdentityFile,\n AgentSkillAttachment,\n AgentStatus,\n AgentTrigger,\n Group,\n LoadedProfile,\n Message,\n OpenAICodexStatus,\n Profile,\n ReasoningLevel,\n ResolvedAgent,\n SkillMeta,\n SkillsMode,\n Timestamp,\n TriggerKind,\n WebToken,\n} from './entities.ts'\nexport { REASONING_LEVELS } from './entities.ts'\nexport type {\n ChatFrame,\n ProviderMessage,\n Role,\n SessionEvent,\n ToolCall,\n ToolDef,\n} from './events.ts'\nexport type { MemoryEntry, MemoryHit } from './memory.ts'\n\nimport type { AgentTrigger, Message, ReasoningLevel, WebToken } from './entities.ts'\n\nexport interface ApiError {\n error: string\n code?: string\n}\n\n// --- agents ---\n\nexport interface ListAgentsQuery {\n includeArchived?: boolean\n}\n\nexport interface SpawnAgentRequest {\n profileId: string\n name?: string\n model?: string\n reasoningLevel?: ReasoningLevel\n /** Group the new agent joins. Falls back to the seeded 'default' group when omitted. */\n groupId?: string\n}\n\nexport interface UpdateAgentRequest {\n modelOverride?: string | null\n reasoningLevel?: ReasoningLevel\n}\n\nexport interface AttachSkillRequest {\n skill: string\n}\n\n/** Body for `PATCH /api/agents/:id/group`: move the agent to a new group. */\nexport interface MoveAgentRequest {\n groupId: string\n}\n\nexport interface SendMessageRequest {\n from: string\n payload: { text: string }\n replyTo?: string\n}\n\nexport interface ListInboxQuery {\n unread?: boolean\n}\n\nexport interface ListInboxResponse {\n messages: Message[]\n}\n\nexport interface UpdateMessageRequest {\n read: true\n}\n\n// --- profiles ---\n\nexport interface UpdateProfileRequest {\n name?: string\n defaultModel?: string\n skillsMode?: 'all' | 'selected'\n defaultSkills?: string[]\n}\n\nexport interface CreateProfileRequest {\n id: string\n name?: string\n defaultModel: string\n skillsMode?: 'all' | 'selected'\n defaultSkills?: string[]\n /** Initial SOUL.md content. Falls back to the built-in template when omitted. */\n soul?: string\n /** Initial IDENTITY.md content. Falls back to the built-in template when omitted. */\n identity?: string\n /** Initial BOOTSTRAP.md content. Omit for default; pass null to skip bootstrap entirely. */\n bootstrap?: string | null\n /** Initial AGENTS.md content. Omit to skip; pass a string to seed the file. */\n agents?: string\n /** Initial TOOLS.md content. Omit to skip; pass a string to seed the file. */\n tools?: string\n /** Initial HEARTBEAT.md content. Omit to skip; pass a string to seed the file. */\n heartbeat?: string\n}\n\n// --- groups ---\n\nexport interface RegisterGroupRequest {\n /** Slug (lowercase, digits, hyphens). Becomes the row id AND the directory\n * name under `~/.bazilion/groups/<slug>/`. */\n id: string\n /** Optional human-readable label. Defaults to `id`. */\n name?: string\n /**\n * Optional symlink target. When set, the daemon materializes the group\n * slot as a symlink to this absolute path instead of as a real directory\n * — useful for \"agents working on my existing project tree.\" Target must\n * exist and be a directory.\n */\n link?: string\n}\n\n/** Body for `PUT /api/groups/:id/user-md`. */\nexport interface SetGroupUserMdRequest {\n userMd: string\n}\n\n// --- skills (write) ---\n\nexport interface ImportSkillsRequest {\n source: string\n force?: boolean\n}\n\nexport interface ImportSkillsResponse {\n imported: string[]\n skipped: { name: string; reason: string }[]\n}\n\n// --- providers (write) ---\n\nexport interface ProviderTestRequest {\n model: string\n message?: string\n}\n\nexport interface ProviderTestResponse {\n content: string\n usage?: {\n promptTokens: number\n completionTokens: number\n }\n}\n\n// --- chat streaming ---\n\nexport interface ChatRequest {\n message: string\n}\n\n// --- profile files ---\n\nexport type ProfileFileName =\n | 'profile.json'\n | 'SOUL.md'\n | 'IDENTITY.md'\n | 'BOOTSTRAP.md'\n | 'AGENTS.md'\n | 'TOOLS.md'\n | 'HEARTBEAT.md'\n\nexport const PROFILE_FILES: ProfileFileName[] = [\n 'profile.json',\n 'SOUL.md',\n 'IDENTITY.md',\n 'BOOTSTRAP.md',\n 'AGENTS.md',\n 'TOOLS.md',\n 'HEARTBEAT.md',\n]\n\nexport interface FileContentResponse {\n content: string\n}\n\nexport interface PutFileRequest {\n content: string\n}\n\n// --- skills ---\n\nexport interface SkillInfo {\n name: string\n description: string\n source: string | null\n importedAt: number | null\n parseError?: string\n}\n\nexport interface ResolvedSkillsResponse {\n resolved: SkillInfo[]\n missing: { name: string; reason: string }[]\n}\n\nexport interface TruncateChatRequest {\n /** Number of leading messages to preserve; everything after is dropped. */\n keepCount: number\n}\n\nexport interface TruncateChatResponse {\n before: number\n after: number\n}\n\n/**\n * Lightweight \"has anything new happened on this agent's session?\" probe.\n * Polled by the web chat UI to detect out-of-band activity (inbox-wakes,\n * scheduled triggers, turns run from another tab) so it can prompt the user\n * to refresh — the session JSONL is append-only, so either a new filename or\n * a bigger byte-count means new entries landed.\n */\nexport interface SessionHeadResponse {\n /** Basename of the most-recent `.jsonl` session file, or `null` if none. */\n file: string | null\n /** Byte size of that file (monotonically increasing while in use). */\n size: number\n}\n\nexport interface ContextFileEntry {\n /** Basename of the injected profile file (e.g. SOUL.md). */\n name: string\n /** Full character count of the file's contribution to the system prompt. */\n chars: number\n /** Rough token estimate (chars / 4). */\n tokens: number\n}\n\nexport interface ContextToolEntry {\n name: string\n /** JSON schema char size (what the provider sees as tool definitions). */\n schemaChars: number\n /** Description char size. */\n descriptionChars: number\n /** Count of top-level properties on the input schema, when shaped like JSONSchema. */\n paramCount: number | null\n}\n\nexport interface ContextSkillEntry {\n name: string\n /** Char count of the skill block injected into the system prompt (currently just the name). */\n blockChars: number\n}\n\nexport interface ContextGroupEntry {\n id: string\n name: string\n path: string\n userMdChars: number\n}\n\nexport interface ContextHistoryBreakdown {\n /** Count of `message` entries. */\n messageEntries: number\n /** Count of `compaction` entries (summarization boundaries). */\n compactionEntries: number\n /** Char sum of message `content` fields (LLM input surface). */\n chars: number\n /** Raw wire size of the serialized log on disk. */\n bytes: number\n /** Rough token estimate (chars / 4) for history alone. */\n tokensEstimate: number\n}\n\nexport interface ChatContextResponse {\n /** Agent being reported on. */\n agentId: string\n /** provider:model string the agent currently resolves to. */\n model: string\n systemPrompt: {\n chars: number\n tokens: number\n /** Per-file breakdown of profile markdown sources (AGENTS.md, SOUL.md, TOOLS.md, IDENTITY.md, HEARTBEAT.md, BOOTSTRAP.md). */\n files: ContextFileEntry[]\n /** Char count of the skill-list text rendered into the system prompt. */\n skillsListChars: number\n /** Char count of the group block rendered into the system prompt. */\n groupListChars: number\n /** Char count of the USER.md block (0 when the group's userMd is empty). */\n userMdChars: number\n /** Fixed memory-hint block the runtime always appends. */\n memoryHintChars: number\n }\n tools: {\n count: number\n listChars: number\n schemaChars: number\n entries: ContextToolEntry[]\n }\n skills: {\n count: number\n entries: ContextSkillEntry[]\n }\n group: ContextGroupEntry\n history: ContextHistoryBreakdown\n /** Sum of system prompt + tool schemas + history, in chars + tokens. */\n totals: { chars: number; tokens: number }\n}\n\nexport interface ChatCompactRequest {\n /** Number of trailing message entries to keep verbatim. Default 10. */\n keepTail?: number\n /** Optional freeform guidance prepended to the summarizer system prompt. */\n customInstructions?: string\n}\n\nexport interface ChatCompactResponse {\n /** Entry count before compaction. */\n before: number\n /** Entry count after compaction (1 compaction + `keptTail` messages). */\n after: number\n /** Message entries summarized into the compaction (the head that was dropped). */\n summarized: number\n /** Message entries preserved verbatim after the compaction boundary. */\n keptTail: number\n /** Rough token estimate of the log before compaction. */\n tokensBefore: number\n /** Rough token estimate of the log after compaction. */\n tokensAfter: number\n /** The summary text produced by the model. */\n summary: string\n}\n\n// --- triggers (heartbeats / cron) ---\n\nexport interface CreateTriggerRequest {\n kind: 'interval' | 'cron'\n /** required when kind='interval' */\n intervalSec?: number\n /** required when kind='cron' — 5-field expression (\"m h dom mon dow\") */\n cronExpr?: string\n /** injected as the user message when the trigger fires */\n message: string\n enabled?: boolean\n}\n\nexport interface UpdateTriggerRequest {\n enabled?: boolean\n}\n\nexport interface CreateTriggerResponse {\n trigger: AgentTrigger\n}\n\nexport interface UpdateTriggerResponse {\n trigger: AgentTrigger\n}\n\nexport interface ListTriggersResponse {\n triggers: AgentTrigger[]\n}\n\n// --- config page (providers + services + fields) ---\n\n/** Per-field UI + storage descriptor — source-of-truth is SERVICES in apps/daemon/src/core/services.ts. */\nexport interface ServiceFieldState {\n envVar: string\n kind: 'secret' | 'config'\n label: string\n placeholder?: string\n description?: string\n /** True when the field has a non-empty value in its storage backend. */\n set: boolean\n /** For `kind: 'config'` (plaintext): the actual value. Omitted for secrets. */\n value?: string\n /** For `kind: 'secret'`: a truncated preview like \"sk-abc…\" so the UI can confirm something is stored. Omitted when unset. */\n preview?: string\n}\n\nexport interface ServiceCard {\n id: string\n displayName: string\n /** Present for category==='provider' cards — tracks whether the pi-adapter sees it as configured. */\n enabled?: boolean\n envHint?: string\n hint?: string\n /** Display grouping label (e.g. \"Web tools\"). Cards without a group are bucketed under \"Other\". */\n group?: string\n fields: ServiceFieldState[]\n}\n\nexport interface ProviderConfigEntry extends ServiceCard {\n enabled: boolean\n envHint: string\n /** Static catalog from pi-ai's typed model list — empty for providers not in the catalog. */\n catalog: string[]\n /** Live `/v1/models` query — omitted when the provider doesn't expose one. */\n live?: { models: string[]; error?: string }\n /** Curated models the admin has selected — drives the dropdowns in profile/agent forms. */\n curated: string[]\n}\n\nexport interface ProviderConfigResponse {\n providers: ProviderConfigEntry[]\n}\n\nexport interface ServiceConfigResponse {\n services: ServiceCard[]\n}\n\nexport interface SetFieldRequest {\n value: string\n}\n\nexport interface SetProviderModelsRequest {\n models: string[]\n}\n\nexport interface SetProviderModelsResponse {\n models: string[]\n}\n\nexport interface SetProviderEnabledRequest {\n enabled: boolean\n}\n\nexport interface SetProviderEnabledResponse {\n name: string\n enabled: boolean\n}\n\n// --- web tokens ---\n\nexport interface CreateTokenRequest {\n label: string\n}\n\nexport interface CreateTokenResponse {\n /** Plaintext token — returned exactly once. */\n token: string\n meta: WebToken\n}\n\nexport interface ListTokensResponse {\n tokens: WebToken[]\n}\n\n// --- health (doctor) ---\n\nexport interface HealthReport {\n ok: boolean\n home: string\n paths: {\n home: boolean\n db: boolean\n auth: boolean\n profiles: boolean\n agents: boolean\n skills: boolean\n }\n database:\n | { ok: true; profiles: number; activeAgents: number; totalAgents: number; groups: number }\n | { ok: false; error: string }\n | null\n skills: { installed: number; parseErrors: number }\n providers: {\n /** Names of cloud providers with credentials configured (e.g. ['anthropic', 'groq']). */\n configured: string[]\n lmstudio: { baseURL: string; hasKey: boolean }\n ollama: { baseURL: string }\n }\n webSearch: { bravePreview: string | null; searxngUrl: string | null }\n openclaw: { path: string; exists: boolean }\n triggers: { active: number; disabled: number }\n tokens: { active: number }\n scheduler: { enabled: boolean; tickMs: number }\n}\n","import { agentRepo, type BazilionDb } from '../core/index.ts'\n\n/**\n * Expand an agent ID prefix (from URL params) to the full UUID.\n *\n * Returns the resolved full ID when the prefix is exact or uniquely resolves;\n * returns the raw input otherwise so the caller's existing \"not found\" branch\n * fires with the original value in the error message.\n */\nexport function resolveAgentIdParam(db: BazilionDb, raw: string | undefined): string {\n if (!raw) return ''\n return agentRepo.resolveId(db, raw) ?? raw\n}\n","// /api/auth/openai/* — ChatGPT OAuth provider connection state.\n// /api/providers/test — model smoke-test.\n// /api/login — token-based browser login (sets the bz_token cookie).\n\nimport { spawn } from 'node:child_process'\nimport type { ProviderTestRequest, ProviderTestResponse } from '@bazilion/api-types'\nimport { Hono } from 'hono'\nimport { setCookie } from 'hono/cookie'\nimport { isSetupComplete, mergeSecretsIntoEnv, providerStateRepo } from '../core/index.ts'\nimport { isValidToken } from '../lib/auth.ts'\nimport { getCtx } from '../lib/ctx.ts'\nimport {\n clearOpenAICodexCredentials,\n createProviderRegistry,\n getOpenAICodexStatus,\n loadProviderConfigFromEnv,\n loginOpenAICodex,\n saveOpenAICodexLoginCredentials,\n} from '../runtime/index.ts'\n\nexport const authRouter = new Hono()\n\n// ─── Auth probe ──────────────────────────────────────────────────────────\n\n/**\n * Cheap session validator. Web SSR middleware calls this once per request\n * to translate \"is the cookie still good?\" + \"has setup been finished?\"\n * into JSON-status pairs that the Astro middleware turns into redirects.\n *\n * Reaching this handler at all means auth passed (the daemon's own\n * middleware-auth would have 401'd otherwise). The body just exposes the\n * setup-complete bit so the web layer can route accordingly.\n */\nauthRouter.get('/auth/me', (c) => {\n const { db } = getCtx()\n return c.json({ authed: true, setupComplete: isSetupComplete(db) })\n})\n\n// ─── ChatGPT OAuth ───────────────────────────────────────────────────────\n\nauthRouter.get('/auth/openai', (c) => {\n const { db, authToken } = getCtx()\n return c.json(getOpenAICodexStatus(db, authToken))\n})\n\nauthRouter.put('/auth/openai', async (c) => {\n const body = (await c.req.json().catch(() => null)) as {\n refresh?: unknown\n access?: unknown\n expires?: unknown\n } | null\n if (\n !body ||\n typeof body.refresh !== 'string' ||\n typeof body.access !== 'string' ||\n typeof body.expires !== 'number'\n ) {\n return c.json(\n { error: 'body must be { refresh: string, access: string, expires: number }' },\n 400,\n )\n }\n const { db, authToken } = getCtx()\n saveOpenAICodexLoginCredentials(db, authToken, {\n refresh: body.refresh,\n access: body.access,\n expires: body.expires,\n })\n return c.json(getOpenAICodexStatus(db, authToken))\n})\n\nauthRouter.delete('/auth/openai', (c) => {\n const { db, authToken } = getCtx()\n clearOpenAICodexCredentials(db, authToken)\n return c.json({ connected: false, expiresAt: null, accountId: null })\n})\n\nauthRouter.post('/auth/openai/login', async (c) => {\n const { db, authToken } = getCtx()\n try {\n const creds = await loginOpenAICodex({\n onAuth: ({ url }) => openBrowser(url),\n onPrompt: () =>\n Promise.reject(\n new Error(\n 'interactive paste not supported in the web flow — cancel and try again, or use `bazilion auth openai login`',\n ),\n ),\n onProgress: () => {\n // single blocking POST keeps the UI simple\n },\n })\n saveOpenAICodexLoginCredentials(db, authToken, creds)\n return c.json(getOpenAICodexStatus(db, authToken))\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n})\n\n// ─── Provider model smoke-test ───────────────────────────────────────────\n\nauthRouter.post('/providers/test', async (c) => {\n const body = (await c.req.json().catch(() => null)) as ProviderTestRequest | null\n if (!body || typeof body.model !== 'string' || !body.model) {\n return c.json({ error: 'model is required' }, 400)\n }\n const message = typeof body.message === 'string' && body.message ? body.message : 'say hi briefly'\n const { db, paths, authToken } = getCtx()\n const env = mergeSecretsIntoEnv(db, authToken)\n const reg = createProviderRegistry(loadProviderConfigFromEnv(env, { db, authToken }), {\n enabledSet: providerStateRepo.listEnabled(db),\n })\n try {\n const { provider, model } = reg.resolve(body.model)\n const res = await provider.chat({\n model,\n messages: [{ role: 'user', content: message }],\n maxTokens: 256,\n })\n const out: ProviderTestResponse = { content: res.content, usage: res.usage }\n return c.json(out)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n})\n\n// ─── Browser login ───────────────────────────────────────────────────────\n\n/**\n * Token-based login. Two body shapes accepted:\n * - `application/json`: `{ token: \"<value>\" }` → returns `{ ok: true }` on\n * success, sets the `bz_token` cookie. Used by clients (web pages, mobile)\n * that prefer JSON.\n * - `application/x-www-form-urlencoded`: `token=<value>` → 302 to `/` on\n * success or `/login?error=1` on failure. Used by the legacy `<form>` on\n * the Astro `/login` page; preserved for compatibility through Stage A.\n */\nauthRouter.post('/login', async (c) => {\n const ct = c.req.header('content-type') ?? ''\n let token: string | null = null\n\n if (ct.startsWith('application/json')) {\n const body = (await c.req.json().catch(() => null)) as { token?: unknown } | null\n if (body && typeof body.token === 'string') token = body.token\n } else {\n const form = await c.req.formData().catch(() => null)\n const v = form?.get('token')\n if (typeof v === 'string') token = v\n }\n\n if (!token || !isValidToken(token)) {\n if (ct.startsWith('application/json')) {\n return c.json({ error: 'invalid token' }, 401)\n }\n return c.redirect('/login?error=1', 302)\n }\n\n setCookie(c, 'bz_token', token, {\n path: '/',\n httpOnly: true,\n sameSite: 'Lax',\n maxAge: 60 * 60 * 24 * 30,\n })\n\n if (ct.startsWith('application/json')) {\n return c.json({ ok: true })\n }\n return c.redirect('/', 302)\n})\n\n/**\n * Open `url` in the host's default browser. Only called by the OAuth flow\n * triggered from /config — the user is on the same machine as the daemon in\n * that scenario (loopback-only `bazilion serve`).\n */\nfunction openBrowser(url: string): void {\n const platform = process.platform\n const [cmd, ...args] =\n platform === 'darwin'\n ? ['open', url]\n : platform === 'win32'\n ? ['cmd', '/c', 'start', '\"\"', url]\n : ['xdg-open', url]\n try {\n const child = spawn(cmd as string, args, { stdio: 'ignore', detached: true })\n child.unref()\n child.on('error', () => {\n // xdg-open missing on minimal installs — swallow so the flow still works\n })\n } catch {\n // spawn failed — user will still see the URL in the progress log\n }\n}\n","// /api/config/* — provider matrix, services, per-provider enabled toggle and\n// curated models, and per-field config/secret writes.\n\nimport type {\n ProviderConfigEntry,\n ProviderConfigResponse,\n ServiceCard,\n ServiceConfigResponse,\n ServiceFieldState,\n SetProviderModelsRequest,\n} from '@bazilion/api-types'\nimport { Hono } from 'hono'\nimport {\n ensureSetupSeeded,\n findFieldByEnvVar,\n groupAvailableModels,\n mergeSecretsIntoEnv,\n openConfig,\n openSecrets,\n providerModelRepo,\n providerStateRepo,\n type ServiceDef,\n servicesByCategory,\n} from '../core/index.ts'\nimport { getCtx } from '../lib/ctx.ts'\nimport {\n listAllProviders,\n listCatalogModels,\n listCatalogModelsSync,\n loadProviderConfigFromEnv,\n} from '../runtime/index.ts'\n\nexport const configRouter = new Hono()\n\n// /api/config/providers\nconfigRouter.get('/providers', async (c) => {\n const { db, paths, authToken } = getCtx()\n const env = mergeSecretsIntoEnv(db, authToken)\n const registryProviders = listAllProviders(loadProviderConfigFromEnv(env, { db, authToken }))\n const registryByName = new Map(registryProviders.map((p) => [p.name, p]))\n\n const configValues = readAll(() => openConfig(db).getAll())\n const secretValues = readAll(() => openSecrets(db, authToken).getAll())\n\n const providerServices = servicesByCategory('provider')\n const enabledSet = providerStateRepo.listEnabled(db)\n\n const entries = await Promise.all(\n providerServices.map(async (svc): Promise<ProviderConfigEntry> => {\n const meta = registryByName.get(svc.id)\n const enabled = enabledSet.has(svc.id)\n const envHint = meta?.envHint ?? ''\n const ac = new AbortController()\n const t = setTimeout(() => ac.abort(), 5_000)\n try {\n const { catalog, live } = enabled\n ? await listCatalogModels(svc.id, env, ac.signal)\n : { catalog: listCatalogModelsSync(svc.id), live: undefined }\n return {\n id: svc.id,\n displayName: svc.displayName,\n ...(svc.hint ? { hint: svc.hint } : {}),\n enabled,\n envHint,\n fields: resolveFieldStates(svc, configValues, secretValues),\n catalog,\n ...(live ? { live } : {}),\n curated: providerModelRepo.list(db, svc.id),\n }\n } finally {\n clearTimeout(t)\n }\n }),\n )\n\n const body: ProviderConfigResponse = { providers: entries }\n return c.json(body)\n})\n\n// /api/config/services — non-provider service cards (e.g. SearXNG, Brave).\nconfigRouter.get('/services', (c) => {\n const { db, authToken } = getCtx()\n const configValues = readAll(() => openConfig(db).getAll())\n const secretValues = readAll(() => openSecrets(db, authToken).getAll())\n\n const services: ServiceCard[] = servicesByCategory('service').map((svc) => ({\n id: svc.id,\n displayName: svc.displayName,\n ...(svc.hint ? { hint: svc.hint } : {}),\n ...(svc.group ? { group: svc.group } : {}),\n fields: resolveFieldStates(svc, configValues, secretValues),\n }))\n\n const body: ServiceConfigResponse = { services }\n return c.json(body)\n})\n\n// /api/config/providers/:name/enabled — flip the admin switch.\nconfigRouter.put('/providers/:name/enabled', async (c) => {\n const name = c.req.param('name')\n if (!knownProviderIds().has(name)) return c.json({ error: `unknown provider: ${name}` }, 404)\n\n const body = (await c.req.json().catch(() => null)) as { enabled?: unknown } | null\n if (!body || (typeof body.enabled !== 'boolean' && typeof body.enabled !== 'string')) {\n return c.json({ error: 'body must be {\"enabled\": boolean}' }, 400)\n }\n const enabled =\n typeof body.enabled === 'boolean' ? body.enabled : body.enabled.toLowerCase() === 'true'\n\n const { db, paths } = getCtx()\n providerStateRepo.setEnabled(db, name, enabled)\n ensureSetupSeeded(db, paths)\n return c.json({ name, enabled })\n})\n\n// /api/config/providers/:name/models — curated model list.\nconfigRouter.get('/providers/:name/models', (c) => {\n const name = c.req.param('name')\n if (!knownProviderRegistryNames().has(name))\n return c.json({ error: `unknown provider: ${name}` }, 404)\n const { db } = getCtx()\n return c.json({ models: providerModelRepo.list(db, name) })\n})\n\nconfigRouter.put('/providers/:name/models', async (c) => {\n const name = c.req.param('name')\n if (!knownProviderRegistryNames().has(name))\n return c.json({ error: `unknown provider: ${name}` }, 404)\n const body = (await c.req.json().catch(() => null)) as Partial<SetProviderModelsRequest> | null\n if (!body) return c.json({ error: 'invalid JSON body' }, 400)\n\n // Accept textarea-style newline-separated input from web forms in addition\n // to the CLI's array shape.\n let models: string[] = []\n if (Array.isArray(body.models)) {\n models = body.models.filter((m): m is string => typeof m === 'string')\n } else if (typeof (body as Record<string, unknown>).models === 'string') {\n models = ((body as Record<string, unknown>).models as string).split(/\\r?\\n/)\n } else {\n return c.json(\n { error: 'models must be an array of strings or a newline-separated string' },\n 400,\n )\n }\n\n const { db, paths } = getCtx()\n providerModelRepo.replace(db, name, models)\n ensureSetupSeeded(db, paths)\n return c.json({ models: providerModelRepo.list(db, name) })\n})\n\n// /api/config/fields/:envVar — write-through for any envVar the registry knows.\nconfigRouter.put('/fields/:envVar', async (c) => {\n const envVar = c.req.param('envVar')\n const found = findFieldByEnvVar(envVar)\n if (!found) return c.json({ error: `unknown envVar: ${envVar}` }, 404)\n\n const body = (await c.req.json().catch(() => null)) as { value?: unknown } | null\n if (!body || typeof body.value !== 'string') {\n return c.json({ error: 'body must be {\"value\": \"<string>\"}' }, 400)\n }\n\n const { db, authToken } = getCtx()\n if (found.field.kind === 'config') {\n const store = openConfig(db)\n if (body.value === '') store.remove(envVar)\n else store.set(envVar, body.value)\n } else {\n const store = openSecrets(db, authToken)\n if (body.value === '') store.remove(envVar)\n else store.set(envVar, body.value)\n }\n\n return c.json(readFieldState(db, authToken, envVar, found.field.kind))\n})\n\n// /api/config/available-models — provider-grouped curated models. Drives\n// the model dropdowns on the profile + agent spawn pages.\nconfigRouter.get('/available-models', (c) => {\n const { db } = getCtx()\n return c.json({ groups: groupAvailableModels(db) })\n})\n\nconfigRouter.delete('/fields/:envVar', (c) => {\n const envVar = c.req.param('envVar')\n const found = findFieldByEnvVar(envVar)\n if (!found) return c.json({ error: `unknown envVar: ${envVar}` }, 404)\n\n const { db, authToken } = getCtx()\n if (found.field.kind === 'config') {\n openConfig(db).remove(envVar)\n } else {\n openSecrets(db, authToken).remove(envVar)\n }\n return c.body(null, 204)\n})\n\n// ─── helpers ─────────────────────────────────────────────────────────────\n\nfunction mask(value: string): string {\n if (value.length === 0) return ''\n return value.length > 8 ? `${value.slice(0, 6)}…` : '***'\n}\n\nfunction resolveFieldStates(\n service: ServiceDef,\n configValues: Record<string, string>,\n secretValues: Record<string, string>,\n): ServiceFieldState[] {\n return service.fields.map((f) => {\n const val = (f.kind === 'config' ? configValues[f.envVar] : secretValues[f.envVar]) ?? ''\n const state: ServiceFieldState = {\n envVar: f.envVar,\n kind: f.kind,\n label: f.label,\n set: val.length > 0,\n ...(f.placeholder ? { placeholder: f.placeholder } : {}),\n ...(f.description ? { description: f.description } : {}),\n }\n if (f.kind === 'config') {\n state.value = val\n } else if (val.length > 0) {\n state.preview = mask(val)\n }\n return state\n })\n}\n\nfunction readAll(read: () => Record<string, string>): Record<string, string> {\n try {\n return read()\n } catch {\n return {}\n }\n}\n\ninterface FieldState {\n envVar: string\n kind: 'secret' | 'config'\n set: boolean\n value?: string\n preview?: string\n}\n\nfunction readFieldState(\n db: import('../core/index.ts').BazilionDb,\n authToken: string,\n envVar: string,\n kind: 'secret' | 'config',\n): FieldState {\n if (kind === 'config') {\n const v = openConfig(db).get(envVar) ?? ''\n return { envVar, kind, set: v.length > 0, value: v }\n }\n const v = openSecrets(db, authToken).get(envVar) ?? ''\n return { envVar, kind, set: v.length > 0, ...(v.length > 0 ? { preview: mask(v) } : {}) }\n}\n\nfunction knownProviderIds(): Set<string> {\n return new Set(servicesByCategory('provider').map((s) => s.id))\n}\n\nfunction knownProviderRegistryNames(): Set<string> {\n const { db, authToken } = getCtx()\n return new Set(\n listAllProviders(loadProviderConfigFromEnv(process.env, { db, authToken })).map((p) => p.name),\n )\n}\n","// /api/groups/* — group registry, per-group USER.md, per-group shared\n// memory. Memory is keyed by the group slug because the qmd index lives at\n// `<group.path>/memory/` and is shared by every agent in the group.\n\nimport { join } from 'node:path'\nimport type { RegisterGroupRequest, SetGroupUserMdRequest } from '@bazilion/api-types'\nimport { Hono } from 'hono'\nimport { deleteGroup, groupRepo, registerGroup } from '../core/index.ts'\nimport { getCtx } from '../lib/ctx.ts'\nimport { qmdBackend } from '../runtime/index.ts'\n\n// 12 KB cap matches OpenClaw's bootstrapMaxChars default — enough for a rich\n// USER.md, small enough that it can't silently blow out the system prompt.\nconst USER_MD_MAX_BYTES = 12_000\n\nexport const groupsRouter = new Hono()\n\ngroupsRouter.get('/', (c) => {\n const { db, paths } = getCtx()\n return c.json(groupRepo.list(db, paths))\n})\n\ngroupsRouter.post('/', async (c) => {\n const body = (await c.req.json().catch(() => null)) as RegisterGroupRequest | null\n if (!body || typeof body.id !== 'string') {\n return c.json({ error: 'id is required' }, 400)\n }\n const { db, paths } = getCtx()\n try {\n const g = registerGroup(db, { id: body.id, name: body.name, link: body.link }, paths)\n return c.json(g, 201)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n})\n\ngroupsRouter.get('/:id', (c) => {\n const { db, paths } = getCtx()\n const g = groupRepo.get(db, c.req.param('id'), paths)\n if (!g) return c.json({ error: `group not found: ${c.req.param('id')}` }, 404)\n return c.json(g)\n})\n\ngroupsRouter.delete('/:id', (c) => {\n const { db, paths } = getCtx()\n try {\n deleteGroup(db, paths, c.req.param('id'))\n return c.body(null, 204)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n})\n\ngroupsRouter.put('/:id/user-md', async (c) => {\n const body = (await c.req.json().catch(() => null)) as SetGroupUserMdRequest | null\n if (!body || typeof body.userMd !== 'string') {\n return c.json({ error: 'userMd (string) is required' }, 400)\n }\n if (Buffer.byteLength(body.userMd, 'utf8') > USER_MD_MAX_BYTES) {\n return c.json({ error: `userMd exceeds ${USER_MD_MAX_BYTES}-byte cap` }, 413)\n }\n const { db, paths } = getCtx()\n const g = groupRepo.get(db, c.req.param('id'), paths)\n if (!g) return c.json({ error: `group not found: ${c.req.param('id')}` }, 404)\n groupRepo.setUserMd(db, c.req.param('id'), body.userMd)\n return c.json(groupRepo.get(db, c.req.param('id'), paths))\n})\n\n// ─── Memory (per-group, shared across all member agents) ──────────────────\n\nasync function openMemory(rawId: string) {\n const { db, paths } = getCtx()\n const group = groupRepo.get(db, rawId, paths)\n if (!group) throw new Error(`group not found: ${rawId}`)\n const mem = qmdBackend(join(group.path, 'memory'))\n await mem.init()\n return { mem, group }\n}\n\ngroupsRouter.get('/:id/memory', async (c) => {\n try {\n const { mem } = await openMemory(c.req.param('id'))\n return c.json(await mem.list())\n } catch (err) {\n return c.json({ error: (err as Error).message }, 404)\n }\n})\n\ngroupsRouter.get('/:id/memory/search', async (c) => {\n const q = c.req.query('q')\n if (!q) return c.json({ error: 'q is required' }, 400)\n const limit = Number.parseInt(c.req.query('limit') ?? '10', 10)\n try {\n const { mem } = await openMemory(c.req.param('id'))\n return c.json(await mem.search(q, { limit }))\n } catch (err) {\n return c.json({ error: (err as Error).message }, 404)\n }\n})\n\n// `:key{.+}` matches multi-segment paths so memory keys with slashes (e.g.\n// `notes/2026-04-25.md`) survive the routing layer. Without the regex Hono\n// would only capture a single segment.\ngroupsRouter.get('/:id/memory/:key{.+}', async (c) => {\n try {\n const { mem } = await openMemory(c.req.param('id'))\n return c.json(await mem.read(c.req.param('key')))\n } catch (err) {\n return c.json({ error: (err as Error).message }, 404)\n }\n})\n\ngroupsRouter.put('/:id/memory/:key{.+}', async (c) => {\n const body = (await c.req.json().catch(() => null)) as { content?: string } | null\n if (!body || typeof body.content !== 'string')\n return c.json({ error: 'content is required' }, 400)\n try {\n const { mem } = await openMemory(c.req.param('id'))\n return c.json(await mem.write(c.req.param('key'), body.content))\n } catch (err) {\n return c.json({ error: (err as Error).message }, 500)\n }\n})\n\ngroupsRouter.delete('/:id/memory/:key{.+}', async (c) => {\n try {\n const { mem } = await openMemory(c.req.param('id'))\n await mem.remove(c.req.param('key'))\n return c.body(null, 204)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 500)\n }\n})\n","// /api/messages/:id — fetch + mark-read for a single message. (Inbox listing\n// + send is per-agent at /api/agents/:id/messages.)\n\nimport type { UpdateMessageRequest } from '@bazilion/api-types'\nimport { Hono } from 'hono'\nimport { messageRepo } from '../core/index.ts'\nimport { getCtx } from '../lib/ctx.ts'\n\nexport const messagesRouter = new Hono()\n\nmessagesRouter.get('/:id', (c) => {\n const { db } = getCtx()\n const msg = messageRepo.get(db, c.req.param('id'))\n if (!msg) return c.json({ error: `message not found: ${c.req.param('id')}` }, 404)\n return c.json(msg)\n})\n\nmessagesRouter.patch('/:id', async (c) => {\n const id = c.req.param('id')\n const body = (await c.req.json().catch(() => null)) as UpdateMessageRequest | null\n if (!body || body.read !== true) {\n return c.json({ error: 'body must be {read: true}' }, 400)\n }\n const { db } = getCtx()\n const existing = messageRepo.get(db, id)\n if (!existing) return c.json({ error: `message not found: ${id}` }, 404)\n messageRepo.markRead(db, id)\n return c.json(messageRepo.get(db, id))\n})\n","// Single-route resources: /api/health, /api/backup, /api/tokens.\n\nimport { spawn } from 'node:child_process'\nimport { existsSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport type {\n CreateTokenRequest,\n CreateTokenResponse,\n HealthReport,\n ListTokensResponse,\n} from '@bazilion/api-types'\nimport { Hono } from 'hono'\nimport {\n agentRepo,\n discoverSkills,\n groupRepo,\n mergeSecretsIntoEnv,\n parseSkillFile,\n profileRepo,\n resolvePaths,\n webTokenRepo,\n} from '../core/index.ts'\nimport { getCtx } from '../lib/ctx.ts'\nimport { loadProviderConfigFromEnv } from '../runtime/index.ts'\n\nexport const miscRouter = new Hono()\n\n// /api/health — install diagnostics. Public (auth middleware whitelists it)\n// so the doctor command and external probes can run without a token.\nmiscRouter.get('/health', (c) => {\n const paths = resolvePaths()\n\n const pathChecks = {\n home: existsSync(paths.home),\n db: existsSync(paths.db),\n auth: existsSync(paths.authFile),\n profiles: existsSync(paths.profilesDir),\n agents: existsSync(paths.agentsDir),\n skills: existsSync(paths.skillsDir),\n }\n\n let database: HealthReport['database'] = null\n const triggersSection: HealthReport['triggers'] = { active: 0, disabled: 0 }\n let tokensSection: HealthReport['tokens'] = { active: 0 }\n if (pathChecks.db) {\n try {\n const { db } = getCtx()\n database = {\n ok: true,\n profiles: profileRepo.list(db).length,\n activeAgents: agentRepo.list(db).length,\n totalAgents: agentRepo.list(db, { includeArchived: true }).length,\n groups: groupRepo.list(db, paths).length,\n }\n const triggerRows = db.raw\n .query<{ enabled: number; n: number }, []>(\n 'SELECT enabled, COUNT(*) AS n FROM agent_triggers GROUP BY enabled',\n )\n .all()\n for (const r of triggerRows) {\n if (r.enabled === 1) triggersSection.active = r.n\n else triggersSection.disabled = r.n\n }\n tokensSection = { active: webTokenRepo.list(db).length }\n } catch (err) {\n database = { ok: false, error: (err as Error).message }\n }\n }\n\n const skills = discoverSkills(paths)\n let parseErrors = 0\n for (const s of skills) {\n try {\n parseSkillFile(s.skillFile)\n } catch {\n parseErrors++\n }\n }\n\n let effectiveEnv: NodeJS.ProcessEnv = process.env\n let oauth: { db: import('../core/index.ts').BazilionDb; authToken: string } | undefined\n if (pathChecks.auth && pathChecks.db) {\n try {\n const { db, authToken } = getCtx()\n effectiveEnv = mergeSecretsIntoEnv(db, authToken)\n oauth = { db, authToken }\n } catch {\n // first-run / partially-initialized — fall through with bare env\n }\n }\n const providerConfig = loadProviderConfigFromEnv(effectiveEnv, oauth)\n const braveKey = effectiveEnv.BRAVE_API_KEY\n const openclawSkillsDir = join(homedir(), '.openclaw', 'skills')\n\n const CLOUD_KEYS: Array<[string, keyof typeof providerConfig]> = [\n ['anthropic', 'anthropic'],\n ['openai', 'openai'],\n ['google', 'google'],\n ['azure-openai', 'azureOpenai'],\n ['bedrock', 'bedrock'],\n ['google-vertex', 'googleVertex'],\n ['mistral', 'mistral'],\n ['groq', 'groq'],\n ['cerebras', 'cerebras'],\n ['xai', 'xai'],\n ['zai', 'zai'],\n ['huggingface', 'huggingface'],\n ['openrouter', 'openrouter'],\n ['vercel-ai-gateway', 'vercelAiGateway'],\n ]\n const providerSection: HealthReport['providers'] = {\n configured: CLOUD_KEYS.filter(([, key]) => providerConfig[key]).map(([name]) => name),\n lmstudio: {\n baseURL: providerConfig.lmstudio?.baseURL ?? 'http://localhost:1234/v1',\n hasKey: Boolean(providerConfig.lmstudio?.apiKey),\n },\n ollama: { baseURL: providerConfig.ollama?.baseURL ?? 'http://localhost:11434/v1' },\n }\n\n const report: HealthReport = {\n ok:\n pathChecks.home &&\n pathChecks.db &&\n pathChecks.auth &&\n pathChecks.profiles &&\n pathChecks.agents &&\n pathChecks.skills &&\n (database === null || database.ok) &&\n parseErrors === 0,\n home: paths.home,\n paths: pathChecks,\n database,\n skills: { installed: skills.length, parseErrors },\n providers: providerSection,\n webSearch: {\n bravePreview: braveKey ? `${braveKey.slice(0, 6)}…` : null,\n searxngUrl: effectiveEnv.SEARXNG_URL ?? null,\n },\n openclaw: {\n path: openclawSkillsDir,\n exists: existsSync(openclawSkillsDir),\n },\n triggers: triggersSection,\n tokens: tokensSection,\n scheduler: {\n enabled: process.env.BAZILION_SCHEDULER !== 'off',\n tickMs: Number(process.env.BAZILION_SCHEDULER_TICK_MS ?? 5_000),\n },\n }\n return c.json(report)\n})\n\n// /api/backup — streams a tar.gz of $BAZILION_HOME\nmiscRouter.get('/backup', (c) => {\n const paths = resolvePaths()\n if (!existsSync(paths.home)) {\n return c.json({ error: `bazilion home not found at ${paths.home}` }, 404)\n }\n\n const proc = spawn('tar', ['-czf', '-', '-C', paths.home, '.'], {\n stdio: ['ignore', 'pipe', 'pipe'],\n })\n\n const stream = new ReadableStream({\n start(controller) {\n proc.stdout.on('data', (chunk: Buffer) => controller.enqueue(chunk))\n proc.stdout.on('end', () => {\n try {\n controller.close()\n } catch {}\n })\n proc.on('error', (err) => {\n try {\n controller.error(err)\n } catch {}\n })\n proc.on('exit', (code) => {\n if (code !== 0) {\n try {\n controller.error(new Error(`tar exited with code ${code}`))\n } catch {}\n }\n })\n },\n cancel() {\n proc.kill('SIGTERM')\n },\n })\n\n const date = new Date().toISOString().slice(0, 10)\n return new Response(stream, {\n headers: {\n 'content-type': 'application/gzip',\n 'content-disposition': `attachment; filename=\"bazilion-backup-${date}.tar.gz\"`,\n },\n })\n})\n\n// /api/tokens\nmiscRouter.get('/tokens', (c) => {\n const { db } = getCtx()\n const includeRevoked = c.req.query('includeRevoked') === '1'\n const tokens = webTokenRepo.list(db, { includeRevoked })\n return c.json({ tokens } satisfies ListTokensResponse)\n})\n\nmiscRouter.post('/tokens', async (c) => {\n const body = (await c.req.json().catch(() => null)) as CreateTokenRequest | null\n if (!body || typeof body.label !== 'string' || !body.label.trim()) {\n return c.json({ error: 'label is required' }, 400)\n }\n const { db } = getCtx()\n const created = webTokenRepo.create(db, body.label.trim())\n return c.json({ token: created.token, meta: created.meta } satisfies CreateTokenResponse, 201)\n})\n\nmiscRouter.delete('/tokens/:id', (c) => {\n const { db, authToken } = getCtx()\n const id = c.req.param('id')\n const existing = webTokenRepo.get(db, id)\n if (!existing) return c.json({ error: `token not found: ${id}` }, 404)\n if (existing.revokedAt) return c.json({ error: 'token already revoked' }, 409)\n // Refuse to revoke the bootstrap token — that's the plaintext in auth.json\n // the local CLI uses for loopback. Revoking it would lock the operator out\n // of their own daemon. Match by hash (label is editable, hash isn't).\n const bootstrap = webTokenRepo.findActiveByToken(db, authToken)\n if (bootstrap && bootstrap.id === id) {\n return c.json(\n {\n error:\n 'cannot revoke the bootstrap token — it lives in ~/.bazilion/auth.json and is the local CLI loopback credential',\n },\n 409,\n )\n }\n webTokenRepo.revoke(db, id)\n return c.body(null, 204)\n})\n","// /api/profiles/* — profile CRUD + per-profile template files.\n\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type {\n CreateProfileRequest,\n FileContentResponse,\n ProfileFileName,\n PutFileRequest,\n SkillsMode,\n UpdateProfileRequest,\n} from '@bazilion/api-types'\nimport { PROFILE_FILES } from '@bazilion/api-types'\nimport { Hono } from 'hono'\nimport {\n agentRepo,\n createProfile,\n DEFAULT_BOOTSTRAP,\n DEFAULT_IDENTITY,\n DEFAULT_SOUL,\n deleteProfile,\n loadProfile,\n profileRepo,\n updateProfile,\n} from '../core/index.ts'\nimport { getCtx } from '../lib/ctx.ts'\n\nexport const profilesRouter = new Hono()\n\nprofilesRouter.get('/', (c) => {\n const { db } = getCtx()\n const profiles = profileRepo.list(db)\n // Hydrate with the per-profile fields the listing UI needs (agent counts,\n // default-skill list) so callers don't fan out to extra endpoints per row.\n const hydrated = profiles.map((p) => ({\n ...p,\n agentCount: agentRepo.countByProfile(db, p.id),\n defaultSkills: profileRepo.getDefaultSkills(db, p.id),\n }))\n return c.json(hydrated)\n})\n\n// /api/profiles/_/templates — built-in defaults for the SOUL/IDENTITY/BOOTSTRAP\n// markdown templates. Underscore prefix avoids clashing with the `:id` route.\nprofilesRouter.get('/_/templates', (c) => {\n return c.json({\n soul: DEFAULT_SOUL,\n identity: DEFAULT_IDENTITY,\n bootstrap: DEFAULT_BOOTSTRAP,\n })\n})\n\nprofilesRouter.post('/', async (c) => {\n const raw = (await c.req.json().catch(() => null)) as\n | (Record<string, unknown> & Partial<CreateProfileRequest>)\n | null\n if (!raw) return c.json({ error: 'invalid JSON body' }, 400)\n const id = typeof raw.id === 'string' ? raw.id : ''\n const defaultModel =\n typeof raw.defaultModel === 'string'\n ? raw.defaultModel\n : typeof raw.model === 'string'\n ? raw.model\n : ''\n if (!id || !defaultModel) return c.json({ error: 'id and model are required' }, 400)\n const name = typeof raw.name === 'string' ? raw.name : undefined\n\n const skillsMode = toSkillsMode(raw.skillsMode) ?? 'selected'\n const defaultSkills = csvToArray(raw.defaultSkills ?? raw.skills)\n\n const templates: {\n soul?: string\n identity?: string\n bootstrap?: string | null\n agents?: string\n tools?: string\n heartbeat?: string\n } = {}\n if (typeof raw.soul === 'string' && raw.soul.length > 0) templates.soul = raw.soul\n if (typeof raw.identity === 'string' && raw.identity.length > 0) templates.identity = raw.identity\n if (raw.skipBootstrap === true || raw.bootstrap === null) templates.bootstrap = null\n else if (typeof raw.bootstrap === 'string' && raw.bootstrap.length > 0)\n templates.bootstrap = raw.bootstrap\n if (typeof raw.agents === 'string' && raw.agents.length > 0) templates.agents = raw.agents\n if (typeof raw.tools === 'string' && raw.tools.length > 0) templates.tools = raw.tools\n if (typeof raw.heartbeat === 'string' && raw.heartbeat.length > 0)\n templates.heartbeat = raw.heartbeat\n\n const { db, paths } = getCtx()\n try {\n const profile = createProfile(db, paths, {\n id,\n name,\n defaultModel,\n skillsMode,\n defaultSkills,\n ...(Object.keys(templates).length > 0 ? { templates } : {}),\n })\n return c.json(profile, 201)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n})\n\nprofilesRouter.get('/:id', (c) => {\n const { db } = getCtx()\n try {\n return c.json(loadProfile(db, c.req.param('id')))\n } catch (err) {\n return c.json({ error: (err as Error).message }, 404)\n }\n})\n\nprofilesRouter.patch('/:id', async (c) => {\n const raw = (await c.req.json().catch(() => null)) as\n | (UpdateProfileRequest & Record<string, unknown>)\n | null\n if (!raw) return c.json({ error: 'invalid JSON body' }, 400)\n\n const input: UpdateProfileRequest = {}\n if (typeof raw.name === 'string') input.name = raw.name\n if (typeof raw.defaultModel === 'string' && raw.defaultModel.length > 0)\n input.defaultModel = raw.defaultModel\n if (raw.skillsMode === 'all' || raw.skillsMode === 'selected') {\n input.skillsMode = raw.skillsMode\n }\n const rawSkills: unknown = raw.defaultSkills\n if (Array.isArray(rawSkills)) {\n input.defaultSkills = rawSkills.filter((s): s is string => typeof s === 'string')\n } else if (typeof rawSkills === 'string') {\n input.defaultSkills = rawSkills\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean)\n }\n const { db, paths } = getCtx()\n try {\n return c.json(updateProfile(db, paths, c.req.param('id'), input))\n } catch (err) {\n const msg = (err as Error).message\n return c.json({ error: msg }, msg.startsWith('profile not found') ? 404 : 400)\n }\n})\n\nprofilesRouter.delete('/:id', (c) => {\n const { db } = getCtx()\n try {\n deleteProfile(db, c.req.param('id'))\n return c.body(null, 204)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n})\n\nprofilesRouter.get('/:id/files/:file', (c) => {\n const { db, paths } = getCtx()\n if (!profileRepo.get(db, c.req.param('id')))\n return c.json({ error: `profile not found: ${c.req.param('id')}` }, 404)\n const path = resolveFilePath(paths.profilesDir, c.req.param('id'), c.req.param('file'))\n if (!path) return c.json({ error: `unsupported file: ${c.req.param('file')}` }, 400)\n if (!existsSync(path)) return c.json({ error: `file not present: ${c.req.param('file')}` }, 404)\n const body: FileContentResponse = { content: readFileSync(path, 'utf8') }\n return c.json(body)\n})\n\nprofilesRouter.put('/:id/files/:file', async (c) => {\n const body = (await c.req.json().catch(() => null)) as PutFileRequest | null\n if (!body || typeof body.content !== 'string')\n return c.json({ error: 'content is required' }, 400)\n const { db, paths } = getCtx()\n if (!profileRepo.get(db, c.req.param('id')))\n return c.json({ error: `profile not found: ${c.req.param('id')}` }, 404)\n const path = resolveFilePath(paths.profilesDir, c.req.param('id'), c.req.param('file'))\n if (!path) return c.json({ error: `unsupported file: ${c.req.param('file')}` }, 400)\n writeFileSync(path, body.content)\n return c.body(null, 204)\n})\n\nfunction resolveFilePath(profilesDir: string, id: string, file: string): string | null {\n if (!(PROFILE_FILES as readonly string[]).includes(file)) return null\n return join(profilesDir, id, file as ProfileFileName)\n}\n\nfunction csvToArray(v: unknown): string[] | undefined {\n if (Array.isArray(v)) return v.filter((s): s is string => typeof s === 'string')\n if (typeof v === 'string' && v.length > 0) {\n return v\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean)\n }\n return undefined\n}\n\nfunction toSkillsMode(v: unknown): SkillsMode | undefined {\n return v === 'all' || v === 'selected' ? v : undefined\n}\n","// /api/skills/* — skill discovery, removal, and import (file-path or zip upload).\n\nimport { existsSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'\nimport { homedir, tmpdir } from 'node:os'\nimport { join } from 'node:path'\nimport type { ImportSkillsRequest, ImportSkillsResponse, SkillInfo } from '@bazilion/api-types'\nimport { Hono } from 'hono'\nimport { discoverSkills, importSkills, parseSkillFile, skillMetaRepo } from '../core/index.ts'\nimport { getCtx } from '../lib/ctx.ts'\n\n// 50 MiB cap — generous headroom for a bundle of skills, tight enough to\n// reject obviously-malicious payloads without needing a streaming upload.\nconst MAX_ZIP_BYTES = 50 * 1024 * 1024\n\nexport const skillsRouter = new Hono()\n\nskillsRouter.get('/', (c) => {\n const { db, paths } = getCtx()\n const out: SkillInfo[] = []\n for (const s of discoverSkills(paths)) {\n const meta = skillMetaRepo.get(db, s.name)\n const entry: SkillInfo = {\n name: s.name,\n description: '',\n source: meta?.source ?? null,\n importedAt: meta?.importedAt ?? null,\n }\n try {\n const parsed = parseSkillFile(s.skillFile)\n entry.description = parsed.frontmatter.description\n } catch (err) {\n entry.parseError = (err as Error).message\n }\n out.push(entry)\n }\n return c.json(out)\n})\n\nskillsRouter.delete('/:name', (c) => {\n const { db, paths } = getCtx()\n const name = c.req.param('name')\n const dir = paths.skillDir(name)\n if (!existsSync(dir)) return c.json({ error: `skill not found: ${name}` }, 404)\n rmSync(dir, { recursive: true, force: true })\n skillMetaRepo.remove(db, name)\n return c.body(null, 204)\n})\n\nskillsRouter.post('/import', async (c) => {\n let input: ParsedImportInput\n try {\n input = await parseImportInput(c.req.raw)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n\n const { db, paths } = getCtx()\n try {\n const result = importSkills(paths, { source: input.source, force: input.force })\n const now = Date.now()\n for (const name of result.imported) {\n skillMetaRepo.upsert(db, { name, source: input.sourceLabel, importedAt: now })\n }\n const res: ImportSkillsResponse = { imported: result.imported, skipped: result.skipped }\n return c.json(res)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n } finally {\n if (input.tempZipPath) rmSync(input.tempZipPath, { recursive: true, force: true })\n }\n})\n\ninterface ParsedImportInput {\n source: string\n force: boolean\n /** when set, a temp zip was written and should be rm'd after import */\n tempZipPath: string | null\n /** label stored in skill_meta.source (e.g. \"uploaded:foo.zip\" for uploads) */\n sourceLabel: string\n}\n\nasync function parseImportInput(request: Request): Promise<ParsedImportInput> {\n const contentType = request.headers.get('content-type') ?? ''\n if (contentType.startsWith('multipart/form-data')) {\n const form = await request.formData()\n const file = form.get('file')\n if (!(file instanceof File) || file.size === 0) {\n throw new Error('multipart upload missing \"file\" field')\n }\n if (file.size > MAX_ZIP_BYTES) {\n throw new Error(`zip too large: ${file.size} bytes (max ${MAX_ZIP_BYTES})`)\n }\n const filename = file.name || 'upload.zip'\n if (!filename.toLowerCase().endsWith('.zip')) {\n throw new Error('uploaded file must be a .zip archive')\n }\n const tmpDir = mkdtempSync(join(tmpdir(), 'bazilion-skill-upload-'))\n const zipPath = join(tmpDir, filename.replace(/[^\\w.-]+/g, '_'))\n const buf = Buffer.from(await file.arrayBuffer())\n writeFileSync(zipPath, buf)\n const forceField = form.get('force')\n return {\n source: zipPath,\n force: forceField === 'true' || forceField === 'on' || forceField === '1',\n tempZipPath: tmpDir,\n sourceLabel: `uploaded:${filename}`,\n }\n }\n\n const body = (await request.json().catch(() => null)) as\n | (Partial<ImportSkillsRequest> & { from?: string })\n | null\n if (!body) throw new Error('invalid JSON body')\n const from = body.source ?? body.from\n if (typeof from !== 'string' || !from) throw new Error('source is required')\n const source = from === 'openclaw' ? join(homedir(), '.openclaw', 'skills') : from\n return {\n source,\n force: Boolean(body.force),\n tempZipPath: null,\n sourceLabel: from,\n }\n}\n","// /api/triggers/:id — enable/disable + delete. (Listing is per-agent at\n// /api/agents/:id/triggers; creation is also per-agent.)\n\nimport type { UpdateTriggerRequest } from '@bazilion/api-types'\nimport { Hono } from 'hono'\nimport { triggerRepo } from '../core/index.ts'\nimport { getCtx } from '../lib/ctx.ts'\n\nexport const triggersRouter = new Hono()\n\ntriggersRouter.delete('/:id', (c) => {\n const { db } = getCtx()\n const id = c.req.param('id')\n if (!triggerRepo.get(db, id)) return c.json({ error: `trigger not found: ${id}` }, 404)\n triggerRepo.remove(db, id)\n return c.body(null, 204)\n})\n\ntriggersRouter.patch('/:id', async (c) => {\n const id = c.req.param('id')\n const body = (await c.req.json().catch(() => null)) as UpdateTriggerRequest | null\n if (!body) return c.json({ error: 'invalid JSON body' }, 400)\n const { db } = getCtx()\n if (!triggerRepo.get(db, id)) return c.json({ error: `trigger not found: ${id}` }, 404)\n if (typeof body.enabled === 'boolean') {\n triggerRepo.setEnabled(db, id, body.enabled)\n }\n return c.json({ trigger: triggerRepo.get(db, id) })\n})\n"],"mappings":"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","names":["Hono","get","insert","list","remove","get","insert","list","remove","get","mkdirSync","writeFileSync","join","existsSync","readFileSync","existsSync","readFileSync","get","bootstrap","list","remove","list","existsSync","get","existsSync","insert","mkdirSync","join","mkdirSync","bootstrap","join","insert","get","existsSync","join","mkdirSync","join","writeFileSync","get","readdirSync","readFileSync","join","get","remove","join","existsSync","rmSync","get","remove","existsSync","rmSync","writeFileSync","join","get","writeFileSync","join","get","randomUUID","listAll","get","listAll","remove","get","insert","listEnabled","remove","setEnabled","randomUUID","get","list","randomBytes","randomUUID","existsSync","readFileSync","existsSync","readFileSync","existsSync","readdirSync","rmSync","statSync","join","resolve","readFileSync","join","resolve","rmSync","readdirSync","existsSync","statSync","existsSync","mkdirSync","writeFileSync","existsSync","mkdirSync","readdirSync","readFileSync","rmSync","statSync","writeFileSync","dirname","join","existsSync","mkdirSync","readdirSync","readFileSync","rmSync","statSync","writeFileSync","dirname","join","existsSync","mkdirSync","readdirSync","statSync","basename","join","resolve","get","existsSync","readFileSync","join","bootstrap","Type","existsSync","rmSync","join","readdirSync","readFileSync","statSync","writeFileSync","join","host","host","undiciFetch","ipv4","host","undiciFetch","Type","resolveApiKey","existsSync","mkdirSync","join","join","existsSync","statSync","basename","existsSync","readdirSync","join","statSync","undiciFetch","existsSync","fileURLToPath","resolve","host","createHash","createHash","decodeText","mkdirSync","existsSync","writeFileSync","existsSync","readdirSync","readFileSync","rmSync","join","toAgent","join","CONTEXT_FILE_ORDER","existsSync","readFileSync","readdirSync","rmSync","spawn","Hono","Hono","spawn","Hono","Hono","state","v","join","Hono","USER_MD_MAX_BYTES","Hono","join","Hono","Hono","spawn","existsSync","homedir","join","Hono","Hono","existsSync","join","homedir","spawn","bootstrap","existsSync","readFileSync","writeFileSync","join","Hono","Hono","existsSync","readFileSync","writeFileSync","join","existsSync","mkdtempSync","rmSync","writeFileSync","homedir","tmpdir","join","Hono","Hono","existsSync","rmSync","mkdtempSync","join","tmpdir","writeFileSync","homedir","Hono","Hono","app","Hono"]}
1
+ {"version":3,"sources":["../../daemon/src/index.ts","../../daemon/src/app.ts","../../daemon/src/lib/middleware-auth.ts","../../daemon/src/core/repos/agents.ts","../../daemon/src/core/agent/archive.ts","../../daemon/src/core/agent/delete.ts","../../daemon/src/core/repos/groups.ts","../../daemon/src/core/repos/profiles.ts","../../daemon/src/core/agent/resolve.ts","../../daemon/src/core/agent/spawn.ts","../../daemon/src/core/profile/load.ts","../../daemon/src/core/profile/identity.ts","../../daemon/src/core/repos/providerModels.ts","../../daemon/src/core/repos/providerState.ts","../../daemon/src/core/availableModels.ts","../../daemon/src/core/group/register.ts","../../daemon/src/core/profile/validate.ts","../../daemon/src/core/profile/create.ts","../../daemon/src/core/profile/templates.ts","../../daemon/src/core/profile/seed.ts","../../daemon/src/core/skills/discover.ts","../../daemon/src/core/agent/unarchive.ts","../../daemon/src/core/db/client.ts","../../daemon/src/core/db/migrate.ts","../../daemon/src/core/group/delete.ts","../../daemon/src/core/paths.ts","../../daemon/src/core/profile/delete.ts","../../daemon/src/core/repos/profileGroups.ts","../../daemon/src/core/profile/update.ts","../../daemon/src/core/profile-group/spawn.ts","../../daemon/src/core/profile-group/rm-with-retry.ts","../../daemon/src/core/services.ts","../../daemon/src/core/repos/config.ts","../../daemon/src/core/repos/messages.ts","../../daemon/src/core/repos/secrets.ts","../../daemon/src/core/repos/skillMeta.ts","../../daemon/src/core/repos/triggers.ts","../../daemon/src/core/repos/webTokens.ts","../../daemon/src/core/secrets.ts","../../daemon/src/core/skills/import.ts","../../daemon/src/core/skills/parse.ts","../../daemon/src/core/skills/resolve.ts","../../daemon/src/lib/ctx.ts","../../daemon/src/lib/agent-cancel.ts","../../daemon/src/runtime/auth/openai-codex.ts","../../daemon/src/runtime/auto-reply/heartbeat.ts","../../daemon/src/runtime/memory/files.ts","../../daemon/src/runtime/memory/qmd.ts","../../daemon/src/runtime/pi/events.ts","../../daemon/src/runtime/pi/session.ts","../../daemon/src/runtime/providers/pi-adapter.ts","../../daemon/src/runtime/providers/retry.ts","../../daemon/src/runtime/providers/registry.ts","../../daemon/src/runtime/session/prompt.ts","../../daemon/src/runtime/pi/tools.ts","../../daemon/src/runtime/tools/bootstrap.ts","../../daemon/src/runtime/tools/home.ts","../../daemon/src/runtime/tools/memory.ts","../../daemon/src/runtime/tools/messaging.ts","../../daemon/src/runtime/tools/user-md.ts","../../daemon/src/runtime/tools/web.ts","../../daemon/src/runtime/tools/web-extract.ts","../../daemon/src/runtime/tools/web-ssrf.ts","../../daemon/src/runtime/providers/catalog.ts","../../daemon/src/runtime/worker/spawn.ts","../../daemon/src/lib/api-key.ts","../../daemon/src/lib/messaging-host.ts","../../daemon/src/lib/user-md-host.ts","../../daemon/src/lib/agent-turn.ts","../../daemon/src/lib/cron.ts","../../daemon/src/lib/scheduler.ts","../../daemon/src/lib/auth.ts","../../daemon/src/routes/agents.ts","../../../packages/api-types/src/entities.ts","../../../packages/api-types/src/index.ts","../../daemon/src/lib/agent-id.ts","../../daemon/src/routes/auth-login.ts","../../daemon/src/routes/config.ts","../../daemon/src/routes/groups.ts","../../daemon/src/routes/messages.ts","../../daemon/src/routes/misc.ts","../../daemon/src/routes/profile-groups.ts","../../daemon/src/routes/profiles.ts","../../daemon/src/routes/skills.ts","../../daemon/src/routes/triggers.ts"],"sourcesContent":["// Daemon entry point. Reads HOST/PORT env, boots the Hono app, and waits on\n// SIGINT/SIGTERM for shutdown.\n//\n// This process is the single owner of `~/.bazilion`. The web app, CLI, and\n// mobile clients all talk to it over HTTP via @bazilion/client.\n\nimport { serve } from '@hono/node-server'\nimport { createApp } from './app.ts'\nimport { getCtx } from './lib/ctx.ts'\n\nconst host = process.env.HOST ?? '127.0.0.1'\nconst port = Number.parseInt(process.env.PORT ?? '4321', 10)\n\n// Eagerly bootstrap ~/.bazilion (mkdir, openDb, runMigrations, mint token,\n// write auth.json) before binding the port. Otherwise the first request\n// would race with bootstrap and the operator wouldn't see the bootstrap\n// message until something actually hits the daemon.\ngetCtx()\n\nconst app = createApp()\n\nconst server = serve({ fetch: app.fetch, hostname: host, port }, (info) => {\n console.log(`bazilion daemon listening at http://${info.address}:${info.port}`)\n if (host !== '127.0.0.1' && host !== 'localhost' && host !== '::1') {\n console.error('')\n console.error(`⚠ binding to ${host} — the daemon is now reachable beyond loopback.`)\n console.error(' anyone on this network who has a valid token can reach every API.')\n console.error(' put a TLS proxy in front for untrusted networks.')\n console.error('')\n }\n})\n\nconst shutdown = (signal: NodeJS.Signals): void => {\n console.log(`\\nbazilion daemon caught ${signal}, shutting down…`)\n server.close((err) => {\n if (err) {\n console.error('shutdown error:', err)\n process.exit(1)\n }\n process.exit(0)\n })\n}\n\nprocess.on('SIGINT', () => shutdown('SIGINT'))\nprocess.on('SIGTERM', () => shutdown('SIGTERM'))\n","// Hono app factory.\n//\n// Returns a fully-wired Hono app: middleware (auth + first-run gate) +\n// routes. Kept as a factory so tests can build one with a dedicated DB\n// without touching the global ctx singleton.\n\nimport { Hono } from 'hono'\nimport { authMiddleware } from './lib/middleware-auth.ts'\nimport { agentsRouter } from './routes/agents.ts'\nimport { authRouter } from './routes/auth-login.ts'\nimport { configRouter } from './routes/config.ts'\nimport { groupsRouter } from './routes/groups.ts'\nimport { messagesRouter } from './routes/messages.ts'\nimport { miscRouter } from './routes/misc.ts'\nimport { profileGroupsRouter } from './routes/profile-groups.ts'\nimport { profilesRouter } from './routes/profiles.ts'\nimport { skillsRouter } from './routes/skills.ts'\nimport { triggersRouter } from './routes/triggers.ts'\n\nexport function createApp(): Hono {\n const app = new Hono()\n\n // Auth + first-run gate runs before every route. Public paths (/api/login,\n // /api/health) and the setup-open prefixes (/api/config, /api/auth) are\n // whitelisted inside the middleware itself.\n app.use('*', authMiddleware)\n\n app.route('/api/agents', agentsRouter)\n app.route('/api/groups', groupsRouter)\n app.route('/api/profile-groups', profileGroupsRouter)\n app.route('/api/profiles', profilesRouter)\n app.route('/api/skills', skillsRouter)\n app.route('/api/triggers', triggersRouter)\n app.route('/api/messages', messagesRouter)\n app.route('/api/config', configRouter)\n // miscRouter exposes /backup, /tokens, /tokens/:id directly under /api —\n // mounted at the API root so each handler can use its full path.\n // authRouter likewise: /auth/openai*, /providers/test, /login.\n app.route('/api', miscRouter)\n app.route('/api', authRouter)\n\n return app\n}\n","// Hono auth + first-run gate middleware.\n//\n// Mirrors what apps/web/src/middleware.ts used to do for `/api/*` paths,\n// but framework-typed for Hono. Web SSR auth (login redirect, welcome\n// redirect) stays in the Astro app's own middleware — the daemon only\n// returns JSON status codes; the web app translates those to redirects.\n\nimport type { Context, Next } from 'hono'\nimport { getCookie } from 'hono/cookie'\nimport { isSetupComplete } from '../core/index.ts'\nimport { extractBearer, isValidToken } from './auth.ts'\nimport { getCtx } from './ctx.ts'\n\n/** Reachable without a token. The login route mints them; health is a probe. */\nconst PUBLIC_PATHS = new Set(['/api/login', '/api/health'])\n\n/**\n * Once authenticated, these paths still pass through the first-run gate so\n * users can finish their initial setup. Everything else 409s until the user\n * has at least one enabled provider with ≥1 curated model.\n */\nconst SETUP_OPEN_PREFIXES = ['/api/config', '/api/auth', '/api/health']\n\nfunction isSetupOpen(path: string): boolean {\n for (const prefix of SETUP_OPEN_PREFIXES) {\n if (path === prefix || path.startsWith(`${prefix}/`)) return true\n }\n return false\n}\n\n// biome-ignore lint/suspicious/noConfusingVoidType: hono's Next() returns Promise<void>; the union is the framework's middleware contract.\nexport async function authMiddleware(c: Context, next: Next): Promise<Response | void> {\n const path = c.req.path\n if (PUBLIC_PATHS.has(path)) {\n await next()\n return\n }\n\n const bearer = extractBearer(c.req.header('authorization'))\n const cookie = getCookie(c, 'bz_token')\n const token = bearer ?? cookie\n\n if (!token || !isValidToken(token)) {\n return c.json({ error: 'unauthorized' }, 401)\n }\n\n if (!isSetupOpen(path) && !isSetupComplete(getCtx().db)) {\n return c.json({ error: 'setup incomplete' }, 409)\n }\n\n await next()\n}\n","import type { Agent, AgentSkillAttachment, AgentStatus, ReasoningLevel } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\n\ninterface RawAgent {\n id: string\n profile_id: string\n name: string\n model_override: string | null\n reasoning_level: string\n status: string\n dir: string\n group_id: string\n created_at: number\n archived_at: number | null\n}\n\nfunction toAgent(r: RawAgent): Agent {\n return {\n id: r.id,\n profileId: r.profile_id,\n name: r.name,\n modelOverride: r.model_override,\n reasoningLevel: r.reasoning_level as ReasoningLevel,\n status: r.status as AgentStatus,\n dir: r.dir,\n groupId: r.group_id,\n createdAt: r.created_at,\n archivedAt: r.archived_at,\n }\n}\n\nexport function insert(db: BazilionDb, a: Omit<Agent, 'createdAt' | 'archivedAt'>): Agent {\n const now = Date.now()\n db.raw.run(\n `INSERT INTO agents (id, profile_id, name, model_override, reasoning_level, status, dir, group_id, created_at, archived_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL)`,\n [a.id, a.profileId, a.name, a.modelOverride, a.reasoningLevel, a.status, a.dir, a.groupId, now],\n )\n return { ...a, createdAt: now, archivedAt: null }\n}\n\nexport function setReasoningLevel(db: BazilionDb, id: string, level: ReasoningLevel): void {\n db.raw.run('UPDATE agents SET reasoning_level = ? WHERE id = ?', [level, id])\n}\n\nexport function setModelOverride(db: BazilionDb, id: string, model: string | null): void {\n db.raw.run('UPDATE agents SET model_override = ? WHERE id = ?', [model, id])\n}\n\nexport function setName(db: BazilionDb, id: string, name: string): void {\n db.raw.run('UPDATE agents SET name = ? WHERE id = ?', [name, id])\n}\n\n/** Move the agent to a different group. The new group must exist. */\nexport function setGroup(db: BazilionDb, id: string, groupId: string): void {\n db.raw.run('UPDATE agents SET group_id = ? WHERE id = ?', [groupId, id])\n}\n\n/**\n * Lookup by full UUID, exact name, or unambiguous UUID prefix (git-style\n * shorthand). Resolution order: (1) exact id, (2) exact name — only if\n * unique — (3) ≥4-char id prefix — only if unique. Ambiguous name or prefix\n * returns null so the caller's \"not found\" branch fires. Internal callers\n * always pass full UUIDs, so this only exercises on the new path (URL params,\n * CLI arguments).\n *\n * Name comes before prefix so that a hex-looking name like \"abcd1234\" resolves\n * to the named agent rather than accidentally matching a UUID prefix.\n */\nexport function get(db: BazilionDb, idOrName: string): Agent | null {\n if (!idOrName) return null\n const exactId = db.raw\n .query<RawAgent, [string]>('SELECT * FROM agents WHERE id = ?')\n .get(idOrName)\n if (exactId) return toAgent(exactId)\n const byName = db.raw\n .query<RawAgent, [string]>('SELECT * FROM agents WHERE name = ? LIMIT 2')\n .all(idOrName)\n if (byName.length === 1 && byName[0]) return toAgent(byName[0])\n if (byName.length > 1) return null\n if (idOrName.length < 4) return null\n const byPrefix = db.raw\n .query<RawAgent, [string]>('SELECT * FROM agents WHERE id LIKE ? LIMIT 2')\n .all(`${idOrName}%`)\n return byPrefix.length === 1 && byPrefix[0] ? toAgent(byPrefix[0]) : null\n}\n\n/**\n * Resolve `idOrPrefix` to a full agent ID, or null if not found / ambiguous.\n * Thin wrapper around `get` for callers that want the canonical ID without\n * the rest of the row (e.g. URL param normalization).\n */\nexport function resolveId(db: BazilionDb, idOrPrefix: string): string | null {\n return get(db, idOrPrefix)?.id ?? null\n}\n\nexport function list(db: BazilionDb, opts?: { includeArchived?: boolean }): Agent[] {\n const sql = opts?.includeArchived\n ? 'SELECT * FROM agents ORDER BY created_at ASC'\n : \"SELECT * FROM agents WHERE status != 'archived' ORDER BY created_at ASC\"\n return db.raw.query<RawAgent, []>(sql).all().map(toAgent)\n}\n\nexport function countByProfile(db: BazilionDb, profileId: string): number {\n return (\n db.raw\n .query<{ c: number }, [string]>('SELECT COUNT(*) as c FROM agents WHERE profile_id = ?')\n .get(profileId)?.c ?? 0\n )\n}\n\n/**\n * Count agents whose group_id matches. Blocks group deletion when > 0 (the\n * `agents.group_id` FK is `ON DELETE RESTRICT` — members must be moved or\n * archived before a group can go away).\n */\nexport function countByGroup(db: BazilionDb, groupId: string): number {\n return (\n db.raw\n .query<{ c: number }, [string]>('SELECT COUNT(*) as c FROM agents WHERE group_id = ?')\n .get(groupId)?.c ?? 0\n )\n}\n\nexport function setStatus(db: BazilionDb, id: string, status: AgentStatus): void {\n db.raw.run('UPDATE agents SET status = ? WHERE id = ?', [status, id])\n}\n\nexport function archive(db: BazilionDb, id: string): void {\n db.raw.run(\"UPDATE agents SET status = 'archived', archived_at = ? WHERE id = ?\", [\n Date.now(),\n id,\n ])\n}\n\nexport function unarchive(db: BazilionDb, id: string): void {\n db.raw.run(\"UPDATE agents SET status = 'idle', archived_at = NULL WHERE id = ?\", [id])\n}\n\nexport function remove(db: BazilionDb, id: string): void {\n db.raw.run('DELETE FROM agents WHERE id = ?', [id])\n}\n\n// --- skill attachments ---\n\ninterface RawSkill {\n agent_id: string\n skill_name: string\n attached_at: number\n}\n\nfunction toSkillAttachment(r: RawSkill): AgentSkillAttachment {\n return {\n agentId: r.agent_id,\n skillName: r.skill_name,\n attachedAt: r.attached_at,\n }\n}\n\nexport function attachSkill(\n db: BazilionDb,\n agentId: string,\n skillName: string,\n): AgentSkillAttachment {\n const now = Date.now()\n db.raw.run(\n `INSERT INTO agent_skills (agent_id, skill_name, attached_at)\n VALUES (?, ?, ?)\n ON CONFLICT (agent_id, skill_name) DO NOTHING`,\n [agentId, skillName, now],\n )\n return { agentId, skillName, attachedAt: now }\n}\n\nexport function detachSkill(db: BazilionDb, agentId: string, skillName: string): void {\n db.raw.run('DELETE FROM agent_skills WHERE agent_id = ? AND skill_name = ?', [agentId, skillName])\n}\n\nexport function listAttachedSkills(db: BazilionDb, agentId: string): string[] {\n return db.raw\n .query<{ skill_name: string }, [string]>(\n 'SELECT skill_name FROM agent_skills WHERE agent_id = ? ORDER BY attached_at ASC',\n )\n .all(agentId)\n .map((r) => r.skill_name)\n}\n\nexport function listSkillAttachments(db: BazilionDb, agentId: string): AgentSkillAttachment[] {\n return db.raw\n .query<RawSkill, [string]>(\n 'SELECT * FROM agent_skills WHERE agent_id = ? ORDER BY attached_at ASC',\n )\n .all(agentId)\n .map(toSkillAttachment)\n}\n\n// --- chat history snapshot ---\n//\n// Conversation transcript storage lives in pi-coding-agent's SessionManager\n// (JSONL under `~/.bazilion/agents/<id>/sessions/<sessionId>.jsonl`).\n// Clear/truncate/rotate operations go through the runtime's\n// `apps/daemon/src/runtime/pi/session.ts` helpers, not repo-level accessors.\n","import type { BazilionDb } from '../db/client.ts'\nimport * as agentRepo from '../repos/agents.ts'\n\nexport function archiveAgent(db: BazilionDb, id: string): void {\n const agent = agentRepo.get(db, id)\n if (!agent) throw new Error(`agent not found: ${id}`)\n agentRepo.archive(db, agent.id)\n}\n","import { existsSync, rmSync } from 'node:fs'\nimport type { BazilionDb } from '../db/client.ts'\nimport * as agentRepo from '../repos/agents.ts'\n\nexport function deleteAgent(db: BazilionDb, id: string): void {\n const agent = agentRepo.get(db, id)\n if (!agent) throw new Error(`agent not found: ${id}`)\n const fullId = agent.id\n\n db.raw.transaction(() => {\n // messages.from_agent_id and to_agent_id reference agents(id) with no ON\n // DELETE rule, and messages.reply_to references messages(id) the same way,\n // so a naive DELETE of the agent fails if it has any mailbox history.\n // Null out inbound reply pointers to this agent's messages, then purge the\n // messages themselves, then let agentRepo.remove cascade the rest\n // (agent_skills, runs, events). agents.group_id is `ON DELETE RESTRICT`\n // from the group side, but the agent row itself goes away freely.\n db.raw.run(\n `UPDATE messages SET reply_to = NULL\n WHERE reply_to IN (SELECT id FROM messages WHERE from_agent_id = ? OR to_agent_id = ?)`,\n [fullId, fullId],\n )\n db.raw.run('DELETE FROM messages WHERE from_agent_id = ? OR to_agent_id = ?', [fullId, fullId])\n agentRepo.remove(db, fullId)\n })()\n\n if (existsSync(agent.dir)) {\n rmSync(agent.dir, { recursive: true, force: true })\n }\n}\n","// Groups repo. The group `id` is the slug AND the directory name under\n// `~/.bazilion/groups/<slug>/`. There is no `path` column — callers\n// derive `paths.groupDir(id)` at read time. That makes the on-disk path\n// canonical: a real directory or a symlink, but always at the same slot.\n\nimport type { Group } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\nimport type { Paths } from '../paths.ts'\n\ninterface RawGroup {\n id: string\n name: string\n user_md: string\n created_at: number\n}\n\nfunction toGroup(r: RawGroup, paths: Paths): Group {\n return {\n id: r.id,\n name: r.name,\n path: paths.groupDir(r.id),\n userMd: r.user_md,\n createdAt: r.created_at,\n }\n}\n\nexport function insert(db: BazilionDb, g: { id: string; name: string }, paths: Paths): Group {\n const now = Date.now()\n db.raw.run(\"INSERT INTO groups (id, name, user_md, created_at) VALUES (?, ?, '', ?)\", [\n g.id,\n g.name,\n now,\n ])\n return { id: g.id, name: g.name, path: paths.groupDir(g.id), userMd: '', createdAt: now }\n}\n\nexport function get(db: BazilionDb, id: string, paths: Paths): Group | null {\n const row = db.raw.query<RawGroup, [string]>('SELECT * FROM groups WHERE id = ?').get(id)\n return row ? toGroup(row, paths) : null\n}\n\nexport function list(db: BazilionDb, paths: Paths): Group[] {\n return db.raw\n .query<RawGroup, []>('SELECT * FROM groups ORDER BY created_at ASC')\n .all()\n .map((r) => toGroup(r, paths))\n}\n\nexport function remove(db: BazilionDb, id: string): void {\n db.raw.run('DELETE FROM groups WHERE id = ?', [id])\n}\n\nexport function setUserMd(db: BazilionDb, id: string, userMd: string): void {\n db.raw.run('UPDATE groups SET user_md = ? WHERE id = ?', [userMd, id])\n}\n","import type { Profile, SkillsMode } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\n\ninterface RawProfile {\n id: string\n name: string\n dir: string\n default_model: string\n skills_mode: string\n created_at: number\n updated_at: number\n}\n\nfunction toProfile(r: RawProfile): Profile {\n return {\n id: r.id,\n name: r.name,\n dir: r.dir,\n defaultModel: r.default_model,\n skillsMode: r.skills_mode as SkillsMode,\n createdAt: r.created_at,\n updatedAt: r.updated_at,\n }\n}\n\nexport function insert(db: BazilionDb, p: Omit<Profile, 'createdAt' | 'updatedAt'>): Profile {\n const now = Date.now()\n db.raw.run(\n `INSERT INTO profiles (id, name, dir, default_model, skills_mode, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)`,\n [p.id, p.name, p.dir, p.defaultModel, p.skillsMode, now, now],\n )\n return { ...p, createdAt: now, updatedAt: now }\n}\n\nexport function get(db: BazilionDb, id: string): Profile | null {\n const row = db.raw.query<RawProfile, [string]>('SELECT * FROM profiles WHERE id = ?').get(id)\n return row ? toProfile(row) : null\n}\n\nexport function list(db: BazilionDb): Profile[] {\n return db.raw\n .query<RawProfile, []>('SELECT * FROM profiles ORDER BY created_at ASC')\n .all()\n .map(toProfile)\n}\n\nexport function remove(db: BazilionDb, id: string): void {\n db.raw.run('DELETE FROM profiles WHERE id = ?', [id])\n}\n\nexport function update(\n db: BazilionDb,\n id: string,\n fields: { name: string; defaultModel: string; skillsMode: SkillsMode },\n): void {\n db.raw.run(\n `UPDATE profiles\n SET name = ?, default_model = ?, skills_mode = ?, updated_at = ?\n WHERE id = ?`,\n [fields.name, fields.defaultModel, fields.skillsMode, Date.now(), id],\n )\n}\n\nexport function setDefaultSkills(db: BazilionDb, profileId: string, skills: string[]): void {\n const tx = db.raw.transaction(() => {\n db.raw.run('DELETE FROM profile_default_skills WHERE profile_id = ?', [profileId])\n const stmt = db.raw.query(\n 'INSERT INTO profile_default_skills (profile_id, skill_name) VALUES (?, ?)',\n )\n for (const s of skills) stmt.run(profileId, s)\n })\n tx()\n}\n\nexport function getDefaultSkills(db: BazilionDb, profileId: string): string[] {\n return db.raw\n .query<{ skill_name: string }, [string]>(\n 'SELECT skill_name FROM profile_default_skills WHERE profile_id = ? ORDER BY skill_name',\n )\n .all(profileId)\n .map((r) => r.skill_name)\n}\n","import type { ResolvedAgent } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\nimport type { Paths } from '../paths.ts'\nimport * as agentRepo from '../repos/agents.ts'\nimport * as groupRepo from '../repos/groups.ts'\nimport * as profileRepo from '../repos/profiles.ts'\n\nexport function resolveAgent(db: BazilionDb, paths: Paths, agentId: string): ResolvedAgent {\n // `agentRepo.get` accepts either a full UUID or an unambiguous prefix.\n const agent = agentRepo.get(db, agentId)\n if (!agent) throw new Error(`agent not found: ${agentId}`)\n\n const profile = profileRepo.get(db, agent.profileId)\n if (!profile) {\n throw new Error(`profile not found for agent ${agentId}: ${agent.profileId}`)\n }\n\n const group = groupRepo.get(db, agent.groupId, paths)\n if (!group) {\n throw new Error(`group not found for agent ${agentId}: ${agent.groupId}`)\n }\n\n return {\n agent,\n profile,\n model: agent.modelOverride ?? profile.defaultModel,\n reasoningLevel: agent.reasoningLevel,\n group,\n skills: agentRepo.listAttachedSkills(db, agentId),\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport { mkdirSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { Agent, ReasoningLevel } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\nimport type { Paths } from '../paths.ts'\nimport { loadProfile } from '../profile/load.ts'\nimport { DEFAULT_GROUP_ID } from '../profile/seed.ts'\nimport * as agentRepo from '../repos/agents.ts'\nimport * as groupRepo from '../repos/groups.ts'\nimport { discoverSkills } from '../skills/discover.ts'\n\nexport interface SpawnAgentInput {\n profileId: string\n name?: string\n modelOverride?: string | null\n reasoningLevel?: ReasoningLevel\n /**\n * Group the new agent joins. One agent belongs to exactly one group. When\n * omitted, falls back to the seeded 'default' group — the same fallback\n * used everywhere we need a sensible cwd. Must refer to an existing group.\n */\n groupId?: string\n}\n\nexport function spawnAgent(db: BazilionDb, paths: Paths, input: SpawnAgentInput): Agent {\n const loaded = loadProfile(db, input.profileId)\n const id = randomUUID()\n const dir = paths.agentDir(id)\n // Agent's private home: identity files + sessions. Memory now lives at\n // the group level (`groups/<slug>/memory/`), shared by all member agents,\n // so we no longer create per-agent memory dirs here.\n mkdirSync(dir, { recursive: true })\n mkdirSync(join(dir, 'sessions'), { recursive: true })\n\n // Copy profile templates verbatim so the agent can diverge per-instance.\n // BOOTSTRAP.md is intentionally NOT personalized with the spawn slug —\n // the slug is a routing label, not necessarily the persona name. Bootstrap\n // is a pure conversation: the agent asks, the human answers, IDENTITY.md\n // is populated from that exchange.\n writeFileSync(join(dir, 'SOUL.md'), loaded.files.soul)\n writeFileSync(join(dir, 'IDENTITY.md'), loaded.files.identity)\n if (loaded.files.bootstrap !== null) {\n writeFileSync(join(dir, 'BOOTSTRAP.md'), loaded.files.bootstrap)\n }\n if (loaded.files.agents !== null) {\n writeFileSync(join(dir, 'AGENTS.md'), loaded.files.agents)\n }\n if (loaded.files.tools !== null) {\n writeFileSync(join(dir, 'TOOLS.md'), loaded.files.tools)\n }\n if (loaded.files.heartbeat !== null) {\n writeFileSync(join(dir, 'HEARTBEAT.md'), loaded.files.heartbeat)\n }\n\n const reasoningLevel: ReasoningLevel = input.reasoningLevel ?? 'medium'\n\n // Resolve group: explicit input wins; otherwise fall back to the seeded\n // 'default'. If neither exists, error out — an agent can't live without a\n // group (the FK `agents.group_id REFERENCES groups(id)` enforces it too).\n const groupId = input.groupId ?? DEFAULT_GROUP_ID\n const group = groupRepo.get(db, groupId, paths)\n if (!group) {\n throw new Error(\n `spawnAgent: group \"${groupId}\" does not exist. Pass an explicit --group or complete first-run setup first.`,\n )\n }\n\n const agentJson = {\n profileId: input.profileId,\n name: input.name ?? loaded.profile.name,\n modelOverride: input.modelOverride ?? null,\n reasoningLevel,\n groupId: group.id,\n }\n writeFileSync(join(dir, 'agent.json'), `${JSON.stringify(agentJson, null, 2)}\\n`)\n\n const agent = agentRepo.insert(db, {\n id,\n profileId: input.profileId,\n name: agentJson.name,\n modelOverride: agentJson.modelOverride,\n reasoningLevel,\n status: 'idle',\n dir,\n groupId: group.id,\n })\n\n // Skills come from the profile only — `skills_mode='all'` attaches every\n // installed skill, `'selected'` attaches the profile's default list.\n // Per-agent skill changes happen post-spawn via `agent skill add/rm`.\n const skills =\n loaded.profile.skillsMode === 'all'\n ? discoverSkills(paths).map((s) => s.name)\n : loaded.defaultSkills\n for (const s of skills) agentRepo.attachSkill(db, id, s)\n\n return agent\n}\n","import { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { LoadedProfile } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\nimport * as profileRepo from '../repos/profiles.ts'\nimport { parseIdentityMarkdown } from './identity.ts'\n\nfunction readOptional(path: string): string | null {\n return existsSync(path) ? readFileSync(path, 'utf8') : null\n}\n\nexport function loadProfile(db: BazilionDb, id: string): LoadedProfile {\n const profile = profileRepo.get(db, id)\n if (!profile) throw new Error(`profile not found: ${id}`)\n\n const soul = readFileSync(join(profile.dir, 'SOUL.md'), 'utf8')\n const identityRaw = readFileSync(join(profile.dir, 'IDENTITY.md'), 'utf8')\n const bootstrap = readOptional(join(profile.dir, 'BOOTSTRAP.md'))\n const agents = readOptional(join(profile.dir, 'AGENTS.md'))\n const tools = readOptional(join(profile.dir, 'TOOLS.md'))\n const heartbeat = readOptional(join(profile.dir, 'HEARTBEAT.md'))\n\n const parsedIdentity = parseIdentityMarkdown(identityRaw)\n const anyIdentity =\n parsedIdentity.name ||\n parsedIdentity.emoji ||\n parsedIdentity.theme ||\n parsedIdentity.creature ||\n parsedIdentity.vibe ||\n parsedIdentity.avatar\n\n return {\n profile,\n defaultSkills: profileRepo.getDefaultSkills(db, id),\n files: {\n soul,\n identity: identityRaw,\n bootstrap,\n agents,\n tools,\n heartbeat,\n },\n identity: anyIdentity ? parsedIdentity : null,\n }\n}\n","import { readFileSync } from 'node:fs'\nimport type { AgentIdentityFile } from '@bazilion/api-types'\n\nconst IDENTITY_PLACEHOLDER_VALUES = new Set([\n 'pick something you like',\n 'ai? robot? familiar? ghost in the machine? something weirder?',\n 'how do you come across? sharp? warm? chaotic? calm?',\n 'your signature - pick one that feels right',\n 'workspace-relative path, http(s) url, or data uri',\n])\n\nfunction normalizeIdentityValue(value: string): string {\n let normalized = value.trim()\n normalized = normalized.replace(/^[*_]+|[*_]+$/g, '').trim()\n if (normalized.startsWith('(') && normalized.endsWith(')')) {\n normalized = normalized.slice(1, -1).trim()\n }\n normalized = normalized.replace(/[\\u2013\\u2014]/g, '-')\n normalized = normalized.replace(/\\s+/g, ' ').toLowerCase()\n return normalized\n}\n\nfunction isIdentityPlaceholder(value: string): boolean {\n return IDENTITY_PLACEHOLDER_VALUES.has(normalizeIdentityValue(value))\n}\n\nexport function parseIdentityMarkdown(content: string): AgentIdentityFile {\n const identity: AgentIdentityFile = {}\n for (const line of content.split(/\\r?\\n/)) {\n const cleaned = line.trim().replace(/^\\s*-\\s*/, '')\n const colonIndex = cleaned.indexOf(':')\n if (colonIndex === -1) continue\n const label = cleaned.slice(0, colonIndex).replace(/[*_]/g, '').trim().toLowerCase()\n const value = cleaned\n .slice(colonIndex + 1)\n .replace(/^[*_]+|[*_]+$/g, '')\n .trim()\n if (!value) continue\n if (isIdentityPlaceholder(value)) continue\n if (label === 'name') identity.name = value\n else if (label === 'emoji') identity.emoji = value\n else if (label === 'creature') identity.creature = value\n else if (label === 'vibe') identity.vibe = value\n else if (label === 'theme') identity.theme = value\n else if (label === 'avatar') identity.avatar = value\n }\n return identity\n}\n\nexport function identityHasValues(identity: AgentIdentityFile): boolean {\n return Boolean(\n identity.name ||\n identity.emoji ||\n identity.theme ||\n identity.creature ||\n identity.vibe ||\n identity.avatar,\n )\n}\n\nexport function loadIdentityFromFile(path: string): AgentIdentityFile | null {\n let content: string\n try {\n content = readFileSync(path, 'utf8')\n } catch {\n return null\n }\n const parsed = parseIdentityMarkdown(content)\n return identityHasValues(parsed) ? parsed : null\n}\n","import type { BazilionDb } from '../db/client.ts'\n\ninterface RawRow {\n provider: string\n model: string\n added_at: number\n}\n\n/** Curated model names for one provider, in insertion order. */\nexport function list(db: BazilionDb, provider: string): string[] {\n return db.raw\n .query<RawRow, [string]>(\n 'SELECT * FROM provider_models WHERE provider = ? ORDER BY added_at ASC',\n )\n .all(provider)\n .map((r) => r.model)\n}\n\n/** All curated models grouped by provider. Empty providers are omitted. */\nexport function listAll(db: BazilionDb): Record<string, string[]> {\n const out: Record<string, string[]> = {}\n for (const row of db.raw\n .query<RawRow, []>('SELECT * FROM provider_models ORDER BY provider ASC, added_at ASC')\n .all()) {\n const bucket = out[row.provider] ?? []\n bucket.push(row.model)\n out[row.provider] = bucket\n }\n return out\n}\n\n/**\n * Replace the curated list for one provider atomically. Empty `models` clears\n * the list. De-dupes (case-sensitive) and preserves incoming order.\n */\nexport function replace(db: BazilionDb, provider: string, models: string[]): void {\n const seen = new Set<string>()\n const clean = models\n .map((m) => m.trim())\n .filter((m) => m.length > 0 && !seen.has(m) && seen.add(m))\n db.raw.transaction(() => {\n db.raw.run('DELETE FROM provider_models WHERE provider = ?', [provider])\n const now = Date.now()\n for (let i = 0; i < clean.length; i++) {\n // Offset by index so ordering is preserved by added_at.\n db.raw.run('INSERT INTO provider_models (provider, model, added_at) VALUES (?, ?, ?)', [\n provider,\n clean[i] as string,\n now + i,\n ])\n }\n })()\n}\n\n/** Remove a single curated model. No-op if not present. */\nexport function remove(db: BazilionDb, provider: string, model: string): void {\n db.raw.run('DELETE FROM provider_models WHERE provider = ? AND model = ?', [provider, model])\n}\n","import type { BazilionDb } from '../db/client.ts'\n\ninterface RawRow {\n provider_id: string\n enabled: number\n updated_at: number\n}\n\nexport function isEnabled(db: BazilionDb, providerId: string): boolean {\n const row = db.raw\n .query<RawRow, [string]>('SELECT * FROM provider_state WHERE provider_id = ?')\n .get(providerId)\n return row?.enabled === 1\n}\n\nexport function setEnabled(db: BazilionDb, providerId: string, enabled: boolean): void {\n db.raw.run(\n `INSERT INTO provider_state (provider_id, enabled, updated_at)\n VALUES (?, ?, ?)\n ON CONFLICT (provider_id) DO UPDATE SET\n enabled = excluded.enabled,\n updated_at = excluded.updated_at`,\n [providerId, enabled ? 1 : 0, Date.now()],\n )\n}\n\n/** Set of provider ids currently toggled on. Convenience for batch checks. */\nexport function listEnabled(db: BazilionDb): Set<string> {\n return new Set(\n db.raw\n .query<{ provider_id: string }, []>(\n 'SELECT provider_id FROM provider_state WHERE enabled = 1',\n )\n .all()\n .map((r) => r.provider_id),\n )\n}\n","// Enumerates models that agents are actually allowed to use right now:\n// every curated model of every currently-enabled provider. Drives the model\n// dropdowns on the profile and agent forms.\n//\n// A provider must be both (a) toggled on in `provider_state` AND (b) have\n// at least one curated entry in `provider_models` to show up here. Drop a\n// provider off either side and it disappears from the list without a UI\n// edit — the dropdowns are entirely data-driven.\n\nimport type { BazilionDb } from './db/client.ts'\nimport * as providerModelRepo from './repos/providerModels.ts'\nimport * as providerStateRepo from './repos/providerState.ts'\n\nexport interface AvailableModel {\n provider: string\n model: string\n /** The `provider:model` string used as the form value and in model resolution. */\n value: string\n}\n\n/**\n * Flat list of `{provider, model, value}` for every curated model of every\n * enabled provider. Iteration order: providers as they're stored in\n * `provider_state` (by insertion time), models as curated (preserving the\n * admin's ordering from the textarea).\n */\nexport function listAvailableModels(db: BazilionDb): AvailableModel[] {\n const enabled = providerStateRepo.listEnabled(db)\n const out: AvailableModel[] = []\n for (const provider of enabled) {\n for (const model of providerModelRepo.list(db, provider)) {\n out.push({ provider, model, value: `${provider}:${model}` })\n }\n }\n return out\n}\n\n/**\n * Same as `listAvailableModels` but grouped by provider — the shape the web\n * dropdowns consume directly via `<optgroup>`.\n */\nexport function groupAvailableModels(db: BazilionDb): { provider: string; models: string[] }[] {\n const enabled = providerStateRepo.listEnabled(db)\n const groups: { provider: string; models: string[] }[] = []\n for (const provider of enabled) {\n const models = providerModelRepo.list(db, provider)\n if (models.length > 0) groups.push({ provider, models })\n }\n return groups\n}\n\n/**\n * True once the user has at least one usable model — i.e. at least one enabled\n * provider with at least one curated model. Gates the first-run flow.\n */\nexport function isSetupComplete(db: BazilionDb): boolean {\n return listAvailableModels(db).length > 0\n}\n","// Register a group: pick a slug, materialize `~/.bazilion/groups/<slug>/`\n// (real dir or symlink), insert the row.\n//\n// Two modes:\n// - default: creates a real directory at `paths.groupDir(slug)`.\n// - `--link <target>`: creates a symlink at `paths.groupDir(slug)` →\n// `<target>`. The link target must exist and be a directory — that's\n// the \"I want my agents working on my existing project tree\" path.\n//\n// Slug = the row's id. Names are humanized labels separate from the slug;\n// callers may pass `name` explicitly or let it default to the slug.\n\nimport { existsSync, mkdirSync, statSync, symlinkSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport type { Group } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\nimport type { Paths } from '../paths.ts'\nimport { validateSlug } from '../profile/validate.ts'\nimport * as groupRepo from '../repos/groups.ts'\n\nexport interface RegisterGroupInput {\n /** Slug. Becomes the row id AND the directory name under `groups/`. */\n id: string\n /** Human-readable label. Defaults to `id`. */\n name?: string\n /**\n * If set, materialize `paths.groupDir(id)` as a symlink to this absolute\n * path instead of as a real directory. Target must exist and be a dir.\n */\n link?: string\n}\n\nexport function registerGroup(db: BazilionDb, input: RegisterGroupInput, paths: Paths): Group {\n validateSlug(input.id)\n\n if (groupRepo.get(db, input.id, paths)) {\n throw new Error(`group already registered: ${input.id}`)\n }\n\n const slot = paths.groupDir(input.id)\n if (existsSync(slot)) {\n throw new Error(`group slot already on disk at ${slot} (move or remove it first)`)\n }\n\n // Make sure the parent `groups/` dir exists — the daemon's bootstrap creates\n // it but tests sometimes resolve a custom $BAZILION_HOME without going\n // through bootstrap.\n mkdirSync(paths.groupsDir, { recursive: true })\n\n if (input.link) {\n const target = resolve(input.link)\n if (!existsSync(target)) {\n throw new Error(`--link target does not exist: ${target}`)\n }\n if (!statSync(target).isDirectory()) {\n throw new Error(`--link target is not a directory: ${target}`)\n }\n symlinkSync(target, slot, 'dir')\n } else {\n mkdirSync(slot, { recursive: true })\n }\n\n // Memory subdir is the qmd index root for this group — created here so\n // the first tool call doesn't have to ensure it.\n mkdirSync(resolve(slot, 'memory'), { recursive: true })\n\n return groupRepo.insert(db, { id: input.id, name: input.name ?? input.id }, paths)\n}\n","const SLUG = /^[a-z0-9][a-z0-9-]*$/\n\nexport function validateSlug(s: string): void {\n if (!SLUG.test(s)) {\n throw new Error(\n `invalid slug \"${s}\": must match /^[a-z0-9][a-z0-9-]*$/ (lowercase letters, digits, hyphens; must start with letter or digit)`,\n )\n }\n}\n","import { mkdirSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { Profile, SkillsMode } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\nimport type { Paths } from '../paths.ts'\nimport * as profileRepo from '../repos/profiles.ts'\nimport { DEFAULT_BOOTSTRAP, DEFAULT_IDENTITY, DEFAULT_SOUL } from './templates.ts'\nimport { validateSlug } from './validate.ts'\n\nexport interface CreateProfileInput {\n id: string\n name?: string\n defaultModel: string\n skillsMode?: SkillsMode\n defaultSkills?: string[]\n templates?: {\n soul?: string\n identity?: string\n /** undefined = default bootstrap, null = skip bootstrap, string = override */\n bootstrap?: string | null\n /** undefined = skip, string = seed with this content */\n agents?: string\n /** undefined = skip, string = seed with this content */\n tools?: string\n /** undefined = skip, string = seed with this content */\n heartbeat?: string\n }\n}\n\nexport function createProfile(db: BazilionDb, paths: Paths, input: CreateProfileInput): Profile {\n validateSlug(input.id)\n\n const dir = paths.profileDir(input.id)\n mkdirSync(dir, { recursive: true })\n\n const soul = input.templates?.soul ?? DEFAULT_SOUL\n const identity = input.templates?.identity ?? DEFAULT_IDENTITY\n const bootstrap =\n input.templates?.bootstrap === null ? null : (input.templates?.bootstrap ?? DEFAULT_BOOTSTRAP)\n\n writeFileSync(join(dir, 'SOUL.md'), soul)\n writeFileSync(join(dir, 'IDENTITY.md'), identity)\n if (bootstrap !== null) {\n writeFileSync(join(dir, 'BOOTSTRAP.md'), bootstrap)\n }\n if (typeof input.templates?.agents === 'string') {\n writeFileSync(join(dir, 'AGENTS.md'), input.templates.agents)\n }\n if (typeof input.templates?.tools === 'string') {\n writeFileSync(join(dir, 'TOOLS.md'), input.templates.tools)\n }\n if (typeof input.templates?.heartbeat === 'string') {\n writeFileSync(join(dir, 'HEARTBEAT.md'), input.templates.heartbeat)\n }\n\n const skillsMode: SkillsMode = input.skillsMode ?? 'selected'\n const profileJson = {\n name: input.name ?? input.id,\n defaultModel: input.defaultModel,\n skillsMode,\n defaultSkills: input.defaultSkills ?? [],\n }\n writeFileSync(join(dir, 'profile.json'), `${JSON.stringify(profileJson, null, 2)}\\n`)\n\n const profile = profileRepo.insert(db, {\n id: input.id,\n name: profileJson.name,\n dir,\n defaultModel: input.defaultModel,\n skillsMode,\n })\n\n if (skillsMode === 'selected' && input.defaultSkills && input.defaultSkills.length > 0) {\n profileRepo.setDefaultSkills(db, input.id, input.defaultSkills)\n }\n\n return profile\n}\n","export const DEFAULT_SOUL = `# SOUL.md — Who You Are\n\nThis is your personality and operating principles. Edit it freely to make this agent yours.\n\n## Core\n- Be genuinely helpful, not performatively helpful.\n- Have opinions. Push back when you disagree.\n- Be resourceful before asking — read the file, check context, then ask if stuck.\n\n## Boundaries\n- Private things stay private.\n- Confirm before destructive or external actions.\n- You're a guest in someone's environment. Treat it with respect.\n`\n\nexport const DEFAULT_IDENTITY = `# IDENTITY.md — Who Am I?\n\nFill this in during your first conversation. Make it yours.\n\n- **Name:**\n- **Vibe:**\n- **Emoji:**\n`\n\nexport const DEFAULT_BOOTSTRAP = `# BOOTSTRAP.md — First Run\n\nYou just woke up. There is no memory yet — that's normal. This is a multi-turn\nritual: ask ONE question per turn and wait for the human's reply before moving\non. Do not race through it. Do not call any tool until the ritual is finished.\n\n## The ritual\n\n**Turn 1 (right now):** Greet the human warmly and ask a single opening\nquestion — what should they call you, or what should you focus on for them.\nDo NOT call any tool yet. Just reply with greeting + one question.\n\n**Turn 2+:** Continue with one more question per turn to fill in the rest of\nyour identity — vibe (warm / sharp / playful / calm / …), an emoji that\nfeels right. Each turn is acknowledging the previous answer + at most one\nnew question. Skip a turn when you already have enough.\n\n**Final turn:** Once you have everything (Name, Vibe, Emoji), call \\`home_write\\`\nwith \\`file: \"IDENTITY.md\"\\` and the populated content. Do NOT use the generic\n\\`edit\\` / \\`write\\` tools — those land in the shared workspace.\n\nThen call \\`bootstrap_done\\` to retire this ritual file. After that, future\nsessions skip the bootstrap and start from IDENTITY.md directly.\n\n## Hard rules\n- Do not invent a name on your own. Ask the human and use what they say.\n- Do not call \\`home_write\\` or \\`bootstrap_done\\` on your very first reply.\n- One question per turn. Wait for the human to answer.\n`\n\nexport const DEFAULT_AGENTS = `# AGENTS.md — Peers & Routing\n\nDocument the other agents you can reach and when to involve them. If you're\nthe only agent in this workspace, leave this short or delete it.\n\n## Peers\n- (name): what they're good at, when to hand off\n`\n\nexport const DEFAULT_TOOLS = `# TOOLS.md — Tool Playbook\n\nNotes on tool usage patterns that are specific to this agent. Keep generic\ntool docs out — those live in SOUL.md or come from the tool descriptions.\n\n## Patterns\n- (pattern): when to use, what to avoid\n`\n\nexport const DEFAULT_HEARTBEAT = `# HEARTBEAT.md — Scheduled Wake-Ups\n\nTasks the agent should check on every heartbeat. Leave empty (or commented)\nto opt out — an empty file means \"nothing to do right now\".\n\n## Tasks\n- (task): cadence, exit criteria\n`\n","import type { Group, Profile } from '@bazilion/api-types'\nimport { isSetupComplete, listAvailableModels } from '../availableModels.ts'\nimport type { BazilionDb } from '../db/client.ts'\nimport { registerGroup } from '../group/register.ts'\nimport type { Paths } from '../paths.ts'\nimport * as groupRepo from '../repos/groups.ts'\nimport * as profileRepo from '../repos/profiles.ts'\nimport { createProfile } from './create.ts'\n\nexport const DEFAULT_PROFILE_ID = 'default'\nexport const DEFAULT_GROUP_ID = 'default'\n\nexport interface SeedDefaultsInput {\n /** `provider:model` used as the profile's defaultModel. */\n model: string\n}\n\nexport interface SeedResult {\n profile: Profile\n group: Group\n /** true if the helper created the profile this call (vs. returned an existing one). */\n profileCreated: boolean\n /** true if the helper created the group this call. */\n groupCreated: boolean\n}\n\n/**\n * Seed the on-disk + DB defaults users land on after finishing first-run setup:\n * a `default` group at `~/.bazilion/groups/default/` and a `default` profile\n * wired to the just-enabled model. Fresh agents spawned from the default\n * profile land in the default group unless another is specified.\n *\n * Idempotent: re-seeding reuses whichever pieces already exist, so it's safe\n * to call whenever the setup state changes.\n */\nexport function seedDefaults(db: BazilionDb, paths: Paths, input: SeedDefaultsInput): SeedResult {\n let group = groupRepo.get(db, DEFAULT_GROUP_ID, paths)\n let groupCreated = false\n if (!group) {\n group = registerGroup(db, { id: DEFAULT_GROUP_ID, name: 'Default' }, paths)\n groupCreated = true\n }\n\n let profile = profileRepo.get(db, DEFAULT_PROFILE_ID)\n let profileCreated = false\n if (!profile) {\n // skillsMode='all' so freshly-spawned default agents inherit every\n // installed skill — the friendlier first-run posture. Custom profiles\n // still default to 'selected' (createProfile's own default).\n profile = createProfile(db, paths, {\n id: DEFAULT_PROFILE_ID,\n name: 'Default',\n defaultModel: input.model,\n skillsMode: 'all',\n })\n profileCreated = true\n }\n\n return { profile, group, profileCreated, groupCreated }\n}\n\n/**\n * Safe to call from any endpoint that can change setup state (toggling a\n * provider, editing model lists). No-op when either setup isn't complete\n * (nothing to seed against yet) or the default profile already exists.\n * Returns the seed result only on the cold-start transition.\n */\nexport function ensureSetupSeeded(db: BazilionDb, paths: Paths): SeedResult | null {\n if (!isSetupComplete(db)) return null\n if (profileRepo.get(db, DEFAULT_PROFILE_ID)) return null\n const first = listAvailableModels(db)[0]\n if (!first) return null\n return seedDefaults(db, paths, { model: first.value })\n}\n","import { existsSync, readdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { Paths } from '../paths.ts'\n\nexport interface DiscoveredSkill {\n name: string\n dir: string\n skillFile: string\n}\n\n/**\n * Walk the bazilion skill library and return every directory that contains a\n * SKILL.md file. Pure filesystem read — does not parse the markdown.\n */\nexport function discoverSkills(paths: Paths): DiscoveredSkill[] {\n if (!existsSync(paths.skillsDir)) return []\n\n const entries = readdirSync(paths.skillsDir, { withFileTypes: true })\n const skills: DiscoveredSkill[] = []\n for (const entry of entries) {\n if (!entry.isDirectory()) continue\n const dir = join(paths.skillsDir, entry.name)\n const skillFile = join(dir, 'SKILL.md')\n if (!existsSync(skillFile)) continue\n skills.push({ name: entry.name, dir, skillFile })\n }\n return skills.sort((a, b) => a.name.localeCompare(b.name))\n}\n","import type { BazilionDb } from '../db/client.ts'\nimport * as agentRepo from '../repos/agents.ts'\n\nexport function unarchiveAgent(db: BazilionDb, id: string): void {\n const agent = agentRepo.get(db, id)\n if (!agent) throw new Error(`agent not found: ${id}`)\n if (agent.status !== 'archived') {\n throw new Error(`agent is not archived (status: ${agent.status})`)\n }\n agentRepo.unarchive(db, agent.id)\n}\n","import { DatabaseSync, type SQLInputValue } from 'node:sqlite'\n\nexport interface QueryStmt<RowType, ParamsType extends unknown[]> {\n get(...params: ParamsType): RowType | null\n all(...params: ParamsType): RowType[]\n run(...params: ParamsType): { changes: number; lastInsertRowid: number | bigint }\n}\n\nexport interface QueryableDatabase {\n query<RowType, ParamsType extends unknown[]>(sql: string): QueryStmt<RowType, ParamsType>\n run(sql: string, params?: unknown[]): { changes: number; lastInsertRowid: number | bigint }\n exec(sql: string): void\n transaction<T>(fn: () => T): () => T\n}\n\nexport interface BazilionDb {\n raw: QueryableDatabase\n close(): void\n}\n\nfunction wrap(rawDb: DatabaseSync): QueryableDatabase {\n const cache = new Map<string, ReturnType<DatabaseSync['prepare']>>()\n function getStmt(sql: string) {\n let s = cache.get(sql)\n if (!s) {\n s = rawDb.prepare(sql)\n cache.set(sql, s)\n }\n return s\n }\n\n return {\n query<R, P extends unknown[]>(sql: string): QueryStmt<R, P> {\n const stmt = getStmt(sql)\n return {\n get(...params: P): R | null {\n const result = stmt.get(...(params as SQLInputValue[]))\n return (result as R | undefined) ?? null\n },\n all(...params: P): R[] {\n return stmt.all(...(params as SQLInputValue[])) as R[]\n },\n run(...params: P) {\n return stmt.run(...(params as SQLInputValue[])) as {\n changes: number\n lastInsertRowid: number | bigint\n }\n },\n }\n },\n run(sql, params) {\n const stmt = getStmt(sql)\n return stmt.run(...((params ?? []) as SQLInputValue[])) as {\n changes: number\n lastInsertRowid: number | bigint\n }\n },\n exec(sql) {\n rawDb.exec(sql)\n },\n // node:sqlite has no callable `transaction` wrapper; use manual BEGIN/COMMIT/ROLLBACK.\n transaction<T>(fn: () => T): () => T {\n return () => {\n rawDb.exec('BEGIN')\n try {\n const result = fn()\n rawDb.exec('COMMIT')\n return result\n } catch (err) {\n rawDb.exec('ROLLBACK')\n throw err\n }\n }\n },\n }\n}\n\nfunction applyPragmas(rawDb: DatabaseSync, includeWal: boolean): void {\n if (includeWal) {\n try {\n rawDb.exec('PRAGMA journal_mode = WAL')\n } catch {\n // some sqlite builds reject WAL on :memory: — ignore\n }\n }\n rawDb.exec('PRAGMA foreign_keys = ON')\n}\n\nexport function openDb(path: string): BazilionDb {\n const raw = new DatabaseSync(path)\n applyPragmas(raw, true)\n return {\n raw: wrap(raw),\n close() {\n raw.close()\n },\n }\n}\n\nexport function openInMemoryDb(): BazilionDb {\n const raw = new DatabaseSync(':memory:')\n applyPragmas(raw, false)\n return {\n raw: wrap(raw),\n close() {\n raw.close()\n },\n }\n}\n\nexport function inTx<T>(db: BazilionDb, fn: () => T): T {\n return db.raw.transaction(fn)()\n}\n","import { readdirSync, readFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { BazilionDb } from './client.ts'\n\nconst migrationsDir = join(dirname(fileURLToPath(import.meta.url)), 'migrations')\n\nexport function runMigrations(db: BazilionDb): void {\n db.raw.exec(`\n CREATE TABLE IF NOT EXISTS schema_migrations (\n version TEXT PRIMARY KEY,\n applied_at INTEGER NOT NULL\n )\n `)\n\n const applied = new Set(\n db.raw\n .query<{ version: string }, []>('SELECT version FROM schema_migrations')\n .all()\n .map((r) => r.version),\n )\n\n const files = readdirSync(migrationsDir)\n .filter((f) => f.endsWith('.sql'))\n .sort()\n\n for (const file of files) {\n const version = file.replace(/\\.sql$/, '')\n if (applied.has(version)) continue\n\n const sql = readFileSync(join(migrationsDir, file), 'utf8')\n const tx = db.raw.transaction(() => {\n db.raw.exec(sql)\n db.raw.run('INSERT INTO schema_migrations (version, applied_at) VALUES (?, ?)', [\n version,\n Date.now(),\n ])\n })\n tx()\n }\n}\n","import type { BazilionDb } from '../db/client.ts'\nimport type { Paths } from '../paths.ts'\nimport * as agentRepo from '../repos/agents.ts'\nimport * as groupRepo from '../repos/groups.ts'\n\nexport function deleteGroup(db: BazilionDb, paths: Paths, id: string): void {\n const g = groupRepo.get(db, id, paths)\n if (!g) throw new Error(`group not found: ${id}`)\n\n // ON DELETE RESTRICT on agents.group_id enforces this at the SQL layer,\n // but we surface a friendlier error listing the blocking members.\n const members = agentRepo.list(db, { includeArchived: true }).filter((a) => a.groupId === id)\n if (members.length > 0) {\n const names = members.map((a) => `${a.name} (${a.id.slice(0, 8)})`).join(', ')\n throw new Error(\n `cannot delete group \"${id}\": ${members.length} agent(s) still belong to it: ${names}. Move or archive them first.`,\n )\n }\n\n groupRepo.remove(db, id)\n}\n","import { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nexport interface Paths {\n home: string\n db: string\n /**\n * Bootstrap auth file shared by the daemon and the CLI: `{token, remote?}`.\n * - `token` is the plaintext of the bootstrap web token. The daemon reads\n * it once at startup to derive the encryption key for the `secrets`\n * table (PBKDF2 over it) and to validate that it matches a row in\n * `web_tokens` (so a corrupted file fails loudly). The CLI reads it as\n * its loopback bearer.\n * - `remote` (set via `bazilion login`) is a CLI-only override pointing at\n * a remote daemon. The local daemon ignores this field.\n *\n * One file replaces the previous `config.json` + `secrets.enc` split:\n * encrypted secrets and plaintext config now live as DB rows.\n */\n authFile: string\n profilesDir: string\n agentsDir: string\n skillsDir: string\n groupsDir: string\n logsDir: string\n profileDir(id: string): string\n agentDir(id: string): string\n skillDir(name: string): string\n groupDir(slug: string): string\n}\n\nexport function resolvePaths(home?: string): Paths {\n const root = home ?? process.env.BAZILION_HOME ?? join(homedir(), '.bazilion')\n return {\n home: root,\n db: join(root, 'bazilion.db'),\n authFile: join(root, 'auth.json'),\n profilesDir: join(root, 'profiles'),\n agentsDir: join(root, 'agents'),\n skillsDir: join(root, 'skills'),\n groupsDir: join(root, 'groups'),\n logsDir: join(root, 'logs'),\n profileDir(id) {\n return join(root, 'profiles', id)\n },\n agentDir(id) {\n return join(root, 'agents', id)\n },\n skillDir(name) {\n return join(root, 'skills', name)\n },\n groupDir(slug) {\n return join(root, 'groups', slug)\n },\n }\n}\n","import { existsSync, rmSync } from 'node:fs'\nimport type { BazilionDb } from '../db/client.ts'\nimport * as agentRepo from '../repos/agents.ts'\nimport * as profileGroupRepo from '../repos/profileGroups.ts'\nimport * as profileRepo from '../repos/profiles.ts'\n\nexport function deleteProfile(db: BazilionDb, id: string): void {\n const profile = profileRepo.get(db, id)\n if (!profile) throw new Error(`profile not found: ${id}`)\n\n // Check for agents still using this profile\n const agents = agentRepo.list(db, { includeArchived: true }).filter((a) => a.profileId === id)\n if (agents.length > 0) {\n const names = agents.map((a) => `${a.name} (${a.id.slice(0, 8)})`).join(', ')\n throw new Error(\n `cannot delete profile \"${id}\": ${agents.length} agent(s) still reference it: ${names}. Delete or re-profile them first.`,\n )\n }\n\n // Check for profile groups (team templates) still referencing this profile —\n // the FK on profile_group_members.profile_id is RESTRICT, so a raw delete\n // would surface as an opaque SQLite constraint error.\n const refGroups = profileGroupRepo.findReferencingProfile(db, id)\n if (refGroups.length > 0) {\n const names = refGroups.map((g) => `${g.name} (${g.id})`).join(', ')\n throw new Error(\n `cannot delete profile \"${id}\": ${refGroups.length} profile group(s) still reference it: ${names}. Remove the member(s) first.`,\n )\n }\n\n // Remove from DB (CASCADE deletes profile_default_skills)\n profileRepo.remove(db, id)\n\n // Remove the profile directory from disk\n if (existsSync(profile.dir)) {\n rmSync(profile.dir, { recursive: true, force: true })\n }\n}\n","import type {\n ProfileGroup,\n ProfileGroupMember,\n ProfileGroupWithCount,\n ReasoningLevel,\n} from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\n\ninterface RawProfileGroup {\n id: string\n name: string\n user_md: string | null\n created_at: number\n updated_at: number\n}\n\ninterface RawProfileGroupWithCount extends RawProfileGroup {\n member_count: number\n}\n\ninterface RawProfileGroupMember {\n profile_group_id: string\n position: number\n profile_id: string\n agent_name: string\n model_override: string | null\n reasoning_level: string | null\n}\n\nfunction toProfileGroup(r: RawProfileGroup): ProfileGroup {\n return {\n id: r.id,\n name: r.name,\n userMd: r.user_md,\n createdAt: r.created_at,\n updatedAt: r.updated_at,\n }\n}\n\nfunction toMember(r: RawProfileGroupMember): ProfileGroupMember {\n return {\n profileGroupId: r.profile_group_id,\n position: r.position,\n profileId: r.profile_id,\n agentName: r.agent_name,\n modelOverride: r.model_override,\n reasoningLevel: r.reasoning_level as ReasoningLevel | null,\n }\n}\n\nexport function insert(\n db: BazilionDb,\n p: Omit<ProfileGroup, 'createdAt' | 'updatedAt'>,\n): ProfileGroup {\n const now = Date.now()\n db.raw.run(\n `INSERT INTO profile_groups (id, name, user_md, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?)`,\n [p.id, p.name, p.userMd, now, now],\n )\n return { ...p, createdAt: now, updatedAt: now }\n}\n\nexport function get(db: BazilionDb, id: string): ProfileGroup | null {\n const row = db.raw\n .query<RawProfileGroup, [string]>('SELECT * FROM profile_groups WHERE id = ?')\n .get(id)\n return row ? toProfileGroup(row) : null\n}\n\nexport function list(db: BazilionDb): ProfileGroupWithCount[] {\n return db.raw\n .query<RawProfileGroupWithCount, []>(\n `SELECT pg.*, COALESCE(m.cnt, 0) AS member_count\n FROM profile_groups pg\n LEFT JOIN (\n SELECT profile_group_id, COUNT(*) AS cnt\n FROM profile_group_members\n GROUP BY profile_group_id\n ) m ON m.profile_group_id = pg.id\n ORDER BY pg.created_at ASC`,\n )\n .all()\n .map((r) => ({ ...toProfileGroup(r), memberCount: r.member_count }))\n}\n\nexport interface UpdateProfileGroupPatch {\n name?: string\n /** Pass `null` to clear; omit to leave unchanged. */\n userMd?: string | null\n}\n\nexport function update(db: BazilionDb, id: string, patch: UpdateProfileGroupPatch): void {\n // Distinguish `undefined` (don't touch) from `null` (set NULL). Use\n // Object.hasOwn so an explicit `null` in the patch is honored.\n const sets: string[] = []\n const args: (string | number | null)[] = []\n if (Object.hasOwn(patch, 'name')) {\n sets.push('name = ?')\n args.push(patch.name as string)\n }\n if (Object.hasOwn(patch, 'userMd')) {\n sets.push('user_md = ?')\n args.push(patch.userMd ?? null)\n }\n if (sets.length === 0) return\n sets.push('updated_at = ?')\n args.push(Date.now())\n args.push(id)\n db.raw.run(`UPDATE profile_groups SET ${sets.join(', ')} WHERE id = ?`, args)\n}\n\nexport function remove(db: BazilionDb, id: string): void {\n db.raw.run('DELETE FROM profile_groups WHERE id = ?', [id])\n}\n\nexport function members(db: BazilionDb, profileGroupId: string): ProfileGroupMember[] {\n return db.raw\n .query<RawProfileGroupMember, [string]>(\n `SELECT * FROM profile_group_members\n WHERE profile_group_id = ?\n ORDER BY position ASC`,\n )\n .all(profileGroupId)\n .map(toMember)\n}\n\n/** Distinct profile groups that still reference the given profile id. */\nexport function findReferencingProfile(\n db: BazilionDb,\n profileId: string,\n): Array<{ id: string; name: string }> {\n return db.raw\n .query<{ id: string; name: string }, [string]>(\n `SELECT DISTINCT pg.id AS id, pg.name AS name\n FROM profile_groups pg\n JOIN profile_group_members m ON m.profile_group_id = pg.id\n WHERE m.profile_id = ?`,\n )\n .all(profileId)\n}\n\nexport type MemberInput = Omit<ProfileGroupMember, 'profileGroupId' | 'position'>\n\n/**\n * PUT-replace semantics: delete every existing member for this profile group,\n * then re-insert each item in `newMembers` with `position` = array index.\n * Wrapped in a transaction so a partial failure rolls back.\n *\n * Duplicate `agentName` values across members are accepted here — the spawn\n * op resolves collisions with `-2`, `-3`, ... suffixes at spawn time.\n */\nexport function replaceMembers(\n db: BazilionDb,\n profileGroupId: string,\n newMembers: MemberInput[],\n): void {\n const tx = db.raw.transaction(() => {\n db.raw.run('DELETE FROM profile_group_members WHERE profile_group_id = ?', [profileGroupId])\n const stmt = db.raw.query(\n `INSERT INTO profile_group_members\n (profile_group_id, position, profile_id, agent_name, model_override, reasoning_level)\n VALUES (?, ?, ?, ?, ?, ?)`,\n )\n for (let i = 0; i < newMembers.length; i++) {\n const m = newMembers[i]\n if (!m) continue\n stmt.run(\n profileGroupId,\n i,\n m.profileId,\n m.agentName,\n m.modelOverride ?? null,\n m.reasoningLevel ?? null,\n )\n }\n })\n tx()\n}\n","import { writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { Profile, SkillsMode } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\nimport type { Paths } from '../paths.ts'\nimport * as profileRepo from '../repos/profiles.ts'\n\nexport interface UpdateProfileInput {\n name?: string\n defaultModel?: string\n skillsMode?: SkillsMode\n defaultSkills?: string[]\n}\n\n/**\n * Update the mutable settings in profile.json + the DB row in lockstep.\n * Profile files (SOUL/IDENTITY/BOOTSTRAP) and the memory backend are NOT\n * touched — those have their own paths.\n */\nexport function updateProfile(\n db: BazilionDb,\n paths: Paths,\n id: string,\n input: UpdateProfileInput,\n): Profile {\n const existing = profileRepo.get(db, id)\n if (!existing) throw new Error(`profile not found: ${id}`)\n\n const nextSkillsMode: SkillsMode = input.skillsMode ?? existing.skillsMode\n\n const next = {\n name: input.name ?? existing.name,\n defaultModel: input.defaultModel ?? existing.defaultModel,\n skillsMode: nextSkillsMode,\n }\n profileRepo.update(db, id, next)\n\n if (input.defaultSkills !== undefined) {\n profileRepo.setDefaultSkills(db, id, input.defaultSkills)\n }\n\n const skills = profileRepo.getDefaultSkills(db, id)\n const profileJson = {\n name: next.name,\n defaultModel: next.defaultModel,\n skillsMode: next.skillsMode,\n defaultSkills: skills,\n }\n writeFileSync(\n join(paths.profileDir(id), 'profile.json'),\n `${JSON.stringify(profileJson, null, 2)}\\n`,\n )\n\n const updated = profileRepo.get(db, id)\n if (!updated) throw new Error(`profile vanished after update: ${id}`)\n return updated\n}\n","import { readdirSync, rmSync } from 'node:fs'\nimport type { ProfileGroupMember } from '@bazilion/api-types'\nimport { spawnAgent } from '../agent/spawn.ts'\nimport type { BazilionDb } from '../db/client.ts'\nimport { inTx } from '../db/client.ts'\nimport { registerGroup } from '../group/register.ts'\nimport type { Paths } from '../paths.ts'\nimport { DEFAULT_GROUP_ID } from '../profile/seed.ts'\nimport * as groupRepo from '../repos/groups.ts'\nimport * as profileGroupRepo from '../repos/profileGroups.ts'\nimport * as profileRepo from '../repos/profiles.ts'\nimport { rmWithRetry } from './rm-with-retry.ts'\n\nexport interface SpawnProfileGroupInput {\n profileGroupId: string\n /** Target group slug. Falls back to the default group when omitted. */\n groupSlug?: string\n /** Override the template's `userMd` for this spawn only. */\n userMd?: string\n}\n\nexport interface SpawnProfileGroupResult {\n groupSlug: string\n /** Created agents in spawn order, with their final (post-suffix) names. */\n agents: { id: string; name: string }[]\n /** Empty on success; populated only by `SpawnProfileGroupError`. */\n orphanAgentIds: string[]\n}\n\n/**\n * Thrown when the spawn loop fails. The DB transaction is rolled back by\n * the time this is constructed; `orphanAgentIds` lists any agent dirs the\n * cleanup retry helper couldn't remove (typically empty — populated when\n * the filesystem rejects the rmSync after all three retries).\n */\nexport class SpawnProfileGroupError extends Error {\n override name = 'SpawnProfileGroupError'\n orphanAgentIds: string[]\n override cause: unknown\n constructor(message: string, orphanAgentIds: string[], cause: unknown) {\n super(message)\n this.orphanAgentIds = orphanAgentIds\n this.cause = cause\n }\n}\n\n/**\n * Walk members in `position` order, resolving each `agentName` to a unique\n * final name by appending `-2`, `-3`, ... when taken. The `existing` set\n * starts with whatever agents already live in the target group; resolved\n * names are added back into it so two members that share an `agentName`\n * collide with each other as well as with pre-existing agents.\n *\n * Pure function — exported so the spawn integration test can target the\n * algorithm directly without orchestrating a full spawn.\n */\nexport function resolveMemberNames(\n existing: ReadonlySet<string>,\n members: ProfileGroupMember[],\n): string[] {\n const taken = new Set(existing)\n const out: string[] = []\n for (const m of members) {\n let candidate = m.agentName\n let n = 2\n while (taken.has(candidate)) {\n candidate = `${m.agentName}-${n}`\n n++\n }\n taken.add(candidate)\n out.push(candidate)\n }\n return out\n}\n\nexport async function spawnProfileGroup(\n db: BazilionDb,\n paths: Paths,\n input: SpawnProfileGroupInput,\n): Promise<SpawnProfileGroupResult> {\n const template = profileGroupRepo.get(db, input.profileGroupId)\n if (!template) {\n throw new Error(`profile group not found: ${input.profileGroupId}`)\n }\n const members = profileGroupRepo.members(db, input.profileGroupId)\n\n // Pre-flight: every referenced profile must still exist. Bail before any\n // side effect rather than discovering it mid-loop.\n const missing: string[] = []\n for (const m of members) {\n if (!profileRepo.get(db, m.profileId)) missing.push(m.profileId)\n }\n if (missing.length > 0) {\n throw new Error(`profile group spawn: missing profiles: ${missing.join(', ')}`)\n }\n\n const targetSlug = input.groupSlug ?? DEFAULT_GROUP_ID\n const targetGroupExists = !!groupRepo.get(db, targetSlug, paths)\n const existingNames = new Set<string>(\n targetGroupExists\n ? db.raw\n .query<{ name: string }, [string]>('SELECT name FROM agents WHERE group_id = ?')\n .all(targetSlug)\n .map((r) => r.name)\n : [],\n )\n const resolvedNames = resolveMemberNames(existingNames, members)\n\n // Snapshot dir contents so the rollback path can identify fs orphans by\n // diff regardless of whether spawnAgent crashed before or after its DB\n // insert. The agents-dir scan catches the rare mkdir-then-fail window;\n // the groups-dir scan catches a registerGroup that wrote the dir before\n // failing on the INSERT.\n const beforeAgentDirs = new Set(safeReaddir(paths.agentsDir))\n const beforeGroupDirs = new Set(safeReaddir(paths.groupsDir))\n\n let groupCreated = false\n const created: { id: string; name: string }[] = []\n try {\n inTx(db, () => {\n if (!targetGroupExists) {\n registerGroup(db, { id: targetSlug, name: targetSlug }, paths)\n groupCreated = true\n }\n // Decision #5 (BAZ-002): the existing groups table stores user_md as\n // NOT NULL DEFAULT '', so a pre-existing group's empty user_md is\n // operator-mediated (initial value or explicit clear). Seed only into\n // a group we just created in this same spawn — never overwrite an\n // existing row.\n const seedUserMd = input.userMd ?? template.userMd ?? null\n if (groupCreated && seedUserMd) {\n groupRepo.setUserMd(db, targetSlug, seedUserMd)\n }\n for (let i = 0; i < members.length; i++) {\n const member = members[i]\n const name = resolvedNames[i]\n if (!member || !name) continue\n const agent = spawnAgent(db, paths, {\n profileId: member.profileId,\n name,\n modelOverride: member.modelOverride,\n reasoningLevel: member.reasoningLevel ?? 'medium',\n groupId: targetSlug,\n })\n created.push({ id: agent.id, name: agent.name })\n }\n })\n return { groupSlug: targetSlug, agents: created, orphanAgentIds: [] }\n } catch (err) {\n const newAgentDirs = safeReaddir(paths.agentsDir).filter((d) => !beforeAgentDirs.has(d))\n const orphans: string[] = []\n for (const dir of newAgentDirs) {\n if (!(await rmWithRetry(paths.agentDir(dir)))) {\n orphans.push(dir)\n }\n }\n const newGroupDirs = safeReaddir(paths.groupsDir).filter((d) => !beforeGroupDirs.has(d))\n for (const slug of newGroupDirs) {\n try {\n rmSync(paths.groupDir(slug), { recursive: true, force: true })\n } catch (cleanupErr) {\n console.error(`spawnProfileGroup: failed to clean up group dir ${slug}`, cleanupErr)\n }\n }\n for (const id of orphans) {\n console.error(`spawnProfileGroup: orphan agent dir left on disk: ${paths.agentDir(id)}`)\n }\n const original = err instanceof Error ? err.message : String(err)\n const message =\n orphans.length > 0 ? `${original} (orphan agent dirs: ${orphans.join(', ')})` : original\n throw new SpawnProfileGroupError(message, orphans, err)\n }\n}\n\nfunction safeReaddir(dir: string): string[] {\n try {\n return readdirSync(dir)\n } catch {\n return []\n }\n}\n","import { rmSync } from 'node:fs'\n\nexport const DEFAULT_RM_RETRY_DELAYS_MS = [100, 500, 2000] as const\n\nexport interface RmRetryOptions {\n /** Injectable rm fn for tests. Defaults to `rmSync(target, { recursive, force })`. */\n rm?: (target: string) => void\n /** Backoff between attempts. Defaults to [100, 500, 2000]. */\n delays?: readonly number[]\n /** Injectable sleep for tests. Defaults to `setTimeout`-backed promise. */\n sleep?: (ms: number) => Promise<void>\n}\n\n/**\n * Retry filesystem removal with backoff. Returns true if the target is\n * gone after some attempt, false if every attempt failed. Used during\n * profile-group spawn rollback to clean up agent dirs created by\n * successful `spawnAgent` calls before the failing slot.\n *\n * The default rm is `rmSync(target, { recursive: true, force: true })` —\n * `force: true` swallows ENOENT, so a missing target counts as success.\n */\nexport async function rmWithRetry(target: string, opts: RmRetryOptions = {}): Promise<boolean> {\n const rm = opts.rm ?? ((p: string) => rmSync(p, { recursive: true, force: true }))\n const delays = opts.delays ?? DEFAULT_RM_RETRY_DELAYS_MS\n const sleep = opts.sleep ?? ((ms: number) => new Promise<void>((r) => setTimeout(r, ms)))\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n try {\n rm(target)\n return true\n } catch {\n if (attempt === delays.length) return false\n const delay = delays[attempt] ?? 0\n await sleep(delay)\n }\n }\n return false\n}\n","// Per-service field registry — the shape of the /config page.\n//\n// Each entry describes one \"thing\" the user might configure: an LLM provider\n// (Anthropic, LM Studio, …) or an ancillary service (Brave Search, SearXNG).\n// Fields know which storage backend they live in: `secret` → the encrypted\n// `secrets` table, `config` → the plaintext `config` table. The registry is\n// the single source of truth for the UI layout and for the generic\n// field-write endpoint's dispatch.\n//\n// When adding a new provider or service, append an entry here and the\n// config page + CLI pick it up automatically.\n\nexport type FieldKind = 'secret' | 'config'\n\nexport interface ServiceField {\n /** Env var name — canonical key in both stores. */\n envVar: string\n kind: FieldKind\n label: string\n placeholder?: string\n description?: string\n}\n\nexport type ServiceCategory = 'provider' | 'service'\n\nexport interface ServiceDef {\n /** Matches the provider-registry key for providers (e.g. 'anthropic'). */\n id: string\n displayName: string\n category: ServiceCategory\n /** Display grouping label shown above the card on the /config tabs. */\n group?: string\n /** Sign-up link, docs, or 1-line description shown on the card. */\n hint?: string\n fields: ServiceField[]\n}\n\n/**\n * One-liner: what's shown on each service card.\n * Order here is the display order on the config page.\n */\nexport const SERVICES: ServiceDef[] = [\n // --- LLM providers (configured via API keys / URLs) ---\n // Top 3: openai-codex (ChatGPT OAuth), openai (API key), anthropic.\n // Everything else in rough popularity order; locals last.\n {\n id: 'openai-codex',\n displayName: 'OpenAI ChatGPT (OAuth)',\n category: 'provider',\n hint: 'Use your ChatGPT Plus/Pro/Team account (same login as Codex CLI)',\n // No form fields — credentials come from an OAuth flow. The /config page\n // renders a Connect/Disconnect card using /api/auth/openai instead of the\n // standard field inputs.\n fields: [],\n },\n {\n id: 'openai',\n displayName: 'OpenAI',\n category: 'provider',\n hint: 'GPT models · platform.openai.com',\n fields: [{ envVar: 'OPENAI_API_KEY', kind: 'secret', label: 'API key', placeholder: 'sk-...' }],\n },\n {\n id: 'anthropic',\n displayName: 'Anthropic',\n category: 'provider',\n hint: 'Claude models · console.anthropic.com',\n fields: [\n { envVar: 'ANTHROPIC_API_KEY', kind: 'secret', label: 'API key', placeholder: 'sk-ant-...' },\n {\n envVar: 'ANTHROPIC_OAUTH_TOKEN',\n kind: 'secret',\n label: 'OAuth token (alternative to API key)',\n description: 'Takes precedence over ANTHROPIC_API_KEY when set',\n },\n ],\n },\n {\n id: 'google',\n displayName: 'Google (Gemini)',\n category: 'provider',\n hint: 'Gemini models · ai.google.dev (free tier available)',\n fields: [\n { envVar: 'GEMINI_API_KEY', kind: 'secret', label: 'API key', placeholder: 'AIza...' },\n ],\n },\n {\n id: 'google-vertex',\n displayName: 'Google Vertex AI',\n category: 'provider',\n hint: 'Authenticates via `gcloud auth application-default login`',\n fields: [\n {\n envVar: 'GOOGLE_CLOUD_PROJECT',\n kind: 'config',\n label: 'GCP project ID',\n placeholder: 'my-project-123456',\n },\n {\n envVar: 'GOOGLE_CLOUD_LOCATION',\n kind: 'config',\n label: 'GCP region',\n placeholder: 'us-central1',\n },\n ],\n },\n {\n id: 'azure-openai',\n displayName: 'Azure OpenAI',\n category: 'provider',\n fields: [{ envVar: 'AZURE_OPENAI_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'bedrock',\n displayName: 'Amazon Bedrock',\n category: 'provider',\n hint: 'Authenticates via AWS SDK env (AWS_PROFILE or AWS_ACCESS_KEY_ID/SECRET)',\n fields: [],\n },\n {\n id: 'github-copilot',\n displayName: 'GitHub Copilot',\n category: 'provider',\n hint: 'Use a GitHub Copilot subscription to call Claude/GPT/Gemini via Copilot',\n fields: [\n {\n envVar: 'COPILOT_GITHUB_TOKEN',\n kind: 'secret',\n label: 'GitHub token',\n description:\n 'Generic GH_TOKEN/GITHUB_TOKEN are ignored — set this scoped variable explicitly (or run `bazilion auth copilot login` once available).',\n },\n ],\n },\n {\n id: 'deepseek',\n displayName: 'DeepSeek',\n category: 'provider',\n hint: 'DeepSeek V4 Flash / Pro · platform.deepseek.com',\n fields: [{ envVar: 'DEEPSEEK_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'mistral',\n displayName: 'Mistral',\n category: 'provider',\n hint: 'mistral.ai',\n fields: [{ envVar: 'MISTRAL_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'xai',\n displayName: 'xAI',\n category: 'provider',\n hint: 'Grok · x.ai',\n fields: [{ envVar: 'XAI_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'groq',\n displayName: 'Groq',\n category: 'provider',\n hint: 'Fast inference · groq.com',\n fields: [{ envVar: 'GROQ_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'cerebras',\n displayName: 'Cerebras',\n category: 'provider',\n fields: [{ envVar: 'CEREBRAS_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'fireworks',\n displayName: 'Fireworks AI',\n category: 'provider',\n hint: 'DeepSeek/GLM/Kimi via fireworks.ai',\n fields: [{ envVar: 'FIREWORKS_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'together',\n displayName: 'Together AI',\n category: 'provider',\n hint: 'Open-weight models · together.ai',\n fields: [{ envVar: 'TOGETHER_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'moonshotai',\n displayName: 'Moonshot AI',\n category: 'provider',\n hint: 'Kimi K2/K2.5/K2.6 · platform.moonshot.ai',\n fields: [{ envVar: 'MOONSHOT_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'kimi-coding',\n displayName: 'Kimi Coding',\n category: 'provider',\n hint: 'Coding-tuned Kimi endpoint · platform.moonshot.cn',\n fields: [{ envVar: 'KIMI_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'minimax',\n displayName: 'MiniMax',\n category: 'provider',\n hint: 'MiniMax M2 family · platform.minimaxi.com',\n fields: [{ envVar: 'MINIMAX_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'xiaomi',\n displayName: 'Xiaomi MiMo',\n category: 'provider',\n hint: 'API billing endpoint · platform.xiaomimimo.com',\n fields: [{ envVar: 'XIAOMI_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'zai',\n displayName: 'zAI',\n category: 'provider',\n fields: [{ envVar: 'ZAI_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'huggingface',\n displayName: 'Hugging Face',\n category: 'provider',\n hint: 'Inference endpoints · huggingface.co',\n fields: [{ envVar: 'HF_TOKEN', kind: 'secret', label: 'Access token', placeholder: 'hf_...' }],\n },\n {\n id: 'cloudflare-ai-gateway',\n displayName: 'Cloudflare AI Gateway',\n category: 'provider',\n hint: 'Per-gateway routing to OpenAI/Anthropic/Workers AI',\n fields: [\n { envVar: 'CLOUDFLARE_API_KEY', kind: 'secret', label: 'API key' },\n { envVar: 'CLOUDFLARE_ACCOUNT_ID', kind: 'config', label: 'Account ID' },\n { envVar: 'CLOUDFLARE_GATEWAY_ID', kind: 'config', label: 'Gateway ID' },\n ],\n },\n {\n id: 'cloudflare-workers-ai',\n displayName: 'Cloudflare Workers AI',\n category: 'provider',\n hint: 'Inference on Cloudflare Workers · ai.cloudflare.com',\n fields: [\n { envVar: 'CLOUDFLARE_API_KEY', kind: 'secret', label: 'API key' },\n { envVar: 'CLOUDFLARE_ACCOUNT_ID', kind: 'config', label: 'Account ID' },\n ],\n },\n {\n id: 'openrouter',\n displayName: 'OpenRouter',\n category: 'provider',\n hint: 'Proxy for 200+ models · openrouter.ai',\n fields: [\n { envVar: 'OPENROUTER_API_KEY', kind: 'secret', label: 'API key', placeholder: 'sk-or-...' },\n ],\n },\n {\n id: 'vercel-ai-gateway',\n displayName: 'Vercel AI Gateway',\n category: 'provider',\n fields: [\n { envVar: 'AI_GATEWAY_API_KEY', kind: 'secret', label: 'API key' },\n {\n envVar: 'AI_GATEWAY_BASE_URL',\n kind: 'config',\n label: 'Base URL (optional)',\n placeholder: 'https://ai-gateway.vercel.sh/v1',\n },\n ],\n },\n {\n id: 'opencode',\n displayName: 'OpenCode',\n category: 'provider',\n hint: 'OpenAI-compatible proxy from the OpenCode CLI',\n fields: [{ envVar: 'OPENCODE_API_KEY', kind: 'secret', label: 'API key' }],\n },\n {\n id: 'lmstudio',\n displayName: 'LM Studio',\n category: 'provider',\n hint: 'Local inference · lmstudio.ai',\n fields: [\n {\n envVar: 'LMSTUDIO_URL',\n kind: 'config',\n label: 'Endpoint URL',\n placeholder: 'http://127.0.0.1:1234/v1',\n },\n {\n envVar: 'LMSTUDIO_API_KEY',\n kind: 'secret',\n label: 'API key (rarely needed)',\n },\n ],\n },\n {\n id: 'ollama',\n displayName: 'Ollama',\n category: 'provider',\n hint: 'Local inference · ollama.com',\n fields: [\n {\n envVar: 'OLLAMA_URL',\n kind: 'config',\n label: 'Endpoint URL',\n placeholder: 'http://127.0.0.1:11434/v1',\n },\n {\n envVar: 'OLLAMA_API_KEY',\n kind: 'secret',\n label: 'API key (rarely needed)',\n },\n ],\n },\n {\n id: 'llamacpp',\n displayName: 'llama.cpp',\n category: 'provider',\n hint: 'Local inference · llama.cpp llama-server (OpenAI-compat /v1 endpoint)',\n fields: [\n {\n envVar: 'LLAMACPP_URL',\n kind: 'config',\n label: 'Endpoint URL',\n placeholder: 'http://127.0.0.1:8080/v1',\n },\n {\n envVar: 'LLAMACPP_API_KEY',\n kind: 'secret',\n label: 'API key (only if started with --api-key)',\n description:\n 'llama-server runs without auth by default. Set this only if you launched the server with the `--api-key KEY` flag.',\n },\n ],\n },\n\n // --- Ancillary services (web search, etc) ---\n {\n id: 'firecrawl',\n displayName: 'Firecrawl',\n category: 'service',\n group: 'Web Search',\n hint: 'web_fetch fallback for JS-heavy/blocked pages · firecrawl.dev (free tier available)',\n fields: [\n {\n envVar: 'FIRECRAWL_API_KEY',\n kind: 'secret',\n label: 'API key',\n placeholder: 'fc-...',\n description:\n 'When set, web_fetch automatically falls back to Firecrawl if the primary Readability extraction yields too little content.',\n },\n {\n envVar: 'FIRECRAWL_URL',\n kind: 'config',\n label: 'Base URL (optional, for self-hosted)',\n placeholder: 'https://api.firecrawl.dev',\n },\n ],\n },\n {\n id: 'brave-search',\n displayName: 'Brave Search',\n category: 'service',\n group: 'Web Search',\n hint: 'Web search tool · free tier at brave.com/search/api/',\n fields: [{ envVar: 'BRAVE_API_KEY', kind: 'secret', label: 'API key', placeholder: 'BSA...' }],\n },\n {\n id: 'searxng',\n displayName: 'SearXNG',\n category: 'service',\n group: 'Web Search',\n hint: 'Self-hosted meta-search engine · searxng.org',\n fields: [\n {\n envVar: 'SEARXNG_URL',\n kind: 'config',\n label: 'Instance URL',\n placeholder: 'https://searxng.example.com',\n },\n ],\n },\n]\n\n/**\n * Fast lookup: envVar → the field definition + owning service.\n * Rebuilt once at module init — the list is static.\n */\nconst FIELD_INDEX: Map<string, { service: ServiceDef; field: ServiceField }> = (() => {\n const m = new Map<string, { service: ServiceDef; field: ServiceField }>()\n for (const service of SERVICES) {\n for (const field of service.fields) {\n m.set(field.envVar, { service, field })\n }\n }\n return m\n})()\n\nexport function findFieldByEnvVar(\n envVar: string,\n): { service: ServiceDef; field: ServiceField } | undefined {\n return FIELD_INDEX.get(envVar)\n}\n\nexport function servicesByCategory(category: ServiceCategory): ServiceDef[] {\n return SERVICES.filter((s) => s.category === category)\n}\n","// Plaintext config store, backed by the `config` table.\n//\n// Companion to `secrets.ts` — same key-shaped values, but for the ones that\n// don't need confidentiality (server URLs, region slugs, project IDs). Kept\n// separate so the /config UI can show plaintext values directly without\n// extra masking logic.\n//\n// The CONFIG_KEYS allowlist (derived from the services registry) is enforced\n// here on writes — a typo or accidental misclassification can't put an API\n// key in this table.\n\nimport type { BazilionDb } from '../db/client.ts'\nimport { SERVICES } from '../services.ts'\n\n/**\n * Env var names that live in the plaintext config store. Derived from the\n * services registry — any field marked `kind: 'config'` ends up here.\n */\nexport const CONFIG_KEYS: readonly string[] = SERVICES.flatMap((s) =>\n s.fields.filter((f) => f.kind === 'config').map((f) => f.envVar),\n)\n\nconst CONFIG_KEY_SET = new Set<string>(CONFIG_KEYS)\n\nexport function isConfigKey(key: string): boolean {\n return CONFIG_KEY_SET.has(key)\n}\n\ninterface RawRow {\n key: string\n value: string\n updated_at: number\n}\n\nexport interface ConfigStore {\n get(key: string): string | undefined\n set(key: string, value: string): void\n remove(key: string): void\n list(): { key: string; value: string }[]\n getAll(): Record<string, string>\n}\n\nexport function openConfig(db: BazilionDb): ConfigStore {\n return {\n get(key) {\n const row = db.raw.query<RawRow, [string]>('SELECT * FROM config WHERE key = ?').get(key)\n return row?.value\n },\n set(key, value) {\n if (!isConfigKey(key)) {\n throw new Error(\n `config.set: \"${key}\" is not a known config key (${CONFIG_KEYS.join(', ')})`,\n )\n }\n db.raw.run(\n `INSERT INTO config (key, value, updated_at) VALUES (?, ?, ?)\n ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`,\n [key, value, Date.now()],\n )\n },\n remove(key) {\n db.raw.run('DELETE FROM config WHERE key = ?', [key])\n },\n list() {\n return db.raw\n .query<RawRow, []>('SELECT * FROM config ORDER BY key ASC')\n .all()\n .map((r) => ({ key: r.key, value: r.value }))\n },\n getAll() {\n const out: Record<string, string> = {}\n for (const r of db.raw.query<RawRow, []>('SELECT * FROM config').all()) {\n out[r.key] = r.value\n }\n return out\n },\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport type { Message } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\n\ninterface RawMessage {\n id: string\n from_agent_id: string\n to_agent_id: string\n reply_to: string | null\n payload: string\n created_at: number\n read_at: number | null\n}\n\nfunction toMessage(r: RawMessage): Message {\n return {\n id: r.id,\n fromAgentId: r.from_agent_id,\n toAgentId: r.to_agent_id,\n replyTo: r.reply_to,\n payload: r.payload,\n createdAt: r.created_at,\n readAt: r.read_at,\n }\n}\n\nexport function send(\n db: BazilionDb,\n input: { from: string; to: string; payload: string; replyTo?: string | null },\n): Message {\n const id = randomUUID()\n const now = Date.now()\n db.raw.run(\n `INSERT INTO messages (id, from_agent_id, to_agent_id, reply_to, payload, created_at, read_at)\n VALUES (?, ?, ?, ?, ?, ?, NULL)`,\n [id, input.from, input.to, input.replyTo ?? null, input.payload, now],\n )\n return {\n id,\n fromAgentId: input.from,\n toAgentId: input.to,\n replyTo: input.replyTo ?? null,\n payload: input.payload,\n createdAt: now,\n readAt: null,\n }\n}\n\nexport function get(db: BazilionDb, id: string): Message | null {\n const row = db.raw.query<RawMessage, [string]>('SELECT * FROM messages WHERE id = ?').get(id)\n return row ? toMessage(row) : null\n}\n\nexport function listInbox(\n db: BazilionDb,\n agentId: string,\n opts?: { unreadOnly?: boolean },\n): Message[] {\n const sql = opts?.unreadOnly\n ? 'SELECT * FROM messages WHERE to_agent_id = ? AND read_at IS NULL ORDER BY created_at ASC'\n : 'SELECT * FROM messages WHERE to_agent_id = ? ORDER BY created_at ASC'\n return db.raw.query<RawMessage, [string]>(sql).all(agentId).map(toMessage)\n}\n\nexport function markRead(db: BazilionDb, id: string): void {\n db.raw.run('UPDATE messages SET read_at = ? WHERE id = ? AND read_at IS NULL', [Date.now(), id])\n}\n\n/**\n * Find messages that are replies to a given message id, addressed to a specific agent.\n * Used by `wait_for_reply` to poll for incoming responses.\n */\nexport function findReplies(db: BazilionDb, toAgentId: string, inReplyTo: string): Message[] {\n return db.raw\n .query<RawMessage, [string, string]>(\n `SELECT * FROM messages\n WHERE to_agent_id = ? AND reply_to = ?\n ORDER BY created_at ASC`,\n )\n .all(toAgentId, inReplyTo)\n .map(toMessage)\n}\n\n/**\n * Return the distinct `to_agent_id`s that currently have at least one unread\n * message, filtered to agents not in a terminal state (idle or starting).\n * Used by the scheduler's message-wake loop so a tick can fan-out auto-\n * delivery turns without walking every agent in the DB.\n */\nexport function listRecipientsWithUnread(db: BazilionDb): string[] {\n const rows = db.raw\n .query<{ to_agent_id: string }, []>(\n `SELECT DISTINCT m.to_agent_id FROM messages m\n JOIN agents a ON a.id = m.to_agent_id\n WHERE m.read_at IS NULL AND a.status = 'idle'\n ORDER BY m.to_agent_id`,\n )\n .all()\n return rows.map((r) => r.to_agent_id)\n}\n\n/**\n * Atomically fetch + mark-read all unread messages addressed to `agentId`.\n * Runs inside a transaction so two concurrent schedulers / manual deliveries\n * can't double-dispatch the same message. Returns the fetched messages in\n * ascending `created_at` order — callers format them into the recipient's\n * wake-up prompt.\n */\nexport function drainUnreadForAgent(db: BazilionDb, agentId: string): Message[] {\n return db.raw.transaction(() => {\n const rows = db.raw\n .query<RawMessage, [string]>(\n `SELECT * FROM messages\n WHERE to_agent_id = ? AND read_at IS NULL\n ORDER BY created_at ASC`,\n )\n .all(agentId)\n if (rows.length === 0) return []\n const now = Date.now()\n db.raw.run(\n `UPDATE messages SET read_at = ?\n WHERE to_agent_id = ? AND read_at IS NULL`,\n [now, agentId],\n )\n return rows.map((r) => toMessage({ ...r, read_at: now }))\n })()\n}\n","// Encrypted secrets store, backed by the `secrets` table.\n//\n// Layout: one row per env-var-shaped key (`ANTHROPIC_API_KEY`,\n// `OPENAI_CODEX_OAUTH`, …). Each value is an AES-256-GCM envelope (salt +\n// iv + tag + data, hex-encoded JSON), with the key derived from the\n// bootstrap token via PBKDF2-SHA256 (100k iterations). The crypto matches\n// the previous `secrets.enc` file format byte-for-byte — only the storage\n// medium changed.\n//\n// Why encrypt at all when the password lives in `~/.bazilion/auth.json`\n// next to the DB? Same reason as before: it's defense against accidental\n// exposure (cat'd dumps, screenshares, naive backups), not against an\n// attacker with filesystem read. Anyone who can read both files wins.\n//\n// Caching: `deriveKey` runs PBKDF2 once per (password, salt) pair and the\n// salt is per-row, so a busy daemon does ~one PBKDF2 per secret read. The\n// `secretCache` keeps decrypted values in-memory keyed by row id so repeated\n// reads inside one process don't repeat the work; mutations clear the cache\n// row.\n\nimport { createCipheriv, createDecipheriv, pbkdf2Sync, randomBytes } from 'node:crypto'\nimport type { BazilionDb } from '../db/client.ts'\n\nconst ALGORITHM = 'aes-256-gcm'\nconst KEY_LEN = 32\nconst ITERATIONS = 100_000\nconst DIGEST = 'sha256'\n\ninterface EncryptedEnvelope {\n salt: string\n iv: string\n tag: string\n data: string\n}\n\nfunction deriveKey(password: string, salt: Buffer): Buffer {\n return pbkdf2Sync(password, salt, ITERATIONS, KEY_LEN, DIGEST)\n}\n\nfunction encrypt(plaintext: string, password: string): EncryptedEnvelope {\n const salt = randomBytes(16)\n const key = deriveKey(password, salt)\n const iv = randomBytes(12)\n const cipher = createCipheriv(ALGORITHM, key, iv)\n let data = cipher.update(plaintext, 'utf8', 'hex')\n data += cipher.final('hex')\n const tag = cipher.getAuthTag()\n return {\n salt: salt.toString('hex'),\n iv: iv.toString('hex'),\n tag: tag.toString('hex'),\n data,\n }\n}\n\nfunction decrypt(envelope: EncryptedEnvelope, password: string): string {\n const salt = Buffer.from(envelope.salt, 'hex')\n const key = deriveKey(password, salt)\n const iv = Buffer.from(envelope.iv, 'hex')\n const tag = Buffer.from(envelope.tag, 'hex')\n const decipher = createDecipheriv(ALGORITHM, key, iv)\n decipher.setAuthTag(tag)\n let plaintext = decipher.update(envelope.data, 'hex', 'utf8')\n plaintext += decipher.final('utf8')\n return plaintext\n}\n\ninterface RawRow {\n key: string\n envelope: string\n updated_at: number\n}\n\nexport interface SecretsStore {\n get(key: string): string | undefined\n set(key: string, value: string): void\n remove(key: string): void\n has(key: string): boolean\n list(): { key: string; preview: string }[]\n getAll(): Record<string, string>\n}\n\n/**\n * Open the encrypted secrets store. `password` is the bootstrap token\n * (read from `auth.json` by the caller). Throws on individual-row decrypt\n * failures only when actively reading that row — bad rows show as\n * `undefined` from `get`, the caller can `set` to overwrite.\n */\nexport function openSecrets(db: BazilionDb, password: string): SecretsStore {\n function getRow(key: string): RawRow | null {\n return db.raw.query<RawRow, [string]>('SELECT * FROM secrets WHERE key = ?').get(key)\n }\n\n function listAll(): RawRow[] {\n return db.raw.query<RawRow, []>('SELECT * FROM secrets ORDER BY key ASC').all()\n }\n\n function tryDecrypt(row: RawRow): string | undefined {\n try {\n const envelope = JSON.parse(row.envelope) as EncryptedEnvelope\n return decrypt(envelope, password)\n } catch {\n return undefined\n }\n }\n\n return {\n get(key) {\n const row = getRow(key)\n if (!row) return undefined\n return tryDecrypt(row)\n },\n set(key, value) {\n const envelope = JSON.stringify(encrypt(value, password))\n db.raw.run(\n `INSERT INTO secrets (key, envelope, updated_at) VALUES (?, ?, ?)\n ON CONFLICT(key) DO UPDATE SET envelope = excluded.envelope, updated_at = excluded.updated_at`,\n [key, envelope, Date.now()],\n )\n },\n remove(key) {\n db.raw.run('DELETE FROM secrets WHERE key = ?', [key])\n },\n has(key) {\n return getRow(key) !== null\n },\n list() {\n return listAll().map((r) => {\n const value = tryDecrypt(r)\n return {\n key: r.key,\n preview: value ? (value.length > 8 ? `${value.slice(0, 6)}…` : '***') : '(unreadable)',\n }\n })\n },\n getAll() {\n const out: Record<string, string> = {}\n for (const r of listAll()) {\n const v = tryDecrypt(r)\n if (v !== undefined) out[r.key] = v\n }\n return out\n },\n }\n}\n","import type { SkillMeta } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\n\ninterface RawMeta {\n name: string\n source: string | null\n imported_at: number | null\n}\n\nfunction toMeta(r: RawMeta): SkillMeta {\n return {\n name: r.name,\n source: r.source,\n importedAt: r.imported_at,\n }\n}\n\nexport function get(db: BazilionDb, name: string): SkillMeta | null {\n const row = db.raw.query<RawMeta, [string]>('SELECT * FROM skill_meta WHERE name = ?').get(name)\n return row ? toMeta(row) : null\n}\n\nexport function listAll(db: BazilionDb): SkillMeta[] {\n return db.raw.query<RawMeta, []>('SELECT * FROM skill_meta ORDER BY name ASC').all().map(toMeta)\n}\n\nexport interface UpsertInput {\n name: string\n source?: string | null\n importedAt?: number | null\n}\n\nexport function upsert(db: BazilionDb, input: UpsertInput): SkillMeta {\n const existing = get(db, input.name)\n const source = input.source !== undefined ? input.source : (existing?.source ?? null)\n const importedAt =\n input.importedAt !== undefined ? input.importedAt : (existing?.importedAt ?? null)\n db.raw.run(\n `INSERT INTO skill_meta (name, source, imported_at)\n VALUES (?, ?, ?)\n ON CONFLICT(name) DO UPDATE SET source = excluded.source, imported_at = excluded.imported_at`,\n [input.name, source, importedAt],\n )\n return { name: input.name, source, importedAt }\n}\n\nexport function remove(db: BazilionDb, name: string): void {\n db.raw.run('DELETE FROM skill_meta WHERE name = ?', [name])\n}\n","import { randomUUID } from 'node:crypto'\nimport type { AgentTrigger, TriggerKind } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\n\ninterface RawTrigger {\n id: string\n agent_id: string\n kind: string\n interval_sec: number | null\n cron_expr: string | null\n message: string\n enabled: number\n last_fired_at: number | null\n created_at: number\n}\n\nfunction toTrigger(r: RawTrigger): AgentTrigger {\n return {\n id: r.id,\n agentId: r.agent_id,\n kind: r.kind as TriggerKind,\n intervalSec: r.interval_sec,\n cronExpr: r.cron_expr,\n message: r.message,\n enabled: r.enabled === 1,\n lastFiredAt: r.last_fired_at,\n createdAt: r.created_at,\n }\n}\n\nexport interface InsertTriggerInput {\n agentId: string\n kind: TriggerKind\n intervalSec: number | null\n cronExpr: string | null\n message: string\n enabled?: boolean\n}\n\nexport function insert(db: BazilionDb, input: InsertTriggerInput): AgentTrigger {\n const id = randomUUID()\n const now = Date.now()\n const enabled = input.enabled === false ? 0 : 1\n db.raw.run(\n `INSERT INTO agent_triggers\n (id, agent_id, kind, interval_sec, cron_expr, message, enabled, last_fired_at, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, NULL, ?)`,\n [id, input.agentId, input.kind, input.intervalSec, input.cronExpr, input.message, enabled, now],\n )\n return {\n id,\n agentId: input.agentId,\n kind: input.kind,\n intervalSec: input.intervalSec,\n cronExpr: input.cronExpr,\n message: input.message,\n enabled: enabled === 1,\n lastFiredAt: null,\n createdAt: now,\n }\n}\n\nexport function get(db: BazilionDb, id: string): AgentTrigger | null {\n const row = db.raw\n .query<RawTrigger, [string]>('SELECT * FROM agent_triggers WHERE id = ?')\n .get(id)\n return row ? toTrigger(row) : null\n}\n\nexport function listForAgent(db: BazilionDb, agentId: string): AgentTrigger[] {\n return db.raw\n .query<RawTrigger, [string]>(\n 'SELECT * FROM agent_triggers WHERE agent_id = ? ORDER BY created_at ASC',\n )\n .all(agentId)\n .map(toTrigger)\n}\n\nexport function listEnabled(db: BazilionDb): AgentTrigger[] {\n return db.raw\n .query<RawTrigger, []>(\n `SELECT t.* FROM agent_triggers t\n JOIN agents a ON a.id = t.agent_id\n WHERE t.enabled = 1 AND a.status != 'archived'\n ORDER BY t.created_at ASC`,\n )\n .all()\n .map(toTrigger)\n}\n\nexport function setEnabled(db: BazilionDb, id: string, enabled: boolean): void {\n db.raw.run('UPDATE agent_triggers SET enabled = ? WHERE id = ?', [enabled ? 1 : 0, id])\n}\n\nexport function markFired(db: BazilionDb, id: string, when: number = Date.now()): void {\n db.raw.run('UPDATE agent_triggers SET last_fired_at = ? WHERE id = ?', [when, id])\n}\n\nexport function remove(db: BazilionDb, id: string): void {\n db.raw.run('DELETE FROM agent_triggers WHERE id = ?', [id])\n}\n","import { createHash, randomBytes, randomUUID } from 'node:crypto'\nimport type { WebToken } from '@bazilion/api-types'\nimport type { BazilionDb } from '../db/client.ts'\n\ninterface RawToken {\n id: string\n label: string\n token_hash: string\n created_at: number\n last_used_at: number | null\n revoked_at: number | null\n}\n\nfunction toToken(r: RawToken): WebToken {\n return {\n id: r.id,\n label: r.label,\n createdAt: r.created_at,\n lastUsedAt: r.last_used_at,\n revokedAt: r.revoked_at,\n }\n}\n\nexport function hashToken(token: string): string {\n return createHash('sha256').update(token).digest('hex')\n}\n\nexport interface CreatedToken {\n meta: WebToken\n /** Plaintext token — shown exactly once, never re-queryable. */\n token: string\n}\n\nexport function create(db: BazilionDb, label: string): CreatedToken {\n const id = randomUUID()\n const token = randomBytes(24).toString('hex')\n const tokenHash = hashToken(token)\n const now = Date.now()\n db.raw.run(\n `INSERT INTO web_tokens (id, label, token_hash, created_at, last_used_at, revoked_at)\n VALUES (?, ?, ?, ?, NULL, NULL)`,\n [id, label, tokenHash, now],\n )\n return {\n token,\n meta: { id, label, createdAt: now, lastUsedAt: null, revokedAt: null },\n }\n}\n\nexport function list(db: BazilionDb, opts?: { includeRevoked?: boolean }): WebToken[] {\n const sql = opts?.includeRevoked\n ? 'SELECT * FROM web_tokens ORDER BY created_at ASC'\n : 'SELECT * FROM web_tokens WHERE revoked_at IS NULL ORDER BY created_at ASC'\n return db.raw.query<RawToken, []>(sql).all().map(toToken)\n}\n\nexport function get(db: BazilionDb, id: string): WebToken | null {\n const row = db.raw.query<RawToken, [string]>('SELECT * FROM web_tokens WHERE id = ?').get(id)\n return row ? toToken(row) : null\n}\n\n/**\n * Returns the active token row matching the given plaintext, or null.\n * Does NOT bump last_used_at — call markUsed separately once the caller\n * has decided the request is authorized.\n */\nexport function findActiveByToken(db: BazilionDb, token: string): WebToken | null {\n const tokenHash = hashToken(token)\n const row = db.raw\n .query<RawToken, [string]>(\n 'SELECT * FROM web_tokens WHERE token_hash = ? AND revoked_at IS NULL',\n )\n .get(tokenHash)\n return row ? toToken(row) : null\n}\n\nexport function markUsed(db: BazilionDb, id: string, when: number = Date.now()): void {\n db.raw.run('UPDATE web_tokens SET last_used_at = ? WHERE id = ?', [when, id])\n}\n\nexport function revoke(db: BazilionDb, id: string, when: number = Date.now()): boolean {\n const res = db.raw.run(\n 'UPDATE web_tokens SET revoked_at = ? WHERE id = ? AND revoked_at IS NULL',\n [when, id],\n )\n return res.changes > 0\n}\n","// Auth / secrets entry points keyed off the bootstrap `auth.json` file.\n//\n// `auth.json` carries one mandatory field — `token` — written by the daemon's\n// first-run bootstrap. The daemon uses it as the PBKDF2 seed for the `secrets`\n// table; the CLI uses it as the bearer for loopback HTTP. CLI-side `remote`\n// overrides (set by `bazilion login`) coexist in the same file.\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport type { BazilionDb } from './db/client.ts'\nimport { openConfig } from './repos/config.ts'\nimport { openSecrets } from './repos/secrets.ts'\n\nexport interface AuthFile {\n token: string\n remote?: { server: string; token: string } | null\n}\n\n/**\n * Read `auth.json` and return the parsed contents. Throws when missing or\n * malformed — callers should treat that as \"bazilion not initialized.\"\n */\nexport function readAuthFile(authFile: string): AuthFile {\n if (!existsSync(authFile)) {\n throw new Error(\n `${authFile} not found. Start the daemon (\\`bazilion serve\\`) — it auto-bootstraps on first run.`,\n )\n }\n const raw = readFileSync(authFile, 'utf8')\n const parsed = JSON.parse(raw) as Partial<AuthFile>\n if (typeof parsed.token !== 'string' || !parsed.token) {\n throw new Error(`${authFile} is missing the \"token\" field`)\n }\n return {\n token: parsed.token,\n remote: parsed.remote ?? null,\n }\n}\n\n/**\n * Merge plaintext config + decrypted secrets + process env into a single\n * env-shaped record. Precedence (low → high): config → secrets → env. The\n * caller supplies the bootstrap `password` (typically `readAuthFile().token`)\n * because the secrets table is encrypted with it.\n *\n * Either layer may fail to read (corrupt row, wrong key, table absent at\n * fixture-bootstrap time); failures are swallowed per-layer so a single bad\n * value never blocks the merge.\n */\nexport function mergeSecretsIntoEnv(\n db: BazilionDb,\n password: string,\n env: NodeJS.ProcessEnv = process.env,\n): NodeJS.ProcessEnv {\n let configValues: Record<string, string> = {}\n let secretValues: Record<string, string> = {}\n try {\n configValues = openConfig(db).getAll()\n } catch {\n // table missing or unreadable — continue without the layer\n }\n try {\n secretValues = openSecrets(db, password).getAll()\n } catch {\n // table missing or wrong password — continue without the layer\n }\n return { ...configValues, ...secretValues, ...env }\n}\n","import { cpSync, existsSync, mkdtempSync, readdirSync, rmSync, statSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { basename, join, resolve, sep } from 'node:path'\nimport AdmZip from 'adm-zip'\nimport type { Paths } from '../paths.ts'\nimport { parseSkillFile } from './parse.ts'\n\nexport interface ImportSkillsInput {\n /**\n * Absolute path to either:\n * - a single skill folder (contains SKILL.md),\n * - a parent directory containing multiple skill folders,\n * - a `.zip` file whose top level holds one-folder-per-skill (or a single\n * wrapping folder that holds them).\n */\n source: string\n /** overwrite existing target skills */\n force?: boolean\n}\n\nexport interface ImportResult {\n imported: string[]\n skipped: { name: string; reason: string }[]\n}\n\n/**\n * Extract a zip archive into a fresh temp dir with a zip-slip guard — every\n * entry's resolved path must stay under the extraction root. Returns both the\n * mkdtemp root (for cleanup) and the effective source path to hand to the\n * importer. When the archive is wrapped in a single top-level directory\n * (common with GitHub-style archives), we descend into it so `source` lines\n * up with the \"parent-of-skill-dirs\" shape the importer already understands.\n */\nfunction extractZipSafely(zipPath: string): { root: string; effectiveSource: string } {\n const root = mkdtempSync(join(tmpdir(), 'bazilion-skill-zip-'))\n try {\n const zip = new AdmZip(zipPath)\n for (const entry of zip.getEntries()) {\n const rawName = entry.entryName\n if (rawName.startsWith('/') || rawName.startsWith('\\\\')) {\n throw new Error(`zip entry has absolute path: ${rawName}`)\n }\n const resolved = resolve(root, rawName)\n if (resolved !== root && !resolved.startsWith(root + sep)) {\n throw new Error(`zip entry escapes extraction root: ${rawName}`)\n }\n }\n zip.extractAllTo(root, true)\n } catch (err) {\n rmSync(root, { recursive: true, force: true })\n throw err\n }\n\n // Unwrap a single top-level folder if present — the importer's\n // \"source-is-a-directory\" cases (single-skill dir vs. parent-of-skills dir)\n // both apply equally well to the unwrapped path.\n let effectiveSource = root\n const topEntries = readdirSync(root, { withFileTypes: true })\n if (topEntries.length === 1 && topEntries[0]?.isDirectory()) {\n effectiveSource = join(root, topEntries[0].name)\n }\n return { root, effectiveSource }\n}\n\nexport function importSkills(paths: Paths, input: ImportSkillsInput): ImportResult {\n const rawSource = resolve(input.source)\n if (!existsSync(rawSource)) {\n throw new Error(`source does not exist: ${rawSource}`)\n }\n\n let source = rawSource\n let tempRoot: string | null = null\n const sourceStat = statSync(rawSource)\n if (sourceStat.isFile()) {\n if (!rawSource.toLowerCase().endsWith('.zip')) {\n throw new Error(`source file must be a .zip archive: ${rawSource}`)\n }\n const { root, effectiveSource } = extractZipSafely(rawSource)\n tempRoot = root\n source = effectiveSource\n } else if (!sourceStat.isDirectory()) {\n throw new Error(`source is not a directory: ${rawSource}`)\n }\n\n try {\n return importSkillsFromDir(paths, source, input)\n } finally {\n if (tempRoot) rmSync(tempRoot, { recursive: true, force: true })\n }\n}\n\nfunction importSkillsFromDir(paths: Paths, source: string, input: ImportSkillsInput): ImportResult {\n const candidates: { name: string; dir: string }[] = []\n\n // Two shapes are accepted:\n // 1. source is itself a single skill dir (contains SKILL.md)\n // 2. source is a parent containing multiple skill dirs\n if (existsSync(join(source, 'SKILL.md'))) {\n candidates.push({ name: basename(source), dir: source })\n } else {\n const entries = readdirSync(source, { withFileTypes: true })\n for (const e of entries) {\n if (!e.isDirectory()) continue\n const skillDir = join(source, e.name)\n if (!existsSync(join(skillDir, 'SKILL.md'))) continue\n candidates.push({ name: e.name, dir: skillDir })\n }\n }\n\n if (candidates.length === 0) {\n throw new Error(`no skills found in ${source}`)\n }\n\n // Validate every SKILL.md before touching the target dir.\n for (const c of candidates) {\n parseSkillFile(join(c.dir, 'SKILL.md'))\n }\n\n const imported: string[] = []\n const skipped: { name: string; reason: string }[] = []\n\n for (const c of candidates) {\n const target = join(paths.skillsDir, c.name)\n if (existsSync(target) && !input.force) {\n skipped.push({\n name: c.name,\n reason: 'already exists (use --force to overwrite)',\n })\n continue\n }\n cpSync(c.dir, target, { recursive: true, force: !!input.force })\n imported.push(c.name)\n }\n\n return { imported, skipped }\n}\n","import { readFileSync } from 'node:fs'\nimport { parse as parseYaml } from 'yaml'\n\n/**\n * Standard agent-skill frontmatter. Required fields are typed; the rest is open\n * (skill formats may add fields like `allowed-tools`, `homepage`, etc.).\n */\nexport interface SkillFrontmatter {\n name: string\n description: string\n [key: string]: unknown\n}\n\nexport interface ParsedSkill {\n frontmatter: SkillFrontmatter\n body: string\n raw: string\n}\n\nconst FRONTMATTER_RE = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/\n\nexport function parseSkillContent(raw: string): ParsedSkill {\n const m = raw.match(FRONTMATTER_RE)\n if (!m) {\n throw new Error('SKILL.md missing YAML frontmatter (expected leading \"---\")')\n }\n const yamlBlock = m[1] ?? ''\n const body = m[2] ?? ''\n\n let fm: unknown\n try {\n fm = parseYaml(yamlBlock)\n } catch (err) {\n throw new Error(`SKILL.md frontmatter is not valid YAML: ${(err as Error).message}`)\n }\n if (!fm || typeof fm !== 'object' || Array.isArray(fm)) {\n throw new Error('SKILL.md frontmatter must be a YAML object')\n }\n const fmObj = fm as Record<string, unknown>\n if (typeof fmObj.name !== 'string' || fmObj.name.length === 0) {\n throw new Error('SKILL.md frontmatter missing required \"name\"')\n }\n if (typeof fmObj.description !== 'string' || fmObj.description.length === 0) {\n throw new Error('SKILL.md frontmatter missing required \"description\"')\n }\n return { frontmatter: fmObj as SkillFrontmatter, body, raw }\n}\n\nexport function parseSkillFile(path: string): ParsedSkill {\n const raw = readFileSync(path, 'utf8')\n return parseSkillContent(raw)\n}\n","import type { BazilionDb } from '../db/client.ts'\nimport type { Paths } from '../paths.ts'\nimport * as agentRepo from '../repos/agents.ts'\nimport { discoverSkills } from './discover.ts'\nimport { type ParsedSkill, parseSkillFile } from './parse.ts'\n\nexport interface ResolvedSkill {\n name: string\n dir: string\n parsed: ParsedSkill\n}\n\nexport interface ResolvedSkillSet {\n /** skills attached to the agent that exist and parse correctly */\n resolved: ResolvedSkill[]\n /** attached skill names that are missing from the library or fail to parse */\n missing: { name: string; reason: string }[]\n}\n\n/**\n * Given an agent, return the parsed skills currently attached to it. Skill\n * attachments live in `agent_skills`; the source of truth for content is\n * `~/.bazilion/skills/<name>/SKILL.md`.\n */\nexport function resolveAgentSkills(\n db: BazilionDb,\n paths: Paths,\n agentId: string,\n): ResolvedSkillSet {\n const attached = agentRepo.listAttachedSkills(db, agentId)\n const discovered = new Map(discoverSkills(paths).map((s) => [s.name, s]))\n\n const resolved: ResolvedSkill[] = []\n const missing: { name: string; reason: string }[] = []\n\n for (const name of attached) {\n const ds = discovered.get(name)\n if (!ds) {\n missing.push({ name, reason: 'not in library' })\n continue\n }\n try {\n const parsed = parseSkillFile(ds.skillFile)\n resolved.push({ name, dir: ds.dir, parsed })\n } catch (err) {\n missing.push({ name, reason: (err as Error).message })\n }\n }\n return { resolved, missing }\n}\n","import { chmodSync, existsSync, mkdirSync, writeFileSync } from 'node:fs'\nimport {\n type BazilionDb,\n openDb,\n type Paths,\n readAuthFile,\n resolvePaths,\n runMigrations,\n webTokenRepo,\n} from '../core/index.ts'\nimport { startScheduler } from './scheduler.ts'\n\nlet _db: BazilionDb | null = null\nlet _paths: Paths | null = null\nlet _authToken: string | null = null\nlet _schedulerStarted = false\n\nexport interface DaemonCtx {\n db: BazilionDb\n paths: Paths\n /**\n * Plaintext bootstrap token from `auth.json`. Used to derive the encryption\n * key for the `secrets` table — `mergeSecretsIntoEnv(db, ctx.authToken)`.\n * Cached for the process lifetime; if the user rotates the token, the\n * daemon must restart to pick it up.\n */\n authToken: string\n}\n\n/**\n * One-shot first-run bootstrap. Idempotent: every step skips itself when its\n * artifact already exists. Mints the bootstrap web_tokens row + writes the\n * plaintext into auth.json the first time we see no auth file.\n */\nfunction bootstrap(paths: Paths): { db: BazilionDb; authToken: string } {\n for (const d of [\n paths.home,\n paths.profilesDir,\n paths.agentsDir,\n paths.skillsDir,\n paths.groupsDir,\n paths.logsDir,\n ]) {\n mkdirSync(d, { recursive: true })\n }\n\n const db = openDb(paths.db)\n runMigrations(db)\n\n if (!existsSync(paths.authFile)) {\n const created = webTokenRepo.create(db, 'bootstrap')\n writeFileSync(paths.authFile, `${JSON.stringify({ token: created.token }, null, 2)}\\n`, {\n mode: 0o600,\n })\n try {\n chmodSync(paths.authFile, 0o600)\n } catch {\n // Windows: chmod is a no-op\n }\n console.log(`bazilion auto-bootstrapped at ${paths.home}`)\n console.log(`bootstrap token written to ${paths.authFile}`)\n return { db, authToken: created.token }\n }\n\n return { db, authToken: readAuthFile(paths.authFile).token }\n}\n\nexport function getCtx(): DaemonCtx {\n if (!_paths) _paths = resolvePaths()\n if (!_db || _authToken === null) {\n const result = bootstrap(_paths)\n _db = result.db\n _authToken = result.authToken\n }\n if (!_schedulerStarted && process.env.BAZILION_SCHEDULER !== 'off') {\n _schedulerStarted = true\n startScheduler()\n }\n return { db: _db, paths: _paths, authToken: _authToken }\n}\n","// In-memory registry of agents currently running a turn and their\n// AbortControllers. The chat / scheduler / inbox-wake paths register before\n// they spawn a worker; the cancel route looks the agent up and calls\n// `abort()`. Doubles as the \"is this agent busy?\" probe the scheduler uses\n// to skip overlapping inbox-wakes and triggers.\n//\n// Pinned to `globalThis` via a well-known Symbol so there is exactly one\n// instance per process even if a bundler ever splits this module across\n// chunks. Two different Map instances would make registrations invisible to\n// the cancel side.\n\nconst REGISTRY_KEY = Symbol.for('bazilion.agent-cancel.registry')\n\ninterface Registry {\n active: Map<string, AbortController>\n}\n\nfunction registry(): Registry {\n const g = globalThis as unknown as Record<symbol, Registry | undefined>\n let r = g[REGISTRY_KEY]\n if (!r) {\n r = { active: new Map() }\n g[REGISTRY_KEY] = r\n }\n return r\n}\n\nexport function registerAgent(agentId: string, controller: AbortController): void {\n registry().active.set(agentId, controller)\n}\n\nexport function unregisterAgent(agentId: string): void {\n registry().active.delete(agentId)\n}\n\n/** Returns true if the agent had an active turn that was aborted, false otherwise. */\nexport function cancelAgent(agentId: string): boolean {\n const { active } = registry()\n const c = active.get(agentId)\n if (!c) return false\n c.abort()\n active.delete(agentId)\n return true\n}\n\nexport function isActiveAgent(agentId: string): boolean {\n return registry().active.has(agentId)\n}\n","// OpenAI ChatGPT / Codex OAuth — token storage + refresh on top of pi-ai.\n//\n// Pi-ai ships a complete OAuth flow for the ChatGPT backend (`@earendil-works/pi-ai`\n// exports `loginOpenAICodex` + `refreshOpenAICodexToken`), so this module is\n// thin: it adapts the credential I/O to Bazilion's encrypted secrets store\n// and exposes a single `loadAccessToken(db, authToken)` call that refreshes\n// when the token is about to expire.\n//\n// Storage: the JSON blob `{refresh, access, expires}` lives under the\n// secrets key `OPENAI_CODEX_OAUTH` in the `secrets` table. The blob is\n// never copied into the env (unlike plain-API-key providers) — refresh is\n// stateful, so every call reads and writes through the live secrets store.\n\nimport type { OpenAICodexStatus } from '@bazilion/api-types'\nimport type { OAuthCredentials } from '@earendil-works/pi-ai'\nimport { loginOpenAICodex, refreshOpenAICodexToken } from '@earendil-works/pi-ai/oauth'\nimport { type BazilionDb, openSecrets } from '../../core/index.ts'\n\nexport const OPENAI_CODEX_SECRET_KEY = 'OPENAI_CODEX_OAUTH'\n\n/** Refresh when the access token has less than this much life left. */\nconst REFRESH_MARGIN_MS = 60_000\n\nexport interface StoredCredentials {\n refresh: string\n access: string\n expires: number\n}\n\nfunction readCredentials(db: BazilionDb, authToken: string): StoredCredentials | null {\n const raw = openSecrets(db, authToken).get(OPENAI_CODEX_SECRET_KEY)\n if (!raw) return null\n try {\n const parsed = JSON.parse(raw) as Partial<StoredCredentials>\n if (\n typeof parsed.refresh === 'string' &&\n typeof parsed.access === 'string' &&\n typeof parsed.expires === 'number'\n ) {\n return { refresh: parsed.refresh, access: parsed.access, expires: parsed.expires }\n }\n return null\n } catch {\n return null\n }\n}\n\nfunction writeCredentials(db: BazilionDb, authToken: string, creds: StoredCredentials): void {\n openSecrets(db, authToken).set(OPENAI_CODEX_SECRET_KEY, JSON.stringify(creds))\n}\n\nexport function clearCredentials(db: BazilionDb, authToken: string): void {\n openSecrets(db, authToken).remove(OPENAI_CODEX_SECRET_KEY)\n}\n\nexport function hasCredentials(db: BazilionDb, authToken: string): boolean {\n return readCredentials(db, authToken) !== null\n}\n\nfunction decodeAccountId(accessToken: string): string | null {\n const parts = accessToken.split('.')\n if (parts.length !== 3) return null\n try {\n const payload = JSON.parse(Buffer.from(parts[1] as string, 'base64').toString('utf8')) as {\n 'https://api.openai.com/auth'?: { chatgpt_account_id?: string }\n }\n return payload['https://api.openai.com/auth']?.chatgpt_account_id ?? null\n } catch {\n return null\n }\n}\n\nexport function getStatus(db: BazilionDb, authToken: string): OpenAICodexStatus {\n const creds = readCredentials(db, authToken)\n if (!creds) return { connected: false, expiresAt: null, accountId: null }\n return {\n connected: true,\n expiresAt: creds.expires,\n accountId: decodeAccountId(creds.access),\n }\n}\n\n/**\n * Returns a valid access token, refreshing via pi-ai if the stored one is\n * within `REFRESH_MARGIN_MS` of expiry. Throws when no credentials are stored\n * so callers can surface an actionable \"run `bazilion auth openai login`\"\n * error rather than a 401 from the upstream API.\n */\nexport async function loadAccessToken(db: BazilionDb, authToken: string): Promise<string> {\n const creds = readCredentials(db, authToken)\n if (!creds) {\n throw new Error(\n 'OpenAI ChatGPT OAuth not configured — run `bazilion auth openai login` (or use the Connect button on /config)',\n )\n }\n if (creds.expires > Date.now() + REFRESH_MARGIN_MS) return creds.access\n\n const refreshed = (await refreshOpenAICodexToken(creds.refresh)) as OAuthCredentials\n const next: StoredCredentials = {\n refresh: refreshed.refresh,\n access: refreshed.access,\n expires: refreshed.expires,\n }\n writeCredentials(db, authToken, next)\n return next.access\n}\n\n/** Persist credentials fetched by pi-ai's `loginOpenAICodex`. */\nexport function saveLoginCredentials(\n db: BazilionDb,\n authToken: string,\n creds: OAuthCredentials,\n): void {\n writeCredentials(db, authToken, {\n refresh: creds.refresh,\n access: creds.access,\n expires: creds.expires,\n })\n}\n\nexport { loginOpenAICodex, refreshOpenAICodexToken }\n","// Default heartbeat prompt. Users paste this constant as a trigger's\n// `message` (or call `resolveHeartbeatPrompt` with a custom one) to wire\n// HEARTBEAT.md into a scheduled wake-up without reinventing the framing.\nexport const HEARTBEAT_PROMPT =\n 'Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply HEARTBEAT_OK.'\n\nexport const DEFAULT_HEARTBEAT_EVERY_SEC = 30 * 60\n\n/**\n * A HEARTBEAT.md is \"effectively empty\" when it has no actionable task lines.\n * Whitespace, ATX headers, and stub checklist items (`- [ ]`) all count as\n * empty so we can skip a turn when the file has been left as a placeholder.\n * Missing content (undefined/null/non-string) returns false — the LLM should\n * still get a chance to act.\n */\nexport function isHeartbeatContentEffectivelyEmpty(content: string | undefined | null): boolean {\n if (typeof content !== 'string') return false\n for (const line of content.split('\\n')) {\n const trimmed = line.trim()\n if (!trimmed) continue\n if (/^#+(\\s|$)/.test(trimmed)) continue\n if (/^[-*+]\\s*(\\[[\\sXx]?\\]\\s*)?$/.test(trimmed)) continue\n return false\n }\n return true\n}\n\nexport function resolveHeartbeatPrompt(raw?: string | null): string {\n const trimmed = typeof raw === 'string' ? raw.trim() : ''\n return trimmed || HEARTBEAT_PROMPT\n}\n","import {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n rmSync,\n statSync,\n writeFileSync,\n} from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport type { MemoryEntry, MemoryHit } from '@bazilion/api-types'\nimport type { MemoryBackend } from './types.ts'\n\nconst SNIPPET_PAD = 60\n\n/**\n * Filesystem-backed memory: every entry is a file under `root`. Search is\n * substring matching across all files. Index = the filesystem itself.\n */\nexport function filesBackend(root: string): MemoryBackend {\n function safe(key: string): string {\n if (key.includes('..') || key.startsWith('/') || key.includes('\\0')) {\n throw new Error(`unsafe memory key: ${key}`)\n }\n return join(root, key)\n }\n\n function walk(dir: string, prefix: string, out: MemoryEntry[]): void {\n if (!existsSync(dir)) return\n for (const e of readdirSync(dir, { withFileTypes: true })) {\n const full = join(dir, e.name)\n const key = prefix ? `${prefix}/${e.name}` : e.name\n if (e.isDirectory()) {\n walk(full, key, out)\n } else if (e.isFile()) {\n const stats = statSync(full)\n out.push({\n key,\n content: readFileSync(full, 'utf8'),\n updatedAt: stats.mtimeMs,\n })\n }\n }\n }\n\n return {\n async init() {\n mkdirSync(root, { recursive: true })\n },\n\n async read(key) {\n const path = safe(key)\n if (!existsSync(path)) {\n throw new Error(`memory entry not found: ${key}`)\n }\n const stats = statSync(path)\n return {\n key,\n content: readFileSync(path, 'utf8'),\n updatedAt: stats.mtimeMs,\n }\n },\n\n async write(key, content) {\n const path = safe(key)\n mkdirSync(dirname(path), { recursive: true })\n writeFileSync(path, content)\n const stats = statSync(path)\n return { key, content, updatedAt: stats.mtimeMs }\n },\n\n async search(query, opts) {\n const limit = opts?.limit ?? 10\n const all: MemoryEntry[] = []\n walk(root, '', all)\n const q = query.toLowerCase()\n const hits: MemoryHit[] = []\n for (const entry of all) {\n const idx = entry.content.toLowerCase().indexOf(q)\n if (idx === -1) continue\n const start = Math.max(0, idx - SNIPPET_PAD)\n const end = Math.min(entry.content.length, idx + query.length + SNIPPET_PAD)\n hits.push({\n key: entry.key,\n snippet: entry.content.slice(start, end),\n score: 1,\n })\n }\n return hits.slice(0, limit)\n },\n\n async list() {\n const out: MemoryEntry[] = []\n walk(root, '', out)\n return out.sort((a, b) => a.key.localeCompare(b.key))\n },\n\n async remove(key) {\n const path = safe(key)\n if (existsSync(path)) rmSync(path)\n },\n }\n}\n","import {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n rmSync,\n statSync,\n writeFileSync,\n} from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport type { MemoryEntry, MemoryHit } from '@bazilion/api-types'\nimport { createStore, extractSnippet, type QMDStore } from '@tobilu/qmd'\nimport type { MemoryBackend } from './types.ts'\n\nconst INDEX_FILENAME = '.qmd-index.sqlite'\nconst COLLECTION_NAME = 'memory'\nconst PATTERN = '**/*.md'\n\n// One store per memory directory per process. createStore opens a SQLite\n// handle; we dedupe so concurrent chat requests for the same agent reuse it.\nconst storeCache = new Map<string, Promise<QMDStore>>()\n\nfunction getStore(dir: string): Promise<QMDStore> {\n let p = storeCache.get(dir)\n if (!p) {\n p = createStore({\n dbPath: join(dir, INDEX_FILENAME),\n config: {\n collections: {\n [COLLECTION_NAME]: { path: dir, pattern: PATTERN },\n },\n },\n })\n storeCache.set(dir, p)\n }\n return p\n}\n\nfunction safeKey(root: string, key: string): string {\n if (key.includes('..') || key.startsWith('/') || key.includes('\\0')) {\n throw new Error(`unsafe memory key: ${key}`)\n }\n return join(root, key)\n}\n\nfunction walkMd(dir: string, prefix: string, out: MemoryEntry[]): void {\n if (!existsSync(dir)) return\n for (const e of readdirSync(dir, { withFileTypes: true })) {\n if (e.name.startsWith('.')) continue // skip .qmd-index.sqlite and friends\n const full = join(dir, e.name)\n const key = prefix ? `${prefix}/${e.name}` : e.name\n if (e.isDirectory()) {\n walkMd(full, key, out)\n } else if (e.isFile() && e.name.endsWith('.md')) {\n const stats = statSync(full)\n out.push({\n key,\n content: readFileSync(full, 'utf8'),\n updatedAt: stats.mtimeMs,\n })\n }\n }\n}\n\n/**\n * Memory backend backed by @tobilu/qmd — BM25 keyword search over markdown\n * files under `root`. Writes markdown to disk, then asks qmd to reindex.\n *\n * Uses `searchLex` only; no embeddings, no LLM rerank, no model download.\n * The hybrid `search()` / `searchVector()` paths exist in the qmd SDK and\n * can be wired in later if we want semantic search — they'd add a dependency\n * on `node-llama-cpp` and several GB of GGUF models.\n */\nexport function qmdBackend(root: string): MemoryBackend {\n return {\n async init() {\n mkdirSync(root, { recursive: true })\n // Opening the store + initial scan. update() is idempotent.\n const store = await getStore(root)\n await store.update()\n },\n\n async read(key) {\n const path = safeKey(root, key)\n if (!existsSync(path)) {\n throw new Error(`memory entry not found: ${key}`)\n }\n const stats = statSync(path)\n return {\n key,\n content: readFileSync(path, 'utf8'),\n updatedAt: stats.mtimeMs,\n }\n },\n\n async write(key, content) {\n const path = safeKey(root, key)\n mkdirSync(dirname(path), { recursive: true })\n writeFileSync(path, content)\n const stats = statSync(path)\n // Reindex so the newly-written file is searchable on the next search().\n // update() re-scans the collection; for typical memory sizes (tens of\n // files) this is sub-millisecond.\n const store = await getStore(root)\n await store.update()\n return { key, content, updatedAt: stats.mtimeMs }\n },\n\n async search(query, opts) {\n const limit = opts?.limit ?? 10\n const store = await getStore(root)\n const results = await store.searchLex(query, {\n limit,\n collection: COLLECTION_NAME,\n })\n const hits: MemoryHit[] = []\n for (const r of results) {\n // qmd's filepath is a synthetic URI (`qmd://<collection>/<path>`);\n // displayPath is collection-prefixed (`<collection>/<path>`). Strip\n // the leading `<collection>/` to get the key the caller wrote.\n const prefix = `${COLLECTION_NAME}/`\n const key = r.displayPath.startsWith(prefix)\n ? r.displayPath.slice(prefix.length)\n : r.displayPath\n let content = r.body ?? ''\n if (!content) {\n try {\n content = readFileSync(join(root, key), 'utf8')\n } catch {\n content = ''\n }\n }\n const snippet = extractSnippet(content, query).snippet\n hits.push({ key, snippet, score: r.score })\n }\n return hits\n },\n\n async list() {\n const out: MemoryEntry[] = []\n walkMd(root, '', out)\n return out.sort((a, b) => a.key.localeCompare(b.key))\n },\n\n async remove(key) {\n const path = safeKey(root, key)\n if (existsSync(path)) rmSync(path)\n const store = await getStore(root)\n await store.update()\n },\n }\n}\n","// Translator: pi `AgentSessionEvent` → Bazilion `SessionEvent[]`.\n//\n// The worker's NDJSON wire format (`ChatFrame`) is still the same discrete\n// event stream CLI / browser clients know how to render. This module is the\n// adapter at the single choke-point — pi event in, zero-or-more Bazilion\n// events out.\n//\n// Coverage:\n// - user message_start → one `user_message`\n// - assistant text_delta → one `assistant_delta` per chunk\n// - assistant message_end:\n// - if the message carries text → one `assistant_message`\n// - for every tool-call content → one `tool_call`\n// - tool_execution_end → `tool_result` or `tool_error` based on isError\n// - message_end with aborted/error stopReason → one `error`\n//\n// Not surfaced (intentional):\n// - agent_start / agent_end — run-row lifecycle, not chat events\n// - turn_start / turn_end — too chatty, nothing to render\n// - message_start (assistant) — text will come via updates + end\n// - message_update (non-text) — thinking deltas etc; left for a later\n// pass when UIs render thinking blocks\n// - queue_update / compaction_* — session meta, not assistant output\n// - auto_retry_* — silently retried, user sees only the\n// eventual success or failure\n\nimport type { ProviderMessage, SessionEvent, ToolCall } from '@bazilion/api-types'\nimport type { AgentMessage, AgentToolResult } from '@earendil-works/pi-agent-core'\nimport type { AssistantMessage } from '@earendil-works/pi-ai'\nimport type { AgentSessionEvent } from '@earendil-works/pi-coding-agent'\n\nexport function translatePiEvent(e: AgentSessionEvent): SessionEvent[] {\n switch (e.type) {\n case 'message_start': {\n if (e.message.role === 'user') {\n return [{ type: 'user_message', text: stringifyContent(e.message.content) }]\n }\n return []\n }\n\n case 'message_update': {\n const inner = e.assistantMessageEvent\n if (inner.type === 'text_delta') {\n return [{ type: 'assistant_delta', delta: inner.delta }]\n }\n return []\n }\n\n case 'message_end': {\n const m = e.message\n if (m.role !== 'assistant') return []\n const out: SessionEvent[] = []\n const text = extractAssistantText(m as AssistantMessage)\n if (text) out.push({ type: 'assistant_message', text })\n for (const block of (m as AssistantMessage).content ?? []) {\n if (block.type === 'toolCall') {\n out.push({\n type: 'tool_call',\n id: block.id,\n name: block.name,\n arguments: JSON.stringify(block.arguments ?? {}),\n })\n }\n }\n const stopReason = (m as AssistantMessage).stopReason\n if (stopReason === 'aborted' || stopReason === 'error') {\n const errText = (m as AssistantMessage).errorMessage ?? stopReason\n out.push({ type: 'error', error: errText })\n }\n return out\n }\n\n case 'tool_execution_end': {\n const text = extractToolResultText(e.result)\n if (e.isError) {\n return [{ type: 'tool_error', id: e.toolCallId, name: e.toolName, error: text }]\n }\n return [{ type: 'tool_result', id: e.toolCallId, name: e.toolName, result: text }]\n }\n\n default:\n return []\n }\n}\n\nexport function extractAssistantText(m: AssistantMessage): string {\n let out = ''\n for (const block of m.content ?? []) {\n if (block.type === 'text') out += block.text\n }\n return out\n}\n\nexport function extractAssistantToolCalls(m: AssistantMessage): ToolCall[] {\n const out: ToolCall[] = []\n for (const block of m.content ?? []) {\n if (block.type === 'toolCall') {\n out.push({ id: block.id, name: block.name, arguments: JSON.stringify(block.arguments ?? {}) })\n }\n }\n return out\n}\n\n/** Flatten `AgentToolResult.content` blocks into a single string — matches the\n * shape Bazilion tools always returned before pi adoption. */\nexport function extractToolResultText(result: unknown): string {\n const r = result as AgentToolResult<unknown> | undefined\n if (!r?.content) return ''\n let out = ''\n for (const block of r.content) {\n if (block.type === 'text') out += block.text\n }\n return out\n}\n\n/** Stringify a pi user-message content array. */\nfunction stringifyContent(content: unknown): string {\n if (typeof content === 'string') return content\n if (!Array.isArray(content)) return ''\n let out = ''\n for (const block of content as { type: string; text?: string }[]) {\n if (block.type === 'text' && typeof block.text === 'string') out += block.text\n }\n return out\n}\n\n/**\n * Convert pi's authoritative `session.state.messages` (AgentMessage[]) into\n * Bazilion's ProviderMessage[] shape, so the `done` ChatFrame stays\n * compatible with browser + CLI clients that rehydrate from it.\n *\n * Notes on role mapping: pi uses `\"toolResult\"` for tool-response messages;\n * Bazilion uses `\"tool\"`. AssistantMessage content arrays become either\n * `content` string (text blocks joined) or a `toolCalls` array (toolCall\n * blocks converted).\n */\nexport function piMessagesToProviderView(messages: AgentMessage[]): ProviderMessage[] {\n const out: ProviderMessage[] = []\n for (const m of messages) {\n // Custom Bazilion message types would land in this switch too, but we\n // don't register any via CustomAgentMessages declaration merging yet.\n switch (m.role) {\n case 'user': {\n out.push({ role: 'user', content: stringifyContent((m as { content: unknown }).content) })\n break\n }\n case 'assistant': {\n const am = m as AssistantMessage\n const text = extractAssistantText(am)\n const toolCalls = extractAssistantToolCalls(am)\n const msg: ProviderMessage = { role: 'assistant', content: text }\n if (toolCalls.length > 0) msg.toolCalls = toolCalls\n out.push(msg)\n break\n }\n case 'toolResult': {\n const tr = m as { content: unknown; toolCallId?: string; toolName?: string }\n out.push({\n role: 'tool',\n content: stringifyContent(tr.content),\n toolCallId: tr.toolCallId,\n toolName: tr.toolName,\n })\n break\n }\n default:\n // System and other unknown roles are skipped — the runtime's system\n // prompt is already wired via pi's settingsManager + our buildSystemPrompt.\n break\n }\n }\n return out\n}\n","// Bazilion → pi-coding-agent session bridge.\n//\n// `createBazilionSession` returns a fully-wired `AgentSession` suitable for\n// calling `session.prompt(text)` / `session.compact(instructions)` / etc.\n//\n// What we take ownership of (and hand to pi):\n// - cwd: the agent's default workspace path (or agent.dir as a degenerate\n// fallback when no workspace is mounted). Pi's built-in `read/bash/edit/\n// write/grep/find/ls` tools are rooted here.\n// - agentDir: `<bazilion-home>/pi` — pi writes transient state here\n// (settings overrides, resource caches). We don't share it with the\n// user's global `~/.pi/agent` so a Bazilion install never clobbers an\n// independent pi CLI install.\n// - authStorage: `InMemoryAuthStorageBackend` pre-seeded with the resolved\n// API key for the agent's current provider. We never let pi read/write\n// its own auth file — secrets live in the daemon-owned `secrets` table\n// and reach us via `opts.apiKey` (initial) + `opts.refreshApiKey`\n// (OAuth refresher for long turns).\n// - modelRegistry: in-memory. Native providers (anthropic/openai/google/…)\n// come from pi's bundled catalog. For Bazilion-only providers\n// (`lmstudio`, `ollama`) we call `registerProvider(name, {baseUrl,\n// api: 'openai-completions', authHeader: false})` — matches the\n// openai-completions shim our pi-adapter has been using.\n// - sessionManager: `SessionManager.create(cwd, <agentDir>/sessions)`\n// writing JSONL to `~/.bazilion/agents/<id>/sessions/<sessionId>.jsonl`.\n// Crash-survival, append-only, branching, compaction entries — all owned\n// by pi now. Replaces our `agents.chat_messages` blob.\n// - settingsManager: in-memory. Bazilion controls auto-compaction\n// (disabled — we compact manually on user request via /compact) and\n// retry (enabled with Bazilion-tuned caps).\n//\n// What stays outside pi's purview:\n// - spawning agents / profiles / skills discovery (core/)\n// - workspaces registry & mount tracking (core/)\n// - inter-agent messaging, triggers, scheduler (core + apps/web)\n// - memory backend (we wrap it as a pi customTool via `createBazilionCustomTools`)\n\nimport { existsSync, mkdirSync, readdirSync, statSync } from 'node:fs'\nimport { basename, join } from 'node:path'\nimport type { ResolvedAgent } from '@bazilion/api-types'\nimport type { AgentMessage, ThinkingLevel } from '@earendil-works/pi-agent-core'\nimport {\n type AgentSession,\n AuthStorage,\n createAgentSession,\n createExtensionRuntime,\n ModelRegistry,\n type ResourceLoader,\n SessionManager,\n SettingsManager,\n} from '@earendil-works/pi-coding-agent'\nimport type { BazilionDb, Paths } from '../../core/index.ts'\nimport { providerStateRepo } from '../../core/index.ts'\nimport type { MemoryBackend } from '../memory/types.ts'\nimport { resolveModel as resolvePiModel } from '../providers/pi-adapter.ts'\nimport { createProviderRegistry, loadProviderConfigFromEnv } from '../providers/registry.ts'\nimport { buildSystemPrompt } from '../session/prompt.ts'\nimport type { MessagingHost, UserMdHost } from '../worker/ipc-protocol.ts'\nimport { createBazilionCustomTools } from './tools.ts'\n\nconst BUILTIN_TOOL_NAMES = ['read', 'bash', 'edit', 'write', 'grep', 'find', 'ls'] as const\n\nexport interface CreateBazilionSessionOptions {\n agent: ResolvedAgent\n paths: Paths\n /** Merged env (process.env + secrets) — produced via `mergeSecretsIntoEnv`. */\n env: NodeJS.ProcessEnv\n memory: MemoryBackend\n /**\n * Names of providers the user has explicitly enabled in /config.\n * Empty set means \"no per-provider gating configured\" — all providers pass.\n * Pre-computed by the daemon and handed in so the session never has to\n * touch the SQLite `provider_state` table itself.\n */\n enabledProviders: Set<string>\n /**\n * Optional host for inter-agent messaging. Wired from the worker's IPC\n * channel back to the daemon — workers no longer hold a SQLite handle of\n * their own. Omit to disable the messaging tools entirely (e.g. unit\n * tests that don't exercise inbox flows).\n */\n messagingHost?: MessagingHost\n /**\n * Optional host for the group-shared USER.md append tool. Like\n * `messagingHost`, this is wired via the worker's IPC channel. Omit to\n * disable the `user_md_append` tool.\n */\n userMdHost?: UserMdHost\n /**\n * Optional explicit API key for the agent's provider. Wins over any value\n * derived from `env`. Required for OAuth-backed providers (`openai-codex`)\n * since their credentials live in the daemon-owned `secrets` table, not\n * in env vars.\n */\n apiKey?: string\n /**\n * Optional callback for OAuth-backed providers whose access tokens may\n * expire mid-turn. When provided, pi calls it to refresh the JWT during\n * long tool-execution loops. Daemon-side callers (compact/context/truncate)\n * wire this directly against the secrets repo; worker turns currently\n * skip it (the initial token from `apiKey` carries the whole turn).\n */\n refreshApiKey?: (providerName: string) => Promise<string>\n /**\n * Session id to resume. When omitted, pi starts a fresh session file.\n * `/reset` passes `undefined` to rotate; normal chat passes the agent's\n * current session id (persisted on the Bazilion side as `agents.session_id`\n * if we later add that column — today we just restore the most recent\n * session file, which pi's SessionManager locates automatically).\n */\n sessionId?: string\n}\n\nexport interface BazilionSessionHandle {\n session: AgentSession\n /** Call when done — disposes listeners + closes the pi session. */\n dispose(): void\n}\n\n/**\n * Build a pi `AgentSession` using Bazilion's resolved agent + provider state.\n * The returned session is ready for `prompt()` / `compact()` / `reset()`.\n */\nexport async function createBazilionSession(\n opts: CreateBazilionSessionOptions,\n): Promise<BazilionSessionHandle> {\n const { agent, paths, env, memory, enabledProviders, messagingHost, userMdHost, refreshApiKey } =\n opts\n\n const { providerName, modelId } = splitModelString(agent.model)\n\n // Enabled-set gate — mirrors createProviderRegistry's check. We keep the\n // Bazilion-side enabled/disabled /config toggles authoritative even though\n // pi does its own provider resolution: we simply refuse to build a session\n // for a disabled provider. The set is pre-computed by the daemon (the\n // worker has no SQLite handle of its own).\n if (enabledProviders.size > 0 && !enabledProviders.has(providerName)) {\n throw new Error(`${providerName} provider is disabled — enable it on the /config page`)\n }\n\n // Build the pi Model<Api>. This reuses the same catalog-lookup + literal-\n // fallback that the pi-adapter uses for Provider.chat today, so `lmstudio:\n // any-model` / unreleased OpenAI models / etc. keep working.\n const piProviderName = mapProviderName(providerName)\n const model = resolvePiModel(\n {\n providerName,\n piProviderName,\n fallbackApi: pickFallbackApi(providerName),\n baseUrl: resolveBaseUrl(providerName, env),\n },\n modelId,\n )\n\n // Resolve the API key. Caller-supplied `opts.apiKey` wins (the daemon\n // passes pre-fetched OAuth tokens for `openai-codex` here); otherwise\n // fall back to the env-derived key. Pi's AuthStorage is in-memory only —\n // we never write `auth.json`. `setRuntimeApiKey` is the process-scoped\n // override hook AuthStorage exposes for exactly this.\n const apiKey = opts.apiKey ?? resolveApiKey(providerName, env)\n\n const authStorage = AuthStorage.inMemory()\n if (apiKey) {\n authStorage.setRuntimeApiKey(piProviderName, apiKey)\n }\n\n const modelRegistry = ModelRegistry.inMemory(authStorage)\n // Bazilion-only providers aren't in pi's bundled catalog; register them\n // dynamically so ModelRegistry accepts the Model<> object + resolves auth.\n if (providerName === 'lmstudio' || providerName === 'ollama') {\n modelRegistry.registerProvider(piProviderName, {\n baseUrl: model.baseUrl,\n api: 'openai-completions',\n authHeader: false,\n apiKey: apiKey ?? 'dummy',\n })\n }\n\n // cwd for pi's coding tools is the agent's group directory. Every agent\n // belongs to exactly one group; the group's filesystem root is where work\n // product lives and where the agent's `read`/`bash`/`edit`/`write` are\n // rooted. Private identity/soul files live in `agent.dir` and are reached\n // through the scoped `home_*` tools, not via cwd.\n const cwd = agent.group.path\n if (!existsSync(cwd)) mkdirSync(cwd, { recursive: true })\n\n // Session file under the agent's own directory. Keeping it under\n // `agents/<id>/sessions/` makes `bazilion uninstall` (data tier) already\n // clean them up without changes.\n //\n // Resume-or-create: pi's SessionManager has no built-in \"latest session\"\n // opener. We walk the session dir for the newest `.jsonl` and open it;\n // fall back to `create()` when none exists (fresh agent or post-/reset).\n // This is what makes turn-to-turn continuity work: each worker turn picks\n // up where the last one left off.\n const sessionDir = join(paths.agentDir(agent.agent.id), 'sessions')\n mkdirSync(sessionDir, { recursive: true })\n const existing = findMostRecent(sessionDir)\n const sessionManager = existing\n ? SessionManager.open(existing, sessionDir, cwd)\n : SessionManager.create(cwd, sessionDir)\n\n // In-memory settings: auto-compaction off (we trigger compaction manually\n // via /compact), retry on with Bazilion-tuned caps matching what withRetry\n // used to apply before pi-adoption.\n const settingsManager = SettingsManager.inMemory({\n compaction: { enabled: false },\n retry: {\n enabled: true,\n maxRetries: 2,\n baseDelayMs: 500,\n provider: { maxRetryDelayMs: 8_000 },\n },\n })\n\n // Bazilion-authored system prompt becomes an `appendSystemPrompt` entry.\n // Pi keeps its default base (which lists built-in tools + guidelines), our\n // profile content (SOUL.md / IDENTITY.md / workspaces / memory hint) is\n // concatenated after it. This is the same injection hook pi extensions use.\n const bazilionPrompt = buildSystemPrompt(agent)\n const resourceLoader = createBazilionResourceLoader(bazilionPrompt)\n await resourceLoader.reload()\n\n // Tool allowlist: pi's `tools` option is exclusive when provided — only\n // the listed names are enabled, regardless of what's in `customTools`.\n // So we have to enumerate both pi's built-in coding tools *and* every\n // Bazilion custom tool we want the LLM to see. Missing the custom names\n // from the allowlist would silently drop memory/messaging/web/bootstrap\n // tools from the agent's surface.\n const customTools = createBazilionCustomTools({ agent, memory, messagingHost, userMdHost, env })\n const allowedTools = [...BUILTIN_TOOL_NAMES, ...customTools.map((t) => t.name)]\n\n const { session } = await createAgentSession({\n cwd,\n agentDir: join(paths.home, 'pi'),\n model,\n thinkingLevel: toPiThinkingLevel(agent.reasoningLevel),\n tools: allowedTools,\n customTools,\n sessionManager,\n settingsManager,\n authStorage,\n modelRegistry,\n resourceLoader,\n })\n\n // OAuth providers: wire pi's per-request `getApiKey` callback so the JWT\n // gets refreshed *during* a long tool-execution loop, not just at the\n // start of the turn. This is exactly the use case pi-agent-core's doc\n // calls out for this hook (\"short-lived OAuth tokens that may expire\n // during long-running tool execution phases\"). Caller supplies the\n // refresher because only they have access to the secrets table.\n if (refreshApiKey) {\n session.agent.getApiKey = async (requestedProvider) => {\n if (requestedProvider !== piProviderName) return undefined\n try {\n return await refreshApiKey(providerName)\n } catch {\n // Stale/removed credentials mid-session → return undefined so pi\n // surfaces a \"no auth\" error cleanly instead of us throwing out of\n // the provider callback (which would drag down the whole turn).\n return undefined\n }\n }\n }\n\n return {\n session,\n dispose() {\n session.dispose()\n },\n }\n}\n\n// --- helpers ---\n\nfunction splitModelString(s: string): { providerName: string; modelId: string } {\n const idx = s.indexOf(':')\n if (idx === -1) {\n throw new Error(`invalid model string \"${s}\": expected \"provider:model\"`)\n }\n return { providerName: s.slice(0, idx), modelId: s.slice(idx + 1) }\n}\n\n/**\n * Map Bazilion provider names to pi's canonical `piProviderName` for catalog\n * lookups. The split exists because Bazilion was registering e.g. `bedrock`\n * but pi catalogs it as `amazon-bedrock`.\n */\nfunction mapProviderName(name: string): string {\n if (name === 'bedrock') return 'amazon-bedrock'\n return name\n}\n\nfunction pickFallbackApi(providerName: string): string {\n switch (providerName) {\n case 'anthropic':\n return 'anthropic-messages'\n case 'google':\n return 'google-generative-ai'\n case 'google-vertex':\n return 'google-vertex'\n case 'azure-openai':\n return 'azure-openai-responses'\n case 'bedrock':\n return 'bedrock-converse-stream'\n case 'openai-codex':\n return 'openai-codex-responses'\n default:\n return 'openai-completions'\n }\n}\n\nfunction resolveBaseUrl(providerName: string, env: NodeJS.ProcessEnv): string | undefined {\n if (providerName === 'lmstudio') return env.LMSTUDIO_URL ?? 'http://127.0.0.1:1234/v1'\n if (providerName === 'ollama') return env.OLLAMA_URL ?? 'http://127.0.0.1:11434/v1'\n return undefined\n}\n\nfunction resolveApiKey(providerName: string, env: NodeJS.ProcessEnv): string | undefined {\n // Hand-written table mirroring loadProviderConfigFromEnv — cheaper than\n // spinning up a whole ProviderRegistry just to pluck one field.\n switch (providerName) {\n case 'anthropic':\n return env.ANTHROPIC_OAUTH_TOKEN ?? env.ANTHROPIC_API_KEY\n case 'openai':\n return env.OPENAI_API_KEY\n case 'google':\n return env.GEMINI_API_KEY\n case 'mistral':\n return env.MISTRAL_API_KEY\n case 'groq':\n return env.GROQ_API_KEY\n case 'cerebras':\n return env.CEREBRAS_API_KEY\n case 'xai':\n return env.XAI_API_KEY\n case 'zai':\n return env.ZAI_API_KEY\n case 'huggingface':\n return env.HF_TOKEN\n case 'openrouter':\n return env.OPENROUTER_API_KEY\n case 'vercel-ai-gateway':\n return env.AI_GATEWAY_API_KEY\n case 'azure-openai':\n return env.AZURE_OPENAI_API_KEY\n case 'lmstudio':\n return env.LMSTUDIO_API_KEY ?? 'lm-studio'\n case 'ollama':\n return env.OLLAMA_API_KEY ?? 'ollama'\n default:\n return undefined\n }\n}\n\nfunction toPiThinkingLevel(level: string): ThinkingLevel {\n switch (level) {\n case 'off':\n case 'minimal':\n case 'low':\n case 'medium':\n case 'high':\n case 'xhigh':\n return level\n default:\n return 'medium'\n }\n}\n\n/**\n * Minimal `ResourceLoader` implementation — feeds pi our Bazilion-authored\n * system prompt block via `getAppendSystemPrompt` and returns empty collections\n * for everything else. Pi's default loader reads skill/prompt/theme markdown\n * from the workspace cwd; we intentionally opt out because Bazilion owns skill\n * discovery at the platform level (see `apps/daemon/src/core/skills`).\n */\nfunction createBazilionResourceLoader(appendSystemPrompt: string): ResourceLoader {\n const extensions = { extensions: [], errors: [], runtime: createExtensionRuntime() }\n return {\n getExtensions: () => extensions,\n getSkills: () => ({ skills: [], diagnostics: [] }),\n getPrompts: () => ({ prompts: [], diagnostics: [] }),\n getThemes: () => ({ themes: [], diagnostics: [] }),\n getAgentsFiles: () => ({ agentsFiles: [] }),\n getSystemPrompt: () => undefined,\n getAppendSystemPrompt: () => (appendSystemPrompt ? [appendSystemPrompt] : []),\n extendResources: () => {},\n async reload() {},\n }\n}\n\n/**\n * Re-exported for callers that want to check whether a provider is\n * Bazilion-enabled before even trying to spawn a session (e.g. /context\n * endpoint which builds a session just to enumerate tools).\n */\nexport function isProviderEnabled(db: BazilionDb, providerName: string): boolean {\n const enabled = providerStateRepo.listEnabled(db)\n return enabled.size === 0 || enabled.has(providerName)\n}\n\n/**\n * Escape hatch for callers that need the raw provider registry (e.g. the\n * current /api/providers/test endpoint). Keeps that one endpoint on our\n * existing non-pi path until we migrate it in a follow-up.\n */\nexport function loadEnabledRegistry(db: BazilionDb, authToken: string, env: NodeJS.ProcessEnv) {\n return createProviderRegistry(loadProviderConfigFromEnv(env, { db, authToken }), {\n enabledSet: providerStateRepo.listEnabled(db),\n })\n}\n\n/**\n * Read the most recent session file for an agent *without* spawning a full\n * AgentSession, and return the resolved provider-message view. Used for SSR\n * page loads that only need to render the canonical transcript — no need\n * to boot pi just to inspect the transcript.\n *\n * Returns an empty array when the agent has no prior session (fresh spawn,\n * or post-/reset).\n */\nexport function loadInitialMessages(agent: ResolvedAgent, paths: Paths): AgentMessage[] {\n const sessionDir = join(paths.agentDir(agent.agent.id), 'sessions')\n if (!existsSync(sessionDir)) return []\n const cwd = agent.group.path\n if (!existsSync(cwd)) return []\n const recent = findMostRecent(sessionDir)\n if (!recent) return []\n try {\n const sm = SessionManager.open(recent, sessionDir)\n const ctx = sm.buildSessionContext()\n return ctx.messages\n } catch (err) {\n // Corrupt session file, stale format, or pi version bump — log loud\n // enough that an operator noticing a blank chat can find the cause in\n // server logs. The turn loop itself starts a fresh session on the\n // next message, so this isn't load-bearing for writes, only reads.\n console.error(\n `[session] loadInitialMessages failed for agent ${agent.agent.id} (${recent}):`,\n err instanceof Error ? (err.stack ?? err.message) : err,\n )\n return []\n }\n}\n\n/**\n * Cheap \"has the session changed?\" probe for polling clients (the web chat\n * stale-tab banner). Returns the most recent session file's basename plus\n * byte size — append-only JSONL, so either value moving means new activity.\n * Returns `{ file: null, size: 0 }` for agents that have never had a turn.\n */\nexport function loadSessionHead(\n agent: ResolvedAgent,\n paths: Paths,\n): { file: string | null; size: number } {\n const sessionDir = join(paths.agentDir(agent.agent.id), 'sessions')\n if (!existsSync(sessionDir)) return { file: null, size: 0 }\n const recent = findMostRecent(sessionDir)\n if (!recent) return { file: null, size: 0 }\n try {\n const s = statSync(recent)\n return { file: basename(recent), size: s.size }\n } catch {\n return { file: null, size: 0 }\n }\n}\n\n/**\n * Test helper: seed a pi session file for an agent with `n` synthetic\n * user/assistant message pairs. Writes a real JSONL entry tree via\n * SessionManager so round-tripping through pi's own reader stays honest.\n * Exported from runtime rather than lived in tests because tests in apps/cli\n * can't directly import pi packages (not a direct dep).\n */\nexport function seedSessionForTest(\n agent: ResolvedAgent,\n paths: Paths,\n messages: Array<{ role: 'user' | 'assistant'; text: string }>,\n): void {\n const cwd = agent.group.path\n if (!existsSync(cwd)) mkdirSync(cwd, { recursive: true })\n const sessionDir = join(paths.agentDir(agent.agent.id), 'sessions')\n mkdirSync(sessionDir, { recursive: true })\n const sm = SessionManager.create(cwd, sessionDir)\n const now = Date.now()\n messages.forEach((m, i) => {\n if (m.role === 'user') {\n sm.appendMessage({\n role: 'user',\n content: [{ type: 'text', text: m.text }],\n timestamp: now + i,\n })\n } else {\n sm.appendMessage({\n role: 'assistant',\n content: [{ type: 'text', text: m.text }],\n api: 'openai-completions',\n provider: 'lmstudio',\n model: 'test-model',\n usage: {\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheWrite: 0,\n totalTokens: 0,\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n },\n stopReason: 'stop',\n timestamp: now + i,\n })\n }\n })\n}\n\n/**\n * Test helper: count message entries on the current leaf's branch of the\n * agent's most-recent session file. Returns 0 when no session file exists.\n */\nexport function countSessionMessagesForTest(agent: ResolvedAgent, paths: Paths): number {\n const sessionDir = join(paths.agentDir(agent.agent.id), 'sessions')\n const recent = findMostRecent(sessionDir)\n if (!recent) return 0\n const cwd = agent.group.path\n try {\n const sm = SessionManager.open(recent, sessionDir, cwd)\n return sm.getBranch().filter((e) => e.type === 'message').length\n } catch {\n return 0\n }\n}\n\n/** Newest `.jsonl` in a pi session directory by mtime, or null if empty. */\nfunction findMostRecent(sessionDir: string): string | null {\n if (!existsSync(sessionDir)) return null\n let newest: { path: string; mtimeMs: number } | null = null\n for (const entry of readdirSync(sessionDir)) {\n if (!entry.endsWith('.jsonl')) continue\n const path = join(sessionDir, entry)\n try {\n const s = statSync(path)\n if (!newest || s.mtimeMs > newest.mtimeMs) newest = { path, mtimeMs: s.mtimeMs }\n } catch {\n // ignore races\n }\n }\n return newest?.path ?? null\n}\n","// Adapter from Bazilion's Provider interface → pi-ai's streamSimple.\n//\n// Pi-ai (`@earendil-works/pi-ai`) is Mario Zechner's unified LLM SDK — 15+\n// providers behind one event-stream API. This file is the only place in the\n// codebase that touches pi-ai directly; everything else downstream\n// (`runTurnStream`, `persistRun`, the worker entry, CLI, web) sees the same\n// `Provider.chat(ProviderRequest): Promise<ProviderResponse>` contract it\n// always has. That keeps the wire format, DB schema, and chat UI stable while\n// giving us cost/usage, thinking levels, prompt caching, and every provider\n// pi supports — for free.\n//\n// Model resolution: we prefer pi's typed catalog via `getModel(provider, id)`\n// which carries cost + context-window metadata; for anything outside the\n// catalog (local models, newly-released models, custom OpenAI-compat\n// endpoints) we construct a `Model<>` literal with sensible defaults. This\n// preserves Bazilion's \"any model string\" flexibility.\n\nimport type { ProviderMessage, ReasoningLevel, ToolCall, ToolDef } from '@bazilion/api-types'\nimport {\n type AssistantMessage,\n getModel,\n type Model,\n type Message as PiMessage,\n type Tool as PiTool,\n type ToolCall as PiToolCall,\n streamSimple,\n type TextContent,\n Type,\n} from '@earendil-works/pi-ai'\nimport type { Provider, ProviderRequest, ProviderResponse, StopReason } from './types.ts'\n\nexport interface PiProviderConfig {\n /** Display name on the returned Provider; also the registry key (e.g. 'bedrock', 'azure-openai'). */\n providerName: string\n /** Pi's canonical provider name for catalog lookup (e.g. 'amazon-bedrock', 'azure-openai-responses'). Defaults to providerName. */\n piProviderName?: string\n /** Override baseUrl for openai-compat endpoints (lmstudio, ollama, custom). */\n baseUrl?: string\n /**\n * Static key or an async supplier. Suppliers are called at the top of each\n * chat() so OAuth-backed providers can refresh expiring tokens without\n * rebuilding the Provider instance (which the registry caches).\n */\n apiKey?: string | (() => string | Promise<string>)\n /** Which pi `Api` to use when the model isn't in pi's catalog. */\n fallbackApi: string\n}\n\nfunction defaultBaseUrlFor(providerName: string): string {\n switch (providerName) {\n case 'lmstudio':\n return process.env.LMSTUDIO_URL ?? 'http://127.0.0.1:1234/v1'\n case 'ollama':\n return process.env.OLLAMA_URL ?? 'http://127.0.0.1:11434/v1'\n default:\n return ''\n }\n}\n\nfunction buildModelLiteral(cfg: PiProviderConfig, modelId: string): Model<string> {\n return {\n id: modelId,\n name: modelId,\n api: cfg.fallbackApi,\n provider: cfg.providerName,\n baseUrl: cfg.baseUrl ?? defaultBaseUrlFor(cfg.providerName),\n reasoning: false,\n input: ['text'],\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n contextWindow: 32_768,\n maxTokens: 4_096,\n }\n}\n\nexport function resolveModel(cfg: PiProviderConfig, modelId: string): Model<string> {\n const lookupName = cfg.piProviderName ?? cfg.providerName\n // Try pi's typed catalog first — gets us cost, context window, reasoning flags\n // for free on the known providers' known models.\n try {\n // getModel's type signature is catalog-constrained, but at runtime it just\n // indexes MODELS[provider][id]. Cast through unknown so unknown ids fall\n // through to the literal builder instead of tripping the compiler.\n const known = (getModel as unknown as (p: string, m: string) => Model<string> | undefined)(\n lookupName,\n modelId,\n )\n if (known && typeof known === 'object' && 'api' in known) {\n // Override baseUrl + provider for local / compat endpoints — pi's catalog\n // doesn't know about lmstudio/ollama but if a user types\n // `openai:gpt-4o` with a custom OPENAI_BASE_URL, honor that here.\n if (cfg.baseUrl) return { ...known, baseUrl: cfg.baseUrl }\n return known\n }\n } catch {\n // Fall through.\n }\n return buildModelLiteral(cfg, modelId)\n}\n\nfunction convertMessages(messages: ProviderMessage[]): PiMessage[] {\n const out: PiMessage[] = []\n const now = Date.now()\n for (const m of messages) {\n if (m.role === 'system') continue // pi takes system prompt separately\n if (m.role === 'user') {\n out.push({ role: 'user', content: m.content, timestamp: now })\n continue\n }\n if (m.role === 'assistant') {\n const content: AssistantMessage['content'] = []\n if (m.content) content.push({ type: 'text', text: m.content } satisfies TextContent)\n if (m.toolCalls) {\n for (const tc of m.toolCalls) {\n let parsed: Record<string, unknown> = {}\n try {\n parsed = JSON.parse(tc.arguments) as Record<string, unknown>\n } catch {\n // leave empty\n }\n content.push({\n type: 'toolCall',\n id: tc.id,\n name: tc.name,\n arguments: parsed,\n } satisfies PiToolCall)\n }\n }\n // Synthesize the AssistantMessage fields pi expects on replays — these\n // are only load-bearing for the LLM that gets the transcript; since we\n // don't persist usage/stopReason in Bazilion's message store, defaults\n // are fine.\n out.push({\n role: 'assistant',\n content,\n api: 'anthropic-messages',\n provider: 'anthropic',\n model: 'unknown',\n usage: {\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheWrite: 0,\n totalTokens: 0,\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n },\n stopReason: 'stop',\n timestamp: now,\n })\n continue\n }\n if (m.role === 'tool') {\n out.push({\n role: 'toolResult',\n toolCallId: m.toolCallId ?? '',\n toolName: m.toolName ?? 'tool',\n content: [{ type: 'text', text: m.content }],\n isError: false,\n timestamp: now,\n })\n }\n }\n return out\n}\n\nfunction convertTools(tools: ToolDef[] | undefined): PiTool[] | undefined {\n if (!tools || tools.length === 0) return undefined\n return tools.map((t) => ({\n name: t.name,\n description: t.description,\n // Type.Unsafe lets us pass raw JSON Schema through without re-authoring in\n // typebox. Providers validate against the schema, not typebox's TSchema.\n parameters: Type.Unsafe<unknown>(t.parameters as Record<string, unknown>),\n }))\n}\n\nfunction toBazilionStopReason(reason: string): StopReason {\n switch (reason) {\n case 'stop':\n return 'stop'\n case 'length':\n return 'length'\n case 'toolUse':\n return 'tool_use'\n default:\n return 'error'\n }\n}\n\nfunction extractFinalResponse(msg: AssistantMessage): ProviderResponse {\n let text = ''\n const toolCalls: ToolCall[] = []\n for (const block of msg.content) {\n if (block.type === 'text') {\n text += block.text\n } else if (block.type === 'toolCall') {\n toolCalls.push({\n id: block.id,\n name: block.name,\n arguments: JSON.stringify(block.arguments ?? {}),\n })\n }\n }\n const res: ProviderResponse = {\n content: text,\n toolCalls,\n stopReason: toBazilionStopReason(msg.stopReason),\n }\n if (msg.usage) {\n res.usage = {\n promptTokens: msg.usage.input,\n completionTokens: msg.usage.output,\n }\n }\n return res\n}\n\nfunction mapReasoning(\n r: ReasoningLevel | undefined,\n): 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | undefined {\n if (!r || r === 'off') return undefined\n return r\n}\n\nasync function resolveApiKey(cfg: PiProviderConfig): Promise<string | undefined> {\n if (typeof cfg.apiKey === 'function') return await cfg.apiKey()\n return cfg.apiKey\n}\n\nexport function piProvider(cfg: PiProviderConfig): Provider {\n return {\n name: cfg.providerName,\n async chat(req: ProviderRequest): Promise<ProviderResponse> {\n const model = resolveModel(cfg, req.model)\n const apiKey = await resolveApiKey(cfg)\n\n const stream = streamSimple(\n model,\n {\n systemPrompt: req.system ?? '',\n messages: convertMessages(req.messages),\n tools: convertTools(req.tools),\n },\n {\n signal: req.signal,\n apiKey,\n reasoning: mapReasoning(req.reasoning),\n maxTokens: req.maxTokens,\n temperature: req.temperature,\n },\n )\n\n let finalMessage: AssistantMessage | null = null\n for await (const event of stream) {\n if (event.type === 'text_delta' && req.onDelta) {\n req.onDelta(event.delta)\n } else if (event.type === 'done') {\n finalMessage = event.message\n } else if (event.type === 'error') {\n finalMessage = event.error\n }\n }\n if (!finalMessage) {\n throw new Error(`pi provider ${cfg.providerName} returned no terminal event`)\n }\n if (finalMessage.stopReason === 'aborted' || finalMessage.stopReason === 'error') {\n const msg = finalMessage.errorMessage ?? 'provider error'\n throw new Error(msg)\n }\n return extractFinalResponse(finalMessage)\n },\n }\n}\n","// Transient-error retry wrapper for Provider.chat().\n//\n// Applied uniformly in `createProviderRegistry` so every provider (anthropic,\n// openai, openai-codex, lmstudio, ollama, …) gets the same retry policy. A\n// one-shot upstream 5xx or rate-limit shouldn't kill the agent's turn — the\n// runtime marks the run `failed` and the user is stuck re-sending the same\n// message by hand, which is hostile UX.\n//\n// What counts as retryable is a small allowlist (server 5xx, rate-limit, a\n// handful of network errnos). Auth errors, invalid-request errors, context\n// overflows, and user-triggered aborts bypass retry entirely — they won't\n// resolve by trying again and the fast failure is the right signal.\n//\n// One hard rule: if the underlying chat already streamed text back via\n// onDelta, we can't retry — a second attempt would emit duplicated text into\n// the UI. The wrapper detects this by shadowing onDelta and tracking whether\n// the callback fired.\n\nimport type { Provider, ProviderRequest, ProviderResponse } from './types.ts'\n\nexport interface RetryOptions {\n /** How many *extra* attempts beyond the first. Default 2 → up to 3 tries total. */\n maxRetries?: number\n /** First backoff delay in ms. Doubles each retry up to maxDelayMs. Default 500. */\n initialDelayMs?: number\n /** Upper bound on a single backoff delay. Default 8000. */\n maxDelayMs?: number\n /** Optional callback invoked before each retry (for logging / telemetry). */\n onRetry?: (info: { attempt: number; delayMs: number; error: Error }) => void\n}\n\n/**\n * Lowercased substrings that mark an error as worth retrying. Checked with a\n * simple `includes` so we don't need to parse the upstream JSON shapes.\n */\nconst RETRYABLE_MARKERS: readonly string[] = [\n 'server_error',\n 'internal_server',\n 'rate_limit',\n 'rate limit',\n 'too many requests',\n 'overloaded', // covers 'overloaded_error' (Anthropic)\n 'service_unavailable',\n 'service unavailable',\n 'gateway_timeout',\n 'gateway timeout',\n 'bad_gateway',\n 'bad gateway',\n 'econnreset',\n 'etimedout',\n 'econnrefused',\n 'enotfound',\n 'eai_again',\n 'socket hang up',\n 'fetch failed',\n 'network error',\n 'connection reset',\n 'status 429',\n 'status 500',\n 'status 502',\n 'status 503',\n 'status 504',\n '\"status\":429',\n '\"status\":500',\n '\"status\":502',\n '\"status\":503',\n '\"status\":504',\n]\n\n/**\n * Non-retryable markers win over retryable ones — if an error mentions\n * authentication or a 4xx (other than 429), retrying won't help.\n */\nconst NON_RETRYABLE_MARKERS: readonly string[] = [\n 'invalid_api_key',\n 'invalid api key',\n 'incorrect_api_key',\n 'authentication',\n 'unauthorized',\n 'permission_denied',\n 'permission denied',\n 'forbidden',\n 'invalid_request',\n 'invalid request',\n 'not_found',\n 'model_not_found',\n 'context_length_exceeded',\n 'context length',\n 'content_filter',\n 'quota_exceeded',\n 'insufficient_quota',\n 'billing',\n 'status 400',\n 'status 401',\n 'status 403',\n 'status 404',\n 'status 422',\n]\n\nexport function isRetryableError(err: unknown): boolean {\n const raw = err instanceof Error ? err.message : typeof err === 'string' ? err : String(err)\n const msg = raw.toLowerCase()\n for (const deny of NON_RETRYABLE_MARKERS) {\n if (msg.includes(deny)) return false\n }\n for (const allow of RETRYABLE_MARKERS) {\n if (msg.includes(allow)) return true\n }\n return false\n}\n\nfunction sleepWithAbort(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(new Error('aborted'))\n return\n }\n const t = setTimeout(() => {\n if (signal) signal.removeEventListener('abort', onAbort)\n resolve()\n }, ms)\n const onAbort = () => {\n clearTimeout(t)\n reject(new Error('aborted'))\n }\n signal?.addEventListener('abort', onAbort, { once: true })\n })\n}\n\nexport function withRetry(provider: Provider, opts: RetryOptions = {}): Provider {\n const maxRetries = opts.maxRetries ?? 2\n const initialDelayMs = opts.initialDelayMs ?? 500\n const maxDelayMs = opts.maxDelayMs ?? 8_000\n\n return {\n name: provider.name,\n async chat(req: ProviderRequest): Promise<ProviderResponse> {\n let attempt = 0\n // Use `let` so each retry gets a fresh shadow; we need to know whether\n // onDelta fired on the *most recent* attempt.\n let lastError: Error | null = null\n while (true) {\n let streamed = false\n const wrappedReq: ProviderRequest = req.onDelta\n ? {\n ...req,\n onDelta: (delta: string) => {\n streamed = true\n req.onDelta?.(delta)\n },\n }\n : req\n try {\n return await provider.chat(wrappedReq)\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err))\n if (req.signal?.aborted) throw lastError\n if (streamed) throw lastError\n if (attempt >= maxRetries) throw lastError\n if (!isRetryableError(lastError)) throw lastError\n const delayMs = Math.min(initialDelayMs * 2 ** attempt, maxDelayMs)\n opts.onRetry?.({ attempt: attempt + 1, delayMs, error: lastError })\n try {\n await sleepWithAbort(delayMs, req.signal)\n } catch {\n // Aborted during backoff — surface the original provider error\n // rather than the synthetic abort so the run's failure reason\n // still points at what actually went wrong.\n throw lastError\n }\n attempt++\n }\n }\n },\n }\n}\n","import type { BazilionDb } from '../../core/index.ts'\nimport {\n hasCredentials as hasOpenAICodexCredentials,\n loadAccessToken as loadOpenAICodexAccessToken,\n} from '../auth/openai-codex.ts'\nimport { piProvider } from './pi-adapter.ts'\nimport { type RetryOptions, withRetry } from './retry.ts'\nimport type { Provider } from './types.ts'\n\nexport interface ProviderConfig {\n anthropic?: { apiKey: string; baseURL?: string }\n openai?: { apiKey: string; baseURL?: string }\n /** ChatGPT/Codex OAuth. The apiKey is fetched+refreshed lazily from secrets. */\n openaiCodex?: { db: BazilionDb; authToken: string }\n google?: { apiKey: string; baseURL?: string }\n azureOpenai?: { apiKey: string; baseURL?: string }\n bedrock?: { apiKey?: string } // auth via AWS SDK env (AWS_PROFILE / AWS_ACCESS_KEY_ID / ...)\n googleVertex?: Record<string, never> // auth via ADC + GOOGLE_CLOUD_PROJECT\n mistral?: { apiKey: string; baseURL?: string }\n groq?: { apiKey: string; baseURL?: string }\n cerebras?: { apiKey: string; baseURL?: string }\n xai?: { apiKey: string; baseURL?: string }\n zai?: { apiKey: string; baseURL?: string }\n huggingface?: { apiKey: string; baseURL?: string }\n openrouter?: { apiKey: string; baseURL?: string }\n vercelAiGateway?: { apiKey: string; baseURL?: string }\n // Providers added in pi-ai 0.70–0.75.\n deepseek?: { apiKey: string; baseURL?: string }\n fireworks?: { apiKey: string; baseURL?: string }\n together?: { apiKey: string; baseURL?: string }\n moonshotai?: { apiKey: string; baseURL?: string }\n kimiCoding?: { apiKey: string; baseURL?: string }\n minimax?: { apiKey: string; baseURL?: string }\n xiaomi?: { apiKey: string; baseURL?: string }\n opencode?: { apiKey: string; baseURL?: string }\n githubCopilot?: { apiKey: string }\n cloudflareAiGateway?: { apiKey: string; accountId?: string; gatewayId?: string }\n cloudflareWorkersAi?: { apiKey: string; accountId?: string }\n lmstudio?: { baseURL?: string; apiKey?: string }\n ollama?: { baseURL?: string; apiKey?: string }\n llamacpp?: { baseURL?: string; apiKey?: string }\n}\n\nexport interface ResolvedModel {\n provider: Provider\n model: string\n}\n\n/**\n * Env var → provider config. Empty / missing vars leave that provider unconfigured.\n *\n * Pass `oauth` (the daemon's `{db, authToken}` pair) to also pick up\n * OAuth-backed providers whose credentials live in the `secrets` table\n * (currently: `openai-codex` / ChatGPT). Env-only callers can omit it —\n * those providers just won't be configured.\n */\nexport function loadProviderConfigFromEnv(\n env: NodeJS.ProcessEnv = process.env,\n oauth?: { db: BazilionDb; authToken: string },\n): ProviderConfig {\n const config: ProviderConfig = {\n lmstudio: {\n ...(env.LMSTUDIO_URL !== undefined ? { baseURL: env.LMSTUDIO_URL } : {}),\n ...(env.LMSTUDIO_API_KEY !== undefined ? { apiKey: env.LMSTUDIO_API_KEY } : {}),\n },\n ollama: {\n ...(env.OLLAMA_URL !== undefined ? { baseURL: env.OLLAMA_URL } : {}),\n ...(env.OLLAMA_API_KEY !== undefined ? { apiKey: env.OLLAMA_API_KEY } : {}),\n },\n llamacpp: {\n ...(env.LLAMACPP_URL !== undefined ? { baseURL: env.LLAMACPP_URL } : {}),\n ...(env.LLAMACPP_API_KEY !== undefined ? { apiKey: env.LLAMACPP_API_KEY } : {}),\n },\n }\n if (env.ANTHROPIC_API_KEY || env.ANTHROPIC_OAUTH_TOKEN) {\n config.anthropic = { apiKey: env.ANTHROPIC_OAUTH_TOKEN ?? env.ANTHROPIC_API_KEY ?? '' }\n }\n if (env.OPENAI_API_KEY) config.openai = { apiKey: env.OPENAI_API_KEY }\n if (env.GEMINI_API_KEY) config.google = { apiKey: env.GEMINI_API_KEY }\n if (env.AZURE_OPENAI_API_KEY) config.azureOpenai = { apiKey: env.AZURE_OPENAI_API_KEY }\n if (\n env.AWS_PROFILE ||\n env.AWS_BEARER_TOKEN_BEDROCK ||\n (env.AWS_ACCESS_KEY_ID && env.AWS_SECRET_ACCESS_KEY)\n ) {\n config.bedrock = {}\n }\n if (env.GOOGLE_CLOUD_PROJECT && env.GOOGLE_CLOUD_LOCATION) {\n config.googleVertex = {}\n }\n if (env.MISTRAL_API_KEY) config.mistral = { apiKey: env.MISTRAL_API_KEY }\n if (env.GROQ_API_KEY) config.groq = { apiKey: env.GROQ_API_KEY }\n if (env.CEREBRAS_API_KEY) config.cerebras = { apiKey: env.CEREBRAS_API_KEY }\n if (env.XAI_API_KEY) config.xai = { apiKey: env.XAI_API_KEY }\n if (env.ZAI_API_KEY) config.zai = { apiKey: env.ZAI_API_KEY }\n if (env.HF_TOKEN) config.huggingface = { apiKey: env.HF_TOKEN }\n if (env.OPENROUTER_API_KEY) config.openrouter = { apiKey: env.OPENROUTER_API_KEY }\n if (env.AI_GATEWAY_API_KEY) config.vercelAiGateway = { apiKey: env.AI_GATEWAY_API_KEY }\n if (env.DEEPSEEK_API_KEY) config.deepseek = { apiKey: env.DEEPSEEK_API_KEY }\n if (env.FIREWORKS_API_KEY) config.fireworks = { apiKey: env.FIREWORKS_API_KEY }\n if (env.TOGETHER_API_KEY) config.together = { apiKey: env.TOGETHER_API_KEY }\n if (env.MOONSHOT_API_KEY) config.moonshotai = { apiKey: env.MOONSHOT_API_KEY }\n if (env.KIMI_API_KEY) config.kimiCoding = { apiKey: env.KIMI_API_KEY }\n if (env.MINIMAX_API_KEY) config.minimax = { apiKey: env.MINIMAX_API_KEY }\n if (env.XIAOMI_API_KEY) config.xiaomi = { apiKey: env.XIAOMI_API_KEY }\n if (env.OPENCODE_API_KEY) config.opencode = { apiKey: env.OPENCODE_API_KEY }\n if (env.COPILOT_GITHUB_TOKEN) config.githubCopilot = { apiKey: env.COPILOT_GITHUB_TOKEN }\n if (env.CLOUDFLARE_API_KEY && env.CLOUDFLARE_ACCOUNT_ID) {\n config.cloudflareWorkersAi = {\n apiKey: env.CLOUDFLARE_API_KEY,\n accountId: env.CLOUDFLARE_ACCOUNT_ID,\n }\n if (env.CLOUDFLARE_GATEWAY_ID) {\n config.cloudflareAiGateway = {\n apiKey: env.CLOUDFLARE_API_KEY,\n accountId: env.CLOUDFLARE_ACCOUNT_ID,\n gatewayId: env.CLOUDFLARE_GATEWAY_ID,\n }\n }\n }\n if (oauth && hasOpenAICodexCredentials(oauth.db, oauth.authToken)) {\n config.openaiCodex = oauth\n }\n return config\n}\n\nexport interface ProviderRegistry {\n resolve(modelString: string): ResolvedModel\n list(): string[]\n}\n\nexport interface ProviderRegistryOptions {\n /** If provided, resolve() refuses any provider not in the set with \"disabled by admin\". */\n enabledSet?: ReadonlySet<string>\n /** Retry policy applied uniformly to every provider; omit for built-in defaults. */\n retry?: RetryOptions\n}\n\ninterface ProviderEntry {\n configured: (c: ProviderConfig) => boolean\n build: (c: ProviderConfig) => Provider\n /** Helpful error hint when the caller references this provider but env isn't set. */\n hint: string\n}\n\nconst PROVIDERS: Record<string, ProviderEntry> = {\n anthropic: {\n configured: (c) => !!c.anthropic,\n build: (c) =>\n piProvider({\n providerName: 'anthropic',\n fallbackApi: 'anthropic-messages',\n apiKey: c.anthropic?.apiKey,\n baseUrl: c.anthropic?.baseURL,\n }),\n hint: 'ANTHROPIC_API_KEY or ANTHROPIC_OAUTH_TOKEN',\n },\n openai: {\n configured: (c) => !!c.openai,\n build: (c) =>\n piProvider({\n providerName: 'openai',\n fallbackApi: 'openai-completions',\n apiKey: c.openai?.apiKey,\n baseUrl: c.openai?.baseURL,\n }),\n hint: 'OPENAI_API_KEY',\n },\n 'openai-codex': {\n configured: (c) => !!c.openaiCodex,\n // Pi-ai's `openai-codex-responses` speaks the ChatGPT backend's Responses\n // API (https://chatgpt.com/backend-api) using a JWT access token as the\n // apiKey. We pass a supplier that refreshes lazily via the OAuth refresh\n // token, so the registry-cached Provider instance stays valid across\n // expiries without rebuild.\n build: (c) => {\n const openaiCodex = c.openaiCodex\n if (!openaiCodex) throw new Error('openai-codex not configured')\n return piProvider({\n providerName: 'openai-codex',\n fallbackApi: 'openai-codex-responses',\n apiKey: () => loadOpenAICodexAccessToken(openaiCodex.db, openaiCodex.authToken),\n })\n },\n hint: 'run `bazilion auth openai login` (or click Connect on /config)',\n },\n google: {\n configured: (c) => !!c.google,\n build: (c) =>\n piProvider({\n providerName: 'google',\n fallbackApi: 'google-generative-ai',\n apiKey: c.google?.apiKey,\n baseUrl: c.google?.baseURL,\n }),\n hint: 'GEMINI_API_KEY',\n },\n 'google-vertex': {\n configured: (c) => !!c.googleVertex,\n build: () => piProvider({ providerName: 'google-vertex', fallbackApi: 'google-vertex' }),\n hint: 'GOOGLE_CLOUD_PROJECT + GOOGLE_CLOUD_LOCATION + ADC (gcloud auth)',\n },\n 'azure-openai': {\n configured: (c) => !!c.azureOpenai,\n build: (c) =>\n piProvider({\n providerName: 'azure-openai',\n fallbackApi: 'azure-openai-responses',\n apiKey: c.azureOpenai?.apiKey,\n baseUrl: c.azureOpenai?.baseURL,\n }),\n hint: 'AZURE_OPENAI_API_KEY',\n },\n bedrock: {\n configured: (c) => !!c.bedrock,\n build: () =>\n piProvider({\n providerName: 'bedrock',\n piProviderName: 'amazon-bedrock',\n fallbackApi: 'bedrock-converse-stream',\n }),\n hint: 'AWS_PROFILE or AWS_ACCESS_KEY_ID+AWS_SECRET_ACCESS_KEY',\n },\n mistral: {\n configured: (c) => !!c.mistral,\n build: (c) =>\n piProvider({\n providerName: 'mistral',\n fallbackApi: 'openai-completions',\n apiKey: c.mistral?.apiKey,\n baseUrl: c.mistral?.baseURL,\n }),\n hint: 'MISTRAL_API_KEY',\n },\n groq: {\n configured: (c) => !!c.groq,\n build: (c) =>\n piProvider({\n providerName: 'groq',\n fallbackApi: 'openai-completions',\n apiKey: c.groq?.apiKey,\n baseUrl: c.groq?.baseURL,\n }),\n hint: 'GROQ_API_KEY',\n },\n cerebras: {\n configured: (c) => !!c.cerebras,\n build: (c) =>\n piProvider({\n providerName: 'cerebras',\n fallbackApi: 'openai-completions',\n apiKey: c.cerebras?.apiKey,\n baseUrl: c.cerebras?.baseURL,\n }),\n hint: 'CEREBRAS_API_KEY',\n },\n xai: {\n configured: (c) => !!c.xai,\n build: (c) =>\n piProvider({\n providerName: 'xai',\n fallbackApi: 'openai-completions',\n apiKey: c.xai?.apiKey,\n baseUrl: c.xai?.baseURL,\n }),\n hint: 'XAI_API_KEY',\n },\n zai: {\n configured: (c) => !!c.zai,\n build: (c) =>\n piProvider({\n providerName: 'zai',\n fallbackApi: 'openai-completions',\n apiKey: c.zai?.apiKey,\n baseUrl: c.zai?.baseURL,\n }),\n hint: 'ZAI_API_KEY',\n },\n huggingface: {\n configured: (c) => !!c.huggingface,\n build: (c) =>\n piProvider({\n providerName: 'huggingface',\n fallbackApi: 'openai-completions',\n apiKey: c.huggingface?.apiKey,\n baseUrl: c.huggingface?.baseURL,\n }),\n hint: 'HF_TOKEN',\n },\n openrouter: {\n configured: (c) => !!c.openrouter,\n build: (c) =>\n piProvider({\n providerName: 'openrouter',\n fallbackApi: 'openai-completions',\n apiKey: c.openrouter?.apiKey,\n baseUrl: c.openrouter?.baseURL,\n }),\n hint: 'OPENROUTER_API_KEY',\n },\n 'vercel-ai-gateway': {\n configured: (c) => !!c.vercelAiGateway,\n build: (c) =>\n piProvider({\n providerName: 'vercel-ai-gateway',\n fallbackApi: 'openai-completions',\n apiKey: c.vercelAiGateway?.apiKey,\n baseUrl: c.vercelAiGateway?.baseURL,\n }),\n hint: 'AI_GATEWAY_API_KEY',\n },\n deepseek: {\n configured: (c) => !!c.deepseek,\n build: (c) =>\n piProvider({\n providerName: 'deepseek',\n fallbackApi: 'openai-completions',\n apiKey: c.deepseek?.apiKey,\n baseUrl: c.deepseek?.baseURL,\n }),\n hint: 'DEEPSEEK_API_KEY',\n },\n fireworks: {\n configured: (c) => !!c.fireworks,\n build: (c) =>\n piProvider({\n providerName: 'fireworks',\n fallbackApi: 'anthropic-messages',\n apiKey: c.fireworks?.apiKey,\n baseUrl: c.fireworks?.baseURL,\n }),\n hint: 'FIREWORKS_API_KEY',\n },\n together: {\n configured: (c) => !!c.together,\n build: (c) =>\n piProvider({\n providerName: 'together',\n fallbackApi: 'openai-completions',\n apiKey: c.together?.apiKey,\n baseUrl: c.together?.baseURL,\n }),\n hint: 'TOGETHER_API_KEY',\n },\n moonshotai: {\n configured: (c) => !!c.moonshotai,\n build: (c) =>\n piProvider({\n providerName: 'moonshotai',\n fallbackApi: 'openai-completions',\n apiKey: c.moonshotai?.apiKey,\n baseUrl: c.moonshotai?.baseURL,\n }),\n hint: 'MOONSHOT_API_KEY',\n },\n 'kimi-coding': {\n configured: (c) => !!c.kimiCoding,\n build: (c) =>\n piProvider({\n providerName: 'kimi-coding',\n fallbackApi: 'anthropic-messages',\n apiKey: c.kimiCoding?.apiKey,\n baseUrl: c.kimiCoding?.baseURL,\n }),\n hint: 'KIMI_API_KEY',\n },\n minimax: {\n configured: (c) => !!c.minimax,\n build: (c) =>\n piProvider({\n providerName: 'minimax',\n fallbackApi: 'anthropic-messages',\n apiKey: c.minimax?.apiKey,\n baseUrl: c.minimax?.baseURL,\n }),\n hint: 'MINIMAX_API_KEY',\n },\n xiaomi: {\n configured: (c) => !!c.xiaomi,\n build: (c) =>\n piProvider({\n providerName: 'xiaomi',\n fallbackApi: 'openai-completions',\n apiKey: c.xiaomi?.apiKey,\n baseUrl: c.xiaomi?.baseURL,\n }),\n hint: 'XIAOMI_API_KEY',\n },\n opencode: {\n configured: (c) => !!c.opencode,\n build: (c) =>\n piProvider({\n providerName: 'opencode',\n fallbackApi: 'openai-completions',\n apiKey: c.opencode?.apiKey,\n baseUrl: c.opencode?.baseURL,\n }),\n hint: 'OPENCODE_API_KEY',\n },\n 'github-copilot': {\n configured: (c) => !!c.githubCopilot,\n build: (c) =>\n piProvider({\n providerName: 'github-copilot',\n fallbackApi: 'anthropic-messages',\n apiKey: c.githubCopilot?.apiKey,\n }),\n hint: 'COPILOT_GITHUB_TOKEN (generic GH_TOKEN/GITHUB_TOKEN are ignored)',\n },\n 'cloudflare-ai-gateway': {\n configured: (c) => !!c.cloudflareAiGateway,\n build: (c) =>\n piProvider({\n providerName: 'cloudflare-ai-gateway',\n fallbackApi: 'anthropic-messages',\n apiKey: c.cloudflareAiGateway?.apiKey,\n }),\n hint: 'CLOUDFLARE_API_KEY + CLOUDFLARE_ACCOUNT_ID + CLOUDFLARE_GATEWAY_ID',\n },\n 'cloudflare-workers-ai': {\n configured: (c) => !!c.cloudflareWorkersAi,\n build: (c) =>\n piProvider({\n providerName: 'cloudflare-workers-ai',\n fallbackApi: 'openai-completions',\n apiKey: c.cloudflareWorkersAi?.apiKey,\n }),\n hint: 'CLOUDFLARE_API_KEY + CLOUDFLARE_ACCOUNT_ID',\n },\n lmstudio: {\n configured: () => true,\n build: (c) =>\n piProvider({\n providerName: 'lmstudio',\n fallbackApi: 'openai-completions',\n apiKey: c.lmstudio?.apiKey ?? 'lm-studio',\n baseUrl: c.lmstudio?.baseURL ?? 'http://127.0.0.1:1234/v1',\n }),\n hint: 'LMSTUDIO_URL (default http://127.0.0.1:1234/v1)',\n },\n ollama: {\n configured: () => true,\n build: (c) =>\n piProvider({\n providerName: 'ollama',\n fallbackApi: 'openai-completions',\n apiKey: c.ollama?.apiKey ?? 'ollama',\n baseUrl: c.ollama?.baseURL ?? 'http://127.0.0.1:11434/v1',\n }),\n hint: 'OLLAMA_URL (default http://127.0.0.1:11434/v1)',\n },\n llamacpp: {\n // Like lmstudio/ollama, always considered \"configured\" — the daemon\n // can't tell if llama-server is actually running until a request hits\n // it. Falls back to the documented default port + a placeholder\n // apiKey (llama-server ignores it unless --api-key was passed).\n configured: () => true,\n build: (c) =>\n piProvider({\n providerName: 'llamacpp',\n fallbackApi: 'openai-completions',\n apiKey: c.llamacpp?.apiKey ?? 'no-key',\n baseUrl: c.llamacpp?.baseURL ?? 'http://127.0.0.1:8080/v1',\n }),\n hint: 'LLAMACPP_URL (default http://127.0.0.1:8080/v1)',\n },\n}\n\n/**\n * Model strings are `provider:model`, e.g.:\n * - `anthropic:claude-opus-4-6`\n * - `openai:gpt-4o`\n * - `google:gemini-2.0-flash-exp`\n * - `groq:llama-3.3-70b-versatile`\n * - `lmstudio:my-loaded-model`\n * - `ollama:llama2`\n */\nexport function createProviderRegistry(\n config: ProviderConfig,\n opts: ProviderRegistryOptions = {},\n): ProviderRegistry {\n const cache = new Map<string, Provider>()\n const enabledSet = opts.enabledSet\n\n function get(name: string): Provider {\n const cached = cache.get(name)\n if (cached) return cached\n const entry = PROVIDERS[name]\n if (!entry) throw new Error(`unknown provider: ${name}`)\n if (enabledSet && !enabledSet.has(name)) {\n throw new Error(`${name} provider is disabled — enable it on the /config page`)\n }\n if (!entry.configured(config)) {\n throw new Error(`${name} provider not configured (set ${entry.hint})`)\n }\n const raw = entry.build(config)\n const provider = withRetry(raw, {\n ...(opts.retry ?? {}),\n onRetry: (info) => {\n opts.retry?.onRetry?.(info)\n console.warn(\n `[provider/${name}] transient error on attempt ${info.attempt}, retrying in ${info.delayMs}ms: ${info.error.message.slice(0, 160)}`,\n )\n },\n })\n cache.set(name, provider)\n return provider\n }\n\n return {\n resolve(modelString: string): ResolvedModel {\n const idx = modelString.indexOf(':')\n if (idx === -1) {\n throw new Error(`invalid model string \"${modelString}\": expected \"provider:model\"`)\n }\n const providerName = modelString.slice(0, idx)\n const model = modelString.slice(idx + 1)\n return { provider: get(providerName), model }\n },\n list() {\n return Object.entries(PROVIDERS)\n .filter(([name, entry]) => {\n if (!entry.configured(config)) return false\n if (enabledSet && !enabledSet.has(name)) return false\n return true\n })\n .map(([name]) => name)\n },\n }\n}\n\nexport interface ProviderMeta {\n name: string\n enabled: boolean\n /** Hint shown when the provider isn't configured — the env var(s) required. */\n envHint: string\n}\n\n/** List every provider the registry knows about, plus whether each is configured. */\nexport function listAllProviders(config: ProviderConfig): ProviderMeta[] {\n return Object.entries(PROVIDERS).map(([name, entry]) => ({\n name,\n enabled: entry.configured(config),\n envHint: entry.hint,\n }))\n}\n","// Bazilion system-prompt builder. Feeds pi's `getAppendSystemPrompt()` hook\n// so the agent sees its persona + skills + workspaces + memory guidance\n// stacked on top of pi's built-in base prompt (which lists coding tools and\n// general guidelines). Pure filesystem read — no LLM, no DB.\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { ResolvedAgent } from '@bazilion/api-types'\n\n// Prompt order: peers first (who else is around), then persona, then tooling\n// hints, then self-knowledge, then the wake-up playbook.\n//\n// BOOTSTRAP.md is intentionally NOT in this generic-context list — it gets\n// its own dedicated \"First-Run Ritual\" section below with explicit\n// anti-checklist framing, so models treat it as multi-turn Q&A guidance\n// rather than a one-shot script to execute. The system prompt regenerates\n// per turn, so the section auto-vanishes when `bootstrap_done` removes the\n// file (vs. wrapping the user message, which would persist in pi's session\n// JSONL forever and replay on every future turn).\nconst CONTEXT_FILE_ORDER = [\n 'AGENTS.md',\n 'SOUL.md',\n 'TOOLS.md',\n 'IDENTITY.md',\n 'HEARTBEAT.md',\n] as const\n\nexport function buildSystemPrompt(agent: ResolvedAgent): string {\n const parts: string[] = []\n\n const contextBlocks: string[] = []\n for (const file of CONTEXT_FILE_ORDER) {\n const path = join(agent.agent.dir, file)\n if (!existsSync(path)) continue\n const content = readFileSync(path, 'utf8').trimEnd()\n if (!content) continue\n contextBlocks.push(`## ${file}\\n\\n${content}`)\n }\n if (contextBlocks.length > 0) {\n parts.push(`# Project Context\\n\\n${contextBlocks.join('\\n\\n')}`)\n }\n\n // First-Run Ritual block — only emitted while BOOTSTRAP.md exists on disk.\n // The wording deliberately frames it as \"multi-turn Q&A\" not \"checklist\"\n // and lists hard rules at the top so tool-eager models still notice them\n // even if they skim the body.\n const bootstrapPath = join(agent.agent.dir, 'BOOTSTRAP.md')\n if (existsSync(bootstrapPath)) {\n const bootstrap = readFileSync(bootstrapPath, 'utf8').trimEnd()\n if (bootstrap) {\n parts.push(\n [\n '# First-Run Ritual',\n '',\n 'This is your first session. The document below is **conversational guidance**, not a checklist to execute in one shot. It describes a multi-turn Q&A you should have with the human, one question per turn.',\n '',\n '## Hard rules',\n '- Your first reply is ONLY a greeting + ONE question. No tool calls. Wait for the human to answer.',\n '- Each subsequent turn: at most one new question. Wait between turns.',\n '- Only after the ritual is complete (you have enough to write IDENTITY.md): call `home_write` once, then `bootstrap_done`.',\n '',\n '## BOOTSTRAP.md',\n '',\n bootstrap,\n ].join('\\n'),\n )\n }\n }\n\n parts.push(\n [\n '# Agent Home',\n '',\n 'Your private home holds who you are — identity, soul, behaviour rules, wake-up routine. It is not shared with other agents and cannot be overwritten by them. The files above (IDENTITY.md, SOUL.md, AGENTS.md, TOOLS.md, HEARTBEAT.md) live in this home, plus BOOTSTRAP.md when you are still in your first-run ritual.',\n '',\n '- To change who you are (name, vibe, personality, how you behave): use `home_write`.',\n '- To inspect exact wording of your own files: use `home_read` or `home_list`.',\n '- To remember facts the user told you or things you learned: use `memory_write` — NOT `home_write`.',\n '- To produce work output (code, docs, artefacts): use `write` / `edit` — those land in your workspace, not your home.',\n ].join('\\n'),\n )\n\n if (agent.skills.length > 0) {\n parts.push(\n `# Available Skills\\n\\nYou have access to the following skills: ${agent.skills.join(', ')}.`,\n )\n }\n\n const groupLines = [\n '# Group',\n '',\n `- ${agent.group.id} (${agent.group.name}): ${agent.group.path}`,\n '',\n 'Your group is where work product lives — code, docs, artefacts, shared scratch. It may be shared with other agents in the same group. Your coding tools (`read`, `bash`, `edit`, `write`, `grep`, `find`, `ls`) are rooted at the group directory. Never use these tools to edit your identity/soul/behaviour files — those live in your home and are reached via `home_write` / `home_read`.',\n ]\n parts.push(groupLines.join('\\n'))\n\n if (agent.group.userMd.trim()) {\n parts.push(\n `# About the User\\n\\nShared context about the human you're working with in this group. Both you and the human curate it. To update: call \\`user_md_get\\` (returns current content + an etag), merge your change into the full text, then call \\`user_md_write\\` with the merged content and the etag. Use this for STABLE user-specific facts (preferences, role, working hours, how they like to be addressed) — and to CORRECT stale entries when the human tells you something different from what's recorded. For project knowledge use \\`memory_write\\` instead; for personal notes about yourself use \\`home_write\\` on IDENTITY.md. **Do NOT send peer messages announcing USER.md changes — every agent in the group sees the new content in their system prompt on their next turn automatically.**\\n\\n${agent.group.userMd.trim()}`,\n )\n } else {\n parts.push(\n `# About the User\\n\\nThis group's USER.md is empty. As you learn STABLE facts about the human (preferences, role, working hours, how they like to be addressed), populate it via \\`user_md_get\\` then \\`user_md_write\\` (always get first — you need the etag). Reserve this for things you're confident are durable — project knowledge belongs in \\`memory_write\\`, personal notes about yourself in \\`home_write\\` on IDENTITY.md. **Do NOT send peer messages announcing USER.md changes — every agent in the group sees the new content in their system prompt on their next turn automatically.**`,\n )\n }\n\n parts.push(\n '# Memory\\n\\nYou share a persistent memory backend with every other agent in this group. Use `memory_write` to remember things across sessions, and `memory_search` / `memory_read` / `memory_list` to recall them. This memory is for project knowledge — codebase notes, decisions, things the user told you about the work. For personal notes about yourself (preferences, persona quirks), use `home_write` on IDENTITY.md instead. Always check memory at the start of a session: another agent in the group may have already learned something useful. **Do NOT send peer messages announcing memory writes — every agent has access to the same store via `memory_search` and will find your note when they need it.**',\n )\n\n return parts.join('\\n\\n---\\n\\n')\n}\n","// Adapter: Bazilion ToolHandler → pi-coding-agent ToolDefinition.\n//\n// Pi expects tools to return `AgentToolResult<TDetails>` =\n// `{ content: (TextContent | ImageContent)[]; details: TDetails; terminate?: boolean }`.\n// Our handlers return plain strings. The adapter wraps the string into a single\n// text content block with empty details — the same fidelity we had before.\n//\n// Pi's tool execute contract: throw on failure. The agent loop wraps thrown\n// errors as tool-result messages with `isError: true`. We preserve this shape\n// directly because our handlers already throw on bad args / runtime failures.\n//\n// What's in this module:\n// - `ourToolToPiTool` — single-handler wrapper.\n// - `createBazilionCustomTools` — composed suite of the Bazilion-specific\n// tools (memory_*, messaging, bootstrap_done, web_search/fetch). File I/O\n// tools are *not* here — pi's createCodingTools(cwd, …) replaces them.\n\nimport type { ResolvedAgent } from '@bazilion/api-types'\nimport type { ToolDefinition } from '@earendil-works/pi-coding-agent'\nimport { Type } from 'typebox'\nimport type { MemoryBackend } from '../memory/types.ts'\nimport { bootstrapTool } from '../tools/bootstrap.ts'\nimport { homeTools } from '../tools/home.ts'\nimport { memoryTools } from '../tools/memory.ts'\nimport { messagingTools } from '../tools/messaging.ts'\nimport type { ToolHandler } from '../tools/types.ts'\nimport { userMdTools } from '../tools/user-md.ts'\nimport { webTools } from '../tools/web.ts'\nimport type { MessagingHost, UserMdHost } from '../worker/ipc-protocol.ts'\n\n/**\n * Wrap a Bazilion `ToolHandler` as a pi `ToolDefinition` so it can be passed\n * through `customTools` to `createAgentSession`.\n *\n * Design note: we keep the same tool name + description + parameter JSON schema\n * that the handler already declares. Pi wants a `TypeBox` schema; we pass the\n * JSONSchema through `Type.Unsafe` so the LLM validation happens on pi's side\n * without us having to re-author schemas in typebox syntax.\n */\nexport function ourToolToPiTool(h: ToolHandler): ToolDefinition {\n return {\n name: h.def.name,\n label: h.def.name,\n description: h.def.description,\n parameters: Type.Unsafe<Record<string, unknown>>(h.def.parameters as Record<string, unknown>),\n async execute(_toolCallId, params) {\n const text = await h.invoke(params as Record<string, unknown>)\n return {\n content: [{ type: 'text', text }],\n details: {},\n }\n },\n }\n}\n\nexport interface BazilionCustomToolsOpts {\n agent: ResolvedAgent\n memory: MemoryBackend\n /** If provided, enables inter-agent messaging tools. */\n messagingHost?: MessagingHost\n /** If provided, enables the `user_md_append` tool. */\n userMdHost?: UserMdHost\n /** Merged env (process.env + secrets). */\n env?: NodeJS.ProcessEnv\n}\n\n/**\n * Build the list of Bazilion-specific custom tools in the shape pi expects.\n *\n * Excludes file-I/O tools (`read`/`bash`/`edit`/`write`/`grep`/`find`/`ls`) —\n * those come from pi's `createCodingTools(cwd, …)` now that we've adopted the\n * richer toolset. Also excludes the legacy `workspace_list/read/write`\n * triumvirate: pi's tools work against a single cwd (the agent's default\n * workspace), and mounted non-default workspaces are reachable via absolute\n * paths through pi's `bash`/`read`/`edit`.\n */\nexport function createBazilionCustomTools(opts: BazilionCustomToolsOpts): ToolDefinition[] {\n const handlers: ToolHandler[] = [\n ...memoryTools(opts.memory),\n ...homeTools(opts.agent.agent.dir),\n bootstrapTool(opts.agent.agent.dir),\n ...webTools({ env: opts.env }),\n ]\n if (opts.messagingHost) {\n handlers.push(...messagingTools(opts.messagingHost, opts.agent.agent.id))\n }\n if (opts.userMdHost) {\n handlers.push(...userMdTools(opts.userMdHost, opts.agent.group.id))\n }\n return handlers.map(ourToolToPiTool)\n}\n","import { existsSync, rmSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { ToolHandler } from './types.ts'\n\nexport function bootstrapTool(agentDir: string): ToolHandler {\n return {\n def: {\n name: 'bootstrap_done',\n description:\n 'Call this once you have finished your bootstrap conversation (introduced yourself, learned the user, updated IDENTITY.md). Removes BOOTSTRAP.md so it does not appear in future sessions.',\n parameters: { type: 'object', properties: {} },\n },\n async invoke() {\n const path = join(agentDir, 'BOOTSTRAP.md')\n if (existsSync(path)) {\n rmSync(path)\n return 'BOOTSTRAP.md removed. Bootstrap is complete.'\n }\n return 'BOOTSTRAP.md was already removed.'\n },\n }\n}\n","import { readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { ToolHandler } from './types.ts'\n\n// Files the agent may read/write in its private home directory.\n// BOOTSTRAP.md is readable but not writable — its lifecycle belongs to\n// the `bootstrap_done` tool, not `home_write`.\nconst HOME_FILES_READABLE = [\n 'IDENTITY.md',\n 'SOUL.md',\n 'BOOTSTRAP.md',\n 'AGENTS.md',\n 'TOOLS.md',\n 'HEARTBEAT.md',\n] as const\n\nconst HOME_FILES_WRITABLE = [\n 'IDENTITY.md',\n 'SOUL.md',\n 'AGENTS.md',\n 'TOOLS.md',\n 'HEARTBEAT.md',\n] as const\n\nexport function homeTools(agentDir: string): ToolHandler[] {\n return [\n {\n def: {\n name: 'home_read',\n description:\n 'Read one of your own home files — your identity, soul, or behaviour rules. These files are private to you and are also injected into your system prompt; read them when you need to quote exact wording or check current state.',\n parameters: {\n type: 'object',\n properties: {\n file: { type: 'string', enum: [...HOME_FILES_READABLE] },\n },\n required: ['file'],\n },\n },\n async invoke(args) {\n const file = String(args.file ?? '')\n if (!HOME_FILES_READABLE.includes(file as (typeof HOME_FILES_READABLE)[number])) {\n throw new Error(\n `home_read: \"file\" must be one of ${HOME_FILES_READABLE.join(', ')}; got \"${file}\"`,\n )\n }\n const path = join(agentDir, file)\n try {\n return readFileSync(path, 'utf8')\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n throw new Error(`home_read: could not read ${file}: ${msg}`)\n }\n },\n },\n {\n def: {\n name: 'home_write',\n description:\n \"Overwrite one of your own home files. Use this to update your name, personality, or persistent self-definition. Do NOT use this for work output (use `write` / `edit` — those land in your group's shared directory) or for facts you want to remember (use `memory_write`). BOOTSTRAP.md is not writable here; call `bootstrap_done` to retire it.\",\n parameters: {\n type: 'object',\n properties: {\n file: { type: 'string', enum: [...HOME_FILES_WRITABLE] },\n content: { type: 'string', description: 'new full file content' },\n },\n required: ['file', 'content'],\n },\n },\n async invoke(args) {\n const file = String(args.file ?? '')\n if (!HOME_FILES_WRITABLE.includes(file as (typeof HOME_FILES_WRITABLE)[number])) {\n throw new Error(\n `home_write: \"file\" must be one of ${HOME_FILES_WRITABLE.join(', ')}; got \"${file}\"`,\n )\n }\n const content = typeof args.content === 'string' ? args.content : ''\n const path = join(agentDir, file)\n writeFileSync(path, content, 'utf8')\n return `wrote ${file} (${Buffer.byteLength(content, 'utf8')} bytes)`\n },\n },\n {\n def: {\n name: 'home_list',\n description: 'List your home files with their sizes.',\n parameters: { type: 'object', properties: {} },\n },\n async invoke() {\n const entries: string[] = []\n for (const file of HOME_FILES_READABLE) {\n const path = join(agentDir, file)\n try {\n const s = statSync(path)\n entries.push(`${file} (${s.size}b)`)\n } catch {\n // file not present — skip\n }\n }\n if (entries.length === 0) {\n const dirEntries = (() => {\n try {\n return readdirSync(agentDir)\n } catch {\n return []\n }\n })()\n return `(no home files found; agent dir contains: ${dirEntries.join(', ') || 'nothing'})`\n }\n return entries.join('\\n')\n },\n },\n ]\n}\n","import type { MemoryBackend } from '../memory/types.ts'\nimport type { ToolHandler } from './types.ts'\n\nexport function memoryTools(memory: MemoryBackend): ToolHandler[] {\n return [\n {\n def: {\n name: 'memory_write',\n description:\n 'Write or update a memory note in the GROUP-SHARED memory. All agents in this group can read what you write. Use it for project knowledge, codebase notes, decisions, and findings — anything other agents in the group should benefit from. For personal notes about yourself (preferences, persona) use `home_write` on IDENTITY.md. For STABLE facts about the human you\\'re working with (their preferences, role, working hours, how they like to be addressed) use `user_md_get` then `user_md_write` — those land in every agent\\'s system prompt directly. Key is a path-like string with a markdown extension, e.g. \"auth-flow.md\" or \"decisions/2026-05-migration.md\".',\n parameters: {\n type: 'object',\n properties: {\n key: { type: 'string', description: 'memory key (relative path)' },\n content: { type: 'string', description: 'note content (plain text or markdown)' },\n },\n required: ['key', 'content'],\n },\n },\n async invoke(args) {\n const key = String(args.key ?? '')\n const content = String(args.content ?? '')\n if (!key) throw new Error('memory_write: \"key\" is required')\n const entry = await memory.write(key, content)\n return `wrote ${entry.key} (${entry.content.length} bytes)`\n },\n },\n {\n def: {\n name: 'memory_search',\n description:\n 'Search the group-shared memory by substring. Returns matching entry keys with short snippets around the match.',\n parameters: {\n type: 'object',\n properties: {\n query: { type: 'string' },\n limit: { type: 'number', description: 'max results (default 10)' },\n },\n required: ['query'],\n },\n },\n async invoke(args) {\n const query = String(args.query ?? '')\n if (!query) throw new Error('memory_search: \"query\" is required')\n const limit = typeof args.limit === 'number' ? args.limit : 10\n const hits = await memory.search(query, { limit })\n if (hits.length === 0) return 'no matches'\n return hits.map((h) => `${h.key}: ${h.snippet.replaceAll('\\n', ' ')}`).join('\\n')\n },\n },\n {\n def: {\n name: 'memory_read',\n description: 'Read a single entry from the group-shared memory by key.',\n parameters: {\n type: 'object',\n properties: { key: { type: 'string' } },\n required: ['key'],\n },\n },\n async invoke(args) {\n const key = String(args.key ?? '')\n if (!key) throw new Error('memory_read: \"key\" is required')\n const entry = await memory.read(key)\n return entry.content\n },\n },\n {\n def: {\n name: 'memory_list',\n description: 'List every entry in the group-shared memory with its byte size.',\n parameters: { type: 'object', properties: {} },\n },\n async invoke() {\n const all = await memory.list()\n if (all.length === 0) return '(empty)'\n return all.map((e) => `${e.key} (${e.content.length}b)`).join('\\n')\n },\n },\n ]\n}\n","import type { MessagingHost } from '../worker/ipc-protocol.ts'\nimport type { ToolHandler } from './types.ts'\n\ninterface MessagePayload {\n text: string\n [key: string]: unknown\n}\n\nfunction decodeText(payload: string): string {\n try {\n const parsed = JSON.parse(payload) as MessagePayload\n if (parsed && typeof parsed.text === 'string') return parsed.text\n } catch {\n // not JSON; return raw payload\n }\n return payload\n}\n\nexport function messagingTools(host: MessagingHost, fromAgentId: string): ToolHandler[] {\n return [\n {\n def: {\n name: 'send_message',\n description:\n 'Send a message to another agent. Use the recipient\\'s agent id (UUID). Use this ONLY for things the recipient needs to ACT on: delegating a task, asking a peer for information you cannot get yourself, escalating a decision. Do NOT use it for status updates or to announce changes to group-shared resources — USER.md and the group memory backend both propagate to every agent in the group automatically on their next turn, so messages like \"I updated USER.md\" or \"I wrote a new memory note\" are pure noise and will trigger an inbox-wake loop on the recipient.',\n parameters: {\n type: 'object',\n properties: {\n to: { type: 'string', description: 'Recipient agent id' },\n text: { type: 'string', description: 'Message text' },\n reply_to: {\n type: 'string',\n description: 'Optional: id of the message you are replying to',\n },\n },\n required: ['to', 'text'],\n },\n },\n async invoke(args) {\n const to = String(args.to ?? '')\n const text = String(args.text ?? '')\n if (!to) throw new Error('send_message: \"to\" is required')\n if (!text) throw new Error('send_message: \"text\" is required')\n if (!(await host.agentExists(to))) {\n throw new Error(`send_message: agent not found: ${to}`)\n }\n const replyTo = typeof args.reply_to === 'string' ? args.reply_to : null\n const { messageId } = await host.sendMessage({\n from: fromAgentId,\n to,\n payload: JSON.stringify({ text }),\n replyTo,\n })\n return `sent message ${messageId}`\n },\n },\n {\n def: {\n name: 'read_inbox',\n description: 'Read messages addressed to you. Marks unread messages as read by default.',\n parameters: {\n type: 'object',\n properties: {\n include_read: {\n type: 'boolean',\n description: 'Also include already-read messages (default false)',\n },\n },\n },\n },\n async invoke(args) {\n const includeRead = args.include_read === true\n const messages = await host.listInbox(fromAgentId, { unreadOnly: !includeRead })\n if (messages.length === 0) return '(no messages)'\n const lines: string[] = []\n for (const m of messages) {\n lines.push(`from ${m.fromAgentId} [${m.id}]: ${decodeText(m.payload)}`)\n if (!m.readAt) await host.markRead(m.id)\n }\n return lines.join('\\n')\n },\n },\n {\n def: {\n name: 'wait_for_reply',\n description:\n 'Block until a reply to a message you sent arrives, or until the timeout expires.',\n parameters: {\n type: 'object',\n properties: {\n message_id: {\n type: 'string',\n description: 'id of the message you sent',\n },\n timeout_ms: {\n type: 'number',\n description: 'max wait in milliseconds (default 30000)',\n },\n poll_ms: {\n type: 'number',\n description: 'poll interval in milliseconds (default 200)',\n },\n },\n required: ['message_id'],\n },\n },\n async invoke(args) {\n const messageId = String(args.message_id ?? '')\n if (!messageId) throw new Error('wait_for_reply: \"message_id\" is required')\n const timeout = typeof args.timeout_ms === 'number' ? args.timeout_ms : 30000\n const poll = typeof args.poll_ms === 'number' ? args.poll_ms : 200\n const start = Date.now()\n while (Date.now() - start < timeout) {\n const replies = await host.findReplies(fromAgentId, messageId)\n if (replies.length > 0) {\n const r = replies[0]\n if (r) {\n if (!r.readAt) await host.markRead(r.id)\n return `reply from ${r.fromAgentId} [${r.id}]: ${decodeText(r.payload)}`\n }\n }\n await new Promise((r) => setTimeout(r, poll))\n }\n return `no reply within ${timeout}ms`\n },\n },\n ]\n}\n","// Group-shared USER.md read/write surface for agents.\n//\n// USER.md is inlined into every agent's system prompt every turn (capped at\n// 12 KB on the daemon-side host). Agents previously could only read it; now\n// they can also update it via read-modify-write so they can correct stale\n// facts, not just stack new ones. Concurrency between multiple agents in\n// the same group is handled via optimistic etag checks — see\n// `lib/user-md-host.ts` for the full rationale.\n//\n// Two tools:\n// - `user_md_get` — returns current content + an etag.\n// - `user_md_write` — replaces content; requires `if_match` to equal the\n// most recent etag, else returns a conflict.\n//\n// Project knowledge (codebase notes, decisions) still goes to `memory_write`.\n// Personal notes about the agent itself go to `home_write` on IDENTITY.md.\n\nimport type { UserMdHost } from '../worker/ipc-protocol.ts'\nimport type { ToolHandler } from './types.ts'\n\nexport function userMdTools(host: UserMdHost, groupId: string): ToolHandler[] {\n return [\n {\n def: {\n name: 'user_md_get',\n description:\n 'Read the group-shared USER.md (facts every agent in the group knows about the human). Returns the current content followed by an `etag:` line — you MUST pass that etag back as `if_match` on the next `user_md_write` so the daemon can detect concurrent edits by other agents in the group. Always call this immediately before any `user_md_write`.',\n parameters: {\n type: 'object',\n properties: {},\n },\n },\n async invoke() {\n const { content, etag } = await host.get(groupId)\n const body = content.length > 0 ? content : '(USER.md is empty)'\n return `${body}\\n\\n---\\netag: ${etag}`\n },\n },\n {\n def: {\n name: 'user_md_write',\n description:\n 'Replace the group-shared USER.md with new content. Use this for STABLE user-specific facts (preferences, role, working hours, how the human likes to be addressed). MANDATORY workflow: (1) call `user_md_get` first, (2) integrate your change into the full content preserving everything unrelated, (3) call `user_md_write` with the merged content and the etag you got from `user_md_get`. If another agent in the group wrote to USER.md between your get and write, this returns an etag-mismatch error — just call `user_md_get` again and retry the merge. The full result must fit under 12 KB. For project knowledge use `memory_write`; for notes about yourself use `home_write` on IDENTITY.md.',\n parameters: {\n type: 'object',\n properties: {\n content: {\n type: 'string',\n description:\n 'Full new contents of USER.md (this is a complete replacement, NOT an append). Include everything you want to keep.',\n },\n if_match: {\n type: 'string',\n description:\n 'The etag returned by your most recent `user_md_get`. The write fails if USER.md changed in the meantime.',\n },\n },\n required: ['content', 'if_match'],\n },\n },\n async invoke(args) {\n const content = String(args.content ?? '')\n const ifMatch = String(args.if_match ?? '')\n if (!ifMatch) {\n throw new Error(\n 'user_md_write: \"if_match\" is required — call user_md_get first to obtain the current etag.',\n )\n }\n const { etag, totalBytes } = await host.write(groupId, content, ifMatch)\n return `wrote USER.md (${totalBytes} bytes, new etag: ${etag})`\n },\n },\n ]\n}\n","import { fetch as undiciFetch } from 'undici'\nimport type { ToolHandler } from './types.ts'\nimport {\n type ExtractMode,\n type ExtractResult,\n extractReadable,\n markdownToPlain,\n} from './web-extract.ts'\nimport { guardedFetch, SsrFBlockedError } from './web-ssrf.ts'\n\nconst DEFAULT_USER_AGENT =\n 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_7_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36'\nconst DEFAULT_CACHE_TTL_MS = 15 * 60_000\nconst DEFAULT_CACHE_MAX = 100\nconst DEFAULT_MAX_LENGTH = 20_000\nconst DEFAULT_TIMEOUT_MS = 30_000\n// Raw body cap applied before parsing. Multi-megabyte HTML (Mintlify/Next.js\n// docs sites, ad-heavy pages) can stall or OOM Readability+linkedom's\n// synchronous DOM walk. 3 MB comfortably covers real articles; anything\n// larger gets truncated and the caller sees a note in the output.\nconst DEFAULT_MAX_BODY_BYTES = 3 * 1024 * 1024\n// If the primary Readability path returns fewer than this many characters\n// from a 2xx HTML response, and FIRECRAWL_API_KEY is configured, retry the\n// fetch via Firecrawl which renders JS server-side. Threshold is heuristic:\n// real articles routinely exceed 200 chars; pages that bottom out below it\n// are almost always JS-shell pages where extraction collapsed.\nconst FIRECRAWL_FALLBACK_THRESHOLD = 200\nconst FIRECRAWL_DEFAULT_URL = 'https://api.firecrawl.dev'\n\ninterface SearchResult {\n title: string\n url: string\n snippet: string\n}\n\nfunction stripHtml(s: string): string {\n return s\n .replace(/<[^>]*>/g, '')\n .replace(/&amp;/g, '&')\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\")\n .replace(/&nbsp;/g, ' ')\n .trim()\n}\n\n// --- search backends ---\n\nasync function braveSearch(\n query: string,\n limit: number,\n apiKey: string,\n fetchFn: typeof fetch,\n): Promise<SearchResult[]> {\n const params = new URLSearchParams({ q: query, count: String(limit) })\n const res = await fetchFn(`https://api.search.brave.com/res/v1/web/search?${params}`, {\n headers: {\n accept: 'application/json',\n 'accept-encoding': 'gzip',\n 'x-subscription-token': apiKey,\n },\n })\n if (!res.ok) throw new Error(`Brave Search: ${res.status} ${await res.text()}`)\n const data = (await res.json()) as {\n web?: { results?: { title?: string; url?: string; description?: string }[] }\n }\n return (data.web?.results ?? []).slice(0, limit).map((r) => ({\n title: r.title ?? '',\n url: r.url ?? '',\n snippet: r.description ? stripHtml(r.description) : '',\n }))\n}\n\nasync function searxngSearch(\n query: string,\n limit: number,\n baseURL: string,\n fetchFn: typeof fetch,\n): Promise<SearchResult[]> {\n const params = new URLSearchParams({ q: query, format: 'json' })\n const res = await fetchFn(`${baseURL}/search?${params}`, {\n headers: { accept: 'application/json' },\n })\n if (!res.ok) throw new Error(`SearXNG: ${res.status} ${await res.text()}`)\n const data = (await res.json()) as {\n results?: { title?: string; url?: string; content?: string }[]\n }\n return (data.results ?? []).slice(0, limit).map((r) => ({\n title: r.title ?? '',\n url: r.url ?? '',\n snippet: r.content ?? '',\n }))\n}\n\n// --- error formatting ---\n\n/**\n * Flatten an Error and its `cause` chain into a single readable string.\n * undici surfaces network failures as `TypeError: fetch failed` with the\n * real reason (UND_ERR_*, ECONNRESET, certificate errors, …) stashed in\n * `err.cause`; without unwrapping it the agent only ever sees \"fetch\n * failed\" and has no path to diagnose or work around the problem.\n */\nfunction describeError(err: unknown): string {\n if (!(err instanceof Error)) return String(err)\n const parts: string[] = []\n const seen = new Set<unknown>()\n let cur: unknown = err\n while (cur instanceof Error && !seen.has(cur)) {\n seen.add(cur)\n const code = (cur as { code?: string }).code\n parts.push(code ? `[${code}] ${cur.message}` : cur.message)\n cur = (cur as { cause?: unknown }).cause\n }\n return parts.join(' — cause: ')\n}\n\n// --- bounded body reader ---\n\n/**\n * Stream `res.body` and accumulate up to `maxBytes`, then truncate. Returns\n * the decoded text (using the charset from content-type, falling back to\n * UTF-8) and a flag the caller can surface to the agent so it knows the\n * page was larger than the cap.\n */\nasync function readBodyCapped(\n res: Response,\n maxBytes: number,\n): Promise<{ text: string; truncated: boolean }> {\n const ct = res.headers.get('content-type') ?? ''\n const charset = /charset=([^;]+)/i.exec(ct)?.[1]?.trim().toLowerCase() || 'utf-8'\n const decoder = new TextDecoder(charset, { fatal: false })\n const reader = res.body?.getReader()\n if (!reader) {\n const text = await res.text()\n if (text.length > maxBytes) return { text: text.slice(0, maxBytes), truncated: true }\n return { text, truncated: false }\n }\n const chunks: Uint8Array[] = []\n let total = 0\n let truncated = false\n while (true) {\n const { value, done } = await reader.read()\n if (done) break\n if (!value) continue\n if (total + value.byteLength > maxBytes) {\n const keep = maxBytes - total\n if (keep > 0) chunks.push(value.subarray(0, keep))\n truncated = true\n try {\n await reader.cancel()\n } catch {\n // body already settled\n }\n break\n }\n chunks.push(value)\n total += value.byteLength\n }\n const sum = chunks.reduce((s, c) => s + c.byteLength, 0)\n const merged = new Uint8Array(sum)\n let off = 0\n for (const c of chunks) {\n merged.set(c, off)\n off += c.byteLength\n }\n return { text: decoder.decode(merged), truncated }\n}\n\n// --- Firecrawl fallback ---\n\ninterface FirecrawlResponse {\n success?: boolean\n data?: {\n markdown?: string\n metadata?: { title?: string }\n }\n error?: string\n}\n\n/**\n * Last-resort HTML rendering via Firecrawl's `/v1/scrape` endpoint. Used\n * when the primary Readability path returns near-empty content from a 2xx\n * HTML response (JS-only shells, anti-bot walls, login redirects). Returns\n * `null` when Firecrawl is not configured or the call fails so the caller\n * falls back to the primary extraction unchanged — Firecrawl is best-effort,\n * never an error source.\n */\nasync function firecrawlScrape(\n url: string,\n mode: ExtractMode,\n env: NodeJS.ProcessEnv,\n fetchFn: typeof fetch,\n timeoutMs: number,\n): Promise<ExtractResult | null> {\n const apiKey = env.FIRECRAWL_API_KEY\n if (!apiKey) return null\n const base = (env.FIRECRAWL_URL ?? FIRECRAWL_DEFAULT_URL).replace(/\\/$/, '')\n const ac = new AbortController()\n const t = setTimeout(() => ac.abort(new Error('firecrawl timeout')), timeoutMs)\n try {\n const res = await fetchFn(`${base}/v1/scrape`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${apiKey}`,\n accept: 'application/json',\n },\n body: JSON.stringify({\n url,\n formats: ['markdown'],\n onlyMainContent: true,\n }),\n signal: ac.signal,\n })\n if (!res.ok) return null\n const body = (await res.json()) as FirecrawlResponse\n if (!body.success || !body.data?.markdown) return null\n const md = body.data.markdown\n const title = body.data.metadata?.title\n const text = mode === 'text' ? markdownToPlain(md) : md\n return title ? { text, title } : { text }\n } catch {\n return null\n } finally {\n clearTimeout(t)\n }\n}\n\n// --- per-URL cache ---\n\ninterface CacheEntry {\n value: ExtractResult\n expiresAt: number\n}\n\nfunction cacheGet(cache: Map<string, CacheEntry>, key: string): ExtractResult | null {\n const entry = cache.get(key)\n if (!entry) return null\n if (entry.expiresAt < Date.now()) {\n cache.delete(key)\n return null\n }\n // Refresh LRU position\n cache.delete(key)\n cache.set(key, entry)\n return entry.value\n}\n\nfunction cacheSet(\n cache: Map<string, CacheEntry>,\n key: string,\n value: ExtractResult,\n ttlMs: number,\n maxEntries: number,\n): void {\n cache.set(key, { value, expiresAt: Date.now() + ttlMs })\n while (cache.size > maxEntries) {\n const oldest = cache.keys().next().value\n if (!oldest) break\n cache.delete(oldest)\n }\n}\n\n// --- tool factory ---\n\nexport interface WebToolsOpts {\n fetchImpl?: typeof fetch\n env?: NodeJS.ProcessEnv\n /** Disable SSRF checks (tests against 127.0.0.1 mock servers). Default false. */\n allowPrivate?: boolean\n /** Cache TTL in ms. Default 15 min. */\n cacheTtlMs?: number\n /** Max cache entries. Default 100. */\n cacheMax?: number\n /** Fetch timeout in ms. Default 30s. */\n timeoutMs?: number\n /** Cap on raw response body bytes before parsing. Default 3 MB. */\n maxBodyBytes?: number\n /** Disable the Firecrawl fallback even when FIRECRAWL_API_KEY is set. */\n firecrawlDisabled?: boolean\n}\n\n/**\n * web_search backends (tried in order):\n * 1. Brave Search (env: BRAVE_API_KEY) — free tier, 2000 req/month\n * 2. SearXNG (env: SEARXNG_URL) — self-hosted, unlimited\n * 3. Error with setup instructions if neither is configured\n *\n * web_fetch: guarded fetch (SSRF-blocked private IPs) + Readability + markdown,\n * with per-URL in-memory cache (15 min TTL).\n */\nexport function webTools(opts?: WebToolsOpts): ToolHandler[] {\n // Default to undici 8's fetch so search-backend HTTP shares the same\n // stack as guardedFetch (and stays out of Node 24's bundled undici 7).\n const fetchFn = opts?.fetchImpl ?? (undiciFetch as unknown as typeof fetch)\n const env = opts?.env ?? process.env\n const allowPrivate = opts?.allowPrivate ?? false\n const cacheTtlMs = opts?.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS\n const cacheMax = opts?.cacheMax ?? DEFAULT_CACHE_MAX\n const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS\n const maxBodyBytes = opts?.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES\n const firecrawlDisabled = opts?.firecrawlDisabled ?? false\n const cache = new Map<string, CacheEntry>()\n\n return [\n {\n def: {\n name: 'web_search',\n description:\n 'Search the internet. Returns a list of titles, URLs, and snippets. Requires BRAVE_API_KEY or SEARXNG_URL to be configured.',\n parameters: {\n type: 'object',\n properties: {\n query: { type: 'string', description: 'Search query' },\n limit: { type: 'number', description: 'Max results to return (default 5)' },\n },\n required: ['query'],\n },\n },\n async invoke(args) {\n const query = String(args.query ?? '')\n if (!query) throw new Error('web_search: query is required')\n const limit = typeof args.limit === 'number' ? args.limit : 5\n\n const braveKey = env.BRAVE_API_KEY\n if (braveKey) {\n const results = await braveSearch(query, limit, braveKey, fetchFn)\n return results.length === 0 ? 'no results' : formatResults(results)\n }\n\n const searxngUrl = env.SEARXNG_URL\n if (searxngUrl) {\n const results = await searxngSearch(query, limit, searxngUrl, fetchFn)\n return results.length === 0 ? 'no results' : formatResults(results)\n }\n\n throw new Error(\n 'web_search: no search backend configured. Set BRAVE_API_KEY (free at https://brave.com/search/api/) or SEARXNG_URL.',\n )\n },\n },\n {\n def: {\n name: 'web_fetch',\n description:\n 'Fetch a URL and return its readable content. HTML is extracted via Readability and converted to markdown. When the primary extraction returns near-empty content from a 2xx HTML page (typical of JS-only shells), the tool automatically retries via Firecrawl if FIRECRAWL_API_KEY is configured. Results are cached for 15 minutes.',\n parameters: {\n type: 'object',\n properties: {\n url: { type: 'string', description: 'The URL to fetch (http or https)' },\n max_length: {\n type: 'number',\n description: 'Max characters to return (default 20000)',\n },\n extract_mode: {\n type: 'string',\n enum: ['markdown', 'text'],\n description: 'Output format for HTML pages. Default \"markdown\".',\n },\n },\n required: ['url'],\n },\n },\n async invoke(args) {\n const url = String(args.url ?? '')\n if (!url) throw new Error('web_fetch: url is required')\n const maxLen = typeof args.max_length === 'number' ? args.max_length : DEFAULT_MAX_LENGTH\n const mode: ExtractMode = args.extract_mode === 'text' ? 'text' : 'markdown'\n const cacheKey = `${mode}|${url}`\n\n const cached = cacheGet(cache, cacheKey)\n if (cached) return formatOutput(cached, maxLen)\n\n let result: GuardedFetchResultShape | null = null\n try {\n result = await guardedFetch({\n url,\n fetchImpl: opts?.fetchImpl,\n allowPrivate,\n timeoutMs,\n init: {\n headers: {\n 'user-agent': DEFAULT_USER_AGENT,\n accept: 'text/html,application/xhtml+xml,application/json,text/plain,*/*',\n 'accept-language': 'en-US,en;q=0.9',\n },\n },\n })\n if (!result.response.ok) {\n throw new Error(`${result.response.status} ${result.response.statusText}`)\n }\n const ct = result.response.headers.get('content-type') ?? ''\n const isHtml = ct.includes('text/html') || ct.includes('xhtml')\n const { text: body, truncated } = await readBodyCapped(result.response, maxBodyBytes)\n let extracted: ExtractResult\n if (isHtml) {\n extracted = extractReadable(body, result.finalUrl, mode)\n } else if (ct.includes('application/json')) {\n try {\n extracted = { text: JSON.stringify(JSON.parse(body), null, 2) }\n } catch {\n extracted = { text: body }\n }\n } else {\n extracted = { text: body }\n }\n // Firecrawl fallback: only meaningful for HTML pages where the\n // primary extractor collapsed. Skip JSON / plain-text bodies and\n // skip when extraction already produced something substantial.\n if (\n isHtml &&\n !firecrawlDisabled &&\n extracted.text.length < FIRECRAWL_FALLBACK_THRESHOLD\n ) {\n const rescued = await firecrawlScrape(result.finalUrl, mode, env, fetchFn, timeoutMs)\n if (rescued) {\n extracted = {\n ...rescued,\n text: `${rescued.text}\\n\\n[content rendered via Firecrawl fallback — primary extraction returned ${extracted.text.length} chars]`,\n }\n }\n }\n if (truncated) {\n extracted = {\n ...extracted,\n text: `${extracted.text}\\n\\n[raw body truncated at ${maxBodyBytes} bytes before extraction — page exceeded the size cap]`,\n }\n }\n cacheSet(cache, cacheKey, extracted, cacheTtlMs, cacheMax)\n return formatOutput(extracted, maxLen)\n } catch (err) {\n if (err instanceof SsrFBlockedError) throw new Error(`web_fetch: ${err.message}`)\n throw new Error(`web_fetch: ${describeError(err)}`)\n } finally {\n if (result) await result.release()\n }\n },\n },\n ]\n}\n\ntype GuardedFetchResultShape = Awaited<ReturnType<typeof guardedFetch>>\n\nfunction formatOutput(r: ExtractResult, maxLen: number): string {\n const body = r.title ? `# ${r.title}\\n\\n${r.text}` : r.text\n if (body.length > maxLen) return `${body.slice(0, maxLen)}\\n\\n[truncated at ${maxLen} chars]`\n return body\n}\n\nfunction formatResults(results: SearchResult[]): string {\n return results.map((r, i) => `${i + 1}. ${r.title}\\n ${r.url}\\n ${r.snippet}`).join('\\n\\n')\n}\n","import { Readability } from '@mozilla/readability'\nimport { parseHTML } from 'linkedom'\n\nexport type ExtractMode = 'markdown' | 'text'\n\nexport interface ExtractResult {\n text: string\n title?: string\n}\n\nfunction decodeEntities(value: string): string {\n return value\n .replace(/&nbsp;/gi, ' ')\n .replace(/&amp;/gi, '&')\n .replace(/&quot;/gi, '\"')\n .replace(/&#39;/gi, \"'\")\n .replace(/&lt;/gi, '<')\n .replace(/&gt;/gi, '>')\n .replace(/&#x([0-9a-f]+);/gi, (_, hex) => String.fromCharCode(Number.parseInt(hex, 16)))\n .replace(/&#(\\d+);/gi, (_, dec) => String.fromCharCode(Number.parseInt(dec, 10)))\n}\n\nfunction stripTags(value: string): string {\n return decodeEntities(value.replace(/<[^>]+>/g, ''))\n}\n\nfunction normalizeWhitespace(value: string): string {\n return value\n .replace(/\\r/g, '')\n .replace(/[ \\t]+\\n/g, '\\n')\n .replace(/\\n{3,}/g, '\\n\\n')\n .replace(/[ \\t]{2,}/g, ' ')\n .trim()\n}\n\nfunction htmlToMarkdown(html: string): { text: string; title?: string } {\n const titleMatch = html.match(/<title[^>]*>([\\s\\S]*?)<\\/title>/i)\n const title = titleMatch ? normalizeWhitespace(stripTags(titleMatch[1] ?? '')) : undefined\n let text = html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, '')\n .replace(/<style[\\s\\S]*?<\\/style>/gi, '')\n .replace(/<noscript[\\s\\S]*?<\\/noscript>/gi, '')\n .replace(/<nav[\\s\\S]*?<\\/nav>/gi, '')\n .replace(/<header[\\s\\S]*?<\\/header>/gi, '')\n .replace(/<footer[\\s\\S]*?<\\/footer>/gi, '')\n text = text.replace(/<a\\s+[^>]*href=[\"']([^\"']+)[\"'][^>]*>([\\s\\S]*?)<\\/a>/gi, (_, href, body) => {\n const label = normalizeWhitespace(stripTags(body))\n return label ? `[${label}](${href})` : href\n })\n text = text.replace(/<h([1-6])[^>]*>([\\s\\S]*?)<\\/h\\1>/gi, (_, level, body) => {\n const n = Math.max(1, Math.min(6, Number.parseInt(level, 10)))\n return `\\n${'#'.repeat(n)} ${normalizeWhitespace(stripTags(body))}\\n`\n })\n text = text.replace(/<li[^>]*>([\\s\\S]*?)<\\/li>/gi, (_, body) => {\n const label = normalizeWhitespace(stripTags(body))\n return label ? `\\n- ${label}` : ''\n })\n text = text\n .replace(/<(br|hr)\\s*\\/?>/gi, '\\n')\n .replace(/<\\/(p|div|section|article|tr|ul|ol|table|blockquote)>/gi, '\\n')\n text = stripTags(text)\n return { text: normalizeWhitespace(text), title }\n}\n\nexport function markdownToPlain(md: string): string {\n let t = md\n t = t.replace(/!\\[[^\\]]*]\\([^)]+\\)/g, '')\n t = t.replace(/\\[([^\\]]+)]\\([^)]+\\)/g, '$1')\n t = t.replace(/```[\\s\\S]*?```/g, (block) =>\n block.replace(/```[^\\n]*\\n?/g, '').replace(/```/g, ''),\n )\n t = t.replace(/`([^`]+)`/g, '$1')\n t = t.replace(/^#{1,6}\\s+/gm, '')\n t = t.replace(/^\\s*[-*+]\\s+/gm, '')\n t = t.replace(/^\\s*\\d+\\.\\s+/gm, '')\n return normalizeWhitespace(t)\n}\n\n/**\n * Extract readable content from HTML using Readability, with a regex-based\n * markdown fallback when Readability can't identify an article.\n */\nexport function extractReadable(html: string, url: string, mode: ExtractMode): ExtractResult {\n const fallback = (): ExtractResult => {\n const r = htmlToMarkdown(html)\n return mode === 'text' ? { text: markdownToPlain(r.text), title: r.title } : r\n }\n try {\n const { document } = parseHTML(html)\n try {\n ;(document as unknown as { baseURI?: string }).baseURI = url\n } catch {\n // best-effort\n }\n type ReadabilityArg = ConstructorParameters<typeof Readability>[0]\n const parsed = new Readability(document as unknown as ReadabilityArg, {\n charThreshold: 0,\n }).parse()\n if (!parsed?.content) return fallback()\n const title = parsed.title || undefined\n if (mode === 'text') {\n const text = normalizeWhitespace(parsed.textContent ?? '')\n return text ? { text, title } : fallback()\n }\n const rendered = htmlToMarkdown(parsed.content)\n return { text: rendered.text, title: title ?? rendered.title }\n } catch {\n return fallback()\n }\n}\n","import { lookup as dnsLookupCb, type LookupAddress } from 'node:dns'\nimport { lookup as dnsLookup } from 'node:dns/promises'\nimport { Agent, type Dispatcher, fetch as undiciFetch } from 'undici'\n\nexport class SsrFBlockedError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'SsrFBlockedError'\n }\n}\n\nconst BLOCKED_HOSTNAMES = new Set(['localhost', 'metadata.google.internal'])\nconst PRIVATE_IPV6_PREFIXES = ['fe80:', 'fec0:', 'fc', 'fd']\n\nfunction normalizeHostname(hostname: string): string {\n let h = hostname.trim().toLowerCase().replace(/\\.$/, '')\n if (h.startsWith('[') && h.endsWith(']')) h = h.slice(1, -1)\n return h\n}\n\nfunction parseIpv4(address: string): number[] | null {\n const parts = address.split('.')\n if (parts.length !== 4) return null\n const nums = parts.map((p) => Number.parseInt(p, 10))\n if (nums.some((n) => Number.isNaN(n) || n < 0 || n > 255)) return null\n return nums\n}\n\nfunction isPrivateIpv4(parts: number[]): boolean {\n const [a, b] = parts as [number, number, number, number]\n if (a === 0 || a === 10 || a === 127) return true\n if (a === 169 && b === 254) return true\n if (a === 172 && b >= 16 && b <= 31) return true\n if (a === 192 && b === 168) return true\n if (a === 100 && b >= 64 && b <= 127) return true\n return false\n}\n\nexport function isPrivateIpAddress(address: string): boolean {\n let norm = address.trim().toLowerCase()\n if (norm.startsWith('[') && norm.endsWith(']')) norm = norm.slice(1, -1)\n if (!norm) return false\n if (norm.startsWith('::ffff:')) {\n const mapped = norm.slice('::ffff:'.length)\n const ipv4 = parseIpv4(mapped)\n if (ipv4) return isPrivateIpv4(ipv4)\n }\n if (norm.includes(':')) {\n if (norm === '::' || norm === '::1') return true\n return PRIVATE_IPV6_PREFIXES.some((p) => norm.startsWith(p))\n }\n const ipv4 = parseIpv4(norm)\n return ipv4 ? isPrivateIpv4(ipv4) : false\n}\n\nexport function isBlockedHostname(hostname: string): boolean {\n const h = normalizeHostname(hostname)\n if (!h) return false\n if (BLOCKED_HOSTNAMES.has(h)) return true\n return h.endsWith('.localhost') || h.endsWith('.local') || h.endsWith('.internal')\n}\n\ntype LookupCallback = (\n err: NodeJS.ErrnoException | null,\n address: string | LookupAddress[],\n family?: number,\n) => void\n\nfunction createPinnedLookup(hostname: string, addresses: string[]): typeof dnsLookupCb {\n const normalized = normalizeHostname(hostname)\n const records = addresses.map((address) => ({\n address,\n family: (address.includes(':') ? 6 : 4) as 4 | 6,\n }))\n let index = 0\n return ((host: string, options?: unknown, callback?: unknown) => {\n const cb: LookupCallback =\n typeof options === 'function' ? (options as LookupCallback) : (callback as LookupCallback)\n if (!cb) return\n if (normalizeHostname(host) !== normalized) {\n if (typeof options === 'function' || options === undefined) {\n return (dnsLookupCb as unknown as (h: string, cb: LookupCallback) => void)(host, cb)\n }\n return (dnsLookupCb as unknown as (h: string, o: unknown, cb: LookupCallback) => void)(\n host,\n options,\n cb,\n )\n }\n const opts =\n typeof options === 'object' && options !== null\n ? (options as { all?: boolean; family?: number })\n : {}\n const family = typeof options === 'number' ? options : (opts.family ?? 0)\n const candidates =\n family === 4 || family === 6 ? records.filter((r) => r.family === family) : records\n const usable = candidates.length > 0 ? candidates : records\n if (opts.all) {\n cb(null, usable as LookupAddress[])\n return\n }\n const chosen = usable[index % usable.length]\n if (!chosen) return\n index += 1\n cb(null, chosen.address, chosen.family)\n }) as typeof dnsLookupCb\n}\n\nasync function resolveAndCheck(hostname: string): Promise<string[]> {\n const norm = normalizeHostname(hostname)\n if (!norm) throw new SsrFBlockedError('Invalid hostname')\n if (isBlockedHostname(norm)) throw new SsrFBlockedError(`Blocked hostname: ${hostname}`)\n if (isPrivateIpAddress(norm)) throw new SsrFBlockedError('Blocked: private IP literal')\n const results = await dnsLookup(norm, { all: true })\n if (results.length === 0) throw new SsrFBlockedError(`Cannot resolve: ${hostname}`)\n for (const r of results) {\n if (isPrivateIpAddress(r.address)) throw new SsrFBlockedError('Blocked: resolves to private IP')\n }\n return Array.from(new Set(results.map((r) => r.address)))\n}\n\ntype FetchLike = (input: string | URL, init?: RequestInit) => Promise<Response>\n\nexport interface GuardedFetchOptions {\n url: string\n fetchImpl?: FetchLike\n init?: RequestInit\n maxRedirects?: number\n timeoutMs?: number\n signal?: AbortSignal\n /** If true, skip all SSRF checks (for tests hitting 127.0.0.1 mocks). */\n allowPrivate?: boolean\n}\n\nexport interface GuardedFetchResult {\n response: Response\n finalUrl: string\n release: () => Promise<void>\n}\n\nfunction isRedirectStatus(s: number): boolean {\n return s === 301 || s === 302 || s === 303 || s === 307 || s === 308\n}\n\nasync function closeDispatcher(d: Dispatcher | null): Promise<void> {\n if (!d) return\n try {\n await d.close()\n } catch {\n // ignore\n }\n}\n\nexport async function guardedFetch(opts: GuardedFetchOptions): Promise<GuardedFetchResult> {\n // Use undici's own fetch (not globalThis.fetch) so the `dispatcher` Agent\n // we attach below is the same undici major version as the fetch impl\n // consuming it. Node 24 ships undici 7.x as its built-in fetch; mixing\n // a standalone undici 8.x Agent with the 7.x dispatcher fails with\n // `UND_ERR_INVALID_ARG: invalid onRequestStart method` because the\n // diagnostics-channel handler signatures changed between majors.\n const fetcher: FetchLike = opts.fetchImpl ?? (undiciFetch as unknown as FetchLike)\n const maxRedirects = opts.maxRedirects ?? 3\n const abortController = new AbortController()\n const timeoutId = opts.timeoutMs\n ? setTimeout(() => abortController.abort(new Error('timeout')), opts.timeoutMs)\n : null\n if (opts.signal) {\n if (opts.signal.aborted) abortController.abort(opts.signal.reason)\n else\n opts.signal.addEventListener('abort', () => abortController.abort(opts.signal?.reason), {\n once: true,\n })\n }\n\n let current = opts.url\n const visited = new Set<string>()\n let redirects = 0\n let dispatcher: Dispatcher | null = null\n\n const release = async (): Promise<void> => {\n if (timeoutId) clearTimeout(timeoutId)\n await closeDispatcher(dispatcher)\n dispatcher = null\n }\n\n while (true) {\n let parsed: URL\n try {\n parsed = new URL(current)\n } catch {\n await release()\n throw new Error('Invalid URL')\n }\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n await release()\n throw new Error('Invalid URL: must be http or https')\n }\n\n // Pin DNS only when we control the dispatcher (native fetch path).\n const canPin = !opts.fetchImpl\n if (!opts.allowPrivate) {\n const addrs = await resolveAndCheck(parsed.hostname)\n await closeDispatcher(dispatcher)\n dispatcher = canPin\n ? new Agent({ connect: { lookup: createPinnedLookup(parsed.hostname, addrs) } })\n : null\n }\n\n const init: RequestInit = {\n ...(opts.init ?? {}),\n redirect: 'manual',\n signal: abortController.signal,\n }\n // `dispatcher` is a Node fetch extension not reflected in the DOM\n // RequestInit type — and the undici Dispatcher type brand can diverge\n // from the one @types/node bundles. Stamp it on via a cast.\n if (dispatcher) (init as unknown as { dispatcher: Dispatcher }).dispatcher = dispatcher\n\n let res: Response\n try {\n res = await fetcher(parsed.toString(), init)\n } catch (err) {\n await release()\n throw err\n }\n\n if (isRedirectStatus(res.status)) {\n const loc = res.headers.get('location')\n if (!loc) {\n await release()\n throw new Error(`Redirect ${res.status} missing Location header`)\n }\n redirects += 1\n if (redirects > maxRedirects) {\n await release()\n throw new Error(`Too many redirects (> ${maxRedirects})`)\n }\n const next = new URL(loc, parsed).toString()\n if (visited.has(next)) {\n await release()\n throw new Error('Redirect loop')\n }\n visited.add(next)\n void res.body?.cancel()\n current = next\n continue\n }\n\n return { response: res, finalUrl: parsed.toString(), release }\n }\n}\n","// Catalog lookup for config UI + CLI: \"what models does provider X offer?\"\n//\n// Two sources, merged and de-duplicated:\n// 1. pi-ai's typed catalog (`getModels(provider)`) — static list of\n// known cloud models with cost + context-window metadata, bundled with\n// pi-ai. Works for the 10ish KnownProvider names; empty for local /\n// alias providers (lmstudio, ollama, bedrock-via-our-alias).\n// 2. For OpenAI-compat endpoints (lmstudio, ollama, openrouter,\n// vercel-ai-gateway, openai with custom baseURL), we query\n// `GET {baseURL}/models` and extract `data[].id`. This picks up\n// newly released models, user-loaded local models, etc.\n//\n// `listCatalogModels(providerName)` returns the union. Errors from live\n// fetches are surfaced so callers can show \"couldn't reach lmstudio\" rather\n// than a silent empty list.\n\nimport { getModels as piGetModels } from '@earendil-works/pi-ai'\nimport { fetch as undiciFetch } from 'undici'\n\n// piProviderName: what pi-ai's catalog indexes by. For bedrock we use the\n// Bazilion-registry-key 'bedrock' externally but pi uses 'amazon-bedrock'.\nconst REGISTRY_TO_PI: Record<string, string> = {\n bedrock: 'amazon-bedrock',\n 'azure-openai': 'azure-openai-responses',\n}\n\n// baseURL for providers whose /v1/models we can probe. Omitted for the\n// big cloud APIs that require a real key and generally aren't \"explore me\"\n// — those come from the pi catalog. `process.env` reads pick up the same\n// secrets/config merge the rest of the runtime uses.\nfunction liveEndpointFor(providerName: string, env: NodeJS.ProcessEnv): string | null {\n switch (providerName) {\n case 'lmstudio':\n return env.LMSTUDIO_URL ?? 'http://127.0.0.1:1234/v1'\n case 'ollama':\n // Ollama has its own /api/tags for model list; its OpenAI-compat /v1\n // endpoint supports /models though, so use that.\n return env.OLLAMA_URL ?? 'http://127.0.0.1:11434/v1'\n case 'llamacpp':\n return env.LLAMACPP_URL ?? 'http://127.0.0.1:8080/v1'\n case 'openrouter':\n return 'https://openrouter.ai/api/v1'\n case 'vercel-ai-gateway':\n return env.AI_GATEWAY_BASE_URL ?? 'https://ai-gateway.vercel.sh/v1'\n case 'groq':\n return 'https://api.groq.com/openai/v1'\n case 'cerebras':\n return 'https://api.cerebras.ai/v1'\n case 'xai':\n return 'https://api.x.ai/v1'\n case 'mistral':\n return 'https://api.mistral.ai/v1'\n default:\n return null\n }\n}\n\nfunction piModels(providerName: string): string[] {\n const piName = REGISTRY_TO_PI[providerName] ?? providerName\n try {\n const models = (piGetModels as unknown as (p: string) => { id: string }[] | undefined)(piName)\n if (!models) return []\n return models.map((m) => m.id)\n } catch {\n return []\n }\n}\n\nexport interface LiveFetchResult {\n models: string[]\n /** Only populated on failure; caller renders for UX. */\n error?: string\n}\n\nasync function fetchModelsFrom(\n baseURL: string,\n apiKey: string | undefined,\n signal?: AbortSignal,\n): Promise<LiveFetchResult> {\n try {\n const headers: Record<string, string> = { accept: 'application/json' }\n if (apiKey) headers.authorization = `Bearer ${apiKey}`\n const res = await undiciFetch(`${baseURL.replace(/\\/$/, '')}/models`, { headers, signal })\n if (!res.ok) return { models: [], error: `${res.status} ${res.statusText}` }\n const body = (await res.json()) as { data?: Array<{ id?: string }> } | null\n const ids = (body?.data ?? []).map((m) => m.id).filter((id): id is string => !!id)\n return { models: ids }\n } catch (err) {\n return { models: [], error: (err as Error).message }\n }\n}\n\nfunction apiKeyFor(providerName: string, env: NodeJS.ProcessEnv): string | undefined {\n switch (providerName) {\n case 'lmstudio':\n return env.LMSTUDIO_API_KEY ?? 'lm-studio'\n case 'ollama':\n return env.OLLAMA_API_KEY ?? 'ollama'\n case 'openrouter':\n return env.OPENROUTER_API_KEY\n case 'vercel-ai-gateway':\n return env.AI_GATEWAY_API_KEY\n case 'groq':\n return env.GROQ_API_KEY\n case 'cerebras':\n return env.CEREBRAS_API_KEY\n case 'xai':\n return env.XAI_API_KEY\n case 'mistral':\n return env.MISTRAL_API_KEY\n default:\n return undefined\n }\n}\n\nexport interface CatalogResult {\n /** Models from pi-ai's typed catalog — stable, no network. */\n catalog: string[]\n /** Live `/v1/models` query — populated only for openai-compat endpoints we know how to probe. */\n live?: LiveFetchResult\n}\n\n/**\n * List known models for a provider. Combines pi's static catalog with a live\n * `/v1/models` query for endpoints that expose one. Returns both separately\n * so the UI can surface which ones come from where.\n *\n * `live` is omitted (not just empty) when the provider doesn't expose a\n * `/v1/models` endpoint — e.g. Anthropic or Bedrock. Those rely on the\n * catalog only.\n */\nexport async function listCatalogModels(\n providerName: string,\n env: NodeJS.ProcessEnv = process.env,\n signal?: AbortSignal,\n): Promise<CatalogResult> {\n const catalog = piModels(providerName)\n const endpoint = liveEndpointFor(providerName, env)\n if (!endpoint) return { catalog }\n const key = apiKeyFor(providerName, env)\n const live = await fetchModelsFrom(endpoint, key, signal)\n return { catalog, live }\n}\n\n/** Synchronous variant for contexts that only want the pi catalog slice. */\nexport function listCatalogModelsSync(providerName: string): string[] {\n return piModels(providerName)\n}\n","// Parent-side spawn helper for whole-run subprocess isolation.\n//\n// `spawnWorkerTurn` launches `./entry.ts` and feeds it a `WorkerInput` JSON\n// blob on stdin describing the turn to run (pre-resolved agent record,\n// enabled-provider set, message text). The worker no longer opens its own\n// SQLite handle — the daemon is the sole owner of `~/.bazilion`.\n//\n// Two channels run between parent and child:\n// - stdout (NDJSON): the worker emits `ChatFrame`s; we line-parse and\n// yield each one to the caller.\n// - IPC (Node `stdio: 'ipc'`): the worker calls back into the parent for\n// anything that needs DB access during the turn (today: the messaging\n// tools `send_message` / `read_inbox` / `wait_for_reply`). We dispatch\n// each `IpcRequest` through the injected `MessagingHost` and reply with\n// `child.send`.\n//\n// Cancellation: wire an AbortSignal via `opts.signal`. On abort we send\n// SIGTERM to the child — the child has a signal handler that calls\n// `session.abort()`, which aborts the provider fetch and surfaces a final\n// `error` SessionEvent before the worker exits cleanly. If the child doesn't\n// exit within `killGraceMs`, we SIGKILL it.\n\nimport { type ChildProcess, spawn } from 'node:child_process'\nimport { existsSync } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport { fileURLToPath, pathToFileURL } from 'node:url'\nimport type { ChatFrame, ResolvedAgent } from '@bazilion/api-types'\nimport type { IpcReply, IpcRequest, MessagingHost, UserMdHost } from './ipc-protocol.ts'\n\nconst DEFAULT_KILL_GRACE_MS = 3_000\n\n// In dev, this file is at apps/daemon/src/runtime/worker/spawn.ts and the\n// worker entry is its `entry.ts` sibling. In the published bundle, all of\n// spawn.ts's code is inlined into dist/daemon.js, where `./entry.ts` does\n// not exist — the worker is bundled separately to dist/worker.js. Pick at\n// load time by probing the filesystem.\nconst sourceEntryPath = fileURLToPath(new URL('./entry.ts', import.meta.url))\nconst bundledEntryPath = fileURLToPath(new URL('./worker.js', import.meta.url))\nconst entryPath = existsSync(sourceEntryPath) ? sourceEntryPath : bundledEntryPath\nconst entryIsTs = entryPath.endsWith('.ts')\n\n// .ts dev entry: Node 24+ runs TS directly via native type-stripping (no\n// `--experimental-strip-types` flag needed in stable 24, but we still pass\n// it for older 22.x dev environments). tsx is the fallback for any runtime\n// where strip-types is missing. `--no-warnings` silences the experimental\n// banner that older Node versions emit on every child start.\n//\n// .js bundled entry: plain `node entry.js` — no type stripping, no tsx.\nfunction workerSpawnArgs(): string[] {\n if (!entryIsTs) return [entryPath]\n const tsFeature = (process.features as unknown as Record<string, unknown>).typescript\n if (typeof tsFeature === 'string' || tsFeature === true) {\n return ['--experimental-strip-types', '--no-warnings', entryPath]\n }\n return ['--import', tsxImportSpecifier(), entryPath]\n}\n\nlet cachedTsxImport: string | null = null\nfunction tsxImportSpecifier(): string {\n if (cachedTsxImport) return cachedTsxImport\n // `require.resolve('tsx')` returns the absolute path to tsx's loader.mjs —\n // the ESM module that hooks the runtime. Passing it to `node --import` as a\n // file:// URL is the most portable way to activate tsx in a subprocess: it\n // avoids CWD-sensitive bare-specifier resolution, and works regardless of\n // where the caller lives in a pnpm-hoisted workspace.\n const req = createRequire(import.meta.url)\n cachedTsxImport = pathToFileURL(req.resolve('tsx')).href\n return cachedTsxImport\n}\n\nexport interface WorkerTurnSpec {\n /** Pre-resolved agent record — the worker never queries the DB itself. */\n agent: ResolvedAgent\n /** First user-message text for this turn. */\n message: string\n /**\n * Names of providers the user has enabled in /config. Empty array means\n * no per-provider gating configured (all providers pass).\n */\n enabledProviders: string[]\n /**\n * Pre-fetched API key for the agent's provider. Required for OAuth-backed\n * providers (`openai-codex`) — the worker has no DB handle to read the\n * secrets table itself. Omit for env-key providers; `pi/session.ts` then\n * derives the key from `process.env`.\n */\n apiKey?: string\n}\n\nexport interface SpawnWorkerOpts {\n /** Abort to kill the in-flight worker. */\n signal?: AbortSignal\n /** ms between SIGTERM and fallback SIGKILL (default 3000). */\n killGraceMs?: number\n /** Override env passed to the child. Defaults to `process.env`. */\n env?: NodeJS.ProcessEnv\n /**\n * Daemon-side implementation of the messaging tools the worker calls back\n * into via IPC. Omit only when the caller knows the agent will not invoke\n * any of `send_message` / `read_inbox` / `wait_for_reply` — passing it\n * costs nothing for turns that don't use messaging.\n */\n messagingHost?: MessagingHost\n /**\n * Daemon-side implementation of the USER.md append tool. Omit and the\n * `user_md_append` tool will be unavailable on this turn.\n */\n userMdHost?: UserMdHost\n}\n\nexport async function* spawnWorkerTurn(\n spec: WorkerTurnSpec,\n opts: SpawnWorkerOpts = {},\n): AsyncGenerator<ChatFrame, void, void> {\n const child = spawn(process.execPath, workerSpawnArgs(), {\n env: opts.env ?? process.env,\n stdio: ['pipe', 'pipe', 'inherit', 'ipc'],\n })\n\n if (opts.messagingHost || opts.userMdHost) {\n attachIpcHandler(child, opts.messagingHost, opts.userMdHost)\n }\n\n child.stdin?.write(JSON.stringify(spec))\n child.stdin?.end()\n\n const grace = opts.killGraceMs ?? DEFAULT_KILL_GRACE_MS\n let killTimer: NodeJS.Timeout | null = null\n const onAbort = (): void => {\n if (child.exitCode !== null || child.signalCode !== null) return\n try {\n child.kill('SIGTERM')\n } catch {\n // process may have already exited between our check and the kill\n }\n killTimer = setTimeout(() => {\n if (child.exitCode === null && child.signalCode === null) {\n try {\n child.kill('SIGKILL')\n } catch {}\n }\n }, grace)\n killTimer.unref()\n }\n if (opts.signal?.aborted) onAbort()\n else opts.signal?.addEventListener('abort', onAbort)\n\n const waitForExit: Promise<{ code: number | null; signal: NodeJS.Signals | null }> = new Promise(\n (resolve) => {\n if (child.exitCode !== null || child.signalCode !== null) {\n resolve({ code: child.exitCode, signal: child.signalCode })\n return\n }\n child.once('close', (code, signal) => resolve({ code, signal }))\n },\n )\n\n let emittedFatal = false\n\n try {\n let buf = ''\n if (!child.stdout) throw new Error('worker spawn: stdout pipe missing')\n for await (const chunk of child.stdout) {\n buf += (chunk as Buffer).toString('utf8')\n let idx = buf.indexOf('\\n')\n while (idx !== -1) {\n const line = buf.slice(0, idx)\n buf = buf.slice(idx + 1)\n if (line.trim()) {\n const frame = parseFrame(line)\n if (frame.kind === 'fatal') emittedFatal = true\n yield frame\n }\n idx = buf.indexOf('\\n')\n }\n }\n if (buf.trim()) {\n const frame = parseFrame(buf)\n if (frame.kind === 'fatal') emittedFatal = true\n yield frame\n }\n\n const exit = await waitForExit\n // Child exited without emitting a fatal frame but with non-zero status —\n // surface that so the caller doesn't silently swallow a crash. Cancelled\n // turns produce an `error` SessionEvent via the worker's signal handler\n // and exit cleanly with code 0; only truly unexpected exits hit this.\n if (!emittedFatal && exit.code !== 0 && exit.code !== null) {\n yield {\n kind: 'fatal',\n error: `worker exited with code ${exit.code}${exit.signal ? ` (${exit.signal})` : ''}`,\n }\n } else if (!emittedFatal && exit.signal && exit.code === null) {\n yield { kind: 'fatal', error: `worker killed by ${exit.signal}` }\n }\n } finally {\n opts.signal?.removeEventListener('abort', onAbort)\n if (killTimer) clearTimeout(killTimer)\n try {\n child.disconnect()\n } catch {\n // already disconnected (child closed first) — fine\n }\n }\n}\n\nfunction parseFrame(line: string): ChatFrame {\n try {\n return JSON.parse(line) as ChatFrame\n } catch {\n return { kind: 'fatal', error: `worker emitted malformed frame: ${line.slice(0, 200)}` }\n }\n}\n\nfunction attachIpcHandler(\n child: ChildProcess,\n messagingHost: MessagingHost | undefined,\n userMdHost: UserMdHost | undefined,\n): void {\n child.on('message', (msg: unknown) => {\n if (!isIpcRequest(msg)) return\n void dispatch(msg, messagingHost, userMdHost).then((reply) => {\n try {\n child.send?.(reply)\n } catch {\n // child may have exited between request and reply — drop silently\n }\n })\n })\n}\n\nfunction isIpcRequest(msg: unknown): msg is IpcRequest {\n if (!msg || typeof msg !== 'object') return false\n const m = msg as Record<string, unknown>\n return m.type === 'rpc' && typeof m.id === 'string' && typeof m.method === 'string'\n}\n\nfunction requireMessagingHost(host: MessagingHost | undefined, method: string): MessagingHost {\n if (!host) throw new Error(`worker called messaging method \"${method}\" without a messagingHost`)\n return host\n}\n\nfunction requireUserMdHost(host: UserMdHost | undefined, method: string): UserMdHost {\n if (!host) throw new Error(`worker called user_md method \"${method}\" without a userMdHost`)\n return host\n}\n\nasync function dispatch(\n req: IpcRequest,\n messagingHost: MessagingHost | undefined,\n userMdHost: UserMdHost | undefined,\n): Promise<IpcReply> {\n try {\n let result: unknown\n switch (req.method) {\n case 'agentExists':\n result = await requireMessagingHost(messagingHost, req.method).agentExists(req.args.agentId)\n break\n case 'sendMessage':\n result = await requireMessagingHost(messagingHost, req.method).sendMessage(req.args)\n break\n case 'listInbox':\n result = await requireMessagingHost(messagingHost, req.method).listInbox(req.args.agentId, {\n unreadOnly: req.args.unreadOnly,\n })\n break\n case 'markRead':\n await requireMessagingHost(messagingHost, req.method).markRead(req.args.messageId)\n result = null\n break\n case 'findReplies':\n result = await requireMessagingHost(messagingHost, req.method).findReplies(\n req.args.agentId,\n req.args.replyTo,\n )\n break\n case 'userMdGet':\n result = await requireUserMdHost(userMdHost, req.method).get(req.args.groupId)\n break\n case 'userMdWrite':\n result = await requireUserMdHost(userMdHost, req.method).write(\n req.args.groupId,\n req.args.content,\n req.args.ifMatch,\n )\n break\n }\n return { type: 'rpc-reply', id: req.id, ok: true, result }\n } catch (err) {\n return { type: 'rpc-reply', id: req.id, ok: false, error: (err as Error).message }\n }\n}\n","// Resolves the API key (and refresher) for an agent's provider. Centralizes\n// the OAuth special case for `openai-codex` — its access token lives in the\n// daemon-owned `secrets` table, not in env vars, so callers can't pluck it\n// from the merged env the way they can for plain API-key providers.\n\nimport type { ResolvedAgent } from '@bazilion/api-types'\nimport type { BazilionDb } from '../core/index.ts'\nimport { hasOpenAICodexCredentials, loadOpenAICodexAccessToken } from '../runtime/index.ts'\n\nexport interface AgentApiKey {\n /** Initial access token / API key. Undefined when the env layer carries it. */\n apiKey?: string\n /**\n * Optional refresher pi calls during long tool-execution loops to swap an\n * expired JWT for a fresh one. Only set for OAuth providers — daemon-side\n * sessions wire this; worker turns currently rely on the initial token\n * carrying the whole turn (subsecond-to-minutes) since they have no DB\n * handle to refresh against.\n */\n refreshApiKey?: (providerName: string) => Promise<string>\n}\n\n/**\n * Pre-fetch the API key for `agent`'s provider. Returns `{}` when the\n * provider is env-key-based (the merged env passed to the session already\n * carries the value). For `openai-codex`, throws a friendly error when the\n * user hasn't connected their ChatGPT account yet — that surfaces in the\n * chat UI as a clear \"go to /config\" message rather than pi's generic\n * \"no API key\" complaint.\n */\nexport async function resolveAgentApiKey(\n db: BazilionDb,\n authToken: string,\n agent: ResolvedAgent,\n opts: { withRefresher?: boolean } = {},\n): Promise<AgentApiKey> {\n const providerName = agent.model.split(':', 1)[0] ?? ''\n if (providerName !== 'openai-codex') return {}\n\n if (!hasOpenAICodexCredentials(db, authToken)) {\n throw new Error(\n 'openai-codex is not connected — run `bazilion auth openai login` or click Connect on /config',\n )\n }\n const apiKey = await loadOpenAICodexAccessToken(db, authToken)\n if (!opts.withRefresher) return { apiKey }\n return {\n apiKey,\n refreshApiKey: async (requestedProvider) => {\n if (requestedProvider !== 'openai-codex') {\n throw new Error(`unexpected refresh request for ${requestedProvider}`)\n }\n return loadOpenAICodexAccessToken(db, authToken)\n },\n }\n}\n","// Daemon-side `MessagingHost` implementation backed by the local SQLite handle.\n//\n// Two consumers:\n// 1. In-process callers (compact / context / truncate endpoints) that build\n// a Bazilion session for inspection and want messaging tools enumerated\n// with the same shape the chat path sees.\n// 2. The IPC handler that services messaging requests issued by worker\n// subprocesses. Workers no longer hold a SQLite handle of their own —\n// they call `process.send({type: 'rpc', ...})` and the parent dispatches\n// through this host.\n\nimport { agentRepo, type BazilionDb, messageRepo } from '../core/index.ts'\nimport type { MessagingHost } from '../runtime/index.ts'\n\nexport function createDbMessagingHost(db: BazilionDb): MessagingHost {\n return {\n agentExists(agentId) {\n return agentRepo.get(db, agentId) !== null\n },\n sendMessage(input) {\n const m = messageRepo.send(db, input)\n return { messageId: m.id }\n },\n listInbox(agentId, opts) {\n return messageRepo.listInbox(db, agentId, opts)\n },\n markRead(messageId) {\n messageRepo.markRead(db, messageId)\n },\n findReplies(agentId, replyTo) {\n return messageRepo.findReplies(db, agentId, replyTo)\n },\n }\n}\n","// Daemon-side `UserMdHost` implementation backed by the local SQLite handle\n// + `groupRepo`. Same shape as `messaging-host.ts`: the worker subprocess\n// calls IPC, the daemon dispatches through this host.\n//\n// Optimistic concurrency: `get` returns the current content plus a short\n// content-derived etag. `write` requires the caller to echo that etag back\n// in `ifMatch`; if the stored content moved on in the meantime (another\n// agent in the same group wrote concurrently) the write fails with a\n// conflict error containing the new etag, and the caller is expected to\n// re-read, re-merge, and retry. No locks, no leases — pessimistic locking\n// would block agents for whole LLM turns (seconds-to-minutes), which is far\n// worse than the vanishingly-rare retry path.\n//\n// USER.md is capped at USER_MD_MAX_BYTES (kept in sync with the cap in\n// routes/groups.ts) because it's inlined into every agent's system prompt\n// on every turn — uncapped growth would silently blow out the context.\n\nimport { createHash } from 'node:crypto'\nimport { type BazilionDb, groupRepo } from '../core/index.ts'\nimport type { Paths } from '../core/paths.ts'\nimport type { UserMdGetResult, UserMdHost, UserMdWriteResult } from '../runtime/index.ts'\n\nexport const USER_MD_MAX_BYTES = 12_000\n\n/** Short content hash. 16 hex chars is comfortable headroom against accidental collision. */\nfunction computeEtag(content: string): string {\n return createHash('sha256').update(content, 'utf8').digest('hex').slice(0, 16)\n}\n\nexport function createDbUserMdHost(db: BazilionDb, paths: Paths): UserMdHost {\n return {\n get(groupId): UserMdGetResult {\n const group = groupRepo.get(db, groupId, paths)\n if (!group) throw new Error(`group not found: ${groupId}`)\n return { content: group.userMd, etag: computeEtag(group.userMd) }\n },\n write(groupId, content, ifMatch): UserMdWriteResult {\n const group = groupRepo.get(db, groupId, paths)\n if (!group) throw new Error(`group not found: ${groupId}`)\n const currentEtag = computeEtag(group.userMd)\n if (currentEtag !== ifMatch) {\n throw new Error(\n `etag mismatch — USER.md was updated by another agent. Current etag is ${currentEtag} (you passed ${ifMatch}). Call user_md_get again to re-read, merge your change, and retry.`,\n )\n }\n const bytes = Buffer.byteLength(content, 'utf8')\n if (bytes > USER_MD_MAX_BYTES) {\n throw new Error(\n `USER.md would exceed the ${USER_MD_MAX_BYTES}-byte cap (you tried to write ${bytes}). Trim your content or ask the human to compact via the web UI.`,\n )\n }\n groupRepo.setUserMd(db, groupId, content)\n return { etag: computeEtag(content), totalBytes: bytes }\n },\n }\n}\n","import type { ChatFrame } from '@bazilion/api-types'\nimport { mergeSecretsIntoEnv, providerStateRepo, resolveAgent } from '../core/index.ts'\nimport { spawnWorkerTurn } from '../runtime/index.ts'\nimport { registerAgent, unregisterAgent } from './agent-cancel.ts'\nimport { resolveAgentApiKey } from './api-key.ts'\nimport { getCtx } from './ctx.ts'\nimport { createDbMessagingHost } from './messaging-host.ts'\nimport { createDbUserMdHost } from './user-md-host.ts'\n\ninterface RunAgentTurnOpts {\n /** If omitted, a fresh AbortController is created internally. */\n controller?: AbortController\n}\n\n/**\n * Runs one full agent turn in an isolated subprocess, streaming `ChatFrame`s\n * in NDJSON-ready order. The heavy lifting (provider calls, tool execution,\n * pi session journal append) happens inside the child; this function is a\n * thin relay that:\n * - resolves the agent + provider gate + secrets envelope here in the\n * daemon (the worker no longer holds a SQLite handle of its own),\n * - spawns the worker with an IPC channel and a `MessagingHost` that\n * services the inter-agent messaging tools the worker calls back into,\n * - forwards stdout frames to the caller and wires cancellation through\n * the agent-cancel registry.\n */\nexport async function* runAgentTurn(\n agentId: string,\n message: string,\n opts: RunAgentTurnOpts = {},\n): AsyncGenerator<ChatFrame> {\n const { db, paths, authToken } = getCtx()\n const agent = resolveAgent(db, paths, agentId)\n const enabledProviders = Array.from(providerStateRepo.listEnabled(db))\n const env = mergeSecretsIntoEnv(db, authToken)\n const messagingHost = createDbMessagingHost(db)\n const userMdHost = createDbUserMdHost(db, paths)\n // Pre-fetch the API key for OAuth providers (`openai-codex`) before the\n // worker spawns — the worker has no DB handle, so it can't reach the\n // secrets table itself. For env-key providers this is a no-op (`{}`).\n // Refresher is intentionally skipped: the worker has no IPC channel for\n // OAuth refresh today, and the initial token comfortably outlives a\n // single turn for ChatGPT-backed sessions.\n const { apiKey } = await resolveAgentApiKey(db, authToken, agent)\n\n const controller = opts.controller ?? new AbortController()\n registerAgent(agentId, controller)\n try {\n for await (const frame of spawnWorkerTurn(\n { agent, message, enabledProviders, apiKey },\n { signal: controller.signal, env, messagingHost, userMdHost },\n )) {\n yield frame\n }\n } finally {\n unregisterAgent(agentId)\n }\n}\n","// Minimal 5-field cron matcher: \"minute hour day-of-month month day-of-week\".\n// Supports *, */N, N, N-M, and comma-separated lists thereof per field.\n// Day-of-week: 0 or 7 = Sunday, 1 = Monday ... 6 = Saturday.\n//\n// Matching semantics match the \"standard\" cron (non-Vixie) rule: if BOTH\n// day-of-month and day-of-week are restricted (i.e. not `*`), the match is an\n// OR — the trigger fires when either matches. Most common expressions are\n// `*/5 * * * *` or `0 9 * * *` where only one of the two is restricted, so\n// the subtlety rarely matters.\n\nfunction parseField(raw: string, min: number, max: number): Set<number> {\n const values = new Set<number>()\n for (const part of raw.split(',')) {\n const [rangePart, stepPart] = part.split('/')\n const step = stepPart === undefined ? 1 : Number(stepPart)\n if (!Number.isInteger(step) || step < 1) {\n throw new Error(`invalid step \"${stepPart}\"`)\n }\n let lo: number\n let hi: number\n if (rangePart === '*' || rangePart === undefined) {\n lo = min\n hi = max\n } else if (rangePart.includes('-')) {\n const [a, b] = rangePart.split('-').map((n) => Number(n))\n if (!Number.isInteger(a) || !Number.isInteger(b)) {\n throw new Error(`invalid range \"${rangePart}\"`)\n }\n lo = a as number\n hi = b as number\n } else {\n const n = Number(rangePart)\n if (!Number.isInteger(n)) {\n throw new Error(`invalid value \"${rangePart}\"`)\n }\n lo = n\n hi = n\n }\n if (lo < min || hi > max || lo > hi) {\n throw new Error(`value out of range ${min}-${max}: \"${part}\"`)\n }\n for (let v = lo; v <= hi; v += step) values.add(v)\n }\n return values\n}\n\nexport interface ParsedCron {\n minute: Set<number>\n hour: Set<number>\n dom: Set<number>\n month: Set<number>\n dow: Set<number>\n domRestricted: boolean\n dowRestricted: boolean\n}\n\nexport function parseCron(expr: string): ParsedCron {\n const parts = expr.trim().split(/\\s+/)\n if (parts.length !== 5) {\n throw new Error(`expected 5 fields, got ${parts.length}: \"${expr}\"`)\n }\n const [m, h, dom, mon, dow] = parts as [string, string, string, string, string]\n const parsed: ParsedCron = {\n minute: parseField(m, 0, 59),\n hour: parseField(h, 0, 23),\n dom: parseField(dom, 1, 31),\n month: parseField(mon, 1, 12),\n // accept 7 as Sunday alias → normalise to 0\n dow: new Set([...parseField(dow.replace(/7/g, '0'), 0, 6)]),\n domRestricted: dom !== '*',\n dowRestricted: dow !== '*',\n }\n return parsed\n}\n\nexport function matchesCron(parsed: ParsedCron, date: Date): boolean {\n if (!parsed.minute.has(date.getMinutes())) return false\n if (!parsed.hour.has(date.getHours())) return false\n if (!parsed.month.has(date.getMonth() + 1)) return false\n const domMatch = parsed.dom.has(date.getDate())\n const dowMatch = parsed.dow.has(date.getDay())\n if (parsed.domRestricted && parsed.dowRestricted) {\n return domMatch || dowMatch\n }\n if (parsed.domRestricted) return domMatch\n if (parsed.dowRestricted) return dowMatch\n return true\n}\n\n/** Validates an expression — throws on syntax errors. Used by API write paths. */\nexport function validateCron(expr: string): void {\n parseCron(expr)\n}\n","// In-process scheduler for agent triggers (heartbeats + cron) and inbox\n// auto-delivery.\n//\n// Each tick does two jobs:\n//\n// 1. Trigger firing. Loads enabled `agent_triggers` rows and fires whichever\n// are due via `runAgentTurn`. A trigger is \"due\" when:\n// - interval: last_fired_at + intervalSec*1000 ≤ now (never-fired\n// uses created_at as the baseline)\n// - cron: current minute's wall-clock matches expression AND\n// last_fired_at's minute < current minute\n//\n// 2. Inbox auto-delivery (always on). Scans `messages` for recipients\n// with unread mail. For each idle recipient (not already running /\n// firing), drains all their unread messages in one transaction and\n// fires a turn whose prompt embeds the messages. Marking read happens\n// *inside* the drain transaction so two concurrent ticks can't\n// double-dispatch. To disable both triggers AND auto-delivery, set\n// `BAZILION_SCHEDULER=off` — there is no separate inbox-only knob\n// because free inter-agent messaging is a baseline Bazilion promise.\n//\n// Concurrency: each trigger gets an in-memory \"firing\" guard so a slow turn\n// can't pile up overlapping runs for the same trigger. Auto-delivery shares\n// the same mechanism keyed on `msg-wake:<agentId>`. The DB is still the\n// source of truth for last_fired_at / read_at — we mark *before* kicking the\n// run, so a server restart won't immediately re-fire.\n\nimport type { AgentTrigger, Message } from '@bazilion/api-types'\nimport { agentRepo, messageRepo, triggerRepo } from '../core/index.ts'\nimport { isActiveAgent } from './agent-cancel.ts'\nimport { runAgentTurn } from './agent-turn.ts'\nimport { matchesCron, type ParsedCron, parseCron } from './cron.ts'\nimport { getCtx } from './ctx.ts'\n\nconst SCHEDULER_KEY = Symbol.for('bazilion.scheduler')\nconst TICK_MS = Number(process.env.BAZILION_SCHEDULER_TICK_MS ?? 5_000)\n\ninterface SchedulerState {\n timer: NodeJS.Timeout | null\n firing: Set<string>\n cronCache: Map<string, ParsedCron>\n /** pinned onStop for graceful shutdown (tests) */\n stopped: boolean\n}\n\nfunction state(): SchedulerState {\n const g = globalThis as unknown as Record<symbol, SchedulerState | undefined>\n let s = g[SCHEDULER_KEY]\n if (!s) {\n s = { timer: null, firing: new Set(), cronCache: new Map(), stopped: false }\n g[SCHEDULER_KEY] = s\n }\n return s\n}\n\nfunction floorToMinute(ms: number): number {\n return Math.floor(ms / 60_000) * 60_000\n}\n\nfunction isDue(t: AgentTrigger, now: number, cronCache: Map<string, ParsedCron>): boolean {\n if (!t.enabled) return false\n if (t.kind === 'interval') {\n const every = (t.intervalSec ?? 0) * 1000\n if (every <= 0) return false\n const baseline = t.lastFiredAt ?? t.createdAt\n return now - baseline >= every\n }\n if (t.kind === 'cron') {\n if (!t.cronExpr) return false\n let parsed = cronCache.get(t.cronExpr)\n if (!parsed) {\n try {\n parsed = parseCron(t.cronExpr)\n } catch {\n return false\n }\n cronCache.set(t.cronExpr, parsed)\n }\n const nowFloor = floorToMinute(now)\n if (t.lastFiredAt && floorToMinute(t.lastFiredAt) === nowFloor) return false\n return matchesCron(parsed, new Date(nowFloor))\n }\n return false\n}\n\nasync function fireTrigger(t: AgentTrigger): Promise<void> {\n const s = state()\n if (s.firing.has(t.id)) return\n s.firing.add(t.id)\n const ctx = getCtx()\n // Mark fired first — if the agent turn fails, we still don't want to loop\n // on the same trigger every tick. The user will see it in `trigger list`\n // (last_fired_at updated) and the run will be marked failed.\n try {\n triggerRepo.markFired(ctx.db, t.id)\n } catch (err) {\n console.error(`[scheduler] markFired failed for ${t.id}:`, err)\n s.firing.delete(t.id)\n return\n }\n try {\n // Drain the turn; we don't stream to anyone. Errors surface as `fatal`\n // frames which we log but don't throw — the run row in the DB carries\n // the real status.\n for await (const frame of runAgentTurn(t.agentId, t.message)) {\n if (frame.kind === 'fatal') {\n console.error(`[scheduler] trigger ${t.id} fatal:`, frame.error)\n }\n }\n } catch (err) {\n console.error(`[scheduler] trigger ${t.id} unexpected throw:`, err)\n } finally {\n s.firing.delete(t.id)\n }\n}\n\nfunction decodeText(payload: string): string {\n try {\n const obj = JSON.parse(payload) as { text?: unknown }\n if (typeof obj.text === 'string') return obj.text\n } catch {}\n return payload\n}\n\n// Sentinel prepended to every inbox-wake prompt. The web chat UI detects it\n// to render the bubble with a distinct \"inter-agent\" style instead of the\n// default user-message styling. Kept in sync by copy with `chat.ts`'s\n// INBOX_WAKE_PREFIX constant.\nconst INBOX_WAKE_PREFIX = '[[bazilion:inbox-wake]]\\n'\n\n/**\n * Build a wake-up prompt for an agent that has unread mail. The prompt is\n * framed as a user-side system notice — not an agent-style message — so the\n * recipient's LLM understands this is the runtime telling it \"here's what\n * arrived for you\".\n *\n * Loop prevention: we differentiate by `replyTo`. A NEW message (no\n * `replyTo`) opens a thread, and the sender is waiting for an answer — the\n * agent must respond at least once. A REPLY (`replyTo` set) is already\n * closing a round-trip, so the agent may acknowledge silently. This single\n * asymmetry is enough to terminate conversations after one exchange instead\n * of ping-ponging forever (\"you have to answer me\" → \"no you have to\n * answer me\" → …).\n */\nfunction buildInboxPrompt(\n agentId: string,\n messages: Message[],\n fromNames: Map<string, string>,\n): string {\n const lines: string[] = [INBOX_WAKE_PREFIX.trimEnd()]\n lines.push(\n `You have ${messages.length} new message${messages.length === 1 ? '' : 's'} in your inbox:`,\n )\n lines.push('')\n const newThread: Message[] = []\n for (const m of messages) {\n const name = fromNames.get(m.fromAgentId)\n const fromLabel = name ? `${name} (${m.fromAgentId})` : m.fromAgentId\n const text = decodeText(m.payload)\n const header = m.replyTo\n ? `--- from ${fromLabel} (message ${m.id}, reply to ${m.replyTo}) ---`\n : `--- from ${fromLabel} (message ${m.id}) ---`\n lines.push(header)\n lines.push(text)\n lines.push('')\n if (!m.replyTo) newThread.push(m)\n }\n if (newThread.length > 0) {\n lines.push(\n `You MUST reply to the ${newThread.length} new message${newThread.length === 1 ? '' : 's'} above ` +\n '(the ones that are NOT marked as a reply). For each, call ' +\n '`send_message(to=<sender agent id>, text=<your reply>, reply_to=<the message id shown in the header>)`. ' +\n 'Give a concrete answer if you can; a brief acknowledgement is fine if the message is purely informational. ' +\n 'Avoid asking follow-up questions — answer with what you already know. ' +\n 'IMPORTANT: do NOT demand a response from the sender in your reply — they already got what they asked for, ' +\n 'and asking them back to reply just creates infinite loops.',\n )\n }\n const replies = messages.filter((m) => m.replyTo)\n if (replies.length > 0) {\n lines.push(\n `The other message${replies.length === 1 ? ' is a reply' : 's are replies'} to something you previously sent. ` +\n 'Read, absorb, and move on — no response is required. Only send a follow-up if there is a ' +\n 'genuinely new question or action that requires it; otherwise this thread is closed.',\n )\n }\n // reference the recipient id so the agent knows which mailbox this is for\n // in case it was spawned without persona context\n lines.push(`(recipient: ${agentId})`)\n return lines.join('\\n')\n}\n\nasync function fireInboxWake(agentId: string): Promise<void> {\n const s = state()\n const key = `msg-wake:${agentId}`\n if (s.firing.has(key)) return\n const ctx = getCtx()\n // Skip agents with an active turn — they'll pick up the messages on their\n // next natural turn or via the next tick after the current one ends.\n if (isActiveAgent(agentId)) return\n\n s.firing.add(key)\n try {\n const msgs = messageRepo.drainUnreadForAgent(ctx.db, agentId)\n if (msgs.length === 0) {\n // Raced with another consumer; nothing to do.\n return\n }\n const fromIds = new Set(msgs.map((m) => m.fromAgentId))\n const fromNames = new Map<string, string>()\n for (const fid of fromIds) {\n const sender = agentRepo.get(ctx.db, fid)\n if (sender) fromNames.set(fid, sender.name)\n }\n const prompt = buildInboxPrompt(agentId, msgs, fromNames)\n\n try {\n for await (const frame of runAgentTurn(agentId, prompt)) {\n if (frame.kind === 'fatal') {\n console.error(`[scheduler] inbox wake ${agentId} fatal:`, frame.error)\n }\n }\n } catch (err) {\n console.error(`[scheduler] inbox wake ${agentId} unexpected throw:`, err)\n }\n } catch (err) {\n console.error(`[scheduler] inbox drain failed for ${agentId}:`, err)\n } finally {\n s.firing.delete(key)\n }\n}\n\nasync function tick(): Promise<void> {\n const s = state()\n if (s.stopped) return\n const now = Date.now()\n let triggers: AgentTrigger[]\n let recipients: string[] = []\n try {\n const ctx = getCtx()\n triggers = triggerRepo.listEnabled(ctx.db)\n recipients = messageRepo.listRecipientsWithUnread(ctx.db)\n } catch (err) {\n console.error('[scheduler] tick read failed:', err)\n return\n }\n for (const t of triggers) {\n if (isDue(t, now, s.cronCache)) {\n // Fire async, don't await — the tick itself must stay fast.\n void fireTrigger(t)\n }\n }\n for (const agentId of recipients) {\n // Same fire-and-forget shape as triggers; `fireInboxWake` internally\n // dedup-gates and bails if the agent already has an active run.\n void fireInboxWake(agentId)\n }\n}\n\nexport function startScheduler(): void {\n const s = state()\n // Replace any existing timer unconditionally so a duplicate startScheduler\n // call (e.g. test harness calling getCtx twice) doesn't leave stale loops.\n if (s.timer) clearInterval(s.timer)\n s.stopped = false\n s.timer = setInterval(() => {\n void tick()\n }, TICK_MS)\n // Unref so the scheduler never blocks process exit in tests.\n if (typeof s.timer.unref === 'function') s.timer.unref()\n}\n\nexport function stopScheduler(): void {\n const s = state()\n s.stopped = true\n if (s.timer) {\n clearInterval(s.timer)\n s.timer = null\n }\n}\n\n// Exposed for tests that want to drive the loop manually rather than wait\n// on wall-clock intervals.\nexport async function _tickOnce(): Promise<void> {\n await tick()\n}\n\nexport function _isDueForTest(\n t: AgentTrigger,\n now: number,\n cronCache: Map<string, ParsedCron> = new Map(),\n): boolean {\n return isDue(t, now, cronCache)\n}\n","// Token verification primitives — framework-agnostic. The Hono auth middleware\n// (lib/middleware-auth.ts) wraps these; native clients (CLI, mobile) pass the\n// same token via `Authorization: Bearer …`, and browsers send the httpOnly\n// `bz_token` cookie minted by `POST /api/login`.\n//\n// All tokens — including the bootstrap one minted by the daemon's first-run\n// bootstrap — live as hashed rows in the `web_tokens` table. The bootstrap\n// row's plaintext is exposed in `~/.bazilion/auth.json` so the daemon (PBKDF2\n// seed for the secrets table) and the CLI (loopback bearer) can use it.\n// Validation goes through `findActiveByToken`, no special-case loopback path.\n\nimport { webTokenRepo } from '../core/index.ts'\nimport { getCtx } from './ctx.ts'\n\n/**\n * Is this string a currently-valid token? Accepts any active (non-revoked)\n * row in `web_tokens` — including the bootstrap row written by the daemon's\n * first-run bootstrap. Bumps `last_used_at` on a match so operators can see\n * idle vs active tokens in `token list`.\n */\nexport function isValidToken(token: string): boolean {\n try {\n const { db } = getCtx()\n const match = webTokenRepo.findActiveByToken(db, token)\n if (match) {\n webTokenRepo.markUsed(db, match.id)\n return true\n }\n } catch {\n // db unavailable — treat as unauthenticated\n }\n return false\n}\n\n/** Pull the bearer token out of an `Authorization: Bearer …` header. */\nexport function extractBearer(authHeader: string | null | undefined): string | null {\n if (!authHeader) return null\n // RFC 6750 auth scheme is case-insensitive.\n const match = /^\\s*Bearer\\s+(.+?)\\s*$/i.exec(authHeader)\n return match?.[1] ?? null\n}\n","// /api/agents/* — agent CRUD + lifecycle + sub-resources (group, skills,\n// triggers, messages, sessions, chat). Memory is per-group and lives on\n// the groups router.\n//\n// Sub-resources are inlined here rather than split across files because they\n// all share `/api/agents/:id/...` and benefit from being adjacent — e.g. the\n// chat streaming endpoint and chat/compact next to each other.\n\nimport { existsSync, readdirSync, readFileSync, rmSync } from 'node:fs'\nimport { join } from 'node:path'\nimport {\n type AttachSkillRequest,\n type ChatCompactRequest,\n type ChatCompactResponse,\n type ChatContextResponse,\n type ContextFileEntry,\n type ContextGroupEntry,\n type ContextSkillEntry,\n type ContextToolEntry,\n type CreateTriggerRequest,\n type ListInboxResponse,\n type MoveAgentRequest,\n REASONING_LEVELS,\n type ReasoningLevel,\n type ResolvedSkillsResponse,\n type SendMessageRequest,\n type SessionHeadResponse,\n type SpawnAgentRequest,\n type TruncateChatRequest,\n type TruncateChatResponse,\n} from '@bazilion/api-types'\nimport { Hono } from 'hono'\nimport {\n agentRepo,\n archiveAgent,\n deleteAgent,\n discoverSkills,\n groupRepo,\n mergeSecretsIntoEnv,\n messageRepo,\n providerStateRepo,\n resolveAgent,\n resolveAgentSkills,\n skillMetaRepo,\n spawnAgent,\n triggerRepo,\n unarchiveAgent,\n} from '../core/index.ts'\nimport { cancelAgent } from '../lib/agent-cancel.ts'\nimport { resolveAgentIdParam } from '../lib/agent-id.ts'\nimport { runAgentTurn } from '../lib/agent-turn.ts'\nimport { resolveAgentApiKey } from '../lib/api-key.ts'\nimport { validateCron } from '../lib/cron.ts'\nimport { getCtx } from '../lib/ctx.ts'\nimport { createDbMessagingHost } from '../lib/messaging-host.ts'\nimport {\n buildSystemPrompt,\n createBazilionSession,\n loadInitialMessages,\n loadSessionHead,\n piMessagesToProviderView,\n qmdBackend,\n} from '../runtime/index.ts'\n\nexport const agentsRouter = new Hono()\n\n// ─── CRUD + lifecycle ────────────────────────────────────────────────────\n\nagentsRouter.get('/', (c) => {\n const includeArchived = c.req.query('includeArchived') === 'true'\n const { db, paths, authToken } = getCtx()\n return c.json(agentRepo.list(db, { includeArchived }))\n})\n\nagentsRouter.post('/', async (c) => {\n const raw = (await c.req.json().catch(() => null)) as\n | (Record<string, unknown> & Partial<SpawnAgentRequest>)\n | null\n if (!raw) return c.json({ error: 'invalid JSON body' }, 400)\n const profileId =\n typeof raw.profileId === 'string'\n ? raw.profileId\n : typeof raw.profile === 'string'\n ? raw.profile\n : ''\n if (!profileId) return c.json({ error: 'profileId is required' }, 400)\n const name = typeof raw.name === 'string' && raw.name ? raw.name : undefined\n const model =\n typeof raw.model === 'string' && raw.model\n ? raw.model\n : typeof raw.modelOverride === 'string' && raw.modelOverride\n ? raw.modelOverride\n : undefined\n const groupId =\n typeof raw.groupId === 'string' && raw.groupId\n ? raw.groupId\n : typeof raw.group === 'string' && raw.group\n ? (raw.group as string)\n : undefined\n let reasoningLevel: ReasoningLevel | undefined\n if (typeof raw.reasoningLevel === 'string') {\n if (!REASONING_LEVELS.includes(raw.reasoningLevel as ReasoningLevel)) {\n return c.json({ error: `invalid reasoningLevel: ${raw.reasoningLevel}` }, 400)\n }\n reasoningLevel = raw.reasoningLevel as ReasoningLevel\n }\n\n const { db, paths, authToken } = getCtx()\n try {\n const agent = spawnAgent(db, paths, {\n profileId,\n name,\n modelOverride: model,\n reasoningLevel,\n groupId,\n })\n return c.json(agent, 201)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n})\n\nagentsRouter.get('/:id', (c) => {\n const { db, paths, authToken } = getCtx()\n const id = resolveAgentIdParam(db, c.req.param('id'))\n try {\n return c.json(resolveAgent(db, paths, id))\n } catch (err) {\n return c.json({ error: (err as Error).message }, 404)\n }\n})\n\nagentsRouter.patch('/:id', async (c) => {\n const body = (await c.req.json().catch(() => null)) as Record<string, unknown> | null\n if (!body) return c.json({ error: 'invalid JSON body' }, 400)\n const { db, paths, authToken } = getCtx()\n const resolvedId = agentRepo.resolveId(db, c.req.param('id'))\n if (!resolvedId) return c.json({ error: `agent not found: ${c.req.param('id')}` }, 404)\n\n if (body.name !== undefined) {\n if (typeof body.name !== 'string') return c.json({ error: 'name must be a string' }, 400)\n const trimmed = body.name.trim()\n if (!trimmed) return c.json({ error: 'name cannot be empty' }, 400)\n agentRepo.setName(db, resolvedId, trimmed)\n }\n if (body.reasoningLevel !== undefined) {\n if (\n typeof body.reasoningLevel !== 'string' ||\n !REASONING_LEVELS.includes(body.reasoningLevel as ReasoningLevel)\n ) {\n return c.json({ error: `invalid reasoningLevel: ${body.reasoningLevel}` }, 400)\n }\n agentRepo.setReasoningLevel(db, resolvedId, body.reasoningLevel as ReasoningLevel)\n }\n if (body.modelOverride !== undefined) {\n if (body.modelOverride !== null && typeof body.modelOverride !== 'string') {\n return c.json({ error: 'modelOverride must be a string or null' }, 400)\n }\n const value = body.modelOverride === '' ? null : (body.modelOverride as string | null)\n agentRepo.setModelOverride(db, resolvedId, value)\n }\n\n const agent = agentRepo.get(db, resolvedId)\n if (!agent) return c.json({ error: 'agent vanished after update' }, 404)\n return c.json(agent)\n})\n\nagentsRouter.delete('/:id', (c) => {\n const { db, paths, authToken } = getCtx()\n try {\n deleteAgent(db, c.req.param('id'))\n return c.body(null, 204)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n})\n\nagentsRouter.post('/:id/archive', (c) => {\n const { db, paths, authToken } = getCtx()\n try {\n archiveAgent(db, c.req.param('id'))\n return c.body(null, 204)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n})\n\nagentsRouter.post('/:id/unarchive', (c) => {\n const { db, paths, authToken } = getCtx()\n try {\n unarchiveAgent(db, c.req.param('id'))\n return c.body(null, 204)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n})\n\n// ─── Group move ──────────────────────────────────────────────────────────\n\nagentsRouter.patch('/:id/group', async (c) => {\n const body = (await c.req.json().catch(() => null)) as MoveAgentRequest | null\n if (!body || typeof body.groupId !== 'string' || !body.groupId) {\n return c.json({ error: 'groupId (string) is required' }, 400)\n }\n const { db, paths, authToken } = getCtx()\n let resolved: ReturnType<typeof resolveAgent>\n try {\n resolved = resolveAgent(db, paths, c.req.param('id'))\n } catch {\n return c.json({ error: `agent not found: ${c.req.param('id')}` }, 404)\n }\n if (!groupRepo.get(db, body.groupId, paths)) {\n return c.json({ error: `group not found: ${body.groupId}` }, 404)\n }\n agentRepo.setGroup(db, resolved.agent.id, body.groupId)\n return c.json(resolveAgent(db, paths, resolved.agent.id))\n})\n\n// ─── Skills ──────────────────────────────────────────────────────────────\n\nagentsRouter.get('/:id/skills', (c) => {\n const { db, paths, authToken } = getCtx()\n const id = resolveAgentIdParam(db, c.req.param('id'))\n const set = resolveAgentSkills(db, paths, id)\n const body: ResolvedSkillsResponse = {\n resolved: set.resolved.map((s) => {\n const meta = skillMetaRepo.get(db, s.name)\n return {\n name: s.name,\n description: s.parsed.frontmatter.description,\n source: meta?.source ?? null,\n importedAt: meta?.importedAt ?? null,\n }\n }),\n missing: set.missing,\n }\n return c.json(body)\n})\n\nagentsRouter.post('/:id/skills', async (c) => {\n const body = (await c.req.json().catch(() => null)) as AttachSkillRequest | null\n if (!body || typeof body.skill !== 'string' || !body.skill) {\n return c.json({ error: 'skill is required' }, 400)\n }\n const { db, paths, authToken } = getCtx()\n const agent = agentRepo.get(db, c.req.param('id'))\n if (!agent) return c.json({ error: `agent not found: ${c.req.param('id')}` }, 404)\n agentRepo.attachSkill(db, agent.id, body.skill)\n return c.body(null, 204)\n})\n\nagentsRouter.delete('/:id/skills/:name', (c) => {\n const { db, paths, authToken } = getCtx()\n const id = resolveAgentIdParam(db, c.req.param('id'))\n agentRepo.detachSkill(db, id, c.req.param('name'))\n return c.body(null, 204)\n})\n\n// ─── Triggers ────────────────────────────────────────────────────────────\n\nagentsRouter.get('/:id/triggers', (c) => {\n const { db, paths, authToken } = getCtx()\n const agent = agentRepo.get(db, c.req.param('id'))\n if (!agent) return c.json({ error: `agent not found: ${c.req.param('id')}` }, 404)\n return c.json({ triggers: triggerRepo.listForAgent(db, agent.id) })\n})\n\nagentsRouter.post('/:id/triggers', async (c) => {\n const body = (await c.req.json().catch(() => null)) as CreateTriggerRequest | null\n if (!body) return c.json({ error: 'invalid JSON body' }, 400)\n if (typeof body.message !== 'string' || !body.message.trim()) {\n return c.json({ error: 'message is required' }, 400)\n }\n const { db, paths, authToken } = getCtx()\n const agent = agentRepo.get(db, c.req.param('id'))\n if (!agent) return c.json({ error: `agent not found: ${c.req.param('id')}` }, 404)\n\n if (body.kind === 'interval') {\n if (!Number.isFinite(body.intervalSec) || (body.intervalSec ?? 0) <= 0) {\n return c.json({ error: 'intervalSec must be a positive number' }, 400)\n }\n const trigger = triggerRepo.insert(db, {\n agentId: agent.id,\n kind: 'interval',\n intervalSec: Math.floor(body.intervalSec as number),\n cronExpr: null,\n message: body.message,\n enabled: body.enabled,\n })\n return c.json({ trigger }, 201)\n }\n\n if (body.kind === 'cron') {\n if (typeof body.cronExpr !== 'string' || !body.cronExpr.trim()) {\n return c.json({ error: 'cronExpr is required for kind=cron' }, 400)\n }\n try {\n validateCron(body.cronExpr)\n } catch (err) {\n return c.json({ error: `invalid cron: ${(err as Error).message}` }, 400)\n }\n const trigger = triggerRepo.insert(db, {\n agentId: agent.id,\n kind: 'cron',\n intervalSec: null,\n cronExpr: body.cronExpr.trim(),\n message: body.message,\n enabled: body.enabled,\n })\n return c.json({ trigger }, 201)\n }\n\n return c.json({ error: `invalid kind: ${body.kind}` }, 400)\n})\n\n// ─── Messages ────────────────────────────────────────────────────────────\n\nagentsRouter.get('/:id/messages', (c) => {\n const { db, paths, authToken } = getCtx()\n const agent = agentRepo.get(db, c.req.param('id'))\n if (!agent) return c.json({ error: `agent not found: ${c.req.param('id')}` }, 404)\n const unreadOnly = c.req.query('unread') === '1'\n const body: ListInboxResponse = {\n messages: messageRepo.listInbox(db, agent.id, { unreadOnly }),\n }\n return c.json(body)\n})\n\nagentsRouter.post('/:id/messages', async (c) => {\n const body = (await c.req.json().catch(() => null)) as SendMessageRequest | null\n if (\n !body ||\n typeof body.from !== 'string' ||\n !body.from ||\n !body.payload ||\n typeof body.payload.text !== 'string'\n ) {\n return c.json({ error: 'from and payload.text are required' }, 400)\n }\n const { db, paths, authToken } = getCtx()\n const fromAgent = agentRepo.get(db, body.from)\n if (!fromAgent) return c.json({ error: `agent not found: ${body.from}` }, 404)\n const toAgent = agentRepo.get(db, c.req.param('id'))\n if (!toAgent) return c.json({ error: `agent not found: ${c.req.param('id')}` }, 404)\n if (body.replyTo && !messageRepo.get(db, body.replyTo)) {\n return c.json({ error: `reply target not found: ${body.replyTo}` }, 404)\n }\n const msg = messageRepo.send(db, {\n from: fromAgent.id,\n to: toAgent.id,\n payload: JSON.stringify({ text: body.payload.text }),\n replyTo: body.replyTo ?? null,\n })\n return c.json(msg, 201)\n})\n\n// ─── Cancel ──────────────────────────────────────────────────────────────\n\n// Aborts the agent's currently-running turn, if any. Returns 204 on a\n// successful abort, 409 when the agent is idle. Cancellation drives off the\n// in-memory agent-cancel registry, which is also what the scheduler probes\n// to skip overlapping inbox wakes / triggers.\nagentsRouter.post('/:id/cancel', (c) => {\n const { db, paths, authToken } = getCtx()\n const id = resolveAgentIdParam(db, c.req.param('id'))\n const cancelled = cancelAgent(id)\n if (!cancelled) return c.json({ error: 'agent has no active turn' }, 409)\n return c.body(null, 204)\n})\n\n// ─── Sessions ────────────────────────────────────────────────────────────\n\nagentsRouter.get('/:id/sessions/head', (c) => {\n const { db, paths, authToken } = getCtx()\n let resolved: ReturnType<typeof resolveAgent>\n try {\n resolved = resolveAgent(db, paths, c.req.param('id'))\n } catch {\n return c.json({ error: `agent not found: ${c.req.param('id')}` }, 404)\n }\n const head: SessionHeadResponse = loadSessionHead(resolved, paths)\n return c.json(head)\n})\n\n/**\n * Returns the agent's prior transcript flattened to ProviderMessage[].\n * SSR loaders use it to render the chat history on first paint without\n * touching pi or the filesystem from the web process.\n */\nagentsRouter.get('/:id/sessions/messages', (c) => {\n const { db, paths, authToken } = getCtx()\n let resolved: ReturnType<typeof resolveAgent>\n try {\n resolved = resolveAgent(db, paths, c.req.param('id'))\n } catch {\n return c.json({ error: `agent not found: ${c.req.param('id')}` }, 404)\n }\n const messages = piMessagesToProviderView(loadInitialMessages(resolved, paths))\n return c.json({ messages })\n})\n\n// ─── Chat ────────────────────────────────────────────────────────────────\n\n/**\n * Streaming chat endpoint. Server-authoritative: prior history is read by\n * pi's SessionManager from the agent's JSONL session file. The client sends\n * only `{ message }`. Response is NDJSON-encoded `ChatFrame`s.\n */\nagentsRouter.post('/:id/chat', async (c) => {\n const { db, paths, authToken } = getCtx()\n const id = resolveAgentIdParam(db, c.req.param('id'))\n\n let body: { message?: string }\n try {\n body = (await c.req.json()) as { message?: string }\n } catch {\n return c.json({ error: 'invalid JSON body' }, 400)\n }\n const message = body.message\n if (!message || typeof message !== 'string') {\n return c.json({ error: 'message is required' }, 400)\n }\n\n const stream = new ReadableStream({\n async start(controller) {\n const encoder = new TextEncoder()\n try {\n for await (const frame of runAgentTurn(id, message)) {\n try {\n controller.enqueue(encoder.encode(`${JSON.stringify(frame)}\\n`))\n } catch {\n // client disconnected — keep draining so state gets saved\n }\n }\n } catch (err) {\n try {\n controller.enqueue(\n encoder.encode(`${JSON.stringify({ kind: 'fatal', error: (err as Error).message })}\\n`),\n )\n } catch {}\n }\n try {\n controller.close()\n } catch {}\n },\n })\n\n return new Response(stream, {\n headers: {\n 'content-type': 'application/x-ndjson',\n 'cache-control': 'no-cache',\n 'x-content-type-options': 'nosniff',\n },\n })\n})\n\nagentsRouter.post('/:id/chat/compact', async (c) => {\n let body: ChatCompactRequest = {}\n if (c.req.header('content-length') !== '0') {\n try {\n const parsed = (await c.req.json()) as ChatCompactRequest | null\n if (parsed && typeof parsed === 'object') body = parsed\n } catch {\n // empty body is allowed — all fields optional\n }\n }\n\n const { db, paths, authToken } = getCtx()\n const id = resolveAgentIdParam(db, c.req.param('id'))\n if (!agentRepo.get(db, id)) return c.json({ error: 'agent not found' }, 404)\n\n const resolved = resolveAgent(db, paths, id)\n const memory = qmdBackend(join(resolved.group.path, 'memory'))\n await memory.init()\n const env = mergeSecretsIntoEnv(db, authToken)\n\n const apiKeyResolution = await resolveAgentApiKey(db, authToken, resolved, {\n withRefresher: true,\n })\n const handle = await createBazilionSession({\n agent: resolved,\n paths,\n env,\n memory,\n enabledProviders: providerStateRepo.listEnabled(db),\n messagingHost: createDbMessagingHost(db),\n ...apiKeyResolution,\n })\n try {\n const entriesBefore = handle.session.sessionManager.getEntries().length\n const result = await handle.session.compact(body.customInstructions)\n const entriesAfter = handle.session.sessionManager.getEntries().length\n\n let keptTail = 0\n if (result.firstKeptEntryId) {\n const branch = handle.session.sessionManager.getBranch()\n const idx = branch.findIndex((e) => e.id === result.firstKeptEntryId)\n if (idx >= 0) for (const e of branch.slice(idx)) if (e.type === 'message') keptTail++\n }\n\n const tokensAfter = handle.session.getContextUsage()?.tokens ?? 0\n\n const resp: ChatCompactResponse = {\n before: entriesBefore,\n after: entriesAfter,\n summarized: Math.max(0, entriesBefore - entriesAfter + 1),\n keptTail,\n tokensBefore: result.tokensBefore,\n tokensAfter,\n summary: result.summary,\n }\n return c.json(resp)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 502)\n } finally {\n handle.dispose()\n }\n})\n\nagentsRouter.get('/:id/chat/context', async (c) => {\n const { db, paths, authToken } = getCtx()\n const id = resolveAgentIdParam(db, c.req.param('id'))\n if (!agentRepo.get(db, id)) return c.json({ error: 'agent not found' }, 404)\n\n const resolved = resolveAgent(db, paths, id)\n\n const files: ContextFileEntry[] = []\n for (const file of CONTEXT_FILE_ORDER) {\n const path = join(resolved.agent.dir, file)\n if (!existsSync(path)) continue\n const content = readFileSync(path, 'utf8').trimEnd()\n if (!content) continue\n const chars = content.length + file.length + 6\n files.push({ name: file, chars, tokens: estimateTokens(chars) })\n }\n const systemPromptText = buildSystemPrompt(resolved)\n const systemPromptChars = systemPromptText.length\n\n const skillsListChars =\n resolved.skills.length > 0\n ? `# Available Skills\\n\\nYou have access to the following skills: ${resolved.skills.join(', ')}.`\n .length\n : 0\n const groupLines = [\n '# Group',\n '',\n `- ${resolved.group.id} (${resolved.group.name}): ${resolved.group.path}`,\n '',\n 'Your group is where work product lives — code, docs, artefacts, shared scratch. It may be shared with other agents in the same group. Your coding tools (`read`, `bash`, `edit`, `write`, `grep`, `find`, `ls`) are rooted at the group directory. Never use these tools to edit your identity/soul/behaviour files — those live in your home and are reached via `home_write` / `home_read`.',\n ]\n const groupListChars = groupLines.join('\\n').length\n const userMdChars = resolved.group.userMd.trim()\n ? `# About the User\\n\\nRead-only context about the human you're working with in this group. You cannot edit this — if it's wrong, say so and they will update it.\\n\\n${resolved.group.userMd.trim()}`\n .length\n : 0\n const memoryHintChars =\n '# Memory\\n\\nYou have a persistent memory backend. Use `memory_write` to remember things across sessions, and `memory_search` / `memory_read` / `memory_list` to recall them. Always check memory at the start of a session if the user might have told you something important before.'\n .length\n\n const memory = qmdBackend(join(resolved.group.path, 'memory'))\n await memory.init()\n const env = mergeSecretsIntoEnv(db, authToken)\n const apiKeyResolution = await resolveAgentApiKey(db, authToken, resolved, {\n withRefresher: true,\n })\n const handle = await createBazilionSession({\n agent: resolved,\n paths,\n env,\n memory,\n enabledProviders: providerStateRepo.listEnabled(db),\n messagingHost: createDbMessagingHost(db),\n ...apiKeyResolution,\n })\n\n try {\n const toolInfos = handle.session.getAllTools()\n let toolsSchemaChars = 0\n let toolsListChars = 0\n const toolEntries: ContextToolEntry[] = []\n for (const info of toolInfos) {\n const schemaJson = JSON.stringify(info.parameters ?? {})\n const schemaChars = schemaJson.length\n const descriptionChars = info.description.length\n toolsSchemaChars += schemaChars\n toolsListChars += info.name.length + descriptionChars + 3\n toolEntries.push({\n name: info.name,\n schemaChars,\n descriptionChars,\n paramCount: countProperties(info.parameters),\n })\n }\n toolEntries.sort((a, b) => b.schemaChars - a.schemaChars)\n\n const installed = discoverSkills(paths)\n const skillEntries: ContextSkillEntry[] = []\n for (const name of resolved.skills) {\n const match = installed.find((s) => s.name === name)\n let blockChars = name.length + 2\n if (match) {\n try {\n blockChars = readFileSync(match.skillFile, 'utf8').length\n } catch {}\n }\n skillEntries.push({ name, blockChars })\n }\n skillEntries.sort((a, b) => b.blockChars - a.blockChars)\n\n const group: ContextGroupEntry = {\n id: resolved.group.id,\n name: resolved.group.name,\n path: resolved.group.path,\n userMdChars: resolved.group.userMd.length,\n }\n\n const stats = handle.session.getSessionStats()\n const historyChars = stats.tokens.total * 4\n const messageEntries = stats.userMessages + stats.assistantMessages + stats.toolResults\n const compactionEntries = handle.session.sessionManager\n .getEntries()\n .filter((e) => e.type === 'compaction').length\n const contextUsage = handle.session.getContextUsage()\n const historyTokens = contextUsage?.tokens ?? stats.tokens.total\n\n const detail = c.req.query('detail') === '1' || c.req.query('json') === '1'\n const CAP = 30\n const toolEntriesOut = detail ? toolEntries : toolEntries.slice(0, CAP)\n const skillEntriesOut = detail ? skillEntries : skillEntries.slice(0, CAP)\n\n const totalsChars = systemPromptChars + toolsSchemaChars + historyChars\n const resp: ChatContextResponse = {\n agentId: resolved.agent.id,\n model: resolved.model,\n systemPrompt: {\n chars: systemPromptChars,\n tokens: estimateTokens(systemPromptChars),\n files,\n skillsListChars,\n groupListChars,\n userMdChars,\n memoryHintChars,\n },\n tools: {\n count: toolInfos.length,\n listChars: toolsListChars,\n schemaChars: toolsSchemaChars,\n entries: toolEntriesOut,\n },\n skills: {\n count: resolved.skills.length,\n entries: skillEntriesOut,\n },\n group,\n history: {\n messageEntries,\n compactionEntries,\n chars: historyChars,\n bytes: historyChars,\n tokensEstimate: historyTokens,\n },\n totals: {\n chars: totalsChars,\n tokens: estimateTokens(totalsChars),\n },\n }\n return c.json(resp)\n } finally {\n handle.dispose()\n }\n})\n\nagentsRouter.post('/:id/chat/reset', (c) => {\n const { db, paths, authToken } = getCtx()\n const id = resolveAgentIdParam(db, c.req.param('id'))\n const agent = agentRepo.get(db, id)\n if (!agent) return c.json({ error: 'agent not found' }, 404)\n\n const sessionsDir = join(paths.agentDir(agent.id), 'sessions')\n let deleted = 0\n if (existsSync(sessionsDir)) {\n for (const file of readdirSync(sessionsDir)) {\n if (!file.endsWith('.jsonl')) continue\n try {\n rmSync(join(sessionsDir, file))\n deleted++\n } catch {\n // best-effort\n }\n }\n }\n return c.json({ ok: true, deletedSessionFiles: deleted })\n})\n\nagentsRouter.post('/:id/chat/truncate', async (c) => {\n let body: TruncateChatRequest\n try {\n body = (await c.req.json()) as TruncateChatRequest\n } catch {\n return c.json({ error: 'invalid JSON body' }, 400)\n }\n const keep = Number(body.keepCount)\n if (!Number.isFinite(keep) || keep < 0 || !Number.isInteger(keep)) {\n return c.json({ error: 'keepCount must be a non-negative integer' }, 400)\n }\n\n const { db, paths, authToken } = getCtx()\n const id = resolveAgentIdParam(db, c.req.param('id'))\n if (!agentRepo.get(db, id)) return c.json({ error: 'agent not found' }, 404)\n\n const resolved = resolveAgent(db, paths, id)\n const memory = qmdBackend(join(resolved.group.path, 'memory'))\n await memory.init()\n const env = mergeSecretsIntoEnv(db, authToken)\n\n const apiKeyResolution = await resolveAgentApiKey(db, authToken, resolved, {\n withRefresher: true,\n })\n const handle = await createBazilionSession({\n agent: resolved,\n paths,\n env,\n memory,\n enabledProviders: providerStateRepo.listEnabled(db),\n messagingHost: createDbMessagingHost(db),\n ...apiKeyResolution,\n })\n try {\n const branch = handle.session.sessionManager.getBranch()\n const messageEntries = branch.filter((e) => e.type === 'message')\n const before = messageEntries.length\n const target = Math.max(0, Math.min(keep, before))\n\n if (target === before) {\n return c.json({ before, after: before } satisfies TruncateChatResponse)\n }\n\n if (target === 0) {\n handle.session.sessionManager.resetLeaf()\n } else {\n const lastKept = messageEntries[target - 1]\n if (!lastKept) return c.json({ error: 'internal: missing target entry' }, 500)\n handle.session.sessionManager.branch(lastKept.id)\n }\n\n return c.json({ before, after: target } satisfies TruncateChatResponse)\n } finally {\n handle.dispose()\n }\n})\n\n// ─── helpers ─────────────────────────────────────────────────────────────\n\nconst CONTEXT_FILE_ORDER = [\n 'AGENTS.md',\n 'SOUL.md',\n 'TOOLS.md',\n 'IDENTITY.md',\n 'HEARTBEAT.md',\n 'BOOTSTRAP.md',\n] as const\n\nfunction estimateTokens(chars: number): number {\n return Math.ceil(Math.max(0, chars) / 4)\n}\n\nfunction countProperties(schema: unknown): number | null {\n if (!schema || typeof schema !== 'object') return null\n const props = (schema as { properties?: unknown }).properties\n if (!props || typeof props !== 'object') return null\n return Object.keys(props as Record<string, unknown>).length\n}\n","// Canonical entity shapes. The daemon's DB schema (apps/daemon/src/core/db)\n// produces these, the daemon serialises them onto the wire, every client\n// (web, mobile, cli, future SDKs) consumes them. Owned here so clients never\n// have to reach into daemon source (which carries node:sqlite) just to know\n// what an Agent is.\n\nexport type Timestamp = number\n\n/**\n * A group is a collaboration context: one filesystem root, one USER.md\n * (read-only to agents, edited by the human), one roster of member agents.\n * Every agent belongs to exactly one group.\n */\nexport interface Group {\n id: string\n name: string\n path: string\n /** Read-only context about the human for all agents in this group.\n * Injected into the system prompt; never exposed as a file on disk. */\n userMd: string\n createdAt: Timestamp\n}\n\nexport type SkillsMode = 'all' | 'selected'\n\nexport interface Profile {\n id: string\n name: string\n dir: string\n defaultModel: string\n skillsMode: SkillsMode\n createdAt: Timestamp\n updatedAt: Timestamp\n}\n\nexport type AgentStatus = 'idle' | 'running' | 'archived'\n\nexport type ReasoningLevel = 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh'\n\nexport const REASONING_LEVELS: ReasoningLevel[] = [\n 'off',\n 'minimal',\n 'low',\n 'medium',\n 'high',\n 'xhigh',\n]\n\nexport interface Agent {\n id: string\n profileId: string\n name: string\n modelOverride: string | null\n reasoningLevel: ReasoningLevel\n status: AgentStatus\n dir: string\n /** The group this agent belongs to. Every agent has exactly one. */\n groupId: string\n createdAt: Timestamp\n archivedAt: Timestamp | null\n}\n\nexport interface AgentSkillAttachment {\n agentId: string\n skillName: string\n attachedAt: Timestamp\n}\n\nexport interface SkillMeta {\n name: string\n source: string | null\n importedAt: Timestamp | null\n}\n\nexport interface Message {\n id: string\n fromAgentId: string\n toAgentId: string\n replyTo: string | null\n payload: string\n createdAt: Timestamp\n readAt: Timestamp | null\n}\n\nexport interface WebToken {\n id: string\n label: string\n createdAt: Timestamp\n lastUsedAt: Timestamp | null\n revokedAt: Timestamp | null\n}\n\nexport type TriggerKind = 'interval' | 'cron'\n\nexport interface AgentTrigger {\n id: string\n agentId: string\n kind: TriggerKind\n intervalSec: number | null\n cronExpr: string | null\n message: string\n enabled: boolean\n lastFiredAt: Timestamp | null\n createdAt: Timestamp\n}\n\nexport interface OpenAICodexStatus {\n connected: boolean\n /** Unix ms expiry of the current access token; null if disconnected. */\n expiresAt: number | null\n /** chatgpt_account_id extracted from the JWT, when available. */\n accountId: string | null\n}\n\nexport interface AgentIdentityFile {\n name?: string\n emoji?: string\n theme?: string\n creature?: string\n vibe?: string\n avatar?: string\n}\n\nexport interface ResolvedAgent {\n agent: Agent\n profile: Profile\n model: string\n reasoningLevel: ReasoningLevel\n group: Group\n skills: string[]\n}\n\n/**\n * A profile group is a reusable team template: an ordered list of slots,\n * each pointing at an existing Profile with optional per-slot overrides.\n * Spawning a profile group creates N agents in one transactional call.\n * Strictly additive — the single-profile spawn path is untouched.\n */\nexport interface ProfileGroup {\n id: string\n name: string\n /** Optional starter USER.md content; only seeded into a freshly-created target group. */\n userMd: string | null\n createdAt: Timestamp\n updatedAt: Timestamp\n}\n\nexport interface ProfileGroupMember {\n profileGroupId: string\n position: number\n profileId: string\n agentName: string\n modelOverride: string | null\n reasoningLevel: ReasoningLevel | null\n}\n\nexport interface ProfileGroupDetail {\n group: ProfileGroup\n members: ProfileGroupMember[]\n}\n\nexport interface ProfileGroupWithCount extends ProfileGroup {\n memberCount: number\n}\n\nexport interface LoadedProfile {\n profile: Profile\n defaultSkills: string[]\n files: {\n soul: string\n identity: string\n bootstrap: string | null\n agents: string | null\n tools: string | null\n heartbeat: string | null\n }\n /** Structured fields parsed from IDENTITY.md — null when no values are set. */\n identity: AgentIdentityFile | null\n}\n","// Wire-shape package. Hermetic: depends on nothing from the daemon, so every\n// client (web, mobile, cli, future SDKs) can pull in API shapes without\n// dragging Node-only code (node:sqlite, undici, pi-ai, the worker spawner)\n// into its TS check graph or runtime bundle. The daemon imports its entity\n// and wire types FROM here.\n\nexport type {\n Agent,\n AgentIdentityFile,\n AgentSkillAttachment,\n AgentStatus,\n AgentTrigger,\n Group,\n LoadedProfile,\n Message,\n OpenAICodexStatus,\n Profile,\n ProfileGroup,\n ProfileGroupDetail,\n ProfileGroupMember,\n ProfileGroupWithCount,\n ReasoningLevel,\n ResolvedAgent,\n SkillMeta,\n SkillsMode,\n Timestamp,\n TriggerKind,\n WebToken,\n} from './entities.ts'\nexport { REASONING_LEVELS } from './entities.ts'\nexport type {\n ChatFrame,\n ProviderMessage,\n Role,\n SessionEvent,\n ToolCall,\n ToolDef,\n} from './events.ts'\nexport type { MemoryEntry, MemoryHit } from './memory.ts'\n\nimport type { AgentTrigger, Message, ReasoningLevel, WebToken } from './entities.ts'\n\nexport interface ApiError {\n error: string\n code?: string\n}\n\n// --- agents ---\n\nexport interface ListAgentsQuery {\n includeArchived?: boolean\n}\n\nexport interface SpawnAgentRequest {\n profileId: string\n name?: string\n model?: string\n reasoningLevel?: ReasoningLevel\n /** Group the new agent joins. Falls back to the seeded 'default' group when omitted. */\n groupId?: string\n}\n\nexport interface UpdateAgentRequest {\n modelOverride?: string | null\n reasoningLevel?: ReasoningLevel\n}\n\nexport interface AttachSkillRequest {\n skill: string\n}\n\n/** Body for `PATCH /api/agents/:id/group`: move the agent to a new group. */\nexport interface MoveAgentRequest {\n groupId: string\n}\n\nexport interface SendMessageRequest {\n from: string\n payload: { text: string }\n replyTo?: string\n}\n\nexport interface ListInboxQuery {\n unread?: boolean\n}\n\nexport interface ListInboxResponse {\n messages: Message[]\n}\n\nexport interface UpdateMessageRequest {\n read: true\n}\n\n// --- profiles ---\n\nexport interface UpdateProfileRequest {\n name?: string\n defaultModel?: string\n skillsMode?: 'all' | 'selected'\n defaultSkills?: string[]\n}\n\nexport interface CreateProfileRequest {\n id: string\n name?: string\n defaultModel: string\n skillsMode?: 'all' | 'selected'\n defaultSkills?: string[]\n /** Initial SOUL.md content. Falls back to the built-in template when omitted. */\n soul?: string\n /** Initial IDENTITY.md content. Falls back to the built-in template when omitted. */\n identity?: string\n /** Initial BOOTSTRAP.md content. Omit for default; pass null to skip bootstrap entirely. */\n bootstrap?: string | null\n /** Initial AGENTS.md content. Omit to skip; pass a string to seed the file. */\n agents?: string\n /** Initial TOOLS.md content. Omit to skip; pass a string to seed the file. */\n tools?: string\n /** Initial HEARTBEAT.md content. Omit to skip; pass a string to seed the file. */\n heartbeat?: string\n}\n\n// --- profile groups ---\n\nexport interface CreateProfileGroupRequest {\n /** Slug (lowercase, digits, hyphens). Becomes the row id. */\n id: string\n /** Optional display name. Defaults to `id`. */\n name?: string\n /** Optional starter USER.md content. */\n userMd?: string\n}\n\nexport interface UpdateProfileGroupRequest {\n name?: string\n /** Pass `null` to clear; omit to leave unchanged. */\n userMd?: string | null\n}\n\n/**\n * PUT-replace semantics: the entire member array is replaced atomically.\n * `position` is implicit from array order (0-based).\n * Duplicate `agentName` values across members are accepted at PUT time —\n * the spawn op auto-suffixes collisions with `-2`, `-3`, ... at spawn time.\n */\nexport interface PutProfileGroupMembersRequest {\n members: Array<{\n profileId: string\n agentName: string\n modelOverride?: string | null\n reasoningLevel?: ReasoningLevel | null\n }>\n}\n\nexport interface SpawnProfileGroupRequest {\n /** Target group slug. Falls back to the default group when omitted. */\n groupSlug?: string\n /** Override the template's `userMd` for this spawn only. */\n userMd?: string\n}\n\nexport interface SpawnProfileGroupResponse {\n groupSlug: string\n /** Created agents in spawn order, with their final (post-suffix) names. */\n agents: { id: string; name: string }[]\n /** Populated only when cleanup retries were exhausted during a rollback. */\n orphanAgentIds?: string[]\n}\n\n// --- groups ---\n\nexport interface RegisterGroupRequest {\n /** Slug (lowercase, digits, hyphens). Becomes the row id AND the directory\n * name under `~/.bazilion/groups/<slug>/`. */\n id: string\n /** Optional human-readable label. Defaults to `id`. */\n name?: string\n /**\n * Optional symlink target. When set, the daemon materializes the group\n * slot as a symlink to this absolute path instead of as a real directory\n * — useful for \"agents working on my existing project tree.\" Target must\n * exist and be a directory.\n */\n link?: string\n}\n\n/** Body for `PUT /api/groups/:id/user-md`. */\nexport interface SetGroupUserMdRequest {\n userMd: string\n}\n\n// --- skills (write) ---\n\nexport interface ImportSkillsRequest {\n source: string\n force?: boolean\n}\n\nexport interface ImportSkillsResponse {\n imported: string[]\n skipped: { name: string; reason: string }[]\n}\n\n// --- providers (write) ---\n\nexport interface ProviderTestRequest {\n model: string\n message?: string\n}\n\nexport interface ProviderTestResponse {\n content: string\n usage?: {\n promptTokens: number\n completionTokens: number\n }\n}\n\n// --- chat streaming ---\n\nexport interface ChatRequest {\n message: string\n}\n\n// --- profile files ---\n\nexport type ProfileFileName =\n | 'profile.json'\n | 'SOUL.md'\n | 'IDENTITY.md'\n | 'BOOTSTRAP.md'\n | 'AGENTS.md'\n | 'TOOLS.md'\n | 'HEARTBEAT.md'\n\nexport const PROFILE_FILES: ProfileFileName[] = [\n 'profile.json',\n 'SOUL.md',\n 'IDENTITY.md',\n 'BOOTSTRAP.md',\n 'AGENTS.md',\n 'TOOLS.md',\n 'HEARTBEAT.md',\n]\n\nexport interface FileContentResponse {\n content: string\n}\n\nexport interface PutFileRequest {\n content: string\n}\n\n// --- skills ---\n\nexport interface SkillInfo {\n name: string\n description: string\n source: string | null\n importedAt: number | null\n parseError?: string\n}\n\nexport interface ResolvedSkillsResponse {\n resolved: SkillInfo[]\n missing: { name: string; reason: string }[]\n}\n\nexport interface TruncateChatRequest {\n /** Number of leading messages to preserve; everything after is dropped. */\n keepCount: number\n}\n\nexport interface TruncateChatResponse {\n before: number\n after: number\n}\n\n/**\n * Lightweight \"has anything new happened on this agent's session?\" probe.\n * Polled by the web chat UI to detect out-of-band activity (inbox-wakes,\n * scheduled triggers, turns run from another tab) so it can prompt the user\n * to refresh — the session JSONL is append-only, so either a new filename or\n * a bigger byte-count means new entries landed.\n */\nexport interface SessionHeadResponse {\n /** Basename of the most-recent `.jsonl` session file, or `null` if none. */\n file: string | null\n /** Byte size of that file (monotonically increasing while in use). */\n size: number\n}\n\nexport interface ContextFileEntry {\n /** Basename of the injected profile file (e.g. SOUL.md). */\n name: string\n /** Full character count of the file's contribution to the system prompt. */\n chars: number\n /** Rough token estimate (chars / 4). */\n tokens: number\n}\n\nexport interface ContextToolEntry {\n name: string\n /** JSON schema char size (what the provider sees as tool definitions). */\n schemaChars: number\n /** Description char size. */\n descriptionChars: number\n /** Count of top-level properties on the input schema, when shaped like JSONSchema. */\n paramCount: number | null\n}\n\nexport interface ContextSkillEntry {\n name: string\n /** Char count of the skill block injected into the system prompt (currently just the name). */\n blockChars: number\n}\n\nexport interface ContextGroupEntry {\n id: string\n name: string\n path: string\n userMdChars: number\n}\n\nexport interface ContextHistoryBreakdown {\n /** Count of `message` entries. */\n messageEntries: number\n /** Count of `compaction` entries (summarization boundaries). */\n compactionEntries: number\n /** Char sum of message `content` fields (LLM input surface). */\n chars: number\n /** Raw wire size of the serialized log on disk. */\n bytes: number\n /** Rough token estimate (chars / 4) for history alone. */\n tokensEstimate: number\n}\n\nexport interface ChatContextResponse {\n /** Agent being reported on. */\n agentId: string\n /** provider:model string the agent currently resolves to. */\n model: string\n systemPrompt: {\n chars: number\n tokens: number\n /** Per-file breakdown of profile markdown sources (AGENTS.md, SOUL.md, TOOLS.md, IDENTITY.md, HEARTBEAT.md, BOOTSTRAP.md). */\n files: ContextFileEntry[]\n /** Char count of the skill-list text rendered into the system prompt. */\n skillsListChars: number\n /** Char count of the group block rendered into the system prompt. */\n groupListChars: number\n /** Char count of the USER.md block (0 when the group's userMd is empty). */\n userMdChars: number\n /** Fixed memory-hint block the runtime always appends. */\n memoryHintChars: number\n }\n tools: {\n count: number\n listChars: number\n schemaChars: number\n entries: ContextToolEntry[]\n }\n skills: {\n count: number\n entries: ContextSkillEntry[]\n }\n group: ContextGroupEntry\n history: ContextHistoryBreakdown\n /** Sum of system prompt + tool schemas + history, in chars + tokens. */\n totals: { chars: number; tokens: number }\n}\n\nexport interface ChatCompactRequest {\n /** Number of trailing message entries to keep verbatim. Default 10. */\n keepTail?: number\n /** Optional freeform guidance prepended to the summarizer system prompt. */\n customInstructions?: string\n}\n\nexport interface ChatCompactResponse {\n /** Entry count before compaction. */\n before: number\n /** Entry count after compaction (1 compaction + `keptTail` messages). */\n after: number\n /** Message entries summarized into the compaction (the head that was dropped). */\n summarized: number\n /** Message entries preserved verbatim after the compaction boundary. */\n keptTail: number\n /** Rough token estimate of the log before compaction. */\n tokensBefore: number\n /** Rough token estimate of the log after compaction. */\n tokensAfter: number\n /** The summary text produced by the model. */\n summary: string\n}\n\n// --- triggers (heartbeats / cron) ---\n\nexport interface CreateTriggerRequest {\n kind: 'interval' | 'cron'\n /** required when kind='interval' */\n intervalSec?: number\n /** required when kind='cron' — 5-field expression (\"m h dom mon dow\") */\n cronExpr?: string\n /** injected as the user message when the trigger fires */\n message: string\n enabled?: boolean\n}\n\nexport interface UpdateTriggerRequest {\n enabled?: boolean\n}\n\nexport interface CreateTriggerResponse {\n trigger: AgentTrigger\n}\n\nexport interface UpdateTriggerResponse {\n trigger: AgentTrigger\n}\n\nexport interface ListTriggersResponse {\n triggers: AgentTrigger[]\n}\n\n// --- config page (providers + services + fields) ---\n\n/** Per-field UI + storage descriptor — source-of-truth is SERVICES in apps/daemon/src/core/services.ts. */\nexport interface ServiceFieldState {\n envVar: string\n kind: 'secret' | 'config'\n label: string\n placeholder?: string\n description?: string\n /** True when the field has a non-empty value in its storage backend. */\n set: boolean\n /** For `kind: 'config'` (plaintext): the actual value. Omitted for secrets. */\n value?: string\n /** For `kind: 'secret'`: a truncated preview like \"sk-abc…\" so the UI can confirm something is stored. Omitted when unset. */\n preview?: string\n}\n\nexport interface ServiceCard {\n id: string\n displayName: string\n /** Present for category==='provider' cards — tracks whether the pi-adapter sees it as configured. */\n enabled?: boolean\n envHint?: string\n hint?: string\n /** Display grouping label (e.g. \"Web tools\"). Cards without a group are bucketed under \"Other\". */\n group?: string\n fields: ServiceFieldState[]\n}\n\nexport interface ProviderConfigEntry extends ServiceCard {\n enabled: boolean\n envHint: string\n /** Static catalog from pi-ai's typed model list — empty for providers not in the catalog. */\n catalog: string[]\n /** Live `/v1/models` query — omitted when the provider doesn't expose one. */\n live?: { models: string[]; error?: string }\n /** Curated models the admin has selected — drives the dropdowns in profile/agent forms. */\n curated: string[]\n}\n\nexport interface ProviderConfigResponse {\n providers: ProviderConfigEntry[]\n}\n\nexport interface ServiceConfigResponse {\n services: ServiceCard[]\n}\n\nexport interface SetFieldRequest {\n value: string\n}\n\nexport interface SetProviderModelsRequest {\n models: string[]\n}\n\nexport interface SetProviderModelsResponse {\n models: string[]\n}\n\nexport interface SetProviderEnabledRequest {\n enabled: boolean\n}\n\nexport interface SetProviderEnabledResponse {\n name: string\n enabled: boolean\n}\n\n// --- web tokens ---\n\nexport interface CreateTokenRequest {\n label: string\n}\n\nexport interface CreateTokenResponse {\n /** Plaintext token — returned exactly once. */\n token: string\n meta: WebToken\n}\n\nexport interface ListTokensResponse {\n tokens: WebToken[]\n}\n\n// --- health (doctor) ---\n\nexport interface HealthReport {\n ok: boolean\n home: string\n paths: {\n home: boolean\n db: boolean\n auth: boolean\n profiles: boolean\n agents: boolean\n skills: boolean\n }\n database:\n | { ok: true; profiles: number; activeAgents: number; totalAgents: number; groups: number }\n | { ok: false; error: string }\n | null\n skills: { installed: number; parseErrors: number }\n providers: {\n /** Names of cloud providers with credentials configured (e.g. ['anthropic', 'groq']). */\n configured: string[]\n lmstudio: { baseURL: string; hasKey: boolean }\n ollama: { baseURL: string }\n }\n webSearch: { bravePreview: string | null; searxngUrl: string | null }\n openclaw: { path: string; exists: boolean }\n triggers: { active: number; disabled: number }\n tokens: { active: number }\n scheduler: { enabled: boolean; tickMs: number }\n}\n","import { agentRepo, type BazilionDb } from '../core/index.ts'\n\n/**\n * Expand an agent ID prefix (from URL params) to the full UUID.\n *\n * Returns the resolved full ID when the prefix is exact or uniquely resolves;\n * returns the raw input otherwise so the caller's existing \"not found\" branch\n * fires with the original value in the error message.\n */\nexport function resolveAgentIdParam(db: BazilionDb, raw: string | undefined): string {\n if (!raw) return ''\n return agentRepo.resolveId(db, raw) ?? raw\n}\n","// /api/auth/openai/* — ChatGPT OAuth provider connection state.\n// /api/providers/test — model smoke-test.\n// /api/login — token-based browser login (sets the bz_token cookie).\n\nimport { spawn } from 'node:child_process'\nimport type { ProviderTestRequest, ProviderTestResponse } from '@bazilion/api-types'\nimport { Hono } from 'hono'\nimport { setCookie } from 'hono/cookie'\nimport { isSetupComplete, mergeSecretsIntoEnv, providerStateRepo } from '../core/index.ts'\nimport { isValidToken } from '../lib/auth.ts'\nimport { getCtx } from '../lib/ctx.ts'\nimport {\n clearOpenAICodexCredentials,\n createProviderRegistry,\n getOpenAICodexStatus,\n loadProviderConfigFromEnv,\n loginOpenAICodex,\n saveOpenAICodexLoginCredentials,\n} from '../runtime/index.ts'\n\nexport const authRouter = new Hono()\n\n// ─── Auth probe ──────────────────────────────────────────────────────────\n\n/**\n * Cheap session validator. Web SSR middleware calls this once per request\n * to translate \"is the cookie still good?\" + \"has setup been finished?\"\n * into JSON-status pairs that the Astro middleware turns into redirects.\n *\n * Reaching this handler at all means auth passed (the daemon's own\n * middleware-auth would have 401'd otherwise). The body just exposes the\n * setup-complete bit so the web layer can route accordingly.\n */\nauthRouter.get('/auth/me', (c) => {\n const { db } = getCtx()\n return c.json({ authed: true, setupComplete: isSetupComplete(db) })\n})\n\n// ─── ChatGPT OAuth ───────────────────────────────────────────────────────\n\nauthRouter.get('/auth/openai', (c) => {\n const { db, authToken } = getCtx()\n return c.json(getOpenAICodexStatus(db, authToken))\n})\n\nauthRouter.put('/auth/openai', async (c) => {\n const body = (await c.req.json().catch(() => null)) as {\n refresh?: unknown\n access?: unknown\n expires?: unknown\n } | null\n if (\n !body ||\n typeof body.refresh !== 'string' ||\n typeof body.access !== 'string' ||\n typeof body.expires !== 'number'\n ) {\n return c.json(\n { error: 'body must be { refresh: string, access: string, expires: number }' },\n 400,\n )\n }\n const { db, authToken } = getCtx()\n saveOpenAICodexLoginCredentials(db, authToken, {\n refresh: body.refresh,\n access: body.access,\n expires: body.expires,\n })\n return c.json(getOpenAICodexStatus(db, authToken))\n})\n\nauthRouter.delete('/auth/openai', (c) => {\n const { db, authToken } = getCtx()\n clearOpenAICodexCredentials(db, authToken)\n return c.json({ connected: false, expiresAt: null, accountId: null })\n})\n\nauthRouter.post('/auth/openai/login', async (c) => {\n const { db, authToken } = getCtx()\n try {\n const creds = await loginOpenAICodex({\n onAuth: ({ url }) => openBrowser(url),\n onPrompt: () =>\n Promise.reject(\n new Error(\n 'interactive paste not supported in the web flow — cancel and try again, or use `bazilion auth openai login`',\n ),\n ),\n onProgress: () => {\n // single blocking POST keeps the UI simple\n },\n })\n saveOpenAICodexLoginCredentials(db, authToken, creds)\n return c.json(getOpenAICodexStatus(db, authToken))\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n})\n\n// ─── Provider model smoke-test ───────────────────────────────────────────\n\nauthRouter.post('/providers/test', async (c) => {\n const body = (await c.req.json().catch(() => null)) as ProviderTestRequest | null\n if (!body || typeof body.model !== 'string' || !body.model) {\n return c.json({ error: 'model is required' }, 400)\n }\n const message = typeof body.message === 'string' && body.message ? body.message : 'say hi briefly'\n const { db, paths, authToken } = getCtx()\n const env = mergeSecretsIntoEnv(db, authToken)\n const reg = createProviderRegistry(loadProviderConfigFromEnv(env, { db, authToken }), {\n enabledSet: providerStateRepo.listEnabled(db),\n })\n try {\n const { provider, model } = reg.resolve(body.model)\n const res = await provider.chat({\n model,\n messages: [{ role: 'user', content: message }],\n maxTokens: 256,\n })\n const out: ProviderTestResponse = { content: res.content, usage: res.usage }\n return c.json(out)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n})\n\n// ─── Browser login ───────────────────────────────────────────────────────\n\n/**\n * Token-based login. Two body shapes accepted:\n * - `application/json`: `{ token: \"<value>\" }` → returns `{ ok: true }` on\n * success, sets the `bz_token` cookie. Used by clients (web pages, mobile)\n * that prefer JSON.\n * - `application/x-www-form-urlencoded`: `token=<value>` → 302 to `/` on\n * success or `/login?error=1` on failure. Used by the legacy `<form>` on\n * the Astro `/login` page; preserved for compatibility through Stage A.\n */\nauthRouter.post('/login', async (c) => {\n const ct = c.req.header('content-type') ?? ''\n let token: string | null = null\n\n if (ct.startsWith('application/json')) {\n const body = (await c.req.json().catch(() => null)) as { token?: unknown } | null\n if (body && typeof body.token === 'string') token = body.token\n } else {\n const form = await c.req.formData().catch(() => null)\n const v = form?.get('token')\n if (typeof v === 'string') token = v\n }\n\n if (!token || !isValidToken(token)) {\n if (ct.startsWith('application/json')) {\n return c.json({ error: 'invalid token' }, 401)\n }\n return c.redirect('/login?error=1', 302)\n }\n\n setCookie(c, 'bz_token', token, {\n path: '/',\n httpOnly: true,\n sameSite: 'Lax',\n maxAge: 60 * 60 * 24 * 30,\n })\n\n if (ct.startsWith('application/json')) {\n return c.json({ ok: true })\n }\n return c.redirect('/', 302)\n})\n\n/**\n * Open `url` in the host's default browser. Only called by the OAuth flow\n * triggered from /config — the user is on the same machine as the daemon in\n * that scenario (loopback-only `bazilion serve`).\n */\nfunction openBrowser(url: string): void {\n const platform = process.platform\n const [cmd, ...args] =\n platform === 'darwin'\n ? ['open', url]\n : platform === 'win32'\n ? ['cmd', '/c', 'start', '\"\"', url]\n : ['xdg-open', url]\n try {\n const child = spawn(cmd as string, args, { stdio: 'ignore', detached: true })\n child.unref()\n child.on('error', () => {\n // xdg-open missing on minimal installs — swallow so the flow still works\n })\n } catch {\n // spawn failed — user will still see the URL in the progress log\n }\n}\n","// /api/config/* — provider matrix, services, per-provider enabled toggle and\n// curated models, and per-field config/secret writes.\n\nimport type {\n ProviderConfigEntry,\n ProviderConfigResponse,\n ServiceCard,\n ServiceConfigResponse,\n ServiceFieldState,\n SetProviderModelsRequest,\n} from '@bazilion/api-types'\nimport { Hono } from 'hono'\nimport {\n ensureSetupSeeded,\n findFieldByEnvVar,\n groupAvailableModels,\n mergeSecretsIntoEnv,\n openConfig,\n openSecrets,\n providerModelRepo,\n providerStateRepo,\n type ServiceDef,\n servicesByCategory,\n} from '../core/index.ts'\nimport { getCtx } from '../lib/ctx.ts'\nimport {\n listAllProviders,\n listCatalogModels,\n listCatalogModelsSync,\n loadProviderConfigFromEnv,\n} from '../runtime/index.ts'\n\nexport const configRouter = new Hono()\n\n// /api/config/providers\nconfigRouter.get('/providers', async (c) => {\n const { db, paths, authToken } = getCtx()\n const env = mergeSecretsIntoEnv(db, authToken)\n const registryProviders = listAllProviders(loadProviderConfigFromEnv(env, { db, authToken }))\n const registryByName = new Map(registryProviders.map((p) => [p.name, p]))\n\n const configValues = readAll(() => openConfig(db).getAll())\n const secretValues = readAll(() => openSecrets(db, authToken).getAll())\n\n const providerServices = servicesByCategory('provider')\n const enabledSet = providerStateRepo.listEnabled(db)\n\n const entries = await Promise.all(\n providerServices.map(async (svc): Promise<ProviderConfigEntry> => {\n const meta = registryByName.get(svc.id)\n const enabled = enabledSet.has(svc.id)\n const envHint = meta?.envHint ?? ''\n const ac = new AbortController()\n const t = setTimeout(() => ac.abort(), 5_000)\n try {\n const { catalog, live } = enabled\n ? await listCatalogModels(svc.id, env, ac.signal)\n : { catalog: listCatalogModelsSync(svc.id), live: undefined }\n return {\n id: svc.id,\n displayName: svc.displayName,\n ...(svc.hint ? { hint: svc.hint } : {}),\n enabled,\n envHint,\n fields: resolveFieldStates(svc, configValues, secretValues),\n catalog,\n ...(live ? { live } : {}),\n curated: providerModelRepo.list(db, svc.id),\n }\n } finally {\n clearTimeout(t)\n }\n }),\n )\n\n const body: ProviderConfigResponse = { providers: entries }\n return c.json(body)\n})\n\n// /api/config/services — non-provider service cards (e.g. SearXNG, Brave).\nconfigRouter.get('/services', (c) => {\n const { db, authToken } = getCtx()\n const configValues = readAll(() => openConfig(db).getAll())\n const secretValues = readAll(() => openSecrets(db, authToken).getAll())\n\n const services: ServiceCard[] = servicesByCategory('service').map((svc) => ({\n id: svc.id,\n displayName: svc.displayName,\n ...(svc.hint ? { hint: svc.hint } : {}),\n ...(svc.group ? { group: svc.group } : {}),\n fields: resolveFieldStates(svc, configValues, secretValues),\n }))\n\n const body: ServiceConfigResponse = { services }\n return c.json(body)\n})\n\n// /api/config/providers/:name/enabled — flip the admin switch.\nconfigRouter.put('/providers/:name/enabled', async (c) => {\n const name = c.req.param('name')\n if (!knownProviderIds().has(name)) return c.json({ error: `unknown provider: ${name}` }, 404)\n\n const body = (await c.req.json().catch(() => null)) as { enabled?: unknown } | null\n if (!body || (typeof body.enabled !== 'boolean' && typeof body.enabled !== 'string')) {\n return c.json({ error: 'body must be {\"enabled\": boolean}' }, 400)\n }\n const enabled =\n typeof body.enabled === 'boolean' ? body.enabled : body.enabled.toLowerCase() === 'true'\n\n const { db, paths } = getCtx()\n providerStateRepo.setEnabled(db, name, enabled)\n ensureSetupSeeded(db, paths)\n return c.json({ name, enabled })\n})\n\n// /api/config/providers/:name/models — curated model list.\nconfigRouter.get('/providers/:name/models', (c) => {\n const name = c.req.param('name')\n if (!knownProviderRegistryNames().has(name))\n return c.json({ error: `unknown provider: ${name}` }, 404)\n const { db } = getCtx()\n return c.json({ models: providerModelRepo.list(db, name) })\n})\n\nconfigRouter.put('/providers/:name/models', async (c) => {\n const name = c.req.param('name')\n if (!knownProviderRegistryNames().has(name))\n return c.json({ error: `unknown provider: ${name}` }, 404)\n const body = (await c.req.json().catch(() => null)) as Partial<SetProviderModelsRequest> | null\n if (!body) return c.json({ error: 'invalid JSON body' }, 400)\n\n // Accept textarea-style newline-separated input from web forms in addition\n // to the CLI's array shape.\n let models: string[] = []\n if (Array.isArray(body.models)) {\n models = body.models.filter((m): m is string => typeof m === 'string')\n } else if (typeof (body as Record<string, unknown>).models === 'string') {\n models = ((body as Record<string, unknown>).models as string).split(/\\r?\\n/)\n } else {\n return c.json(\n { error: 'models must be an array of strings or a newline-separated string' },\n 400,\n )\n }\n\n const { db, paths } = getCtx()\n providerModelRepo.replace(db, name, models)\n ensureSetupSeeded(db, paths)\n return c.json({ models: providerModelRepo.list(db, name) })\n})\n\n// /api/config/fields/:envVar — write-through for any envVar the registry knows.\nconfigRouter.put('/fields/:envVar', async (c) => {\n const envVar = c.req.param('envVar')\n const found = findFieldByEnvVar(envVar)\n if (!found) return c.json({ error: `unknown envVar: ${envVar}` }, 404)\n\n const body = (await c.req.json().catch(() => null)) as { value?: unknown } | null\n if (!body || typeof body.value !== 'string') {\n return c.json({ error: 'body must be {\"value\": \"<string>\"}' }, 400)\n }\n\n const { db, authToken } = getCtx()\n if (found.field.kind === 'config') {\n const store = openConfig(db)\n if (body.value === '') store.remove(envVar)\n else store.set(envVar, body.value)\n } else {\n const store = openSecrets(db, authToken)\n if (body.value === '') store.remove(envVar)\n else store.set(envVar, body.value)\n }\n\n return c.json(readFieldState(db, authToken, envVar, found.field.kind))\n})\n\n// /api/config/available-models — provider-grouped curated models. Drives\n// the model dropdowns on the profile + agent spawn pages.\nconfigRouter.get('/available-models', (c) => {\n const { db } = getCtx()\n return c.json({ groups: groupAvailableModels(db) })\n})\n\nconfigRouter.delete('/fields/:envVar', (c) => {\n const envVar = c.req.param('envVar')\n const found = findFieldByEnvVar(envVar)\n if (!found) return c.json({ error: `unknown envVar: ${envVar}` }, 404)\n\n const { db, authToken } = getCtx()\n if (found.field.kind === 'config') {\n openConfig(db).remove(envVar)\n } else {\n openSecrets(db, authToken).remove(envVar)\n }\n return c.body(null, 204)\n})\n\n// ─── helpers ─────────────────────────────────────────────────────────────\n\nfunction mask(value: string): string {\n if (value.length === 0) return ''\n return value.length > 8 ? `${value.slice(0, 6)}…` : '***'\n}\n\nfunction resolveFieldStates(\n service: ServiceDef,\n configValues: Record<string, string>,\n secretValues: Record<string, string>,\n): ServiceFieldState[] {\n return service.fields.map((f) => {\n const val = (f.kind === 'config' ? configValues[f.envVar] : secretValues[f.envVar]) ?? ''\n const state: ServiceFieldState = {\n envVar: f.envVar,\n kind: f.kind,\n label: f.label,\n set: val.length > 0,\n ...(f.placeholder ? { placeholder: f.placeholder } : {}),\n ...(f.description ? { description: f.description } : {}),\n }\n if (f.kind === 'config') {\n state.value = val\n } else if (val.length > 0) {\n state.preview = mask(val)\n }\n return state\n })\n}\n\nfunction readAll(read: () => Record<string, string>): Record<string, string> {\n try {\n return read()\n } catch {\n return {}\n }\n}\n\ninterface FieldState {\n envVar: string\n kind: 'secret' | 'config'\n set: boolean\n value?: string\n preview?: string\n}\n\nfunction readFieldState(\n db: import('../core/index.ts').BazilionDb,\n authToken: string,\n envVar: string,\n kind: 'secret' | 'config',\n): FieldState {\n if (kind === 'config') {\n const v = openConfig(db).get(envVar) ?? ''\n return { envVar, kind, set: v.length > 0, value: v }\n }\n const v = openSecrets(db, authToken).get(envVar) ?? ''\n return { envVar, kind, set: v.length > 0, ...(v.length > 0 ? { preview: mask(v) } : {}) }\n}\n\nfunction knownProviderIds(): Set<string> {\n return new Set(servicesByCategory('provider').map((s) => s.id))\n}\n\nfunction knownProviderRegistryNames(): Set<string> {\n const { db, authToken } = getCtx()\n return new Set(\n listAllProviders(loadProviderConfigFromEnv(process.env, { db, authToken })).map((p) => p.name),\n )\n}\n","// /api/groups/* — group registry, per-group USER.md, per-group shared\n// memory. Memory is keyed by the group slug because the qmd index lives at\n// `<group.path>/memory/` and is shared by every agent in the group.\n\nimport { join } from 'node:path'\nimport type { RegisterGroupRequest, SetGroupUserMdRequest } from '@bazilion/api-types'\nimport { Hono } from 'hono'\nimport { deleteGroup, groupRepo, registerGroup } from '../core/index.ts'\nimport { getCtx } from '../lib/ctx.ts'\nimport { qmdBackend } from '../runtime/index.ts'\n\n// 12 KB cap matches OpenClaw's bootstrapMaxChars default — enough for a rich\n// USER.md, small enough that it can't silently blow out the system prompt.\nconst USER_MD_MAX_BYTES = 12_000\n\nexport const groupsRouter = new Hono()\n\ngroupsRouter.get('/', (c) => {\n const { db, paths } = getCtx()\n return c.json(groupRepo.list(db, paths))\n})\n\ngroupsRouter.post('/', async (c) => {\n const body = (await c.req.json().catch(() => null)) as RegisterGroupRequest | null\n if (!body || typeof body.id !== 'string') {\n return c.json({ error: 'id is required' }, 400)\n }\n const { db, paths } = getCtx()\n try {\n const g = registerGroup(db, { id: body.id, name: body.name, link: body.link }, paths)\n return c.json(g, 201)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n})\n\ngroupsRouter.get('/:id', (c) => {\n const { db, paths } = getCtx()\n const g = groupRepo.get(db, c.req.param('id'), paths)\n if (!g) return c.json({ error: `group not found: ${c.req.param('id')}` }, 404)\n return c.json(g)\n})\n\ngroupsRouter.delete('/:id', (c) => {\n const { db, paths } = getCtx()\n try {\n deleteGroup(db, paths, c.req.param('id'))\n return c.body(null, 204)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n})\n\ngroupsRouter.put('/:id/user-md', async (c) => {\n const body = (await c.req.json().catch(() => null)) as SetGroupUserMdRequest | null\n if (!body || typeof body.userMd !== 'string') {\n return c.json({ error: 'userMd (string) is required' }, 400)\n }\n if (Buffer.byteLength(body.userMd, 'utf8') > USER_MD_MAX_BYTES) {\n return c.json({ error: `userMd exceeds ${USER_MD_MAX_BYTES}-byte cap` }, 413)\n }\n const { db, paths } = getCtx()\n const g = groupRepo.get(db, c.req.param('id'), paths)\n if (!g) return c.json({ error: `group not found: ${c.req.param('id')}` }, 404)\n groupRepo.setUserMd(db, c.req.param('id'), body.userMd)\n return c.json(groupRepo.get(db, c.req.param('id'), paths))\n})\n\n// ─── Memory (per-group, shared across all member agents) ──────────────────\n\nasync function openMemory(rawId: string) {\n const { db, paths } = getCtx()\n const group = groupRepo.get(db, rawId, paths)\n if (!group) throw new Error(`group not found: ${rawId}`)\n const mem = qmdBackend(join(group.path, 'memory'))\n await mem.init()\n return { mem, group }\n}\n\ngroupsRouter.get('/:id/memory', async (c) => {\n try {\n const { mem } = await openMemory(c.req.param('id'))\n return c.json(await mem.list())\n } catch (err) {\n return c.json({ error: (err as Error).message }, 404)\n }\n})\n\ngroupsRouter.get('/:id/memory/search', async (c) => {\n const q = c.req.query('q')\n if (!q) return c.json({ error: 'q is required' }, 400)\n const limit = Number.parseInt(c.req.query('limit') ?? '10', 10)\n try {\n const { mem } = await openMemory(c.req.param('id'))\n return c.json(await mem.search(q, { limit }))\n } catch (err) {\n return c.json({ error: (err as Error).message }, 404)\n }\n})\n\n// `:key{.+}` matches multi-segment paths so memory keys with slashes (e.g.\n// `notes/2026-04-25.md`) survive the routing layer. Without the regex Hono\n// would only capture a single segment.\ngroupsRouter.get('/:id/memory/:key{.+}', async (c) => {\n try {\n const { mem } = await openMemory(c.req.param('id'))\n return c.json(await mem.read(c.req.param('key')))\n } catch (err) {\n return c.json({ error: (err as Error).message }, 404)\n }\n})\n\ngroupsRouter.put('/:id/memory/:key{.+}', async (c) => {\n const body = (await c.req.json().catch(() => null)) as { content?: string } | null\n if (!body || typeof body.content !== 'string')\n return c.json({ error: 'content is required' }, 400)\n try {\n const { mem } = await openMemory(c.req.param('id'))\n return c.json(await mem.write(c.req.param('key'), body.content))\n } catch (err) {\n return c.json({ error: (err as Error).message }, 500)\n }\n})\n\ngroupsRouter.delete('/:id/memory/:key{.+}', async (c) => {\n try {\n const { mem } = await openMemory(c.req.param('id'))\n await mem.remove(c.req.param('key'))\n return c.body(null, 204)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 500)\n }\n})\n","// /api/messages/:id — fetch + mark-read for a single message. (Inbox listing\n// + send is per-agent at /api/agents/:id/messages.)\n\nimport type { UpdateMessageRequest } from '@bazilion/api-types'\nimport { Hono } from 'hono'\nimport { messageRepo } from '../core/index.ts'\nimport { getCtx } from '../lib/ctx.ts'\n\nexport const messagesRouter = new Hono()\n\nmessagesRouter.get('/:id', (c) => {\n const { db } = getCtx()\n const msg = messageRepo.get(db, c.req.param('id'))\n if (!msg) return c.json({ error: `message not found: ${c.req.param('id')}` }, 404)\n return c.json(msg)\n})\n\nmessagesRouter.patch('/:id', async (c) => {\n const id = c.req.param('id')\n const body = (await c.req.json().catch(() => null)) as UpdateMessageRequest | null\n if (!body || body.read !== true) {\n return c.json({ error: 'body must be {read: true}' }, 400)\n }\n const { db } = getCtx()\n const existing = messageRepo.get(db, id)\n if (!existing) return c.json({ error: `message not found: ${id}` }, 404)\n messageRepo.markRead(db, id)\n return c.json(messageRepo.get(db, id))\n})\n","// Single-route resources: /api/health, /api/backup, /api/tokens.\n\nimport { spawn } from 'node:child_process'\nimport { existsSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport type {\n CreateTokenRequest,\n CreateTokenResponse,\n HealthReport,\n ListTokensResponse,\n} from '@bazilion/api-types'\nimport { Hono } from 'hono'\nimport {\n agentRepo,\n discoverSkills,\n groupRepo,\n mergeSecretsIntoEnv,\n parseSkillFile,\n profileRepo,\n resolvePaths,\n webTokenRepo,\n} from '../core/index.ts'\nimport { getCtx } from '../lib/ctx.ts'\nimport { loadProviderConfigFromEnv } from '../runtime/index.ts'\n\nexport const miscRouter = new Hono()\n\n// /api/health — install diagnostics. Public (auth middleware whitelists it)\n// so the doctor command and external probes can run without a token.\nmiscRouter.get('/health', (c) => {\n const paths = resolvePaths()\n\n const pathChecks = {\n home: existsSync(paths.home),\n db: existsSync(paths.db),\n auth: existsSync(paths.authFile),\n profiles: existsSync(paths.profilesDir),\n agents: existsSync(paths.agentsDir),\n skills: existsSync(paths.skillsDir),\n }\n\n let database: HealthReport['database'] = null\n const triggersSection: HealthReport['triggers'] = { active: 0, disabled: 0 }\n let tokensSection: HealthReport['tokens'] = { active: 0 }\n if (pathChecks.db) {\n try {\n const { db } = getCtx()\n database = {\n ok: true,\n profiles: profileRepo.list(db).length,\n activeAgents: agentRepo.list(db).length,\n totalAgents: agentRepo.list(db, { includeArchived: true }).length,\n groups: groupRepo.list(db, paths).length,\n }\n const triggerRows = db.raw\n .query<{ enabled: number; n: number }, []>(\n 'SELECT enabled, COUNT(*) AS n FROM agent_triggers GROUP BY enabled',\n )\n .all()\n for (const r of triggerRows) {\n if (r.enabled === 1) triggersSection.active = r.n\n else triggersSection.disabled = r.n\n }\n tokensSection = { active: webTokenRepo.list(db).length }\n } catch (err) {\n database = { ok: false, error: (err as Error).message }\n }\n }\n\n const skills = discoverSkills(paths)\n let parseErrors = 0\n for (const s of skills) {\n try {\n parseSkillFile(s.skillFile)\n } catch {\n parseErrors++\n }\n }\n\n let effectiveEnv: NodeJS.ProcessEnv = process.env\n let oauth: { db: import('../core/index.ts').BazilionDb; authToken: string } | undefined\n if (pathChecks.auth && pathChecks.db) {\n try {\n const { db, authToken } = getCtx()\n effectiveEnv = mergeSecretsIntoEnv(db, authToken)\n oauth = { db, authToken }\n } catch {\n // first-run / partially-initialized — fall through with bare env\n }\n }\n const providerConfig = loadProviderConfigFromEnv(effectiveEnv, oauth)\n const braveKey = effectiveEnv.BRAVE_API_KEY\n const openclawSkillsDir = join(homedir(), '.openclaw', 'skills')\n\n const CLOUD_KEYS: Array<[string, keyof typeof providerConfig]> = [\n ['anthropic', 'anthropic'],\n ['openai', 'openai'],\n ['google', 'google'],\n ['azure-openai', 'azureOpenai'],\n ['bedrock', 'bedrock'],\n ['google-vertex', 'googleVertex'],\n ['mistral', 'mistral'],\n ['groq', 'groq'],\n ['cerebras', 'cerebras'],\n ['xai', 'xai'],\n ['zai', 'zai'],\n ['huggingface', 'huggingface'],\n ['openrouter', 'openrouter'],\n ['vercel-ai-gateway', 'vercelAiGateway'],\n ]\n const providerSection: HealthReport['providers'] = {\n configured: CLOUD_KEYS.filter(([, key]) => providerConfig[key]).map(([name]) => name),\n lmstudio: {\n baseURL: providerConfig.lmstudio?.baseURL ?? 'http://localhost:1234/v1',\n hasKey: Boolean(providerConfig.lmstudio?.apiKey),\n },\n ollama: { baseURL: providerConfig.ollama?.baseURL ?? 'http://localhost:11434/v1' },\n }\n\n const report: HealthReport = {\n ok:\n pathChecks.home &&\n pathChecks.db &&\n pathChecks.auth &&\n pathChecks.profiles &&\n pathChecks.agents &&\n pathChecks.skills &&\n (database === null || database.ok) &&\n parseErrors === 0,\n home: paths.home,\n paths: pathChecks,\n database,\n skills: { installed: skills.length, parseErrors },\n providers: providerSection,\n webSearch: {\n bravePreview: braveKey ? `${braveKey.slice(0, 6)}…` : null,\n searxngUrl: effectiveEnv.SEARXNG_URL ?? null,\n },\n openclaw: {\n path: openclawSkillsDir,\n exists: existsSync(openclawSkillsDir),\n },\n triggers: triggersSection,\n tokens: tokensSection,\n scheduler: {\n enabled: process.env.BAZILION_SCHEDULER !== 'off',\n tickMs: Number(process.env.BAZILION_SCHEDULER_TICK_MS ?? 5_000),\n },\n }\n return c.json(report)\n})\n\n// /api/backup — streams a tar.gz of $BAZILION_HOME\nmiscRouter.get('/backup', (c) => {\n const paths = resolvePaths()\n if (!existsSync(paths.home)) {\n return c.json({ error: `bazilion home not found at ${paths.home}` }, 404)\n }\n\n const proc = spawn('tar', ['-czf', '-', '-C', paths.home, '.'], {\n stdio: ['ignore', 'pipe', 'pipe'],\n })\n\n const stream = new ReadableStream({\n start(controller) {\n proc.stdout.on('data', (chunk: Buffer) => controller.enqueue(chunk))\n proc.stdout.on('end', () => {\n try {\n controller.close()\n } catch {}\n })\n proc.on('error', (err) => {\n try {\n controller.error(err)\n } catch {}\n })\n proc.on('exit', (code) => {\n if (code !== 0) {\n try {\n controller.error(new Error(`tar exited with code ${code}`))\n } catch {}\n }\n })\n },\n cancel() {\n proc.kill('SIGTERM')\n },\n })\n\n const date = new Date().toISOString().slice(0, 10)\n return new Response(stream, {\n headers: {\n 'content-type': 'application/gzip',\n 'content-disposition': `attachment; filename=\"bazilion-backup-${date}.tar.gz\"`,\n },\n })\n})\n\n// /api/tokens\nmiscRouter.get('/tokens', (c) => {\n const { db } = getCtx()\n const includeRevoked = c.req.query('includeRevoked') === '1'\n const tokens = webTokenRepo.list(db, { includeRevoked })\n return c.json({ tokens } satisfies ListTokensResponse)\n})\n\nmiscRouter.post('/tokens', async (c) => {\n const body = (await c.req.json().catch(() => null)) as CreateTokenRequest | null\n if (!body || typeof body.label !== 'string' || !body.label.trim()) {\n return c.json({ error: 'label is required' }, 400)\n }\n const { db } = getCtx()\n const created = webTokenRepo.create(db, body.label.trim())\n return c.json({ token: created.token, meta: created.meta } satisfies CreateTokenResponse, 201)\n})\n\nmiscRouter.delete('/tokens/:id', (c) => {\n const { db, authToken } = getCtx()\n const id = c.req.param('id')\n const existing = webTokenRepo.get(db, id)\n if (!existing) return c.json({ error: `token not found: ${id}` }, 404)\n if (existing.revokedAt) return c.json({ error: 'token already revoked' }, 409)\n // Refuse to revoke the bootstrap token — that's the plaintext in auth.json\n // the local CLI uses for loopback. Revoking it would lock the operator out\n // of their own daemon. Match by hash (label is editable, hash isn't).\n const bootstrap = webTokenRepo.findActiveByToken(db, authToken)\n if (bootstrap && bootstrap.id === id) {\n return c.json(\n {\n error:\n 'cannot revoke the bootstrap token — it lives in ~/.bazilion/auth.json and is the local CLI loopback credential',\n },\n 409,\n )\n }\n webTokenRepo.revoke(db, id)\n return c.body(null, 204)\n})\n","// /api/profile-groups/* — preconfigured team templates. Each profile group\n// holds an ordered list of members that the spawn op replays as a single\n// transactional call. See docs/backlog/todo/BAZ-002-profile-groups.md.\n\nimport type {\n CreateProfileGroupRequest,\n ProfileGroupDetail,\n PutProfileGroupMembersRequest,\n ReasoningLevel,\n SpawnProfileGroupRequest,\n SpawnProfileGroupResponse,\n UpdateProfileGroupRequest,\n} from '@bazilion/api-types'\nimport { REASONING_LEVELS } from '@bazilion/api-types'\nimport { Hono } from 'hono'\nimport {\n profileGroupRepo,\n profileRepo,\n SpawnProfileGroupError,\n spawnProfileGroup,\n} from '../core/index.ts'\nimport { validateSlug } from '../core/profile/validate.ts'\nimport type { MemberInput, UpdateProfileGroupPatch } from '../core/repos/profileGroups.ts'\nimport { getCtx } from '../lib/ctx.ts'\n\nexport const profileGroupsRouter = new Hono()\n\nprofileGroupsRouter.get('/', (c) => {\n const { db } = getCtx()\n return c.json(profileGroupRepo.list(db))\n})\n\nprofileGroupsRouter.get('/:id', (c) => {\n const { db } = getCtx()\n const id = c.req.param('id')\n const group = profileGroupRepo.get(db, id)\n if (!group) return c.json({ error: `profile group not found: ${id}` }, 404)\n const body: ProfileGroupDetail = {\n group,\n members: profileGroupRepo.members(db, id),\n }\n return c.json(body)\n})\n\nprofileGroupsRouter.post('/', async (c) => {\n const raw = (await c.req.json().catch(() => null)) as\n | (CreateProfileGroupRequest & Record<string, unknown>)\n | null\n if (!raw) return c.json({ error: 'invalid JSON body' }, 400)\n const id = typeof raw.id === 'string' ? raw.id : ''\n if (!id) return c.json({ error: 'id is required' }, 400)\n try {\n validateSlug(id)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n const { db } = getCtx()\n if (profileGroupRepo.get(db, id)) {\n return c.json({ error: `profile group already exists: ${id}` }, 409)\n }\n const name = typeof raw.name === 'string' && raw.name.length > 0 ? raw.name : id\n const userMd = typeof raw.userMd === 'string' ? raw.userMd : null\n try {\n const inserted = profileGroupRepo.insert(db, { id, name, userMd })\n return c.json(inserted, 201)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n})\n\nprofileGroupsRouter.patch('/:id', async (c) => {\n const raw = (await c.req.json().catch(() => null)) as\n | (UpdateProfileGroupRequest & Record<string, unknown>)\n | null\n if (!raw) return c.json({ error: 'invalid JSON body' }, 400)\n const { db } = getCtx()\n const id = c.req.param('id')\n if (!profileGroupRepo.get(db, id)) {\n return c.json({ error: `profile group not found: ${id}` }, 404)\n }\n // Distinguish undefined (don't touch) from null (clear) per repo semantics.\n const patch: UpdateProfileGroupPatch = {}\n if (Object.hasOwn(raw, 'name') && typeof raw.name === 'string') {\n patch.name = raw.name\n }\n if (Object.hasOwn(raw, 'userMd')) {\n patch.userMd = raw.userMd === null ? null : typeof raw.userMd === 'string' ? raw.userMd : null\n }\n profileGroupRepo.update(db, id, patch)\n return c.json(profileGroupRepo.get(db, id))\n})\n\nprofileGroupsRouter.put('/:id/members', async (c) => {\n const raw = (await c.req.json().catch(() => null)) as\n | (PutProfileGroupMembersRequest & Record<string, unknown>)\n | null\n if (!raw || !Array.isArray(raw.members)) {\n return c.json({ error: 'members array is required' }, 400)\n }\n const { db } = getCtx()\n const id = c.req.param('id')\n if (!profileGroupRepo.get(db, id)) {\n return c.json({ error: `profile group not found: ${id}` }, 404)\n }\n const cleaned: MemberInput[] = []\n const missingProfiles: string[] = []\n for (let i = 0; i < raw.members.length; i++) {\n const m = raw.members[i] as Record<string, unknown> | undefined\n if (!m || typeof m.profileId !== 'string' || typeof m.agentName !== 'string') {\n return c.json({ error: `member ${i}: profileId and agentName are required strings` }, 400)\n }\n if (!profileRepo.get(db, m.profileId)) {\n missingProfiles.push(m.profileId)\n continue\n }\n const modelOverride =\n m.modelOverride === null ? null : typeof m.modelOverride === 'string' ? m.modelOverride : null\n const reasoningLevel =\n m.reasoningLevel === null\n ? null\n : typeof m.reasoningLevel === 'string' &&\n (REASONING_LEVELS as readonly string[]).includes(m.reasoningLevel)\n ? (m.reasoningLevel as ReasoningLevel)\n : null\n cleaned.push({\n profileId: m.profileId,\n agentName: m.agentName,\n modelOverride,\n reasoningLevel,\n })\n }\n if (missingProfiles.length > 0) {\n return c.json({ error: `missing profiles: ${[...new Set(missingProfiles)].join(', ')}` }, 400)\n }\n profileGroupRepo.replaceMembers(db, id, cleaned)\n return c.json({ members: profileGroupRepo.members(db, id) })\n})\n\nprofileGroupsRouter.delete('/:id', (c) => {\n const { db } = getCtx()\n const id = c.req.param('id')\n if (!profileGroupRepo.get(db, id)) {\n return c.json({ error: `profile group not found: ${id}` }, 404)\n }\n profileGroupRepo.remove(db, id)\n return c.body(null, 204)\n})\n\nprofileGroupsRouter.post('/:id/spawn', async (c) => {\n const raw = (await c.req.json().catch(() => ({}))) as\n | (SpawnProfileGroupRequest & Record<string, unknown>)\n | null\n const body = raw ?? {}\n const groupSlug = typeof body.groupSlug === 'string' ? body.groupSlug : undefined\n const userMd = typeof body.userMd === 'string' ? body.userMd : undefined\n const { db, paths } = getCtx()\n const id = c.req.param('id')\n try {\n const result = await spawnProfileGroup(db, paths, {\n profileGroupId: id,\n groupSlug,\n userMd,\n })\n const response: SpawnProfileGroupResponse = {\n groupSlug: result.groupSlug,\n agents: result.agents,\n }\n if (result.orphanAgentIds.length > 0) response.orphanAgentIds = result.orphanAgentIds\n return c.json(response)\n } catch (err) {\n if (err instanceof SpawnProfileGroupError) {\n // The error carries structured orphan IDs separate from the message.\n return c.json({ error: err.message, orphanAgentIds: err.orphanAgentIds }, 500)\n }\n const msg = (err as Error).message\n if (msg.startsWith('profile group not found')) return c.json({ error: msg }, 404)\n if (msg.startsWith('profile group spawn: missing profiles')) {\n return c.json({ error: msg }, 400)\n }\n return c.json({ error: msg }, 500)\n }\n})\n","// /api/profiles/* — profile CRUD + per-profile template files.\n\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type {\n CreateProfileRequest,\n FileContentResponse,\n ProfileFileName,\n PutFileRequest,\n SkillsMode,\n UpdateProfileRequest,\n} from '@bazilion/api-types'\nimport { PROFILE_FILES } from '@bazilion/api-types'\nimport { Hono } from 'hono'\nimport {\n agentRepo,\n createProfile,\n DEFAULT_BOOTSTRAP,\n DEFAULT_IDENTITY,\n DEFAULT_SOUL,\n deleteProfile,\n loadProfile,\n profileRepo,\n updateProfile,\n} from '../core/index.ts'\nimport { getCtx } from '../lib/ctx.ts'\n\nexport const profilesRouter = new Hono()\n\nprofilesRouter.get('/', (c) => {\n const { db } = getCtx()\n const profiles = profileRepo.list(db)\n // Hydrate with the per-profile fields the listing UI needs (agent counts,\n // default-skill list) so callers don't fan out to extra endpoints per row.\n const hydrated = profiles.map((p) => ({\n ...p,\n agentCount: agentRepo.countByProfile(db, p.id),\n defaultSkills: profileRepo.getDefaultSkills(db, p.id),\n }))\n return c.json(hydrated)\n})\n\n// /api/profiles/_/templates — built-in defaults for the SOUL/IDENTITY/BOOTSTRAP\n// markdown templates. Underscore prefix avoids clashing with the `:id` route.\nprofilesRouter.get('/_/templates', (c) => {\n return c.json({\n soul: DEFAULT_SOUL,\n identity: DEFAULT_IDENTITY,\n bootstrap: DEFAULT_BOOTSTRAP,\n })\n})\n\nprofilesRouter.post('/', async (c) => {\n const raw = (await c.req.json().catch(() => null)) as\n | (Record<string, unknown> & Partial<CreateProfileRequest>)\n | null\n if (!raw) return c.json({ error: 'invalid JSON body' }, 400)\n const id = typeof raw.id === 'string' ? raw.id : ''\n const defaultModel =\n typeof raw.defaultModel === 'string'\n ? raw.defaultModel\n : typeof raw.model === 'string'\n ? raw.model\n : ''\n if (!id || !defaultModel) return c.json({ error: 'id and model are required' }, 400)\n const name = typeof raw.name === 'string' ? raw.name : undefined\n\n const skillsMode = toSkillsMode(raw.skillsMode) ?? 'selected'\n const defaultSkills = csvToArray(raw.defaultSkills ?? raw.skills)\n\n const templates: {\n soul?: string\n identity?: string\n bootstrap?: string | null\n agents?: string\n tools?: string\n heartbeat?: string\n } = {}\n if (typeof raw.soul === 'string' && raw.soul.length > 0) templates.soul = raw.soul\n if (typeof raw.identity === 'string' && raw.identity.length > 0) templates.identity = raw.identity\n if (raw.skipBootstrap === true || raw.bootstrap === null) templates.bootstrap = null\n else if (typeof raw.bootstrap === 'string' && raw.bootstrap.length > 0)\n templates.bootstrap = raw.bootstrap\n if (typeof raw.agents === 'string' && raw.agents.length > 0) templates.agents = raw.agents\n if (typeof raw.tools === 'string' && raw.tools.length > 0) templates.tools = raw.tools\n if (typeof raw.heartbeat === 'string' && raw.heartbeat.length > 0)\n templates.heartbeat = raw.heartbeat\n\n const { db, paths } = getCtx()\n try {\n const profile = createProfile(db, paths, {\n id,\n name,\n defaultModel,\n skillsMode,\n defaultSkills,\n ...(Object.keys(templates).length > 0 ? { templates } : {}),\n })\n return c.json(profile, 201)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n})\n\nprofilesRouter.get('/:id', (c) => {\n const { db } = getCtx()\n try {\n return c.json(loadProfile(db, c.req.param('id')))\n } catch (err) {\n return c.json({ error: (err as Error).message }, 404)\n }\n})\n\nprofilesRouter.patch('/:id', async (c) => {\n const raw = (await c.req.json().catch(() => null)) as\n | (UpdateProfileRequest & Record<string, unknown>)\n | null\n if (!raw) return c.json({ error: 'invalid JSON body' }, 400)\n\n const input: UpdateProfileRequest = {}\n if (typeof raw.name === 'string') input.name = raw.name\n if (typeof raw.defaultModel === 'string' && raw.defaultModel.length > 0)\n input.defaultModel = raw.defaultModel\n if (raw.skillsMode === 'all' || raw.skillsMode === 'selected') {\n input.skillsMode = raw.skillsMode\n }\n const rawSkills: unknown = raw.defaultSkills\n if (Array.isArray(rawSkills)) {\n input.defaultSkills = rawSkills.filter((s): s is string => typeof s === 'string')\n } else if (typeof rawSkills === 'string') {\n input.defaultSkills = rawSkills\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean)\n }\n const { db, paths } = getCtx()\n try {\n return c.json(updateProfile(db, paths, c.req.param('id'), input))\n } catch (err) {\n const msg = (err as Error).message\n return c.json({ error: msg }, msg.startsWith('profile not found') ? 404 : 400)\n }\n})\n\nprofilesRouter.delete('/:id', (c) => {\n const { db } = getCtx()\n try {\n deleteProfile(db, c.req.param('id'))\n return c.body(null, 204)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n})\n\nprofilesRouter.get('/:id/files/:file', (c) => {\n const { db, paths } = getCtx()\n if (!profileRepo.get(db, c.req.param('id')))\n return c.json({ error: `profile not found: ${c.req.param('id')}` }, 404)\n const path = resolveFilePath(paths.profilesDir, c.req.param('id'), c.req.param('file'))\n if (!path) return c.json({ error: `unsupported file: ${c.req.param('file')}` }, 400)\n if (!existsSync(path)) return c.json({ error: `file not present: ${c.req.param('file')}` }, 404)\n const body: FileContentResponse = { content: readFileSync(path, 'utf8') }\n return c.json(body)\n})\n\nprofilesRouter.put('/:id/files/:file', async (c) => {\n const body = (await c.req.json().catch(() => null)) as PutFileRequest | null\n if (!body || typeof body.content !== 'string')\n return c.json({ error: 'content is required' }, 400)\n const { db, paths } = getCtx()\n if (!profileRepo.get(db, c.req.param('id')))\n return c.json({ error: `profile not found: ${c.req.param('id')}` }, 404)\n const path = resolveFilePath(paths.profilesDir, c.req.param('id'), c.req.param('file'))\n if (!path) return c.json({ error: `unsupported file: ${c.req.param('file')}` }, 400)\n writeFileSync(path, body.content)\n return c.body(null, 204)\n})\n\nfunction resolveFilePath(profilesDir: string, id: string, file: string): string | null {\n if (!(PROFILE_FILES as readonly string[]).includes(file)) return null\n return join(profilesDir, id, file as ProfileFileName)\n}\n\nfunction csvToArray(v: unknown): string[] | undefined {\n if (Array.isArray(v)) return v.filter((s): s is string => typeof s === 'string')\n if (typeof v === 'string' && v.length > 0) {\n return v\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean)\n }\n return undefined\n}\n\nfunction toSkillsMode(v: unknown): SkillsMode | undefined {\n return v === 'all' || v === 'selected' ? v : undefined\n}\n","// /api/skills/* — skill discovery, removal, and import (file-path or zip upload).\n\nimport { existsSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'\nimport { homedir, tmpdir } from 'node:os'\nimport { join } from 'node:path'\nimport type { ImportSkillsRequest, ImportSkillsResponse, SkillInfo } from '@bazilion/api-types'\nimport { Hono } from 'hono'\nimport { discoverSkills, importSkills, parseSkillFile, skillMetaRepo } from '../core/index.ts'\nimport { getCtx } from '../lib/ctx.ts'\n\n// 50 MiB cap — generous headroom for a bundle of skills, tight enough to\n// reject obviously-malicious payloads without needing a streaming upload.\nconst MAX_ZIP_BYTES = 50 * 1024 * 1024\n\nexport const skillsRouter = new Hono()\n\nskillsRouter.get('/', (c) => {\n const { db, paths } = getCtx()\n const out: SkillInfo[] = []\n for (const s of discoverSkills(paths)) {\n const meta = skillMetaRepo.get(db, s.name)\n const entry: SkillInfo = {\n name: s.name,\n description: '',\n source: meta?.source ?? null,\n importedAt: meta?.importedAt ?? null,\n }\n try {\n const parsed = parseSkillFile(s.skillFile)\n entry.description = parsed.frontmatter.description\n } catch (err) {\n entry.parseError = (err as Error).message\n }\n out.push(entry)\n }\n return c.json(out)\n})\n\nskillsRouter.delete('/:name', (c) => {\n const { db, paths } = getCtx()\n const name = c.req.param('name')\n const dir = paths.skillDir(name)\n if (!existsSync(dir)) return c.json({ error: `skill not found: ${name}` }, 404)\n rmSync(dir, { recursive: true, force: true })\n skillMetaRepo.remove(db, name)\n return c.body(null, 204)\n})\n\nskillsRouter.post('/import', async (c) => {\n let input: ParsedImportInput\n try {\n input = await parseImportInput(c.req.raw)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n }\n\n const { db, paths } = getCtx()\n try {\n const result = importSkills(paths, { source: input.source, force: input.force })\n const now = Date.now()\n for (const name of result.imported) {\n skillMetaRepo.upsert(db, { name, source: input.sourceLabel, importedAt: now })\n }\n const res: ImportSkillsResponse = { imported: result.imported, skipped: result.skipped }\n return c.json(res)\n } catch (err) {\n return c.json({ error: (err as Error).message }, 400)\n } finally {\n if (input.tempZipPath) rmSync(input.tempZipPath, { recursive: true, force: true })\n }\n})\n\ninterface ParsedImportInput {\n source: string\n force: boolean\n /** when set, a temp zip was written and should be rm'd after import */\n tempZipPath: string | null\n /** label stored in skill_meta.source (e.g. \"uploaded:foo.zip\" for uploads) */\n sourceLabel: string\n}\n\nasync function parseImportInput(request: Request): Promise<ParsedImportInput> {\n const contentType = request.headers.get('content-type') ?? ''\n if (contentType.startsWith('multipart/form-data')) {\n const form = await request.formData()\n const file = form.get('file')\n if (!(file instanceof File) || file.size === 0) {\n throw new Error('multipart upload missing \"file\" field')\n }\n if (file.size > MAX_ZIP_BYTES) {\n throw new Error(`zip too large: ${file.size} bytes (max ${MAX_ZIP_BYTES})`)\n }\n const filename = file.name || 'upload.zip'\n if (!filename.toLowerCase().endsWith('.zip')) {\n throw new Error('uploaded file must be a .zip archive')\n }\n const tmpDir = mkdtempSync(join(tmpdir(), 'bazilion-skill-upload-'))\n const zipPath = join(tmpDir, filename.replace(/[^\\w.-]+/g, '_'))\n const buf = Buffer.from(await file.arrayBuffer())\n writeFileSync(zipPath, buf)\n const forceField = form.get('force')\n return {\n source: zipPath,\n force: forceField === 'true' || forceField === 'on' || forceField === '1',\n tempZipPath: tmpDir,\n sourceLabel: `uploaded:${filename}`,\n }\n }\n\n const body = (await request.json().catch(() => null)) as\n | (Partial<ImportSkillsRequest> & { from?: string })\n | null\n if (!body) throw new Error('invalid JSON body')\n const from = body.source ?? body.from\n if (typeof from !== 'string' || !from) throw new Error('source is required')\n const source = from === 'openclaw' ? join(homedir(), '.openclaw', 'skills') : from\n return {\n source,\n force: Boolean(body.force),\n tempZipPath: null,\n sourceLabel: from,\n }\n}\n","// /api/triggers/:id — enable/disable + delete. (Listing is per-agent at\n// /api/agents/:id/triggers; creation is also per-agent.)\n\nimport type { UpdateTriggerRequest } from '@bazilion/api-types'\nimport { Hono } from 'hono'\nimport { triggerRepo } from '../core/index.ts'\nimport { getCtx } from '../lib/ctx.ts'\n\nexport const triggersRouter = new Hono()\n\ntriggersRouter.delete('/:id', (c) => {\n const { db } = getCtx()\n const id = c.req.param('id')\n if (!triggerRepo.get(db, id)) return c.json({ error: `trigger not found: ${id}` }, 404)\n triggerRepo.remove(db, id)\n return c.body(null, 204)\n})\n\ntriggersRouter.patch('/:id', async (c) => {\n const id = c.req.param('id')\n const body = (await c.req.json().catch(() => null)) as UpdateTriggerRequest | null\n if (!body) return c.json({ error: 'invalid JSON body' }, 400)\n const { db } = getCtx()\n if (!triggerRepo.get(db, id)) return c.json({ error: `trigger not found: ${id}` }, 404)\n if (typeof body.enabled === 'boolean') {\n triggerRepo.setEnabled(db, id, body.enabled)\n }\n return c.json({ trigger: triggerRepo.get(db, id) })\n})\n"],"mappings":"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","names":["Hono","get","insert","list","remove","get","insert","list","remove","get","mkdirSync","writeFileSync","join","existsSync","readFileSync","existsSync","readFileSync","get","bootstrap","list","remove","list","existsSync","get","existsSync","insert","mkdirSync","join","mkdirSync","bootstrap","join","insert","get","existsSync","join","mkdirSync","join","writeFileSync","get","readdirSync","readFileSync","join","get","members","remove","join","existsSync","rmSync","get","insert","list","remove","update","get","remove","existsSync","rmSync","writeFileSync","join","get","writeFileSync","join","readdirSync","rmSync","rmSync","members","get","rmSync","readdirSync","get","randomUUID","listAll","get","listAll","remove","get","insert","listEnabled","remove","setEnabled","randomUUID","get","list","randomBytes","randomUUID","existsSync","readFileSync","existsSync","readFileSync","existsSync","readdirSync","rmSync","statSync","join","resolve","readFileSync","join","resolve","rmSync","readdirSync","existsSync","statSync","existsSync","mkdirSync","writeFileSync","existsSync","mkdirSync","readdirSync","readFileSync","rmSync","statSync","writeFileSync","dirname","join","existsSync","mkdirSync","readdirSync","readFileSync","rmSync","statSync","writeFileSync","dirname","join","existsSync","mkdirSync","readdirSync","statSync","basename","join","resolve","get","existsSync","readFileSync","join","bootstrap","Type","existsSync","rmSync","join","readdirSync","readFileSync","statSync","writeFileSync","join","host","host","undiciFetch","ipv4","host","undiciFetch","Type","resolveApiKey","existsSync","mkdirSync","join","join","existsSync","statSync","basename","existsSync","readdirSync","join","statSync","undiciFetch","existsSync","fileURLToPath","resolve","host","createHash","createHash","decodeText","mkdirSync","existsSync","writeFileSync","existsSync","readdirSync","readFileSync","rmSync","join","toAgent","join","CONTEXT_FILE_ORDER","existsSync","readFileSync","readdirSync","rmSync","spawn","Hono","Hono","spawn","Hono","Hono","state","v","join","Hono","USER_MD_MAX_BYTES","Hono","join","Hono","Hono","spawn","existsSync","homedir","join","Hono","Hono","existsSync","join","homedir","spawn","bootstrap","Hono","Hono","existsSync","readFileSync","writeFileSync","join","Hono","Hono","existsSync","readFileSync","writeFileSync","join","existsSync","mkdtempSync","rmSync","writeFileSync","homedir","tmpdir","join","Hono","Hono","existsSync","rmSync","mkdtempSync","join","tmpdir","writeFileSync","homedir","Hono","Hono","app","Hono"]}