agentinbox-cli 0.0.0 → 0.1.0-nightly.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +312 -0
  3. package/dist/audit-CQe-_dPQ.js +2 -0
  4. package/dist/audit-DETqygzG.js +65 -0
  5. package/dist/audit-DETqygzG.js.map +1 -0
  6. package/dist/auth-BniddcRD.js +447 -0
  7. package/dist/auth-BniddcRD.js.map +1 -0
  8. package/dist/auth-C2v7bEmQ.js +2 -0
  9. package/dist/bus-Cz0flS37.js +12 -0
  10. package/dist/bus-Cz0flS37.js.map +1 -0
  11. package/dist/bus-OKIGut72.js +2 -0
  12. package/dist/cli.js +141 -0
  13. package/dist/cli.js.map +1 -0
  14. package/dist/config-CIvgMqLx.js +2 -0
  15. package/dist/config-v975gxv4.js +44 -0
  16. package/dist/config-v975gxv4.js.map +1 -0
  17. package/dist/crypto-DYZ4R7c2.js +74 -0
  18. package/dist/crypto-DYZ4R7c2.js.map +1 -0
  19. package/dist/db-CfoMO5zW.js +2 -0
  20. package/dist/db-DdagFmUY.js +247 -0
  21. package/dist/db-DdagFmUY.js.map +1 -0
  22. package/dist/errors-CJLUPllS.js +38 -0
  23. package/dist/errors-CJLUPllS.js.map +1 -0
  24. package/dist/instance-DZMV78rI.js +2 -0
  25. package/dist/instance-Dy2jeyZc.js +174 -0
  26. package/dist/instance-Dy2jeyZc.js.map +1 -0
  27. package/dist/server-CWqKeCGn.js +981 -0
  28. package/dist/server-CWqKeCGn.js.map +1 -0
  29. package/dist/service-63pdSmhO.js +332 -0
  30. package/dist/service-63pdSmhO.js.map +1 -0
  31. package/dist/settings-Dq2ETFsd.js +98 -0
  32. package/dist/settings-Dq2ETFsd.js.map +1 -0
  33. package/dist/settings-qtn5WTBM.js +2 -0
  34. package/dist/setup-token-Bkwk84l7.js +47 -0
  35. package/dist/setup-token-Bkwk84l7.js.map +1 -0
  36. package/dist/skill/SKILL.md +226 -0
  37. package/dist/skill-BWWtinsE.js +2 -0
  38. package/dist/skill-WKbeyNct.js +43 -0
  39. package/dist/skill-WKbeyNct.js.map +1 -0
  40. package/dist/urls-CNYhbeUQ.js +2 -0
  41. package/dist/urls-DmnonkJo.js +22 -0
  42. package/dist/urls-DmnonkJo.js.map +1 -0
  43. package/dist/web/assets/_agentId-il4y7OCG.js +1 -0
  44. package/dist/web/assets/_app-BIO8WIYB.js +1 -0
  45. package/dist/web/assets/_app-wlLL4MrD.js +63 -0
  46. package/dist/web/assets/_webhookId-CiwDrkY4.js +1 -0
  47. package/dist/web/assets/account-status-at9Bv3_T.js +1 -0
  48. package/dist/web/assets/accounts-B4rfPwCV.js +1 -0
  49. package/dist/web/assets/accounts-list-e--JWxHH.js +1 -0
  50. package/dist/web/assets/activity-zrckFhPk.js +1 -0
  51. package/dist/web/assets/agent-create-form-DaWPR6kx.js +1 -0
  52. package/dist/web/assets/agents-D4gPq4dt.js +1 -0
  53. package/dist/web/assets/approvals-DaoZ6wuf.js +2 -0
  54. package/dist/web/assets/arrow-left-DVJV4Zx7.js +1 -0
  55. package/dist/web/assets/arrow-right-4PFX6MSS.js +1 -0
  56. package/dist/web/assets/audit-bAdLe-px.js +1 -0
  57. package/dist/web/assets/audit-bits-DQHo74i6.js +1 -0
  58. package/dist/web/assets/bot-DVw15lBn.js +1 -0
  59. package/dist/web/assets/card-EQTpqntn.js +1 -0
  60. package/dist/web/assets/checkbox-DDZZurgK.js +1 -0
  61. package/dist/web/assets/chevron-down-892ylB4R.js +1 -0
  62. package/dist/web/assets/chevron-right-CbBKS6-T.js +1 -0
  63. package/dist/web/assets/chips-input-Btdc_f7b.js +1 -0
  64. package/dist/web/assets/circle-x-Bi4IGwky.js +1 -0
  65. package/dist/web/assets/common-h6596gEC.js +1 -0
  66. package/dist/web/assets/connect-host-Co31qIYr.js +1 -0
  67. package/dist/web/assets/data-table-DsKrM62X.js +1 -0
  68. package/dist/web/assets/dialog-CgZr27yw.js +1 -0
  69. package/dist/web/assets/dist-B0e3Ju3r.js +1 -0
  70. package/dist/web/assets/empty-CE_WZGEC.js +1 -0
  71. package/dist/web/assets/es2015-DPaldoxG.js +41 -0
  72. package/dist/web/assets/event-row-C0qRfWuV.js +1 -0
  73. package/dist/web/assets/events-Svyij7mp.js +1 -0
  74. package/dist/web/assets/eye-off-DjpaihHf.js +1 -0
  75. package/dist/web/assets/field-CcyMn3ey.js +1 -0
  76. package/dist/web/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  77. package/dist/web/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  78. package/dist/web/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  79. package/dist/web/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  80. package/dist/web/assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2 +0 -0
  81. package/dist/web/assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2 +0 -0
  82. package/dist/web/assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2 +0 -0
  83. package/dist/web/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
  84. package/dist/web/assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2 +0 -0
  85. package/dist/web/assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2 +0 -0
  86. package/dist/web/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  87. package/dist/web/assets/get-started-Cxfw97sJ.js +1 -0
  88. package/dist/web/assets/grants-BilXCDps.js +1 -0
  89. package/dist/web/assets/index-DgIgw66p.css +2 -0
  90. package/dist/web/assets/index-TbxC5ZgP.js +10 -0
  91. package/dist/web/assets/input-CMhmmHiH.js +1 -0
  92. package/dist/web/assets/input-group-DRs3TNaT.js +1 -0
  93. package/dist/web/assets/key-round-CVIZRCLM.js +1 -0
  94. package/dist/web/assets/labels-C_Pwium9.js +1 -0
  95. package/dist/web/assets/login-DUJia7lg.js +1 -0
  96. package/dist/web/assets/mail-CAVmuESo.js +1 -0
  97. package/dist/web/assets/mutations-D_GluJ0j.js +1 -0
  98. package/dist/web/assets/paperclip-QFjM4y6n.js +1 -0
  99. package/dist/web/assets/password-input-_m9Ycphv.js +1 -0
  100. package/dist/web/assets/pencil-Bf1JhsG0.js +1 -0
  101. package/dist/web/assets/play-DiPk49JH.js +1 -0
  102. package/dist/web/assets/plus-CETmK0SB.js +1 -0
  103. package/dist/web/assets/preload-helper-BFuRUfdt.js +1 -0
  104. package/dist/web/assets/progress-3ZOsbLSK.js +6 -0
  105. package/dist/web/assets/queries-a3M5_loa.js +2 -0
  106. package/dist/web/assets/refresh-cw-DOn9kD7g.js +1 -0
  107. package/dist/web/assets/search-gcYjitzV.js +1 -0
  108. package/dist/web/assets/select-_tULk-vs.js +1 -0
  109. package/dist/web/assets/send-BhQwhuJo.js +1 -0
  110. package/dist/web/assets/settings-Dl4wb4f0.js +1 -0
  111. package/dist/web/assets/settings-form-D21eKBh-.js +1 -0
  112. package/dist/web/assets/setup-DYnNhnfH.js +1 -0
  113. package/dist/web/assets/sheet--2lKU0jN.js +1 -0
  114. package/dist/web/assets/shield-alert-CbFgd06X.js +1 -0
  115. package/dist/web/assets/stamp-CH2OvjH2.js +1 -0
  116. package/dist/web/assets/stream-6OwrgVZw.js +1 -0
  117. package/dist/web/assets/tabs-CiAUEj_y.js +1 -0
  118. package/dist/web/assets/tag-CP72Kk6Y.js +1 -0
  119. package/dist/web/assets/test-connection-F2tMowbv.js +1 -0
  120. package/dist/web/assets/textarea-CCokBZIw.js +1 -0
  121. package/dist/web/assets/toggle-group-D1pC7sJr.js +1 -0
  122. package/dist/web/assets/trash-DxdMNg8B.js +1 -0
  123. package/dist/web/assets/use-sign-out-BuzlTb0Q.js +1 -0
  124. package/dist/web/assets/useInfiniteQuery-DE6WChlb.js +1 -0
  125. package/dist/web/assets/useMatch-BKUnm54_.js +1 -0
  126. package/dist/web/assets/useMutation-DGl4PaZ1.js +1 -0
  127. package/dist/web/assets/useQuery-DAhf1YDH.js +1 -0
  128. package/dist/web/assets/useSelector-D70eKNYs.js +1 -0
  129. package/dist/web/assets/webhook-BWT75M78.js +1 -0
  130. package/dist/web/assets/webhook-sheet-4U_6Rw8I.js +34 -0
  131. package/dist/web/assets/webhooks-C1JvTI88.js +1 -0
  132. package/dist/web/assets/with-selector-CkNyXYMW.js +1 -0
  133. package/dist/web/assets/x-BHjDLXNO.js +1 -0
  134. package/dist/web/favicon.svg +1 -0
  135. package/dist/web/index.html +31 -0
  136. package/package.json +94 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-CWqKeCGn.js","names":[],"sources":["../server/api/util.ts","../server/api/accounts.ts","../server/api/agents.ts","../server/api/approvals.ts","../server/api/audit.ts","../server/api/setup.ts","../server/api/auth.ts","../server/api/events.ts","../server/api/google.ts","../server/api/oauth.ts","../server/api/overview.ts","../server/api/settings.ts","../server/api/system.ts","../server/api/webhooks.ts","../server/csp.ts","../server/mcp/index.ts","../server/app.ts","../server/maintenance.ts","../server/util/log.ts","../server/context.ts","../server/util/stub.ts","../server/events/index.ts","../server/google/index.ts","../server/ingest/index.ts","../server/mail/index.ts","../server/policy/index.ts","../server/webhooks/index.ts","../server/wire.ts","../server/server.ts"],"sourcesContent":["import { type Context, Hono } from \"hono\";\nimport { z } from \"zod\";\nimport type { AuditInput } from \"../audit.ts\";\nimport type { AgentPrincipal } from \"../policy/types.ts\";\nimport { badRequest } from \"../util/errors.ts\";\n\n/**\n * Hono environment for every router. `admin` is set by the console auth middleware (server/app.ts)\n * for /api/* routes; `agent` is set by the MCP bearer auth.\n */\nexport type AppEnv = { Variables: { admin?: true; agent?: AgentPrincipal } };\n\n/**\n * Console API routers are `(ctx) => Hono<AppEnv>` factories with paths relative to /api\n * (e.g. \"/accounts/:id\"). server/app.ts mounts them behind the admin auth middleware and turns\n * thrown HttpError / PolicyDenied into ApiError JSON responses.\n */\nexport const router = () => new Hono<AppEnv>();\n\n/** Parses and validates a JSON body; throws HttpError(400) with a readable message. */\nexport async function readBody<S extends z.ZodType>(c: Context, schema: S): Promise<z.infer<S>> {\n let raw: unknown;\n try {\n const text = await c.req.text();\n raw = text ? JSON.parse(text) : {};\n } catch {\n throw badRequest(\"Request body must be valid JSON\");\n }\n const parsed = schema.safeParse(raw);\n if (!parsed.success) throw badRequest(z.prettifyError(parsed.error));\n return parsed.data;\n}\n\n/** Audit fields for console (admin) actions: spread into ctx.audit.record. */\nexport const ADMIN_ACTOR: Pick<AuditInput, \"actorType\" | \"actorId\"> = { actorType: \"admin\", actorId: null };\n","import type { AppContext } from \"../context.ts\";\nimport { router } from \"./util.ts\";\n\n// PLACEHOLDER: replaced by the owning work area. Paths are relative to /api.\nexport function accountsApi(_ctx: AppContext) {\n return router();\n}\n","import type { AppContext } from \"../context.ts\";\nimport { router } from \"./util.ts\";\n\n// PLACEHOLDER: replaced by the owning work area. Paths are relative to /api.\nexport function agentsApi(_ctx: AppContext) {\n return router();\n}\n","import type { AppContext } from \"../context.ts\";\nimport { router } from \"./util.ts\";\n\n// PLACEHOLDER: replaced by the owning work area. Paths are relative to /api.\nexport function approvalsApi(_ctx: AppContext) {\n return router();\n}\n","import type { AppContext } from \"../context.ts\";\nimport { router } from \"./util.ts\";\n\n// PLACEHOLDER: replaced by the owning work area. Paths are relative to /api.\nexport function auditApi(_ctx: AppContext) {\n return router();\n}\n","import { z } from \"zod\";\nimport type { GoogleClientView, PubsubState, SetupState, SetupStatus } from \"../../shared/types.ts\";\nimport {\n adminAuth,\n checkSecret,\n clientIp,\n hasSession,\n isClaimed,\n lockedOut,\n MAX_PASSWORD_LENGTH,\n MIN_PASSWORD_LENGTH,\n rejection,\n startSession,\n} from \"../auth/index.ts\";\nimport { deleteSetupToken, readSetupToken } from \"../auth/setup-token.ts\";\nimport type { AppContext } from \"../context.ts\";\nimport { cliCommand } from \"../instance.ts\";\nimport { hashPasswordAsync, safeEqual } from \"../crypto.ts\";\nimport { badRequest, conflict, HttpError } from \"../util/errors.ts\";\nimport { readBody, router } from \"./util.ts\";\n\nconst ClaimBody = z.object({\n token: z.string().trim().min(1, \"Setup token is required\").max(200),\n password: z.string().max(MAX_PASSWORD_LENGTH, `Password must be at most ${MAX_PASSWORD_LENGTH} characters`),\n});\n\n/** Unauthenticated: first-run status and the one-time claim. Mounted before the admin guard. */\nexport function setupPublicApi(ctx: AppContext) {\n const auth = adminAuth(ctx);\n return router()\n .get(\"/setup/status\", (c) => {\n c.header(\"Cache-Control\", \"no-store\");\n return c.json<SetupStatus>({ claimed: isClaimed(ctx), authenticated: hasSession(c, ctx) });\n })\n .post(\"/setup/claim\", async (c) => {\n const ip = clientIp(c, ctx.config.trustProxy);\n const banned = auth.limiter.bannedMinutes(ip);\n if (banned) return lockedOut(c, banned);\n const body = await readBody(c, ClaimBody);\n if (isClaimed(ctx)) throw conflict(\"This instance is already claimed\", \"Sign in with the admin password instead.\");\n const expected = readSetupToken(ctx.config.dataDir);\n if (!expected) {\n throw new HttpError(403, \"invalid_token\", \"The setup link has expired\", `Restart agentinbox or run \\`${cliCommand(\"reset-password\")}\\` for a new link.`);\n }\n const check = await checkSecret(ctx, ip, `claim:${body.token}`, () => safeEqual(body.token, expected), { global: false });\n if (!check.ok) {\n const rejected = rejection(c, check);\n if (rejected) return rejected;\n ctx.audit.record({ actorType: \"admin\", action: \"admin.claim\", outcome: \"denied\", reason: check.nowBanned ? \"lockout\" : \"invalid_token\", detail: { ip } });\n throw new HttpError(403, \"invalid_token\", \"Invalid setup token\", \"Use the exact setup link printed by agentinbox on startup.\");\n }\n checkPassword(body.password);\n const hash = await hashPasswordAsync(body.password);\n // A concurrent claim may have won while hashing.\n if (isClaimed(ctx)) throw conflict(\"This instance is already claimed\", \"Sign in with the admin password instead.\");\n ctx.settings.setState(\"admin.passwordHash\", hash);\n deleteSetupToken(ctx.config.dataDir);\n auth.limiter.reset();\n startSession(c, ctx);\n ctx.audit.record({ actorType: \"admin\", action: \"admin.claim\", outcome: \"ok\", detail: { ip } });\n return c.body(null, 204);\n });\n}\n\n/** Authenticated: the setup checklist. */\nexport function setupApi(ctx: AppContext) {\n return router().get(\"/setup/state\", (c) => c.json(setupState(ctx)));\n}\n\nexport function checkPassword(password: string): void {\n if (password.length < MIN_PASSWORD_LENGTH) throw badRequest(`Password must be at least ${MIN_PASSWORD_LENGTH} characters`);\n if (password.length > MAX_PASSWORD_LENGTH) throw badRequest(`Password must be at most ${MAX_PASSWORD_LENGTH} characters`);\n}\n\n/** Composes the setup checklist. Reads the stored state directly if a service is unavailable. */\nexport function setupState(ctx: AppContext): SetupState {\n const claimed = isClaimed(ctx);\n const client = attempt(ctx, () => ctx.google.clientView()) ?? storedClientView(ctx);\n const pubsub = attempt(ctx, () => ctx.google.pubsubState()) ?? storedPubsub(ctx);\n const count = (table: \"accounts\" | \"agents\") => ctx.db.get<{ n: number }>(`SELECT COUNT(*) AS n FROM ${table}`)?.n ?? 0;\n const accountsConnected = count(\"accounts\");\n const googleClientConfigured = !!client.clientId && client.hasSecret;\n return {\n claimed,\n googleClientConfigured,\n gcpProjectId: client.projectId,\n googleAppType: client.appType,\n pubsub,\n accountsConnected,\n agentsCreated: count(\"agents\"),\n complete: claimed && googleClientConfigured && accountsConnected > 0,\n };\n}\n\nfunction attempt<T>(ctx: AppContext, fn: () => T): T | null {\n try {\n return fn();\n } catch (err) {\n ctx.log.debug(\"setup state: falling back to stored state\", { error: err instanceof Error ? err.message : String(err) });\n return null;\n }\n}\n\nfunction storedClientView(ctx: AppContext): Pick<GoogleClientView, \"clientId\" | \"hasSecret\" | \"projectId\" | \"appType\"> {\n const s = ctx.settings.getState(\"google.client\");\n return { clientId: s?.clientId || null, hasSecret: !!s?.clientSecretEnc, projectId: s?.projectId || null, appType: s?.appType ?? null };\n}\n\nfunction storedPubsub(ctx: AppContext): PubsubState {\n const s = ctx.settings.getState(\"pubsub\");\n return {\n mode: ctx.settings.get().ingestMode,\n topic: s?.topic ?? null,\n subscription: s?.subscription ?? null,\n lastError: s?.lastError ?? null,\n lastMessageAt: s?.lastMessageAt ?? null,\n };\n}\n","import { z } from \"zod\";\nimport { adminAuth, checkSecret, clientIp, endSession, lockedOut, MAX_PASSWORD_LENGTH, rejection, sessionToken, startSession } from \"../auth/index.ts\";\nimport type { AppContext } from \"../context.ts\";\nimport { hashPasswordAsync, verifyPasswordAsync } from \"../crypto.ts\";\nimport { conflict, HttpError } from \"../util/errors.ts\";\nimport { checkPassword } from \"./setup.ts\";\nimport { ADMIN_ACTOR, readBody, router } from \"./util.ts\";\n\nconst password = (what: string) => z.string().max(MAX_PASSWORD_LENGTH, `${what} must be at most ${MAX_PASSWORD_LENGTH} characters`);\nconst LoginBody = z.object({ password: password(\"Password\").min(1, \"Password is required\") });\nconst PasswordBody = z.object({ current: password(\"Current password\"), next: password(\"New password\") });\n\n/** Unauthenticated: sign in and out. Mounted before the admin guard. */\nexport function authPublicApi(ctx: AppContext) {\n const auth = adminAuth(ctx);\n return router()\n .post(\"/auth/login\", async (c) => {\n const ip = clientIp(c, ctx.config.trustProxy);\n const banned = auth.limiter.bannedMinutes(ip);\n if (banned) return lockedOut(c, banned);\n const body = await readBody(c, LoginBody);\n const hash = ctx.settings.getState(\"admin.passwordHash\");\n if (!hash) throw conflict(\"This instance has not been claimed yet\", \"Open the setup link printed by agentinbox on startup.\");\n const check = await checkSecret(ctx, ip, body.password, () => verifyPasswordAsync(body.password, hash));\n if (!check.ok) {\n const rejected = rejection(c, check);\n if (rejected) return rejected;\n ctx.audit.record({ ...ADMIN_ACTOR, action: \"admin.login\", outcome: \"denied\", reason: check.nowBanned ? \"lockout\" : \"bad_password\", detail: { ip } });\n throw new HttpError(401, \"invalid_password\", \"Wrong password\");\n }\n startSession(c, ctx);\n ctx.audit.record({ ...ADMIN_ACTOR, action: \"admin.login\", outcome: \"ok\", detail: { ip } });\n return c.body(null, 204);\n })\n .post(\"/auth/logout\", (c) => {\n endSession(c, ctx);\n return c.body(null, 204);\n });\n}\n\n/** Authenticated: change the admin password. Revokes every other session. */\nexport function authApi(ctx: AppContext) {\n const auth = adminAuth(ctx);\n return router().post(\"/auth/password\", async (c) => {\n const ip = clientIp(c, ctx.config.trustProxy);\n const banned = auth.limiter.bannedMinutes(ip);\n if (banned) return lockedOut(c, banned);\n const body = await readBody(c, PasswordBody);\n const hash = ctx.settings.getState(\"admin.passwordHash\");\n const check = await checkSecret(ctx, ip, body.current, async () => !!hash && (await verifyPasswordAsync(body.current, hash)));\n if (!check.ok) {\n const rejected = rejection(c, check);\n if (rejected) return rejected;\n ctx.audit.record({ ...ADMIN_ACTOR, action: \"admin.password_change\", outcome: \"denied\", reason: check.nowBanned ? \"lockout\" : \"bad_password\", detail: { ip } });\n throw new HttpError(400, \"invalid_password\", \"Current password is wrong\");\n }\n checkPassword(body.next);\n ctx.settings.setState(\"admin.passwordHash\", await hashPasswordAsync(body.next));\n const revoked = auth.sessions.deleteAll(sessionToken(c));\n // Secrets that were wrong before may be the password now.\n auth.limiter.reset();\n ctx.audit.record({ ...ADMIN_ACTOR, action: \"admin.password_change\", outcome: \"ok\", detail: { ip, revokedSessions: revoked } });\n return c.body(null, 204);\n });\n}\n","import type { AppContext } from \"../context.ts\";\nimport { router } from \"./util.ts\";\n\n// PLACEHOLDER: replaced by the owning work area. Paths are relative to /api.\nexport function eventsApi(_ctx: AppContext) {\n return router();\n}\n","import type { AppContext } from \"../context.ts\";\nimport { router } from \"./util.ts\";\n\n// PLACEHOLDER: replaced by the owning work area. Paths are relative to /api.\nexport function googleApi(_ctx: AppContext) {\n return router();\n}\n","import type { AppContext } from \"../context.ts\";\nimport { router } from \"./util.ts\";\n\n// PLACEHOLDER: replaced by the owning work area. Mounted at the root (unauthenticated): GET /oauth/callback.\nexport function oauthRoutes(_ctx: AppContext) {\n return router();\n}\n","import type { AppContext } from \"../context.ts\";\nimport { router } from \"./util.ts\";\n\n// PLACEHOLDER: replaced by the owning work area. Paths are relative to /api.\nexport function overviewApi(_ctx: AppContext) {\n return router();\n}\n","import { z } from \"zod\";\nimport type { Settings } from \"../../shared/types.ts\";\nimport type { AppContext } from \"../context.ts\";\nimport { ADMIN_ACTOR, readBody, router } from \"./util.ts\";\n\n/** Shape check only; ranges and URL rules are enforced by SettingsStore.update. */\nconst SettingsPatch = z\n .object({\n publicUrl: z.string().trim(),\n ingestMode: z.enum([\"pubsub\", \"poll\"]),\n pollIntervalSeconds: z.number(),\n maxBodyChars: z.number(),\n retentionDays: z.number(),\n approvalTtlHours: z.number(),\n webhookAllowlist: z.array(z.string()),\n })\n .partial()\n .strict() satisfies z.ZodType<Partial<Settings>>;\n\nexport function settingsApi(ctx: AppContext) {\n return router()\n .get(\"/settings\", (c) => c.json<Settings>(ctx.settings.get()))\n .patch(\"/settings\", async (c) => {\n const patch = await readBody(c, SettingsPatch);\n const before = ctx.settings.get();\n const next = ctx.settings.update(patch);\n const changed = (Object.keys(next) as (keyof Settings)[]).filter((k) => JSON.stringify(before[k]) !== JSON.stringify(next[k]));\n if (changed.length) ctx.audit.record({ ...ADMIN_ACTOR, action: \"settings.update\", outcome: \"ok\", detail: { changed } });\n return c.json<Settings>(next);\n });\n}\n","import { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport type { Context } from \"hono\";\nimport { type HealthResponse, type IngestStatus, NPM_PACKAGE, type SystemInfo, type UpdateInfo } from \"../../shared/types.ts\";\nimport { type Config, DEFAULT_PORT } from \"../config.ts\";\nimport type { AppContext } from \"../context.ts\";\nimport { consoleUrls } from \"../urls.ts\";\nimport { errorMessage } from \"../util/errors.ts\";\nimport { setupState } from \"./setup.ts\";\nimport { type AppEnv, router } from \"./util.ts\";\n\nconst DEFAULT_HOST = \"0.0.0.0\";\nconst LATEST_TTL_MS = 30 * 60_000;\nconst LATEST_RETRY_MS = 5 * 60_000;\n\n/**\n * Public health check for uptime monitors: 200 when healthy, 503 when degraded (an account needs\n * re-auth or is erroring, or ingest reports an error). Only states and the version, never secrets.\n */\nexport function healthRoutes(ctx: AppContext) {\n const handler = (c: Context<AppEnv>) => {\n const body = health(ctx);\n c.header(\"Cache-Control\", \"no-store\");\n return c.json<HealthResponse>(body, body.status === \"ok\" ? 200 : 503);\n };\n // Also with a trailing slash, which would otherwise fall through to the console and keep a monitor green.\n return router().get(\"/health\", handler).get(\"/health/\", handler).get(\"/api/health\", handler).get(\"/api/health/\", handler);\n}\n\nexport function health(ctx: AppContext): HealthResponse {\n const counts = ctx.db.get<{ total: number; attention: number }>(\n \"SELECT COUNT(*) AS total, COALESCE(SUM(status IN ('needs_reauth', 'error')), 0) AS attention FROM accounts\",\n ) ?? { total: 0, attention: 0 };\n let ingestError = false;\n if (counts.total > 0) {\n try {\n ingestError = !!ctx.ingest.status().lastError;\n } catch {\n // Ingest unavailable: account states above still tell the story.\n }\n }\n let setupComplete = false;\n try {\n setupComplete = setupState(ctx).complete;\n } catch {\n // Reported as not complete.\n }\n return {\n status: counts.attention > 0 || ingestError ? \"degraded\" : \"ok\",\n version: ctx.config.version,\n setupComplete,\n };\n}\n\n/** Authenticated: instance facts and the update notice. */\nexport function systemApi(ctx: AppContext) {\n return router()\n .get(\"/system\", (c) => {\n let ingest: IngestStatus;\n try {\n ingest = ctx.ingest.status();\n } catch (err) {\n ingest = { mode: ctx.settings.get().ingestMode, running: false, lastPullAt: null, lastError: errorMessage(err) };\n }\n return c.json<SystemInfo>({\n version: ctx.config.version,\n nodeVersion: process.versions.node,\n dataDir: ctx.config.dataDir,\n service: ctx.config.service,\n addresses: consoleUrls(ctx.config.host, ctx.config.port),\n publicUrl: ctx.settings.publicUrl(),\n ingest,\n });\n })\n .get(\"/system/latest\", async (c) => {\n const latest = await latestVersion(ctx);\n const current = ctx.config.version;\n return c.json<UpdateInfo>({\n current,\n latest,\n updateAvailable: !!latest && compareVersions(latest, current) > 0,\n command: upgradeCommand(ctx.config),\n });\n });\n}\n\nlet latestCache: { at: number; version: string | null } | undefined;\n\n/** The npm `latest` dist-tag, cached for 30 minutes (5 after a failed check). */\nasync function latestVersion(ctx: AppContext): Promise<string | null> {\n if (latestCache && Date.now() - latestCache.at < (latestCache.version ? LATEST_TTL_MS : LATEST_RETRY_MS)) {\n return latestCache.version;\n }\n let version: string | null = null;\n try {\n const res = await fetch(`https://registry.npmjs.org/${NPM_PACKAGE}/latest`, { signal: AbortSignal.timeout(5000) });\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n version = ((await res.json()) as { version?: string }).version ?? null;\n } catch (err) {\n ctx.log.debug(\"Update check failed\", { error: errorMessage(err) });\n }\n latestCache = { at: Date.now(), version };\n return version;\n}\n\n/**\n * Semver precedence: numeric core, then a pre-release sorts before its release, and pre-release\n * identifiers compare numerically when both are numbers (\"nightly.10\" > \"nightly.9\").\n */\nexport function compareVersions(a: string, b: string): number {\n const parse = (v: string) => {\n const clean = v.trim().replace(/^v/, \"\").split(\"+\")[0]!;\n const dash = clean.indexOf(\"-\");\n const core = dash === -1 ? clean : clean.slice(0, dash);\n return { parts: core.split(\".\").map((n) => Number.parseInt(n, 10) || 0), pre: dash === -1 ? null : clean.slice(dash + 1).split(\".\") };\n };\n const x = parse(a);\n const y = parse(b);\n for (let i = 0; i < Math.max(x.parts.length, y.parts.length); i++) {\n const d = (x.parts[i] ?? 0) - (y.parts[i] ?? 0);\n if (d) return Math.sign(d);\n }\n if (!x.pre || !y.pre) return x.pre === y.pre ? 0 : x.pre ? -1 : 1;\n for (let i = 0; i < Math.max(x.pre.length, y.pre.length); i++) {\n const p = x.pre[i];\n const q = y.pre[i];\n if (p === undefined) return -1;\n if (q === undefined) return 1;\n const pn = /^\\d+$/.test(p);\n const qn = /^\\d+$/.test(q);\n if (pn && qn) {\n const d = Number(p) - Number(q);\n if (d) return Math.sign(d);\n } else if (pn !== qn) {\n return pn ? -1 : 1;\n } else if (p !== q) {\n return p < q ? -1 : 1;\n }\n }\n return 0;\n}\n\nconst DEFAULT_DATA_DIR = () => resolve(join(homedir(), \".agentinbox\"));\n\n/** Runs, or reinstalls as a service, the latest version with this instance's options. */\nexport function upgradeCommand(config: Pick<Config, \"service\" | \"dataDir\" | \"port\" | \"host\" | \"trustProxy\">): string {\n // A service keeps TRUST_PROXY from its previous install, but a foreground run needs it again.\n const args = [...(config.trustProxy ? [\"TRUST_PROXY=1\"] : []), \"npx\", \"-y\", NPM_PACKAGE];\n if (config.service) args.push(\"service\", \"install\");\n if (config.dataDir !== DEFAULT_DATA_DIR()) args.push(\"--data\", config.dataDir);\n if (config.port !== DEFAULT_PORT) args.push(\"--port\", String(config.port));\n if (config.host !== DEFAULT_HOST) args.push(\"--host\", config.host);\n return args.map(shellQuote).join(\" \");\n}\n\nexport const shellQuote = (a: string) => (/^[\\w@%+=:,./-]+$/.test(a) ? a : `'${a.replace(/'/g, `'\\\\''`)}'`);\n","import type { AppContext } from \"../context.ts\";\nimport { router } from \"./util.ts\";\n\n// PLACEHOLDER: replaced by the owning work area. Paths are relative to /api.\nexport function webhooksApi(_ctx: AppContext) {\n return router();\n}\n","import { createHash } from \"node:crypto\";\n\n/**\n * Content Security Policy. Inline scripts run only when their exact content is known up front:\n * the console's index.html (hashed when the file is read) and scripts registered here by routes\n * that render HTML. Never hash scripts out of a response body: that would bless injected markup.\n *\n * A server-rendered page with an inline script (e.g. the OAuth callback page) must keep that\n * script static, call `registerInlineScript(source)` once at module load with the exact source,\n * and pass per-request data in a `<script type=\"application/json\" id=\"…\">` block, which CSP\n * doesn't execute and the static script reads with JSON.parse.\n */\nconst registered = new Set<string>();\n\n/** \"sha256-…\" source for a script's exact text (what goes between <script> and </script>). */\nexport const scriptHash = (source: string) => `sha256-${createHash(\"sha256\").update(source).digest(\"base64\")}`;\n\nexport function registerInlineScript(source: string): void {\n registered.add(scriptHash(source));\n}\n\n/** For callers that already have a \"sha256-…\" value. */\nexport function registerInlineScriptHash(hash: string): void {\n if (!/^sha(256|384|512)-[A-Za-z0-9+/]+={0,2}$/.test(hash)) throw new Error(`Invalid CSP hash: ${hash}`);\n registered.add(hash);\n}\n\nexport function contentSecurityPolicy(extraHashes: readonly string[] = []): string {\n const hashes = [...new Set([...registered, ...extraHashes])];\n return [\n \"default-src 'self'\",\n `script-src 'self'${hashes.map((h) => ` '${h}'`).join(\"\")}`,\n \"style-src 'self' 'unsafe-inline'\",\n \"img-src 'self' data:\",\n \"connect-src 'self'\",\n \"object-src 'none'\",\n \"base-uri 'none'\",\n \"frame-ancestors 'none'\",\n \"form-action 'self'\",\n ].join(\"; \");\n}\n\n/** Hashes of the executable inline scripts in a trusted document (the built index.html). */\nexport function inlineScriptHashes(html: string): string[] {\n const hashes = new Set<string>();\n for (const m of html.matchAll(/<script\\b([^>]*)>([\\s\\S]*?)<\\/script\\s*>/gi)) {\n const attrs = m[1]!;\n if (/\\bsrc\\s*=/i.test(attrs) || !m[2]) continue;\n const type = /\\btype\\s*=\\s*[\"']?([^\"'\\s>]+)/i.exec(attrs)?.[1]?.toLowerCase();\n if (type && type !== \"module\" && type !== \"text/javascript\" && type !== \"application/javascript\") continue;\n hashes.add(scriptHash(m[2]));\n }\n return [...hashes];\n}\n","import { router } from \"../api/util.ts\";\nimport type { AppContext } from \"../context.ts\";\n\n// PLACEHOLDER: replaced by the owning work area. Mounted at the root: POST/GET/DELETE /mcp (bearer = agent key).\nexport function mcpRoutes(_ctx: AppContext) {\n return router();\n}\n","import { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { extname, join, resolve, sep } from \"node:path\";\nimport { serveStatic } from \"@hono/node-server/serve-static\";\nimport { type Context, Hono } from \"hono\";\nimport { bodyLimit } from \"hono/body-limit\";\nimport { HTTPException } from \"hono/http-exception\";\nimport { z } from \"zod\";\nimport type { ApiError } from \"../shared/types.ts\";\nimport { accountsApi } from \"./api/accounts.ts\";\nimport { agentsApi } from \"./api/agents.ts\";\nimport { approvalsApi } from \"./api/approvals.ts\";\nimport { auditApi } from \"./api/audit.ts\";\nimport { authApi, authPublicApi } from \"./api/auth.ts\";\nimport { eventsApi } from \"./api/events.ts\";\nimport { googleApi } from \"./api/google.ts\";\nimport { oauthRoutes } from \"./api/oauth.ts\";\nimport { overviewApi } from \"./api/overview.ts\";\nimport { settingsApi } from \"./api/settings.ts\";\nimport { setupApi, setupPublicApi } from \"./api/setup.ts\";\nimport { healthRoutes, systemApi } from \"./api/system.ts\";\nimport type { AppEnv } from \"./api/util.ts\";\nimport { webhooksApi } from \"./api/webhooks.ts\";\nimport { csrfGuard, currentSetupToken, requireAdmin } from \"./auth/index.ts\";\nimport type { AppContext } from \"./context.ts\";\nimport { contentSecurityPolicy, inlineScriptHashes } from \"./csp.ts\";\nimport { mcpRoutes } from \"./mcp/index.ts\";\nimport { renderSkill } from \"./skill/index.ts\";\nimport { HttpError, PolicyDenied } from \"./util/errors.ts\";\n\nexport interface AppOptions {\n /** Built console directory. Defaults to dist/web next to the running module. */\n webDir?: string;\n}\n\n/**\n * dist/web relative to the running module: the bundle (dist/cli.js) and source runs\n * (server/app.ts via tsx) both resolve to <package root>/dist/web.\n */\nexport const DEFAULT_WEB_DIR = resolve(import.meta.dirname, \"..\", \"dist\", \"web\");\n\nconst API_BODY_LIMIT = 1024 * 1024;\nconst AUTH_BODY_LIMIT = 16 * 1024;\nconst AUTH_PATHS = [\"/api/setup/claim\", \"/api/auth/login\", \"/api/auth/password\"];\nconst MCP_BODY_LIMIT = 4 * 1024 * 1024;\nconst AGENT_BODY_LIMIT = 64 * 1024;\n\n/** Extensions served as files; any other path (even with a dot, e.g. /accounts/me@example.com) is a console route. */\nconst ASSET_EXTENSIONS = new Set([\n \".js\", \".mjs\", \".css\", \".map\", \".json\", \".webmanifest\", \".txt\", \".xml\",\n \".png\", \".jpg\", \".jpeg\", \".gif\", \".webp\", \".avif\", \".svg\", \".ico\",\n \".woff\", \".woff2\", \".ttf\", \".otf\", \".wasm\",\n]);\n\n/** Paths the console's index.html fallback must never answer. */\nconst SERVER_PREFIXES = [\"/api\", \"/mcp\", \"/oauth\", \"/skill.md\", \"/health\"];\nconst isServerPath = (path: string) => SERVER_PREFIXES.some((p) => path === p || path.startsWith(p + \"/\"));\n\nexport function createApp(ctx: AppContext, opts: AppOptions = {}): Hono<AppEnv> {\n const app = new Hono<AppEnv>();\n // Make sure the setup link exists before anyone needs it.\n currentSetupToken(ctx);\n\n // Hashes of index.html's inline scripts; set once the console is wired up below.\n let consoleHashes: () => string[] = () => [];\n app.use(\"*\", async (c, next) => {\n await next();\n try {\n c.res.headers.set(\"Content-Security-Policy\", contentSecurityPolicy(consoleHashes()));\n c.res.headers.set(\"X-Frame-Options\", \"DENY\");\n c.res.headers.set(\"X-Content-Type-Options\", \"nosniff\");\n c.res.headers.set(\"Referrer-Policy\", \"no-referrer\");\n } catch {\n // Immutable headers (a proxied Response): leave them as they are.\n }\n });\n\n app.onError((err, c) => errorResponse(ctx, err, c));\n app.notFound((c) => {\n if (c.req.path === \"/api\" || c.req.path.startsWith(\"/api/\")) return apiError(c, 404, \"not_found\", \"No such API route\");\n return c.text(\"Not found\", 404);\n });\n\n // ── Public ──\n const tooLarge = (c: Context) => apiError(c, 413, \"payload_too_large\", \"Request body is too large\");\n const limit = (maxSize: number) => bodyLimit({ maxSize, onError: tooLarge });\n for (const path of AUTH_PATHS) app.use(path, limit(AUTH_BODY_LIMIT));\n app.use(\"/api/*\", limit(API_BODY_LIMIT));\n app.use(\"/mcp\", limit(MCP_BODY_LIMIT));\n app.use(\"/mcp/*\", limit(MCP_BODY_LIMIT));\n app.use(\"/agent/*\", limit(AGENT_BODY_LIMIT));\n app.use(\"/api/*\", csrfGuard());\n app.route(\"/\", healthRoutes(ctx));\n app.route(\"/api\", setupPublicApi(ctx));\n app.route(\"/api\", authPublicApi(ctx));\n app.get(\"/skill.md\", (c) => {\n c.header(\"Content-Type\", \"text/markdown; charset=utf-8\");\n c.header(\"Cache-Control\", \"no-cache\");\n return c.body(renderSkill(ctx.settings.publicUrl()));\n });\n app.route(\"/\", oauthRoutes(ctx));\n app.route(\"/\", mcpRoutes(ctx));\n\n // ── Admin console API ──\n app.use(\"/api/*\", requireAdmin(ctx));\n for (const api of [setupApi, authApi, settingsApi, systemApi, googleApi, accountsApi, agentsApi, approvalsApi, webhooksApi, eventsApi, auditApi, overviewApi]) {\n app.route(\"/api\", api(ctx));\n }\n\n // ── Console ──\n if (ctx.config.dev) app.get(\"*\", (c) => (isServerPath(c.req.path) ? c.notFound() : devPage(c)));\n else consoleHashes = serveConsole(app, opts.webDir ?? DEFAULT_WEB_DIR);\n\n return app;\n}\n\n/** Serves the built console; returns the CSP hashes of index.html's inline scripts (re-read when the file changes). */\nfunction serveConsole(app: Hono<AppEnv>, webDir: string): () => string[] {\n const index = join(webDir, \"index.html\");\n if (!existsSync(index)) {\n app.get(\"*\", (c) => (isServerPath(c.req.path) ? c.notFound() : missingBuildPage(c, webDir)));\n return () => [];\n }\n let cached = { mtimeMs: -1, hashes: [] as string[] };\n const hashes = () => {\n try {\n const { mtimeMs } = statSync(index);\n if (mtimeMs !== cached.mtimeMs) cached = { mtimeMs, hashes: inlineScriptHashes(readFileSync(index, \"utf8\")) };\n } catch {\n // Removed while running: keep the last known hashes.\n }\n return cached.hashes;\n };\n const assets = serveStatic<AppEnv>({ root: webDir });\n const assetsDir = join(webDir, \"assets\") + sep;\n app.use(\"*\", async (c, next) => {\n if (isServerPath(c.req.path)) return next();\n const res = await assets(c, next);\n if (res instanceof Response) {\n // Vite fingerprints everything under assets/; the rest (index.html, favicon) must revalidate.\n const hashed = join(webDir, c.req.path).startsWith(assetsDir);\n res.headers.set(\"Cache-Control\", hashed ? \"public, max-age=31536000, immutable\" : \"no-cache\");\n }\n return res;\n });\n app.get(\"*\", (c) => {\n const path = c.req.path;\n // Client routes get index.html; a missing file (e.g. a stale /assets/x.js) is a real 404.\n if (isServerPath(path) || path.startsWith(\"/assets/\") || ASSET_EXTENSIONS.has(extname(path).toLowerCase())) return c.notFound();\n c.header(\"Cache-Control\", \"no-cache\");\n return c.html(readFileSync(index, \"utf8\"));\n });\n return hashes;\n}\n\nfunction errorResponse(ctx: AppContext, err: Error, c: Context): Response {\n if (err instanceof HttpError) return c.json(err.toJSON(), err.status as 400);\n if (err instanceof PolicyDenied) return apiError(c, 403, \"policy_denied\", err.message);\n if (err instanceof z.ZodError) return apiError(c, 400, \"bad_request\", z.prettifyError(err));\n if (err instanceof HTTPException) return err.res ? err.getResponse() : apiError(c, err.status, \"http_error\", err.message || \"Request failed\");\n if (err instanceof SyntaxError && /JSON/i.test(err.message)) return apiError(c, 400, \"bad_request\", \"Request body must be valid JSON\");\n ctx.log.error(`${c.req.method} ${c.req.path} failed`, { error: err.message, stack: err.stack });\n return apiError(c, 500, \"internal\", \"Something went wrong. Check the agentinbox logs for details.\");\n}\n\nfunction apiError(c: Context, status: number, code: string, message: string): Response {\n return c.json<ApiError>({ error: { code, message } }, status as 400);\n}\n\nconst page = (title: string, body: string) => `<!doctype html>\n<html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<title>${title}</title>\n<style>\n :root { color-scheme: light dark; font-family: ui-sans-serif, system-ui, sans-serif; }\n body { margin: 0; min-height: 100vh; display: grid; place-items: center; background: Canvas; color: CanvasText; }\n main { max-width: 34rem; padding: 2rem; line-height: 1.55; }\n h1 { font-size: 1.25rem; margin: 0 0 .75rem; }\n code { font-family: ui-monospace, monospace; padding: .1rem .35rem; border-radius: .3rem; background: color-mix(in srgb, CanvasText 10%, transparent); }\n p { margin: .5rem 0; opacity: .85; }\n</style></head><body><main>${body}</main></body></html>`;\n\nconst escapeHtml = (s: string) => s.replace(/[&<>\"]/g, (ch) => `&#${ch.charCodeAt(0)};`);\n\nfunction missingBuildPage(c: Context, webDir: string): Response {\n c.header(\"Cache-Control\", \"no-store\");\n return c.html(\n page(\n \"agentinbox: console not built\",\n `<h1>The web console hasn't been built</h1>\n<p>agentinbox is running, but there is no console build in <code>${escapeHtml(webDir)}</code>.</p>\n<p>From a source checkout, run <code>pnpm build</code> and restart, or use <code>pnpm dev</code> for development.</p>\n<p>The API (<code>/api</code>), MCP endpoint (<code>/mcp</code>) and <code>/health</code> work as usual.</p>`,\n ),\n 503,\n );\n}\n\nfunction devPage(c: Context): Response {\n const url = new URL(c.req.url);\n const target = `http://localhost:5173${url.pathname}${url.search}`;\n return c.html(\n page(\n \"agentinbox (dev)\",\n `<h1>agentinbox is running in dev mode</h1>\n<p>The console is served by Vite: open <a href=\"${escapeHtml(target)}\">${escapeHtml(target)}</a>.</p>`,\n ),\n );\n}\n","import { adminAuth } from \"./auth/index.ts\";\nimport type { AppContext } from \"./context.ts\";\nimport { errorMessage } from \"./util/errors.ts\";\n\nconst INTERVAL_MS = 3600_000;\nconst FIRST_RUN_MS = 60_000;\n\nexport interface MaintenanceResult {\n events: number;\n deliveries: number;\n audit: number;\n sessions: number;\n}\n\n/** Prunes data older than Settings.retentionDays and expired admin sessions. Never throws. */\nexport function runMaintenance(ctx: AppContext): MaintenanceResult {\n const log = ctx.log.child(\"maintenance\");\n const before = new Date(Date.now() - ctx.settings.get().retentionDays * 86_400_000).toISOString();\n const step = (name: string, fn: () => number) => {\n try {\n return fn();\n } catch (err) {\n log.warn(`Pruning ${name} failed`, { error: errorMessage(err) });\n return 0;\n }\n };\n // Deliveries first: they point at events.\n const result: MaintenanceResult = {\n deliveries: step(\"deliveries\", () => ctx.webhooks.prune(before)),\n events: step(\"events\", () => ctx.events.prune(before)),\n audit: step(\"audit log\", () => ctx.audit.prune(before)),\n sessions: step(\"sessions\", () => adminAuth(ctx).sessions.pruneExpired()),\n };\n if (Object.values(result).some((n) => n > 0)) log.info(\"Pruned old data\", { ...result });\n return result;\n}\n\n/** Runs maintenance shortly after start, then hourly. Timers are unref'd. Returns a stop function. */\nexport function startMaintenance(ctx: AppContext): () => void {\n const run = () => {\n try {\n runMaintenance(ctx);\n } catch (err) {\n ctx.log.warn(\"Maintenance failed\", { error: errorMessage(err) });\n }\n };\n const first = setTimeout(run, FIRST_RUN_MS).unref();\n const timer = setInterval(run, INTERVAL_MS).unref();\n return () => {\n clearTimeout(first);\n clearInterval(timer);\n };\n}\n","import pc from \"picocolors\";\n\ntype Level = \"debug\" | \"info\" | \"warn\" | \"error\";\nconst order: Record<Level, number> = { debug: 10, info: 20, warn: 30, error: 40 };\nconst min = order[(process.env.AGENTINBOX_LOG_LEVEL as Level) ?? \"info\"] ?? 20;\nconst color: Record<Level, (s: string) => string> = { debug: pc.gray, info: pc.cyan, warn: pc.yellow, error: pc.red };\n\nexport interface Logger {\n debug(msg: string, meta?: Record<string, unknown>): void;\n info(msg: string, meta?: Record<string, unknown>): void;\n warn(msg: string, meta?: Record<string, unknown>): void;\n error(msg: string, meta?: Record<string, unknown>): void;\n child(scope: string): Logger;\n}\n\nexport function createLogger(scope = \"agentinbox\"): Logger {\n const emit = (level: Level, msg: string, meta?: Record<string, unknown>) => {\n if (order[level] < min) return;\n const ts = new Date().toISOString().slice(11, 19);\n const extra = meta && Object.keys(meta).length ? \" \" + pc.gray(JSON.stringify(meta)) : \"\";\n const line = `${pc.gray(ts)} ${color[level](level.padEnd(5))} ${pc.bold(scope)} ${msg}${extra}`;\n (level === \"error\" || level === \"warn\" ? process.stderr : process.stdout).write(line + \"\\n\");\n };\n return {\n debug: (m, x) => emit(\"debug\", m, x),\n info: (m, x) => emit(\"info\", m, x),\n warn: (m, x) => emit(\"warn\", m, x),\n error: (m, x) => emit(\"error\", m, x),\n child: (s) => createLogger(`${scope}:${s}`),\n };\n}\n","// The application context: one object holding the core primitives and every service.\n//\n// Rules for services:\n// - Each domain exposes `createXService(ctx: AppContext): XService` from `server/<domain>/index.ts`.\n// - Factories may keep `ctx` but must NOT call other services while constructing: other members may\n// not exist yet. Cross-service calls happen at request time or after `start()`.\n// - `start()` runs once everything is wired (in SERVICE_ORDER), `stop()` in reverse on shutdown.\n// - Service contracts live in `server/<domain>/types.ts`. Members marked FROZEN there are relied on by\n// other domains.\n\nimport { AuditLog } from \"./audit.ts\";\nimport { type Bus, createBus } from \"./bus.ts\";\nimport type { Config } from \"./config.ts\";\nimport { Crypto } from \"./crypto.ts\";\nimport { Db } from \"./db/index.ts\";\nimport type { EventsService } from \"./events/types.ts\";\nimport type { AccountsService, GoogleService } from \"./google/types.ts\";\nimport type { IngestService } from \"./ingest/types.ts\";\nimport type { MailService } from \"./mail/types.ts\";\nimport type { PolicyService } from \"./policy/types.ts\";\nimport { SettingsStore } from \"./settings.ts\";\nimport { createLogger, type Logger } from \"./util/log.ts\";\nimport type { WebhooksService } from \"./webhooks/types.ts\";\n\nexport interface Lifecycle {\n start?(): void | Promise<void>;\n stop?(): void | Promise<void>;\n}\n\nexport interface CoreContext {\n config: Config;\n db: Db;\n crypto: Crypto;\n log: Logger;\n bus: Bus;\n settings: SettingsStore;\n audit: AuditLog;\n}\n\nexport interface Services {\n accounts: AccountsService;\n google: GoogleService;\n ingest: IngestService;\n events: EventsService;\n policy: PolicyService;\n mail: MailService;\n webhooks: WebhooksService;\n}\n\nexport interface AppContext extends CoreContext, Services {}\n\n/** Start order. Policy and events first (no I/O), ingest last so everything it emits into is running. */\nexport const SERVICE_ORDER: (keyof Services)[] = [\"policy\", \"accounts\", \"events\", \"webhooks\", \"mail\", \"google\", \"ingest\"];\n\nexport function createCore(config: Config): CoreContext {\n const db = new Db(config.dbPath);\n const bus = createBus();\n return {\n config,\n db,\n crypto: Crypto.load(config.masterKeyPath),\n log: createLogger(),\n bus,\n settings: new SettingsStore(db, bus, config),\n audit: new AuditLog(db, bus),\n };\n}\n","/**\n * TEMPORARY scaffolding: a service whose methods throw \"not implemented\". Lets every domain compile\n * and run its own tests before the others land. Removed at integration.\n */\nexport function stubService<T extends object>(name: string): T {\n return new Proxy({} as T, {\n get(_target, prop) {\n if (prop === \"start\" || prop === \"stop\" || prop === \"then\" || typeof prop === \"symbol\") return undefined;\n return () => {\n throw new Error(`${name}.${String(prop)} is not implemented yet`);\n };\n },\n });\n}\n","import type { AppContext } from \"../context.ts\";\nimport { stubService } from \"../util/stub.ts\";\nimport type { EventsService } from \"./types.ts\";\n\n// PLACEHOLDER: replaced by the owning work area.\nexport function createEventsService(_ctx: AppContext): EventsService {\n return stubService<EventsService>(\"events\");\n}\n","import type { AppContext } from \"../context.ts\";\nimport { stubService } from \"../util/stub.ts\";\nimport type { AccountsService, GoogleService } from \"./types.ts\";\n\n// PLACEHOLDER: replaced by the owning work area.\nexport function createGoogleService(_ctx: AppContext): GoogleService {\n return stubService<GoogleService>(\"google\");\n}\n\n// PLACEHOLDER: replaced by the owning work area.\nexport function createAccountsService(_ctx: AppContext): AccountsService {\n return stubService<AccountsService>(\"accounts\");\n}\n","import type { AppContext } from \"../context.ts\";\nimport { stubService } from \"../util/stub.ts\";\nimport type { IngestService } from \"./types.ts\";\n\n// PLACEHOLDER: replaced by the owning work area.\nexport function createIngestService(_ctx: AppContext): IngestService {\n return stubService<IngestService>(\"ingest\");\n}\n","import type { AppContext } from \"../context.ts\";\nimport { stubService } from \"../util/stub.ts\";\nimport type { MailService } from \"./types.ts\";\n\n// PLACEHOLDER: replaced by the owning work area.\nexport function createMailService(_ctx: AppContext): MailService {\n return stubService<MailService>(\"mail\");\n}\n","import type { AppContext } from \"../context.ts\";\nimport { stubService } from \"../util/stub.ts\";\nimport type { PolicyService } from \"./types.ts\";\n\n// PLACEHOLDER: replaced by the owning work area.\nexport function createPolicyService(_ctx: AppContext): PolicyService {\n return stubService<PolicyService>(\"policy\");\n}\n","import type { AppContext } from \"../context.ts\";\nimport { stubService } from \"../util/stub.ts\";\nimport type { WebhooksService } from \"./types.ts\";\n\n// PLACEHOLDER: replaced by the owning work area.\nexport function createWebhooksService(_ctx: AppContext): WebhooksService {\n return stubService<WebhooksService>(\"webhooks\");\n}\n","import type { Config } from \"./config.ts\";\nimport { type AppContext, createCore, SERVICE_ORDER, type Services } from \"./context.ts\";\nimport { createEventsService } from \"./events/index.ts\";\nimport { createAccountsService, createGoogleService } from \"./google/index.ts\";\nimport { createIngestService } from \"./ingest/index.ts\";\nimport { createMailService } from \"./mail/index.ts\";\nimport { createPolicyService } from \"./policy/index.ts\";\nimport { createWebhooksService } from \"./webhooks/index.ts\";\n\n/** Tests replace individual services with fakes. */\nexport type ServiceOverrides = Partial<{ [K in keyof Services]: (ctx: AppContext) => Services[K] }>;\n\nconst FACTORIES: { [K in keyof Services]: (ctx: AppContext) => Services[K] } = {\n accounts: createAccountsService,\n google: createGoogleService,\n ingest: createIngestService,\n events: createEventsService,\n policy: createPolicyService,\n mail: createMailService,\n webhooks: createWebhooksService,\n};\n\n/** Builds the full context. Nothing runs until `startServices`. */\nexport function createAppContext(config: Config, overrides: ServiceOverrides = {}): AppContext {\n const ctx = createCore(config) as AppContext;\n for (const key of SERVICE_ORDER) {\n const factory = (overrides[key] ?? FACTORIES[key]) as (ctx: AppContext) => never;\n (ctx as unknown as Record<string, unknown>)[key] = factory(ctx);\n }\n return ctx;\n}\n\nexport async function startServices(ctx: AppContext): Promise<void> {\n for (const key of SERVICE_ORDER) await ctx[key].start?.();\n}\n\n/** Stops services in reverse order, then closes the database. Errors are logged, not thrown. */\nexport async function stopServices(ctx: AppContext): Promise<void> {\n for (const key of [...SERVICE_ORDER].reverse()) {\n try {\n await ctx[key].stop?.();\n } catch (err) {\n ctx.log.error(`Failed to stop ${key}`, { error: err instanceof Error ? err.message : String(err) });\n }\n }\n ctx.db.close();\n}\n","import type { AddressInfo } from \"node:net\";\nimport { type ServerType, serve } from \"@hono/node-server\";\nimport open from \"open\";\nimport pc from \"picocolors\";\nimport { createApp } from \"./app.ts\";\nimport { currentSetupToken } from \"./auth/index.ts\";\nimport { type Config, type ConfigInput, loadConfig } from \"./config.ts\";\nimport type { AppContext } from \"./context.ts\";\nimport { acquireInstanceLock, assertMasterKeyUsable, cliCommand } from \"./instance.ts\";\nimport { startMaintenance } from \"./maintenance.ts\";\nimport { setupTokenPath } from \"./auth/setup-token.ts\";\nimport { consoleUrls, loopbackUrl } from \"./urls.ts\";\nimport { errorMessage } from \"./util/errors.ts\";\nimport { createAppContext, type ServiceOverrides, startServices, stopServices } from \"./wire.ts\";\n\nexport interface StartOptions {\n config: Config;\n /** Replace services with fakes (tests). */\n overrides?: ServiceOverrides;\n /** Console build directory (defaults to dist/web). */\n webDir?: string;\n}\n\nexport interface RunningServer {\n /** Base URL reachable from this machine, e.g. http://127.0.0.1:54321. */\n url: string;\n ctx: AppContext;\n server: ServerType;\n /** Stops accepting requests, stops services and closes the database. Idempotent. */\n close(): Promise<void>;\n}\n\nconst SHUTDOWN_TIMEOUT_MS = 10_000;\n\n/**\n * Takes the data directory's instance lock, checks the master key against stored secrets, builds\n * the context, binds the port, then starts services (so a second instance never runs ingest\n * against the same data). Use `port: 0` in tests; `config.port` is updated to the bound port.\n */\nexport async function startServer(opts: StartOptions): Promise<RunningServer> {\n const { config } = opts;\n const lock = acquireInstanceLock(config);\n let ctx: AppContext;\n let server: ServerType;\n try {\n assertMasterKeyUsable(config);\n ctx = createAppContext(config, opts.overrides);\n } catch (err) {\n lock.release();\n throw err;\n }\n try {\n const app = createApp(ctx, { webDir: opts.webDir });\n server = await listen(app.fetch, config.host, config.port);\n } catch (err) {\n ctx.db.close();\n lock.release();\n throw friendlyListenError(err, config.port);\n }\n config.port = (server.address() as AddressInfo).port;\n lock.update(config.port);\n\n let stopMaintenance = () => {};\n let closing: Promise<void> | undefined;\n const close = () =>\n (closing ??= (async () => {\n stopMaintenance();\n await new Promise<void>((resolve) => {\n server.close(() => resolve());\n // SSE streams and long polls would otherwise hold the server open.\n (server as { closeAllConnections?: () => void }).closeAllConnections?.();\n });\n await stopServices(ctx);\n lock.release();\n })());\n\n try {\n await startServices(ctx);\n } catch (err) {\n await close();\n throw err;\n }\n stopMaintenance = startMaintenance(ctx);\n return { url: loopbackUrl(config.host, config.port), ctx, server, close };\n}\n\nfunction listen(fetch: Parameters<typeof serve>[0][\"fetch\"], hostname: string, port: number): Promise<ServerType> {\n return new Promise((resolve, reject) => {\n const server = serve({ fetch, hostname, port }, () => {\n server.off(\"error\", reject);\n resolve(server);\n });\n server.once(\"error\", reject);\n });\n}\n\nfunction friendlyListenError(err: unknown, port: number): Error {\n const code = (err as NodeJS.ErrnoException)?.code;\n if (code === \"EADDRINUSE\") return new Error(`Port ${port} is already in use (is agentinbox already running?). Try --port <port>.`);\n if (code === \"EACCES\") return new Error(`Not allowed to listen on port ${port}. Use a port above 1024, e.g. --port 8425.`);\n if (code === \"EADDRNOTAVAIL\") return new Error(`Can't bind to that address. Check --host.`);\n return err instanceof Error ? err : new Error(String(err));\n}\n\nexport interface RunOptions extends ConfigInput {\n /** Open the setup link in a browser on first run. */\n open?: boolean;\n version: string;\n}\n\n/** `agentinbox start`: runs in the foreground until SIGINT/SIGTERM. */\nexport async function runForeground(opts: RunOptions): Promise<void> {\n const config = loadConfig(opts, opts.version);\n const running = await startServer({ config });\n printBanner(running.ctx);\n\n const token = currentSetupToken(running.ctx);\n if (token && opts.open && process.stdout.isTTY && !config.dev && !config.service) {\n openBrowser(`${consoleUrls(config.host, config.port)[0]}/setup?token=${token}`);\n }\n\n for (const signal of [\"SIGINT\", \"SIGTERM\"] as const) {\n process.once(signal, () => {\n console.log(pc.dim(`\\n Stopping agentinbox…`));\n setTimeout(() => {\n console.error(`agentinbox did not stop within ${SHUTDOWN_TIMEOUT_MS / 1000} s; exiting anyway.`);\n process.exit(1);\n }, SHUTDOWN_TIMEOUT_MS).unref();\n running.close().then(\n () => process.exit(0),\n (err) => {\n console.error(errorMessage(err));\n process.exit(1);\n },\n );\n });\n }\n}\n\nfunction printBanner(ctx: AppContext): void {\n const { config } = ctx;\n const urls = config.dev ? [\"http://localhost:5173\"] : consoleUrls(config.host, config.port);\n const token = currentSetupToken(ctx);\n const out: string[] = [\"\", ` ${pc.bold(\"agentinbox\")} ${pc.dim(`v${config.version} · data in ${config.dataDir}`)}`, \"\"];\n if (token && config.service) {\n // Service logs are often readable by others (journal, log files): never print the token there.\n out.push(\n ` ${pc.yellow(\"Not claimed yet.\")} The setup link is ${urls[0]}/setup?token=<token>, with the token in ${setupTokenPath(config.dataDir)}.`,\n ` ${pc.dim(`\\`${cliCommand(\"service install\")}\\` prints the full link.`)}`,\n );\n } else if (token) {\n out.push(` ${pc.yellow(\"First run:\")} open this link to claim the instance and finish setup:`, \"\");\n for (const url of urls) out.push(` ${pc.cyan(`${url}/setup?token=${token}`)}`);\n } else {\n out.push(` ${pc.dim(\"Console\")} ${pc.cyan(urls[0]!)}`);\n for (const url of urls.slice(1)) out.push(` ${pc.cyan(url)}`);\n out.push(` ${pc.dim(\"MCP\")} ${pc.cyan(`${ctx.settings.publicUrl()}/mcp`)}`);\n }\n if (config.dev) out.push(\"\", pc.dim(` Dev mode: API on :${config.port}, console via Vite on :5173.`));\n console.log(out.join(\"\\n\") + \"\\n\");\n}\n\nfunction openBrowser(url: string): void {\n if (process.platform === \"linux\" && !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY) return;\n try {\n open(url).then(\n (child) => child.on(\"error\", () => {}),\n () => {},\n );\n } catch {\n // No browser available: the link is printed above.\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,332 @@
1
+ #!/usr/bin/env node
2
+ import { t as Crypto } from "./crypto-DYZ4R7c2.js";
3
+ import { r as readSetupToken } from "./setup-token-Bkwk84l7.js";
4
+ import { c as NPM_PACKAGE, i as cliCommand, n as assertMasterKeyUsable } from "./instance-Dy2jeyZc.js";
5
+ import { r as loopbackUrl, t as consoleUrls } from "./urls-DmnonkJo.js";
6
+ import { existsSync, mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
7
+ import { homedir, tmpdir, userInfo } from "node:os";
8
+ import { basename, dirname, join, resolve } from "node:path";
9
+ import { execFileSync } from "node:child_process";
10
+ //#region server/service.ts
11
+ /** Installs agentinbox as a background service: systemd on Linux, launchd on macOS. */
12
+ const SERVICE_NAME = "agentinbox";
13
+ const LAUNCHD_LABEL = "com.unlaboredlabs.agentinbox";
14
+ const npm = process.platform === "win32" ? "npm.cmd" : "npm";
15
+ /** Package root: one level above the running module (dist/cli.js or server/service.ts). */
16
+ const ROOT = resolve(import.meta.dirname, "..");
17
+ /**
18
+ * Settings that come from the environment rather than flags. They are kept in `<data>/service.env`
19
+ * (mode 0600) so re-running `service install` from a shell without them (the documented update
20
+ * path) keeps them. Set one to an empty value to drop it.
21
+ */
22
+ const SERVICE_ENV_KEYS = [
23
+ "AGENTINBOX_MASTER_KEY",
24
+ "TRUST_PROXY",
25
+ "TRUST_PROXY_HOPS",
26
+ "AGENTINBOX_LOG_LEVEL"
27
+ ];
28
+ const run = (cmd, args, quiet = false) => execFileSync(cmd, args, { stdio: quiet ? "ignore" : "inherit" });
29
+ const isRoot = () => process.getuid?.() === 0;
30
+ const systemctl = (...args) => run("systemctl", isRoot() ? args : ["--user", ...args]);
31
+ const unitPath = () => isRoot() ? `/etc/systemd/system/${SERVICE_NAME}.service` : join(homedir(), ".config/systemd/user", `${SERVICE_NAME}.service`);
32
+ const plistPath = () => join(homedir(), "Library/LaunchAgents", `${LAUNCHD_LABEL}.plist`);
33
+ const launchdTarget = () => `gui/${process.getuid?.()}`;
34
+ const serviceEnvPath = (dataDir) => join(dataDir, "service.env");
35
+ /** Plain variables written into the unit/plist. Secrets never go into the systemd unit. */
36
+ function plainEnv(spec) {
37
+ return {
38
+ AGENTINBOX_DATA: spec.dataDir,
39
+ PORT: String(spec.port),
40
+ HOST: spec.host,
41
+ AGENTINBOX_SERVICE: "1"
42
+ };
43
+ }
44
+ /** systemd word quoting for ExecStart/Environment: double quotes, escaped backslashes, quotes and specifiers. */
45
+ const sdQuote = (s) => `"${s.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/%/g, "%%")}"`;
46
+ /**
47
+ * The systemd unit. Everything from service.env (including AGENTINBOX_MASTER_KEY) is loaded with
48
+ * EnvironmentFile=, so the world-readable unit holds no secrets. EnvironmentFile takes an
49
+ * unquoted absolute path (systemd ignores quoted ones), which is why data dirs with whitespace are refused.
50
+ */
51
+ function renderSystemdUnit(spec) {
52
+ const vars = Object.entries(plainEnv(spec)).map(([k, v]) => `Environment=${sdQuote(`${k}=${v}`)}`).join("\n");
53
+ const envFile = Object.keys(spec.extraEnv).length ? `\nEnvironmentFile=${serviceEnvPath(spec.dataDir).replace(/%/g, "%%")}` : "";
54
+ return `[Unit]
55
+ Description=agentinbox (Gmail broker for AI agents)
56
+ After=network-online.target
57
+ Wants=network-online.target
58
+
59
+ [Service]
60
+ ExecStart=${sdQuote(spec.execPath)} ${sdQuote(spec.entry)} start --no-open
61
+ ${vars}${envFile}
62
+ Restart=on-failure
63
+ RestartSec=3
64
+ TimeoutStopSec=20
65
+
66
+ [Install]
67
+ WantedBy=${spec.system ? "multi-user.target" : "default.target"}
68
+ `;
69
+ }
70
+ /** The launchd plist. Written with mode 0600, since it may carry AGENTINBOX_MASTER_KEY. */
71
+ function renderLaunchdPlist(spec) {
72
+ const esc = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
73
+ const vars = Object.entries({
74
+ ...plainEnv(spec),
75
+ ...spec.extraEnv
76
+ }).map(([k, v]) => ` <key>${esc(k)}</key><string>${esc(v)}</string>`).join("\n");
77
+ const log = esc(join(spec.dataDir, "agentinbox.log"));
78
+ return `<?xml version="1.0" encoding="UTF-8"?>
79
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
80
+ <plist version="1.0">
81
+ <dict>
82
+ <key>Label</key><string>${LAUNCHD_LABEL}</string>
83
+ <key>ProgramArguments</key>
84
+ <array>
85
+ <string>${esc(spec.execPath)}</string>
86
+ <string>${esc(spec.entry)}</string>
87
+ <string>start</string>
88
+ <string>--no-open</string>
89
+ </array>
90
+ <key>EnvironmentVariables</key>
91
+ <dict>
92
+ ${vars}
93
+ </dict>
94
+ <key>RunAtLoad</key><true/>
95
+ <key>KeepAlive</key><true/>
96
+ <key>StandardOutPath</key><string>${log}</string>
97
+ <key>StandardErrorPath</key><string>${log}</string>
98
+ </dict>
99
+ </plist>
100
+ `;
101
+ }
102
+ /** Parses service.env (KEY=value lines). */
103
+ function parseEnvFile(text) {
104
+ const out = {};
105
+ for (const line of text.split("\n")) {
106
+ const m = /^\s*([A-Z_][A-Z0-9_]*)=(.*)$/.exec(line);
107
+ if (m) out[m[1]] = m[2].trim();
108
+ }
109
+ return out;
110
+ }
111
+ /**
112
+ * The service's env-derived settings: the current shell wins, previous install fills the gaps,
113
+ * an explicitly empty value removes the setting.
114
+ */
115
+ function mergeServiceEnv(previous, current) {
116
+ const out = {};
117
+ for (const key of SERVICE_ENV_KEYS) {
118
+ const value = key in current ? current[key] : previous[key];
119
+ if (value) out[key] = value;
120
+ }
121
+ return out;
122
+ }
123
+ /** Fails early (before anything is touched) when the master key can't work. */
124
+ function validateMasterKey(value) {
125
+ if (!value) return;
126
+ try {
127
+ if (!/^[A-Za-z0-9+/]+={0,2}$/.test(value.trim())) throw new Error("not base64");
128
+ new Crypto(Buffer.from(value, "base64"));
129
+ } catch {
130
+ throw new Error("AGENTINBOX_MASTER_KEY must be 32 random bytes in base64 (e.g. `openssl rand -base64 32`).");
131
+ }
132
+ }
133
+ function readPreviousEnv(dataDir) {
134
+ try {
135
+ return parseEnvFile(readFileSync(serviceEnvPath(dataDir), "utf8"));
136
+ } catch {
137
+ return {};
138
+ }
139
+ }
140
+ function writeServiceEnv(dataDir, env) {
141
+ const file = serviceEnvPath(dataDir);
142
+ if (!Object.keys(env).length) {
143
+ rmSync(file, { force: true });
144
+ return;
145
+ }
146
+ for (const [k, v] of Object.entries(env)) if (/[\r\n]/.test(v)) throw new Error(`${k} must be a single line.`);
147
+ writeFileSync(file, Object.entries(env).map(([k, v]) => `${k}=${v}\n`).join(""), { mode: 384 });
148
+ }
149
+ /**
150
+ * Installs the package into `<data>/app.new`, so a failed npm install leaves the current service
151
+ * untouched. From an installed package that is the latest release; from a source checkout, the
152
+ * local build. Returns the staging directory.
153
+ */
154
+ function stageApp(dataDir) {
155
+ const staging = join(dataDir, "app.new");
156
+ const fromSource = basename(dirname(ROOT)) !== "node_modules";
157
+ let spec = `${NPM_PACKAGE}@latest`;
158
+ let tmp;
159
+ if (fromSource) {
160
+ if (!existsSync(join(ROOT, "dist/cli.js")) || !existsSync(join(ROOT, "dist/web/index.html"))) throw new Error("Run `pnpm build` before installing the service from a source checkout.");
161
+ tmp = mkdtempSync(join(tmpdir(), "agentinbox-pack-"));
162
+ const out = execFileSync(npm, [
163
+ "pack",
164
+ "--ignore-scripts",
165
+ "--pack-destination",
166
+ tmp,
167
+ "--loglevel=error"
168
+ ], {
169
+ cwd: ROOT,
170
+ encoding: "utf8"
171
+ });
172
+ spec = join(tmp, out.trim().split("\n").pop());
173
+ }
174
+ console.log(fromSource ? " Installing this build into the data directory…" : " Installing the latest release into the data directory…");
175
+ rmSync(staging, {
176
+ recursive: true,
177
+ force: true
178
+ });
179
+ mkdirSync(staging, { recursive: true });
180
+ writeFileSync(join(staging, "package.json"), "{ \"private\": true }\n");
181
+ try {
182
+ execFileSync(npm, [
183
+ "install",
184
+ spec,
185
+ "--omit=dev",
186
+ "--prefer-online",
187
+ "--no-audit",
188
+ "--no-fund",
189
+ "--loglevel=error"
190
+ ], {
191
+ cwd: staging,
192
+ stdio: "inherit"
193
+ });
194
+ if (!existsSync(join(staging, "node_modules", "agentinbox-cli", "dist/cli.js"))) throw new Error("the installed package has no dist/cli.js");
195
+ } catch (err) {
196
+ rmSync(staging, {
197
+ recursive: true,
198
+ force: true
199
+ });
200
+ throw new Error(`Installing agentinbox failed, so the existing service was left as it was. ${err instanceof Error ? err.message : ""}`.trim());
201
+ } finally {
202
+ if (tmp) rmSync(tmp, {
203
+ recursive: true,
204
+ force: true
205
+ });
206
+ }
207
+ return staging;
208
+ }
209
+ /** Replaces `<data>/app` with the staged install (call while the service is stopped). */
210
+ function swapApp(dataDir, staging) {
211
+ const app = join(dataDir, "app");
212
+ const old = join(dataDir, "app.old");
213
+ rmSync(old, {
214
+ recursive: true,
215
+ force: true
216
+ });
217
+ if (existsSync(app)) renameSync(app, old);
218
+ renameSync(staging, app);
219
+ rmSync(old, {
220
+ recursive: true,
221
+ force: true
222
+ });
223
+ return join(app, "node_modules", NPM_PACKAGE, "dist/cli.js");
224
+ }
225
+ function assertSupported() {
226
+ if (process.platform !== "linux" && process.platform !== "darwin") throw new Error(`Service install supports Linux (systemd) and macOS (launchd). Elsewhere, run \`${cliCommand("start")}\` under your own supervisor.`);
227
+ }
228
+ async function installService(config) {
229
+ assertSupported();
230
+ if (process.platform === "linux" && /\s/.test(config.dataDir)) throw new Error(`The data directory "${config.dataDir}" contains whitespace, which systemd can't load settings from. Choose another one with --data.`);
231
+ const extraEnv = mergeServiceEnv(readPreviousEnv(config.dataDir), process.env);
232
+ validateMasterKey(extraEnv.AGENTINBOX_MASTER_KEY);
233
+ assertMasterKeyUsable(config, extraEnv.AGENTINBOX_MASTER_KEY ?? "");
234
+ mkdirSync(config.dataDir, {
235
+ recursive: true,
236
+ mode: 448
237
+ });
238
+ const staging = stageApp(config.dataDir);
239
+ uninstallService(config, true);
240
+ const entry = swapApp(config.dataDir, staging);
241
+ writeServiceEnv(config.dataDir, extraEnv);
242
+ const spec = {
243
+ execPath: process.execPath,
244
+ entry,
245
+ dataDir: config.dataDir,
246
+ port: config.port,
247
+ host: config.host,
248
+ extraEnv,
249
+ system: isRoot()
250
+ };
251
+ if (process.platform === "linux") {
252
+ mkdirSync(dirname(unitPath()), { recursive: true });
253
+ writeFileSync(unitPath(), renderSystemdUnit(spec));
254
+ systemctl("daemon-reload");
255
+ systemctl("enable", "--now", SERVICE_NAME);
256
+ if (!isRoot()) {
257
+ const user = userInfo().username;
258
+ try {
259
+ run("loginctl", ["enable-linger", user], true);
260
+ } catch {
261
+ console.warn(` Could not enable lingering. Run \`sudo loginctl enable-linger ${user}\` so the service starts at boot.`);
262
+ }
263
+ }
264
+ } else {
265
+ mkdirSync(dirname(plistPath()), { recursive: true });
266
+ writeFileSync(plistPath(), renderLaunchdPlist(spec), { mode: 384 });
267
+ run("launchctl", [
268
+ "bootstrap",
269
+ launchdTarget(),
270
+ plistPath()
271
+ ]);
272
+ }
273
+ const kept = Object.keys(extraEnv).filter((k) => !(k in process.env));
274
+ console.log(`\n Installed ${SERVICE_NAME} as a ${process.platform === "linux" ? "systemd" : "launchd"} service.`);
275
+ if (kept.length) console.log(` Kept ${kept.join(", ")} from the previous install.`);
276
+ await printWhenReady(config);
277
+ }
278
+ function uninstallService(config, quiet = false) {
279
+ assertSupported();
280
+ if (process.platform === "linux") {
281
+ if (!existsSync(unitPath())) {
282
+ if (!quiet) console.log("The agentinbox service is not installed.");
283
+ return;
284
+ }
285
+ try {
286
+ systemctl("disable", "--now", SERVICE_NAME);
287
+ } catch {}
288
+ rmSync(unitPath());
289
+ systemctl("daemon-reload");
290
+ } else {
291
+ if (!existsSync(plistPath())) {
292
+ if (!quiet) console.log("The agentinbox service is not installed.");
293
+ return;
294
+ }
295
+ try {
296
+ run("launchctl", ["bootout", `${launchdTarget()}/${LAUNCHD_LABEL}`], true);
297
+ } catch {}
298
+ rmSync(plistPath());
299
+ }
300
+ if (!quiet) console.log(`Removed the ${SERVICE_NAME} service. Your data in ${config.dataDir} was kept.`);
301
+ }
302
+ function serviceStatus() {
303
+ assertSupported();
304
+ try {
305
+ if (process.platform === "linux") systemctl("status", SERVICE_NAME, "--no-pager");
306
+ else run("launchctl", ["print", `${launchdTarget()}/${LAUNCHD_LABEL}`]);
307
+ } catch {
308
+ process.exitCode = 1;
309
+ }
310
+ }
311
+ async function printWhenReady(config) {
312
+ const base = loopbackUrl(config.host, config.port);
313
+ for (let i = 0; i < 60; i++) {
314
+ try {
315
+ const res = await fetch(`${base}/api/health`, { signal: AbortSignal.timeout(1e3) });
316
+ if (res.status === 200 || res.status === 503) {
317
+ const token = readSetupToken(config.dataDir);
318
+ console.log(` Running at:\n`);
319
+ for (const url of consoleUrls(config.host, config.port)) console.log(` ${url}${token ? `/setup?token=${token}` : ""}`);
320
+ if (token) console.log(`\n Open the link above to claim the instance and finish setup.`);
321
+ console.log();
322
+ return;
323
+ }
324
+ } catch {}
325
+ await new Promise((r) => setTimeout(r, 500));
326
+ }
327
+ console.warn(` The service did not respond on port ${config.port} yet. Check \`${cliCommand("service status")}\`.`);
328
+ }
329
+ //#endregion
330
+ export { installService, serviceStatus, uninstallService };
331
+
332
+ //# sourceMappingURL=service-63pdSmhO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-63pdSmhO.js","names":["PACKAGE"],"sources":["../server/service.ts"],"sourcesContent":["import { execFileSync } from \"node:child_process\";\nimport { existsSync, mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync, writeFileSync } from \"node:fs\";\nimport { homedir, tmpdir, userInfo } from \"node:os\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport { NPM_PACKAGE as PACKAGE } from \"../shared/types.ts\";\nimport { readSetupToken } from \"./auth/setup-token.ts\";\nimport type { Config } from \"./config.ts\";\nimport { Crypto } from \"./crypto.ts\";\nimport { assertMasterKeyUsable, cliCommand } from \"./instance.ts\";\nimport { consoleUrls, loopbackUrl } from \"./urls.ts\";\n\n/** Installs agentinbox as a background service: systemd on Linux, launchd on macOS. */\n\nexport const SERVICE_NAME = \"agentinbox\";\nexport const LAUNCHD_LABEL = \"com.unlaboredlabs.agentinbox\";\nconst npm = process.platform === \"win32\" ? \"npm.cmd\" : \"npm\";\n/** Package root: one level above the running module (dist/cli.js or server/service.ts). */\nconst ROOT = resolve(import.meta.dirname, \"..\");\n\n/**\n * Settings that come from the environment rather than flags. They are kept in `<data>/service.env`\n * (mode 0600) so re-running `service install` from a shell without them (the documented update\n * path) keeps them. Set one to an empty value to drop it.\n */\nexport const SERVICE_ENV_KEYS = [\"AGENTINBOX_MASTER_KEY\", \"TRUST_PROXY\", \"TRUST_PROXY_HOPS\", \"AGENTINBOX_LOG_LEVEL\"] as const;\n\ntype ServiceConfig = Pick<Config, \"dataDir\" | \"port\" | \"host\" | \"dbPath\" | \"masterKeyPath\">;\n\nconst run = (cmd: string, args: string[], quiet = false) => execFileSync(cmd, args, { stdio: quiet ? \"ignore\" : \"inherit\" });\n\nconst isRoot = () => process.getuid?.() === 0;\nconst systemctl = (...args: string[]) => run(\"systemctl\", isRoot() ? args : [\"--user\", ...args]);\nconst unitPath = () => (isRoot() ? `/etc/systemd/system/${SERVICE_NAME}.service` : join(homedir(), \".config/systemd/user\", `${SERVICE_NAME}.service`));\nconst plistPath = () => join(homedir(), \"Library/LaunchAgents\", `${LAUNCHD_LABEL}.plist`);\nconst launchdTarget = () => `gui/${process.getuid?.()}`;\nexport const serviceEnvPath = (dataDir: string) => join(dataDir, \"service.env\");\n\n// ───────────── Pure rendering (unit-tested) ─────────────\n\nexport interface ServiceSpec {\n /** Node binary. */\n execPath: string;\n /** The installed dist/cli.js. */\n entry: string;\n dataDir: string;\n port: number;\n host: string;\n /** Extra environment from service.env (SERVICE_ENV_KEYS). */\n extraEnv: Record<string, string>;\n /** systemd: system unit (root) rather than a user unit. */\n system?: boolean;\n}\n\n/** Plain variables written into the unit/plist. Secrets never go into the systemd unit. */\nfunction plainEnv(spec: ServiceSpec): Record<string, string> {\n return { AGENTINBOX_DATA: spec.dataDir, PORT: String(spec.port), HOST: spec.host, AGENTINBOX_SERVICE: \"1\" };\n}\n\n/** systemd word quoting for ExecStart/Environment: double quotes, escaped backslashes, quotes and specifiers. */\nconst sdQuote = (s: string) => `\"${s.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"').replace(/%/g, \"%%\")}\"`;\n\n/**\n * The systemd unit. Everything from service.env (including AGENTINBOX_MASTER_KEY) is loaded with\n * EnvironmentFile=, so the world-readable unit holds no secrets. EnvironmentFile takes an\n * unquoted absolute path (systemd ignores quoted ones), which is why data dirs with whitespace are refused.\n */\nexport function renderSystemdUnit(spec: ServiceSpec): string {\n const vars = Object.entries(plainEnv(spec))\n .map(([k, v]) => `Environment=${sdQuote(`${k}=${v}`)}`)\n .join(\"\\n\");\n const envFile = Object.keys(spec.extraEnv).length ? `\\nEnvironmentFile=${serviceEnvPath(spec.dataDir).replace(/%/g, \"%%\")}` : \"\";\n return `[Unit]\nDescription=agentinbox (Gmail broker for AI agents)\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nExecStart=${sdQuote(spec.execPath)} ${sdQuote(spec.entry)} start --no-open\n${vars}${envFile}\nRestart=on-failure\nRestartSec=3\nTimeoutStopSec=20\n\n[Install]\nWantedBy=${spec.system ? \"multi-user.target\" : \"default.target\"}\n`;\n}\n\n/** The launchd plist. Written with mode 0600, since it may carry AGENTINBOX_MASTER_KEY. */\nexport function renderLaunchdPlist(spec: ServiceSpec): string {\n const esc = (s: string) => s.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n const vars = Object.entries({ ...plainEnv(spec), ...spec.extraEnv })\n .map(([k, v]) => ` <key>${esc(k)}</key><string>${esc(v)}</string>`)\n .join(\"\\n\");\n const log = esc(join(spec.dataDir, \"agentinbox.log\"));\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key><string>${LAUNCHD_LABEL}</string>\n <key>ProgramArguments</key>\n <array>\n <string>${esc(spec.execPath)}</string>\n <string>${esc(spec.entry)}</string>\n <string>start</string>\n <string>--no-open</string>\n </array>\n <key>EnvironmentVariables</key>\n <dict>\n${vars}\n </dict>\n <key>RunAtLoad</key><true/>\n <key>KeepAlive</key><true/>\n <key>StandardOutPath</key><string>${log}</string>\n <key>StandardErrorPath</key><string>${log}</string>\n</dict>\n</plist>\n`;\n}\n\n/** Parses service.env (KEY=value lines). */\nexport function parseEnvFile(text: string): Record<string, string> {\n const out: Record<string, string> = {};\n for (const line of text.split(\"\\n\")) {\n const m = /^\\s*([A-Z_][A-Z0-9_]*)=(.*)$/.exec(line);\n if (m) out[m[1]!] = m[2]!.trim();\n }\n return out;\n}\n\n/**\n * The service's env-derived settings: the current shell wins, previous install fills the gaps,\n * an explicitly empty value removes the setting.\n */\nexport function mergeServiceEnv(previous: Record<string, string>, current: NodeJS.ProcessEnv): Record<string, string> {\n const out: Record<string, string> = {};\n for (const key of SERVICE_ENV_KEYS) {\n const value = key in current ? current[key] : previous[key];\n if (value) out[key] = value;\n }\n return out;\n}\n\n/** Fails early (before anything is touched) when the master key can't work. */\nexport function validateMasterKey(value: string | undefined): void {\n if (!value) return;\n try {\n if (!/^[A-Za-z0-9+/]+={0,2}$/.test(value.trim())) throw new Error(\"not base64\");\n new Crypto(Buffer.from(value, \"base64\"));\n } catch {\n throw new Error(\"AGENTINBOX_MASTER_KEY must be 32 random bytes in base64 (e.g. `openssl rand -base64 32`).\");\n }\n}\n\n// ───────────── Install ─────────────\n\nfunction readPreviousEnv(dataDir: string): Record<string, string> {\n try {\n return parseEnvFile(readFileSync(serviceEnvPath(dataDir), \"utf8\"));\n } catch {\n return {};\n }\n}\n\nfunction writeServiceEnv(dataDir: string, env: Record<string, string>): void {\n const file = serviceEnvPath(dataDir);\n if (!Object.keys(env).length) {\n rmSync(file, { force: true });\n return;\n }\n for (const [k, v] of Object.entries(env)) {\n if (/[\\r\\n]/.test(v)) throw new Error(`${k} must be a single line.`);\n }\n writeFileSync(file, Object.entries(env).map(([k, v]) => `${k}=${v}\\n`).join(\"\"), { mode: 0o600 });\n}\n\n/**\n * Installs the package into `<data>/app.new`, so a failed npm install leaves the current service\n * untouched. From an installed package that is the latest release; from a source checkout, the\n * local build. Returns the staging directory.\n */\nfunction stageApp(dataDir: string): string {\n const staging = join(dataDir, \"app.new\");\n const fromSource = basename(dirname(ROOT)) !== \"node_modules\";\n let spec = `${PACKAGE}@latest`;\n let tmp: string | undefined;\n if (fromSource) {\n if (!existsSync(join(ROOT, \"dist/cli.js\")) || !existsSync(join(ROOT, \"dist/web/index.html\"))) {\n throw new Error(\"Run `pnpm build` before installing the service from a source checkout.\");\n }\n tmp = mkdtempSync(join(tmpdir(), \"agentinbox-pack-\"));\n const out = execFileSync(npm, [\"pack\", \"--ignore-scripts\", \"--pack-destination\", tmp, \"--loglevel=error\"], { cwd: ROOT, encoding: \"utf8\" });\n spec = join(tmp, out.trim().split(\"\\n\").pop()!);\n }\n\n console.log(fromSource ? \" Installing this build into the data directory…\" : \" Installing the latest release into the data directory…\");\n rmSync(staging, { recursive: true, force: true });\n mkdirSync(staging, { recursive: true });\n writeFileSync(join(staging, \"package.json\"), '{ \"private\": true }\\n');\n try {\n execFileSync(npm, [\"install\", spec, \"--omit=dev\", \"--prefer-online\", \"--no-audit\", \"--no-fund\", \"--loglevel=error\"], { cwd: staging, stdio: \"inherit\" });\n if (!existsSync(join(staging, \"node_modules\", PACKAGE, \"dist/cli.js\"))) throw new Error(\"the installed package has no dist/cli.js\");\n } catch (err) {\n rmSync(staging, { recursive: true, force: true });\n throw new Error(`Installing agentinbox failed, so the existing service was left as it was. ${err instanceof Error ? err.message : \"\"}`.trim());\n } finally {\n if (tmp) rmSync(tmp, { recursive: true, force: true });\n }\n return staging;\n}\n\n/** Replaces `<data>/app` with the staged install (call while the service is stopped). */\nfunction swapApp(dataDir: string, staging: string): string {\n const app = join(dataDir, \"app\");\n const old = join(dataDir, \"app.old\");\n rmSync(old, { recursive: true, force: true });\n if (existsSync(app)) renameSync(app, old);\n renameSync(staging, app);\n rmSync(old, { recursive: true, force: true });\n return join(app, \"node_modules\", PACKAGE, \"dist/cli.js\");\n}\n\nfunction assertSupported(): void {\n if (process.platform !== \"linux\" && process.platform !== \"darwin\") {\n throw new Error(`Service install supports Linux (systemd) and macOS (launchd). Elsewhere, run \\`${cliCommand(\"start\")}\\` under your own supervisor.`);\n }\n}\n\nexport async function installService(config: ServiceConfig): Promise<void> {\n assertSupported();\n if (process.platform === \"linux\" && /\\s/.test(config.dataDir)) {\n throw new Error(`The data directory \"${config.dataDir}\" contains whitespace, which systemd can't load settings from. Choose another one with --data.`);\n }\n const extraEnv = mergeServiceEnv(readPreviousEnv(config.dataDir), process.env);\n validateMasterKey(extraEnv.AGENTINBOX_MASTER_KEY);\n // The service must be able to read what's already stored, with exactly the key it will get.\n assertMasterKeyUsable(config, extraEnv.AGENTINBOX_MASTER_KEY ?? \"\");\n mkdirSync(config.dataDir, { recursive: true, mode: 0o700 });\n\n const staging = stageApp(config.dataDir);\n uninstallService(config, true);\n const entry = swapApp(config.dataDir, staging);\n writeServiceEnv(config.dataDir, extraEnv);\n const spec: ServiceSpec = { execPath: process.execPath, entry, dataDir: config.dataDir, port: config.port, host: config.host, extraEnv, system: isRoot() };\n\n if (process.platform === \"linux\") {\n mkdirSync(dirname(unitPath()), { recursive: true });\n writeFileSync(unitPath(), renderSystemdUnit(spec));\n systemctl(\"daemon-reload\");\n systemctl(\"enable\", \"--now\", SERVICE_NAME);\n if (!isRoot()) {\n // Keep user services running after logout and start them at boot.\n const user = userInfo().username;\n try {\n run(\"loginctl\", [\"enable-linger\", user], true);\n } catch {\n console.warn(` Could not enable lingering. Run \\`sudo loginctl enable-linger ${user}\\` so the service starts at boot.`);\n }\n }\n } else {\n mkdirSync(dirname(plistPath()), { recursive: true });\n writeFileSync(plistPath(), renderLaunchdPlist(spec), { mode: 0o600 });\n run(\"launchctl\", [\"bootstrap\", launchdTarget(), plistPath()]);\n }\n\n const kept = Object.keys(extraEnv).filter((k) => !(k in process.env));\n console.log(`\\n Installed ${SERVICE_NAME} as a ${process.platform === \"linux\" ? \"systemd\" : \"launchd\"} service.`);\n if (kept.length) console.log(` Kept ${kept.join(\", \")} from the previous install.`);\n await printWhenReady(config);\n}\n\nexport function uninstallService(config: ServiceConfig, quiet = false): void {\n assertSupported();\n if (process.platform === \"linux\") {\n if (!existsSync(unitPath())) {\n if (!quiet) console.log(\"The agentinbox service is not installed.\");\n return;\n }\n try {\n systemctl(\"disable\", \"--now\", SERVICE_NAME);\n } catch {\n // Already stopped.\n }\n rmSync(unitPath());\n systemctl(\"daemon-reload\");\n } else {\n if (!existsSync(plistPath())) {\n if (!quiet) console.log(\"The agentinbox service is not installed.\");\n return;\n }\n try {\n run(\"launchctl\", [\"bootout\", `${launchdTarget()}/${LAUNCHD_LABEL}`], true);\n } catch {\n // Not loaded.\n }\n rmSync(plistPath());\n }\n if (!quiet) console.log(`Removed the ${SERVICE_NAME} service. Your data in ${config.dataDir} was kept.`);\n}\n\nexport function serviceStatus(): void {\n assertSupported();\n try {\n if (process.platform === \"linux\") systemctl(\"status\", SERVICE_NAME, \"--no-pager\");\n else run(\"launchctl\", [\"print\", `${launchdTarget()}/${LAUNCHD_LABEL}`]);\n } catch {\n process.exitCode = 1;\n }\n}\n\nasync function printWhenReady(config: ServiceConfig): Promise<void> {\n const base = loopbackUrl(config.host, config.port);\n for (let i = 0; i < 60; i++) {\n try {\n // 503 means \"up but degraded\", which is still up.\n const res = await fetch(`${base}/api/health`, { signal: AbortSignal.timeout(1000) });\n if (res.status === 200 || res.status === 503) {\n const token = readSetupToken(config.dataDir);\n console.log(` Running at:\\n`);\n for (const url of consoleUrls(config.host, config.port)) console.log(` ${url}${token ? `/setup?token=${token}` : \"\"}`);\n if (token) console.log(`\\n Open the link above to claim the instance and finish setup.`);\n console.log();\n return;\n }\n } catch {\n // Not up yet.\n }\n await new Promise((r) => setTimeout(r, 500));\n }\n console.warn(` The service did not respond on port ${config.port} yet. Check \\`${cliCommand(\"service status\")}\\`.`);\n}\n"],"mappings":";;;;;;;;;;;AAaA,MAAa,eAAe;AAC5B,MAAa,gBAAgB;AAC7B,MAAM,MAAM,QAAQ,aAAa,UAAU,YAAY;;AAEvD,MAAM,OAAO,QAAQ,YAAY,SAAS,IAAI;;;;;;AAO9C,MAAa,mBAAmB;CAAC;CAAyB;CAAe;CAAoB;AAAsB;AAInH,MAAM,OAAO,KAAa,MAAgB,QAAQ,UAAU,aAAa,KAAK,MAAM,EAAE,OAAO,QAAQ,WAAW,UAAU,CAAC;AAE3H,MAAM,eAAe,QAAQ,SAAS,MAAM;AAC5C,MAAM,aAAa,GAAG,SAAmB,IAAI,aAAa,OAAO,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;AAC/F,MAAM,iBAAkB,OAAO,IAAI,uBAAuB,aAAa,YAAY,KAAK,QAAQ,GAAG,wBAAwB,GAAG,aAAa,SAAS;AACpJ,MAAM,kBAAkB,KAAK,QAAQ,GAAG,wBAAwB,GAAG,cAAc,OAAO;AACxF,MAAM,sBAAsB,OAAO,QAAQ,SAAS;AACpD,MAAa,kBAAkB,YAAoB,KAAK,SAAS,aAAa;;AAmB9E,SAAS,SAAS,MAA2C;CAC3D,OAAO;EAAE,iBAAiB,KAAK;EAAS,MAAM,OAAO,KAAK,IAAI;EAAG,MAAM,KAAK;EAAM,oBAAoB;CAAI;AAC5G;;AAGA,MAAM,WAAW,MAAc,IAAI,EAAE,QAAQ,OAAO,MAAM,CAAC,CAAC,QAAQ,MAAM,MAAK,CAAC,CAAC,QAAQ,MAAM,IAAI,EAAE;;;;;;AAOrG,SAAgB,kBAAkB,MAA2B;CAC3D,MAAM,OAAO,OAAO,QAAQ,SAAS,IAAI,CAAC,CAAC,CACxC,KAAK,CAAC,GAAG,OAAO,eAAe,QAAQ,GAAG,EAAE,GAAG,GAAG,GAAG,CAAC,CACtD,KAAK,IAAI;CACZ,MAAM,UAAU,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,SAAS,qBAAqB,eAAe,KAAK,OAAO,CAAC,CAAC,QAAQ,MAAM,IAAI,MAAM;CAC9H,OAAO;;;;;;YAMG,QAAQ,KAAK,QAAQ,EAAE,GAAG,QAAQ,KAAK,KAAK,EAAE;EACxD,OAAO,QAAQ;;;;;;WAMN,KAAK,SAAS,sBAAsB,iBAAiB;;AAEhE;;AAGA,SAAgB,mBAAmB,MAA2B;CAC5D,MAAM,OAAO,MAAc,EAAE,QAAQ,MAAM,OAAO,CAAC,CAAC,QAAQ,MAAM,MAAM,CAAC,CAAC,QAAQ,MAAM,MAAM;CAC9F,MAAM,OAAO,OAAO,QAAQ;EAAE,GAAG,SAAS,IAAI;EAAG,GAAG,KAAK;CAAS,CAAC,CAAC,CACjE,KAAK,CAAC,GAAG,OAAO,YAAY,IAAI,CAAC,EAAE,gBAAgB,IAAI,CAAC,EAAE,UAAU,CAAC,CACrE,KAAK,IAAI;CACZ,MAAM,MAAM,IAAI,KAAK,KAAK,SAAS,gBAAgB,CAAC;CACpD,OAAO;;;;4BAImB,cAAc;;;cAG5B,IAAI,KAAK,QAAQ,EAAE;cACnB,IAAI,KAAK,KAAK,EAAE;;;;;;EAM5B,KAAK;;;;sCAI+B,IAAI;wCACF,IAAI;;;;AAI5C;;AAGA,SAAgB,aAAa,MAAsC;CACjE,MAAM,MAA8B,CAAC;CACrC,KAAK,MAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;EACnC,MAAM,IAAI,+BAA+B,KAAK,IAAI;EAClD,IAAI,GAAG,IAAI,EAAE,MAAO,EAAE,EAAE,CAAE,KAAK;CACjC;CACA,OAAO;AACT;;;;;AAMA,SAAgB,gBAAgB,UAAkC,SAAoD;CACpH,MAAM,MAA8B,CAAC;CACrC,KAAK,MAAM,OAAO,kBAAkB;EAClC,MAAM,QAAQ,OAAO,UAAU,QAAQ,OAAO,SAAS;EACvD,IAAI,OAAO,IAAI,OAAO;CACxB;CACA,OAAO;AACT;;AAGA,SAAgB,kBAAkB,OAAiC;CACjE,IAAI,CAAC,OAAO;CACZ,IAAI;EACF,IAAI,CAAC,yBAAyB,KAAK,MAAM,KAAK,CAAC,GAAG,MAAM,IAAI,MAAM,YAAY;EAC9E,IAAI,OAAO,OAAO,KAAK,OAAO,QAAQ,CAAC;CACzC,QAAQ;EACN,MAAM,IAAI,MAAM,2FAA2F;CAC7G;AACF;AAIA,SAAS,gBAAgB,SAAyC;CAChE,IAAI;EACF,OAAO,aAAa,aAAa,eAAe,OAAO,GAAG,MAAM,CAAC;CACnE,QAAQ;EACN,OAAO,CAAC;CACV;AACF;AAEA,SAAS,gBAAgB,SAAiB,KAAmC;CAC3E,MAAM,OAAO,eAAe,OAAO;CACnC,IAAI,CAAC,OAAO,KAAK,GAAG,CAAC,CAAC,QAAQ;EAC5B,OAAO,MAAM,EAAE,OAAO,KAAK,CAAC;EAC5B;CACF;CACA,KAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,GAAG,GACrC,IAAI,SAAS,KAAK,CAAC,GAAG,MAAM,IAAI,MAAM,GAAG,EAAE,wBAAwB;CAErE,cAAc,MAAM,OAAO,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,OAAO,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,IAAM,CAAC;AAClG;;;;;;AAOA,SAAS,SAAS,SAAyB;CACzC,MAAM,UAAU,KAAK,SAAS,SAAS;CACvC,MAAM,aAAa,SAAS,QAAQ,IAAI,CAAC,MAAM;CAC/C,IAAI,OAAO,GAAGA,YAAQ;CACtB,IAAI;CACJ,IAAI,YAAY;EACd,IAAI,CAAC,WAAW,KAAK,MAAM,aAAa,CAAC,KAAK,CAAC,WAAW,KAAK,MAAM,qBAAqB,CAAC,GACzF,MAAM,IAAI,MAAM,wEAAwE;EAE1F,MAAM,YAAY,KAAK,OAAO,GAAG,kBAAkB,CAAC;EACpD,MAAM,MAAM,aAAa,KAAK;GAAC;GAAQ;GAAoB;GAAsB;GAAK;EAAkB,GAAG;GAAE,KAAK;GAAM,UAAU;EAAO,CAAC;EAC1I,OAAO,KAAK,KAAK,IAAI,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,IAAI,CAAE;CAChD;CAEA,QAAQ,IAAI,aAAa,qDAAqD,0DAA0D;CACxI,OAAO,SAAS;EAAE,WAAW;EAAM,OAAO;CAAK,CAAC;CAChD,UAAU,SAAS,EAAE,WAAW,KAAK,CAAC;CACtC,cAAc,KAAK,SAAS,cAAc,GAAG,yBAAuB;CACpE,IAAI;EACF,aAAa,KAAK;GAAC;GAAW;GAAM;GAAc;GAAmB;GAAc;GAAa;EAAkB,GAAG;GAAE,KAAK;GAAS,OAAO;EAAU,CAAC;EACvJ,IAAI,CAAC,WAAW,KAAK,SAAS,gBAAA,kBAAyB,aAAa,CAAC,GAAG,MAAM,IAAI,MAAM,0CAA0C;CACpI,SAAS,KAAK;EACZ,OAAO,SAAS;GAAE,WAAW;GAAM,OAAO;EAAK,CAAC;EAChD,MAAM,IAAI,MAAM,6EAA6E,eAAe,QAAQ,IAAI,UAAU,KAAK,KAAK,CAAC;CAC/I,UAAU;EACR,IAAI,KAAK,OAAO,KAAK;GAAE,WAAW;GAAM,OAAO;EAAK,CAAC;CACvD;CACA,OAAO;AACT;;AAGA,SAAS,QAAQ,SAAiB,SAAyB;CACzD,MAAM,MAAM,KAAK,SAAS,KAAK;CAC/B,MAAM,MAAM,KAAK,SAAS,SAAS;CACnC,OAAO,KAAK;EAAE,WAAW;EAAM,OAAO;CAAK,CAAC;CAC5C,IAAI,WAAW,GAAG,GAAG,WAAW,KAAK,GAAG;CACxC,WAAW,SAAS,GAAG;CACvB,OAAO,KAAK;EAAE,WAAW;EAAM,OAAO;CAAK,CAAC;CAC5C,OAAO,KAAK,KAAK,gBAAgBA,aAAS,aAAa;AACzD;AAEA,SAAS,kBAAwB;CAC/B,IAAI,QAAQ,aAAa,WAAW,QAAQ,aAAa,UACvD,MAAM,IAAI,MAAM,kFAAkF,WAAW,OAAO,EAAE,8BAA8B;AAExJ;AAEA,eAAsB,eAAe,QAAsC;CACzE,gBAAgB;CAChB,IAAI,QAAQ,aAAa,WAAW,KAAK,KAAK,OAAO,OAAO,GAC1D,MAAM,IAAI,MAAM,uBAAuB,OAAO,QAAQ,+FAA+F;CAEvJ,MAAM,WAAW,gBAAgB,gBAAgB,OAAO,OAAO,GAAG,QAAQ,GAAG;CAC7E,kBAAkB,SAAS,qBAAqB;CAEhD,sBAAsB,QAAQ,SAAS,yBAAyB,EAAE;CAClE,UAAU,OAAO,SAAS;EAAE,WAAW;EAAM,MAAM;CAAM,CAAC;CAE1D,MAAM,UAAU,SAAS,OAAO,OAAO;CACvC,iBAAiB,QAAQ,IAAI;CAC7B,MAAM,QAAQ,QAAQ,OAAO,SAAS,OAAO;CAC7C,gBAAgB,OAAO,SAAS,QAAQ;CACxC,MAAM,OAAoB;EAAE,UAAU,QAAQ;EAAU;EAAO,SAAS,OAAO;EAAS,MAAM,OAAO;EAAM,MAAM,OAAO;EAAM;EAAU,QAAQ,OAAO;CAAE;CAEzJ,IAAI,QAAQ,aAAa,SAAS;EAChC,UAAU,QAAQ,SAAS,CAAC,GAAG,EAAE,WAAW,KAAK,CAAC;EAClD,cAAc,SAAS,GAAG,kBAAkB,IAAI,CAAC;EACjD,UAAU,eAAe;EACzB,UAAU,UAAU,SAAS,YAAY;EACzC,IAAI,CAAC,OAAO,GAAG;GAEb,MAAM,OAAO,SAAS,CAAC,CAAC;GACxB,IAAI;IACF,IAAI,YAAY,CAAC,iBAAiB,IAAI,GAAG,IAAI;GAC/C,QAAQ;IACN,QAAQ,KAAK,mEAAmE,KAAK,kCAAkC;GACzH;EACF;CACF,OAAO;EACL,UAAU,QAAQ,UAAU,CAAC,GAAG,EAAE,WAAW,KAAK,CAAC;EACnD,cAAc,UAAU,GAAG,mBAAmB,IAAI,GAAG,EAAE,MAAM,IAAM,CAAC;EACpE,IAAI,aAAa;GAAC;GAAa,cAAc;GAAG,UAAU;EAAC,CAAC;CAC9D;CAEA,MAAM,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,QAAQ,MAAM,EAAE,KAAK,QAAQ,IAAI;CACpE,QAAQ,IAAI,iBAAiB,aAAa,QAAQ,QAAQ,aAAa,UAAU,YAAY,UAAU,UAAU;CACjH,IAAI,KAAK,QAAQ,QAAQ,IAAI,UAAU,KAAK,KAAK,IAAI,EAAE,4BAA4B;CACnF,MAAM,eAAe,MAAM;AAC7B;AAEA,SAAgB,iBAAiB,QAAuB,QAAQ,OAAa;CAC3E,gBAAgB;CAChB,IAAI,QAAQ,aAAa,SAAS;EAChC,IAAI,CAAC,WAAW,SAAS,CAAC,GAAG;GAC3B,IAAI,CAAC,OAAO,QAAQ,IAAI,0CAA0C;GAClE;EACF;EACA,IAAI;GACF,UAAU,WAAW,SAAS,YAAY;EAC5C,QAAQ,CAER;EACA,OAAO,SAAS,CAAC;EACjB,UAAU,eAAe;CAC3B,OAAO;EACL,IAAI,CAAC,WAAW,UAAU,CAAC,GAAG;GAC5B,IAAI,CAAC,OAAO,QAAQ,IAAI,0CAA0C;GAClE;EACF;EACA,IAAI;GACF,IAAI,aAAa,CAAC,WAAW,GAAG,cAAc,EAAE,GAAG,eAAe,GAAG,IAAI;EAC3E,QAAQ,CAER;EACA,OAAO,UAAU,CAAC;CACpB;CACA,IAAI,CAAC,OAAO,QAAQ,IAAI,eAAe,aAAa,yBAAyB,OAAO,QAAQ,WAAW;AACzG;AAEA,SAAgB,gBAAsB;CACpC,gBAAgB;CAChB,IAAI;EACF,IAAI,QAAQ,aAAa,SAAS,UAAU,UAAU,cAAc,YAAY;OAC3E,IAAI,aAAa,CAAC,SAAS,GAAG,cAAc,EAAE,GAAG,eAAe,CAAC;CACxE,QAAQ;EACN,QAAQ,WAAW;CACrB;AACF;AAEA,eAAe,eAAe,QAAsC;CAClE,MAAM,OAAO,YAAY,OAAO,MAAM,OAAO,IAAI;CACjD,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;EAC3B,IAAI;GAEF,MAAM,MAAM,MAAM,MAAM,GAAG,KAAK,cAAc,EAAE,QAAQ,YAAY,QAAQ,GAAI,EAAE,CAAC;GACnF,IAAI,IAAI,WAAW,OAAO,IAAI,WAAW,KAAK;IAC5C,MAAM,QAAQ,eAAe,OAAO,OAAO;IAC3C,QAAQ,IAAI,iBAAiB;IAC7B,KAAK,MAAM,OAAO,YAAY,OAAO,MAAM,OAAO,IAAI,GAAG,QAAQ,IAAI,OAAO,MAAM,QAAQ,gBAAgB,UAAU,IAAI;IACxH,IAAI,OAAO,QAAQ,IAAI,iEAAiE;IACxF,QAAQ,IAAI;IACZ;GACF;EACF,QAAQ,CAER;EACA,MAAM,IAAI,SAAS,MAAM,WAAW,GAAG,GAAG,CAAC;CAC7C;CACA,QAAQ,KAAK,yCAAyC,OAAO,KAAK,gBAAgB,WAAW,gBAAgB,EAAE,IAAI;AACrH"}