agentix-cli 0.126.1 → 0.127.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/dist/{App-BUYK4EGC.js → App-FF66N2KH.js} +2 -2
  2. package/dist/{ChatApp-ZS6EPDDK.js → ChatApp-HMHQZVVD.js} +2 -2
  3. package/dist/{absorb-eval-5Y5IZWW2.js → absorb-eval-ERKVVTGG.js} +2 -2
  4. package/dist/{agent-WJTYM5HR.js → agent-UAWDO3I2.js} +2 -2
  5. package/dist/{board-dashboard-DQR2OSV7.js → board-dashboard-Y2OECKDG.js} +303 -228
  6. package/dist/board-dashboard-Y2OECKDG.js.map +1 -0
  7. package/dist/{chunk-JUIL2EW3.js → chunk-3KYZOC7N.js} +2 -2
  8. package/dist/{chunk-JIXNSA67.js → chunk-4WZGZ2Z6.js} +2 -2
  9. package/dist/chunk-52SIHG45.js +4 -0
  10. package/dist/chunk-52SIHG45.js.map +1 -0
  11. package/dist/{chunk-FHBPKMCF.js → chunk-73WQ42PO.js} +2 -2
  12. package/dist/{chunk-6GLJIA25.js → chunk-CKYPQMUD.js} +2 -2
  13. package/dist/chunk-COWAAE54.js +128 -0
  14. package/dist/chunk-COWAAE54.js.map +1 -0
  15. package/dist/{chunk-ZQWWMAMJ.js → chunk-EHLTZ6IB.js} +2 -2
  16. package/dist/{chunk-Z7XXUYBB.js → chunk-EJT3F6QM.js} +33 -35
  17. package/dist/chunk-EJT3F6QM.js.map +1 -0
  18. package/dist/{chunk-LVV7JBHM.js → chunk-HNBW5Q47.js} +2 -2
  19. package/dist/{chunk-4VUGJB5S.js → chunk-HYRBBH6T.js} +98 -98
  20. package/dist/chunk-HYRBBH6T.js.map +1 -0
  21. package/dist/{chunk-CY6ABHF2.js → chunk-I4DGMFQG.js} +2 -2
  22. package/dist/{chunk-VXKNB4AW.js → chunk-LTH3AYXC.js} +2 -2
  23. package/dist/{chunk-O4XEQTEN.js → chunk-NUSROFTJ.js} +3 -3
  24. package/dist/chunk-NUSROFTJ.js.map +1 -0
  25. package/dist/chunk-O6FP3LPC.js +4 -0
  26. package/dist/chunk-O6FP3LPC.js.map +1 -0
  27. package/dist/{chunk-WMTGAVPW.js → chunk-PH43FUU7.js} +2 -2
  28. package/dist/{chunk-2W3X6H7Z.js → chunk-PLIT25TH.js} +2 -2
  29. package/dist/chunk-QUXMLLX5.js +2 -0
  30. package/dist/chunk-QUXMLLX5.js.map +1 -0
  31. package/dist/{chunk-D6SWAB5J.js → chunk-QWQOI4G4.js} +32 -32
  32. package/dist/chunk-QWQOI4G4.js.map +1 -0
  33. package/dist/{chunk-YNA5T43U.js → chunk-TJ4P4WW2.js} +2 -2
  34. package/dist/{chunk-2C3X6DVD.js → chunk-UJXS4MS3.js} +2 -2
  35. package/dist/{chunk-GUQDPA6R.js → chunk-VBJTGTF5.js} +2 -2
  36. package/dist/{chunk-FVG2BADS.js → chunk-XX5QKBX4.js} +2 -2
  37. package/dist/{chunk-QQYXYJOG.js → chunk-XYT6XY7G.js} +2 -2
  38. package/dist/{chunk-46JKX6CT.js → chunk-Y27RUOD2.js} +10 -10
  39. package/dist/chunk-Y27RUOD2.js.map +1 -0
  40. package/dist/{chunk-WUDVBPQV.js → chunk-YV22EOGL.js} +2 -2
  41. package/dist/cli.js +1 -1
  42. package/dist/{client-PO5LDFS4.js → client-2VVRJ3UF.js} +2 -2
  43. package/dist/{config-L2RQ6EJX.js → config-YSKHOV44.js} +2 -2
  44. package/dist/config-mutate-47WZDZBO.js +2 -0
  45. package/dist/config-mutator-7DIEQUB5.js +2 -0
  46. package/dist/doctor-Q3QNZVLC.js +2 -0
  47. package/dist/{follow-up-tool-AIOLNUF7.js → follow-up-tool-GKZVG4L2.js} +2 -2
  48. package/dist/{follow-up-tool-AIOLNUF7.js.map → follow-up-tool-GKZVG4L2.js.map} +1 -1
  49. package/dist/hub-DNPINTIF.js +2 -0
  50. package/dist/index.d.ts +115 -50
  51. package/dist/index.js +1 -1
  52. package/dist/index.js.map +1 -1
  53. package/dist/notes-YLTNRMB5.js +2 -0
  54. package/dist/notes-settings-X63D5HPM.js +2 -0
  55. package/dist/{program-EYGICEXY.js → program-4QWUOJE3.js} +214 -214
  56. package/dist/program-4QWUOJE3.js.map +1 -0
  57. package/dist/{promote-MQYJMGGZ.js → promote-PETKX7KR.js} +2 -2
  58. package/dist/query-D44BUTH3.js +2 -0
  59. package/dist/registry-2XDO53AJ.js +2 -0
  60. package/dist/{request-planner-XYHM26CO.js → request-planner-A3WJNPXO.js} +2 -2
  61. package/dist/{review-candidates-XRBAMRBH.js → review-candidates-A6ID2RDX.js} +2 -2
  62. package/dist/routing-NPP3MEUW.js +2 -0
  63. package/dist/schedule-tool-ZECUQMQK.js +2 -0
  64. package/dist/scheduler-T6VLBM3U.js +2 -0
  65. package/dist/scheduler-T6VLBM3U.js.map +1 -0
  66. package/dist/{seat-LKBZ6SDS.js → seat-D3DBYTSC.js} +2 -2
  67. package/dist/seat-D3DBYTSC.js.map +1 -0
  68. package/dist/{select-BSC3TFMZ.js → select-RFY64RY7.js} +2 -2
  69. package/dist/{set-enabled-YWXWSKME.js → set-enabled-AU66DR5C.js} +2 -2
  70. package/dist/{tool-FZEC5FQX.js → tool-F3YA2ZZQ.js} +2 -2
  71. package/dist/{tool-FZEC5FQX.js.map → tool-F3YA2ZZQ.js.map} +1 -1
  72. package/dist/{tool-5JTCSRTW.js → tool-PCHIVR27.js} +2 -2
  73. package/dist/{tool-5JTCSRTW.js.map → tool-PCHIVR27.js.map} +1 -1
  74. package/dist/wiki-NI3ZPUZS.js +2 -0
  75. package/dist/wiki-NI3ZPUZS.js.map +1 -0
  76. package/package.json +1 -1
  77. package/dist/board-dashboard-DQR2OSV7.js.map +0 -1
  78. package/dist/chunk-46JKX6CT.js.map +0 -1
  79. package/dist/chunk-4VUGJB5S.js.map +0 -1
  80. package/dist/chunk-5DFUUYEA.js +0 -126
  81. package/dist/chunk-5DFUUYEA.js.map +0 -1
  82. package/dist/chunk-D6SWAB5J.js.map +0 -1
  83. package/dist/chunk-O4XEQTEN.js.map +0 -1
  84. package/dist/chunk-Z7XXUYBB.js.map +0 -1
  85. package/dist/config-mutator-44OAOZXM.js +0 -2
  86. package/dist/doctor-AU5TCOSG.js +0 -2
  87. package/dist/hub-53YQQCVA.js +0 -2
  88. package/dist/program-EYGICEXY.js.map +0 -1
  89. package/dist/query-DNJONEKC.js +0 -2
  90. package/dist/registry-5A3SLBVJ.js +0 -2
  91. package/dist/routing-OMIWZKNC.js +0 -2
  92. package/dist/schedule-tool-YRANRFHO.js +0 -2
  93. package/dist/scheduler-L4P4Z55R.js +0 -2
  94. package/dist/wiki-BT3H2WCD.js +0 -2
  95. /package/dist/{App-BUYK4EGC.js.map → App-FF66N2KH.js.map} +0 -0
  96. /package/dist/{ChatApp-ZS6EPDDK.js.map → ChatApp-HMHQZVVD.js.map} +0 -0
  97. /package/dist/{absorb-eval-5Y5IZWW2.js.map → absorb-eval-ERKVVTGG.js.map} +0 -0
  98. /package/dist/{agent-WJTYM5HR.js.map → agent-UAWDO3I2.js.map} +0 -0
  99. /package/dist/{chunk-JUIL2EW3.js.map → chunk-3KYZOC7N.js.map} +0 -0
  100. /package/dist/{chunk-JIXNSA67.js.map → chunk-4WZGZ2Z6.js.map} +0 -0
  101. /package/dist/{chunk-FHBPKMCF.js.map → chunk-73WQ42PO.js.map} +0 -0
  102. /package/dist/{chunk-6GLJIA25.js.map → chunk-CKYPQMUD.js.map} +0 -0
  103. /package/dist/{chunk-ZQWWMAMJ.js.map → chunk-EHLTZ6IB.js.map} +0 -0
  104. /package/dist/{chunk-LVV7JBHM.js.map → chunk-HNBW5Q47.js.map} +0 -0
  105. /package/dist/{chunk-CY6ABHF2.js.map → chunk-I4DGMFQG.js.map} +0 -0
  106. /package/dist/{chunk-VXKNB4AW.js.map → chunk-LTH3AYXC.js.map} +0 -0
  107. /package/dist/{chunk-WMTGAVPW.js.map → chunk-PH43FUU7.js.map} +0 -0
  108. /package/dist/{chunk-2W3X6H7Z.js.map → chunk-PLIT25TH.js.map} +0 -0
  109. /package/dist/{chunk-YNA5T43U.js.map → chunk-TJ4P4WW2.js.map} +0 -0
  110. /package/dist/{chunk-2C3X6DVD.js.map → chunk-UJXS4MS3.js.map} +0 -0
  111. /package/dist/{chunk-GUQDPA6R.js.map → chunk-VBJTGTF5.js.map} +0 -0
  112. /package/dist/{chunk-FVG2BADS.js.map → chunk-XX5QKBX4.js.map} +0 -0
  113. /package/dist/{chunk-QQYXYJOG.js.map → chunk-XYT6XY7G.js.map} +0 -0
  114. /package/dist/{chunk-WUDVBPQV.js.map → chunk-YV22EOGL.js.map} +0 -0
  115. /package/dist/{client-PO5LDFS4.js.map → client-2VVRJ3UF.js.map} +0 -0
  116. /package/dist/{config-L2RQ6EJX.js.map → config-YSKHOV44.js.map} +0 -0
  117. /package/dist/{config-mutator-44OAOZXM.js.map → config-mutate-47WZDZBO.js.map} +0 -0
  118. /package/dist/{doctor-AU5TCOSG.js.map → config-mutator-7DIEQUB5.js.map} +0 -0
  119. /package/dist/{hub-53YQQCVA.js.map → doctor-Q3QNZVLC.js.map} +0 -0
  120. /package/dist/{promote-MQYJMGGZ.js.map → hub-DNPINTIF.js.map} +0 -0
  121. /package/dist/{query-DNJONEKC.js.map → notes-YLTNRMB5.js.map} +0 -0
  122. /package/dist/{registry-5A3SLBVJ.js.map → notes-settings-X63D5HPM.js.map} +0 -0
  123. /package/dist/{routing-OMIWZKNC.js.map → promote-PETKX7KR.js.map} +0 -0
  124. /package/dist/{schedule-tool-YRANRFHO.js.map → query-D44BUTH3.js.map} +0 -0
  125. /package/dist/{scheduler-L4P4Z55R.js.map → registry-2XDO53AJ.js.map} +0 -0
  126. /package/dist/{request-planner-XYHM26CO.js.map → request-planner-A3WJNPXO.js.map} +0 -0
  127. /package/dist/{review-candidates-XRBAMRBH.js.map → review-candidates-A6ID2RDX.js.map} +0 -0
  128. /package/dist/{seat-LKBZ6SDS.js.map → routing-NPP3MEUW.js.map} +0 -0
  129. /package/dist/{wiki-BT3H2WCD.js.map → schedule-tool-ZECUQMQK.js.map} +0 -0
  130. /package/dist/{select-BSC3TFMZ.js.map → select-RFY64RY7.js.map} +0 -0
  131. /package/dist/{set-enabled-YWXWSKME.js.map → set-enabled-AU66DR5C.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/daemon/setup-wizard.ts","../src/daemon/config-mutate.ts","../src/daemon/ui/pages/setup.ts","../src/approvals/settings.ts","../src/wiki/serve.ts","../src/wiki/mesh.ts","../src/wiki/ontology/lens.ts","../src/wiki/ontology/view-layout.ts","../src/wiki/ontology/view-panels.ts","../src/wiki/ontology/view-entity.ts","../src/wiki/ontology/view-browse.ts","../src/wiki/ontology/routes.ts","../src/people/activity.ts","../src/members/pairing.ts","../src/requests/status-settings.ts","../src/notify/ntfy-settings.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync, appendFileSync, mkdirSync } from \"fs\"\nimport { dirname, resolve } from \"path\"\nimport { fileURLToPath } from \"url\"\nimport { hostname } from \"os\"\nimport { spawn } from \"child_process\"\nimport type { IncomingMessage, ServerResponse } from \"http\"\nimport { mutateAgentxConfig, writeAgentxConfig } from \"./config-mutate\"\nimport { renderSetupPage } from \"./ui/pages/setup\"\nimport { loadDaemonConfig } from \"./config\"\n\n/** Shape of the pre-render state snapshot — exported so the page file can\n * type its props without re-importing this whole module. */\nexport interface WizardState {\n configExists: boolean\n agentCount: number\n channelCount: number\n nodeName?: string\n}\n\n// --- /setup wizard: form-driven first-run experience for non-technical operators ---\n//\n// This is the web equivalent of `agentx init` + `agentx agent add` + `agentx\n// channel add`, collapsed into one page. It writes agentx.json and scaffolds\n// the first agent's workspace so a business operator can go from a blank\n// machine to a working AgentX install without editing JSON.\n//\n// The route lives on the board-dashboard server (port 4202) because that's the\n// surface operators actually open. It talks to the loopback daemon for the\n// post-install restart; the wizard itself never requires a running daemon.\n\nexport interface WizardPayload {\n nodeName: string\n agent: {\n id: string\n name: string\n triggerWords: string // comma/space separated; we normalise on the server\n tier: \"claude-code\" | \"codex-cli\" | \"opencode\" | \"sdk\" | \"orchestrator\"\n model?: string\n personality?: string // short free text → CLAUDE.md\n }\n telegram?: {\n accountId: string\n botToken: string\n botUsername?: string\n }\n anthropicApiKey?: string\n}\n\n/**\n * Return the current state of the working directory so the wizard can choose\n * between \"fresh install\" and \"add another\" flows.\n */\nexport function wizardState(baseDir: string = process.cwd()): WizardState {\n const file = resolve(baseDir, \"agentx.json\")\n if (!existsSync(file)) return { configExists: false, agentCount: 0, channelCount: 0 }\n try {\n const cfg = JSON.parse(readFileSync(file, \"utf-8\"))\n const agents = cfg.agents ? Object.keys(cfg.agents).length : 0\n const channels = cfg.channels\n ? Object.values(cfg.channels).filter((c: any) => c && c.enabled).length\n : 0\n return { configExists: true, agentCount: agents, channelCount: channels, nodeName: cfg.node?.name }\n } catch {\n return { configExists: false, agentCount: 0, channelCount: 0 }\n }\n}\n\n/**\n * Execute the wizard submission. Returns a short human-readable summary of\n * what was written. Throws on validation error — the caller surfaces the\n * message to the user.\n */\nexport function runWizard(payload: WizardPayload, baseDir: string = process.cwd()): {\n summary: string\n nextSteps: string[]\n backupPath?: string\n} {\n // --- validate ---\n if (!payload.nodeName?.trim()) throw new Error(\"Team name is required.\")\n if (!payload.agent?.id?.trim()) throw new Error(\"Agent id is required.\")\n if (!/^[a-z0-9][a-z0-9_-]*$/.test(payload.agent.id)) {\n throw new Error(\"Agent id must be lowercase (letters, digits, -, _) and start with a letter or digit.\")\n }\n if (!payload.agent.name?.trim()) throw new Error(\"Agent name is required.\")\n const mentions = splitMentions(payload.agent.triggerWords)\n if (mentions.length === 0) throw new Error(\"At least one trigger word is required.\")\n if (\n payload.agent.tier !== \"claude-code\" &&\n payload.agent.tier !== \"codex-cli\" &&\n payload.agent.tier !== \"opencode\" &&\n payload.agent.tier !== \"sdk\" &&\n payload.agent.tier !== \"orchestrator\"\n ) {\n throw new Error(\"AI engine must be claude-code, codex-cli, opencode, sdk, or orchestrator.\")\n }\n\n const configPath = resolve(baseDir, \"agentx.json\")\n const envPath = resolve(baseDir, \".env\")\n const workspaceDir = resolve(baseDir, \"agents\", payload.agent.id)\n const state = wizardState(baseDir)\n\n // --- scaffold workspace ---\n mkdirSync(workspaceDir, { recursive: true })\n const claudeMd = resolve(workspaceDir, \"CLAUDE.md\")\n if (!existsSync(claudeMd)) {\n const personality = payload.agent.personality?.trim() || `You are ${payload.agent.name}, an assistant on the ${payload.nodeName} team.`\n writeFileSync(claudeMd, `# ${payload.agent.name}\\n\\n${personality}\\n`)\n }\n\n // --- build / mutate agentx.json ---\n const telegramTokenRef = payload.telegram\n ? `TG_${payload.agent.id.toUpperCase()}_BOT_TOKEN`\n : undefined\n\n let backupPath: string | undefined\n if (!state.configExists) {\n const cfg = buildFreshConfig(payload, workspaceDir, mentions, telegramTokenRef)\n writeAgentxConfig(cfg, { configPath })\n } else {\n const result = mutateAgentxConfig((cfg) => {\n cfg.node = cfg.node || {}\n if (!cfg.node.name) cfg.node.name = payload.nodeName\n if (!cfg.node.id) cfg.node.id = slugify(payload.nodeName) || \"team\"\n if (!cfg.node.bind) cfg.node.bind = \"127.0.0.1:18800\"\n cfg.node.defaultAgent = cfg.node.defaultAgent || payload.agent.id\n\n cfg.providers = cfg.providers || {}\n if (!cfg.providers.claude) cfg.providers.claude = { apiKey: \"${ANTHROPIC_API_KEY}\" }\n\n cfg.agents = cfg.agents || {}\n if (cfg.agents[payload.agent.id]) throw new Error(`Agent \"${payload.agent.id}\" already exists.`)\n cfg.agents[payload.agent.id] = agentBlock(payload, workspaceDir, mentions)\n\n if (payload.telegram) {\n cfg.channels = cfg.channels || {}\n cfg.channels.telegram = cfg.channels.telegram || { enabled: true, accounts: {}, policy: { dm: \"pair\", group: \"mention-required\" } }\n cfg.channels.telegram.enabled = true\n cfg.channels.telegram.accounts = cfg.channels.telegram.accounts || {}\n cfg.channels.telegram.accounts[payload.telegram.accountId] = telegramAccountBlock(payload, telegramTokenRef!)\n }\n\n return { summary: `added agent \"${payload.agent.id}\"` + (payload.telegram ? \" + telegram account\" : \"\") }\n }, { configPath })\n backupPath = result.backupPath\n }\n\n // --- write / append .env ---\n ensureEnvEntries(envPath, payload, telegramTokenRef)\n\n const nextSteps: string[] = []\n if (payload.anthropicApiKey || !existsSync(resolve(baseDir, \".env\"))) {\n nextSteps.push(\"Double-check the API keys in .env\")\n }\n if (payload.agent.tier === \"claude-code\") {\n nextSteps.push(\"Run claude --version to confirm Claude Code is installed (needed for the claude-code engine)\")\n }\n if (payload.agent.tier === \"codex-cli\") {\n nextSteps.push(\"Run codex --version to confirm Codex CLI is installed (needed for the codex-cli engine)\")\n }\n if (payload.agent.tier === \"opencode\") {\n nextSteps.push(\"Run opencode --version to confirm OpenCode is installed and authenticated\")\n }\n nextSteps.push(\"Start the daemon: agentx daemon start\")\n nextSteps.push(\"Open the dashboard: http://127.0.0.1:4202\")\n\n return {\n summary: state.configExists\n ? `Added agent \"${payload.agent.id}\" to your team.`\n : `Initialized your team with first agent \"${payload.agent.id}\".`,\n nextSteps,\n backupPath,\n }\n}\n\nfunction splitMentions(s: string): string[] {\n return (s || \"\")\n .split(/[,\\s]+/)\n .map((m) => m.trim())\n .filter(Boolean)\n // Normalise: ensure @-prefix entries stay, plain ones are kept as-is.\n .filter((m, i, a) => a.indexOf(m) === i)\n}\n\nfunction slugify(s: string): string {\n return (s || \"\").toLowerCase().replace(/[^a-z0-9-]+/g, \"-\").replace(/^-+|-+$/g, \"\")\n}\n\nfunction buildFreshConfig(payload: WizardPayload, workspaceDir: string, mentions: string[], telegramTokenRef?: string) {\n const id = slugify(payload.nodeName) || \"team\"\n const cfg: any = {\n node: { id, name: payload.nodeName, bind: \"127.0.0.1:18800\", defaultAgent: payload.agent.id },\n providers: { claude: { apiKey: \"${ANTHROPIC_API_KEY}\" } },\n agents: { [payload.agent.id]: agentBlock(payload, workspaceDir, mentions) },\n channels: {},\n crons: {},\n mesh: { enabled: false, peers: [], discovery: \"static\", healthCheck: { interval: 60, timeout: 10 } },\n dashboard: { enabled: true, port: 4202, bind: \"127.0.0.1\", daemonUrl: \"http://localhost:18800\" },\n boards: [],\n }\n if (payload.telegram && telegramTokenRef) {\n cfg.channels.telegram = {\n enabled: true,\n accounts: { [payload.telegram.accountId]: telegramAccountBlock(payload, telegramTokenRef) },\n policy: { dm: \"pair\", group: \"mention-required\" },\n }\n } else {\n cfg.channels.telegram = { enabled: false, accounts: {}, policy: { dm: \"pair\", group: \"mention-required\" } }\n }\n return cfg\n}\n\nfunction agentBlock(payload: WizardPayload, workspaceDir: string, mentions: string[]) {\n const block: any = {\n name: payload.agent.name,\n workspace: workspaceDir,\n tier: payload.agent.tier,\n mentions,\n maxConcurrent: 2,\n permissionMode: \"default\",\n }\n if (payload.agent.model) block.model = payload.agent.model\n if (payload.agent.personality?.trim()) block.systemPrompt = payload.agent.personality.trim().slice(0, 400)\n return block\n}\n\nfunction telegramAccountBlock(payload: WizardPayload, tokenRef: string) {\n // Field names must match telegramAccountSchema (src/daemon/config.ts):\n // token: z.string() — NOT \"botToken\"\n // agentBinding: z.string()\n // Zod silently strips unknown keys, so writing \"botToken\" produced\n // configs that failed validation with `token: Required` even when the\n // operator had TG_<AGENT>_BOT_TOKEN set in .env.\n void payload.telegram?.botUsername // collected by the form but not in the schema; intentional drop.\n return {\n token: \"${\" + tokenRef + \"}\",\n agentBinding: payload.agent.id,\n }\n}\n\nfunction ensureEnvEntries(envPath: string, payload: WizardPayload, telegramTokenRef?: string): void {\n const existing = existsSync(envPath) ? readFileSync(envPath, \"utf-8\") : \"\"\n const lines: string[] = []\n\n if (payload.anthropicApiKey && !existing.includes(\"ANTHROPIC_API_KEY=\")) {\n lines.push(`ANTHROPIC_API_KEY=${payload.anthropicApiKey}`)\n }\n if (payload.telegram && telegramTokenRef && !existing.includes(`${telegramTokenRef}=`)) {\n lines.push(`${telegramTokenRef}=${payload.telegram.botToken}`)\n }\n\n if (!existsSync(envPath)) {\n const header = [\n \"# AgentX environment variables\",\n \"# (Never commit this file — it contains secrets.)\",\n \"\",\n ]\n writeFileSync(envPath, [...header, ...lines, \"\"].join(\"\\n\"))\n return\n }\n if (lines.length > 0) {\n const sep = existing.endsWith(\"\\n\") ? \"\" : \"\\n\"\n appendFileSync(envPath, sep + lines.join(\"\\n\") + \"\\n\")\n }\n}\n\n// --- HTTP handlers used by board-dashboard.ts ---\n\nexport function handleWizardGet(_req: IncomingMessage, res: ServerResponse): void {\n const state = wizardState()\n const defaultNode = state.nodeName || hostname().replace(/\\.local$/, \"\")\n const html = renderSetupPage(state, defaultNode)\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" })\n res.end(html)\n}\n\nexport async function handleWizardPost(req: IncomingMessage, res: ServerResponse): Promise<void> {\n let raw = \"\"\n await new Promise<void>((ok) => { req.on(\"data\", (c) => { raw += c }); req.on(\"end\", () => ok()) })\n let payload: WizardPayload\n try { payload = JSON.parse(raw) }\n catch { res.writeHead(400, { \"Content-Type\": \"application/json\" }); res.end(JSON.stringify({ error: \"Invalid JSON\" })); return }\n try {\n const result = runWizard(payload)\n res.writeHead(200, { \"Content-Type\": \"application/json\" })\n res.end(JSON.stringify(result))\n } catch (e: any) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" })\n res.end(JSON.stringify({ error: e.message || \"wizard failed\" }))\n }\n}\n\n/**\n * POST /api/setup/start-daemon — fork `agentx daemon start` from the wizard's\n * success page so non-technical operators don't have to switch to a terminal.\n *\n * Spawns detached so the daemon survives the wizard process exiting, then\n * polls the daemon URL until it answers (or we hit the timeout). Returns the\n * resolved URL on success, or the underlying error + the path the operator\n * should hit manually on failure.\n */\nexport async function handleStartDaemonPost(_req: IncomingMessage, res: ServerResponse): Promise<void> {\n res.setHeader(\"Content-Type\", \"application/json\")\n let bind: string\n try {\n const cfg = loadDaemonConfig()\n bind = cfg.node?.bind || \"127.0.0.1:18800\"\n } catch (e: any) {\n res.writeHead(400)\n res.end(JSON.stringify({ ok: false, error: `Config validation failed: ${e.message}` }))\n return\n }\n\n const url = `http://${bind.replace(/^0\\.0\\.0\\.0/, \"127.0.0.1\")}`\n // Already up? (Idempotent — clicking the button twice is harmless.)\n if (await probe(url)) {\n res.writeHead(200)\n res.end(JSON.stringify({ ok: true, url, alreadyRunning: true }))\n return\n }\n\n // dist/cli.js sits beside this file's compiled chunk. Use process.argv[1]\n // when available — that's the entrypoint the user invoked, which works for\n // both `agentx setup` (resolves to dist/cli.js) and `tsx src/cli.ts` in dev.\n const cli = process.argv[1] || resolve(dirname(fileURLToPath(import.meta.url)), \"cli.js\")\n try {\n const child = spawn(process.execPath, [cli, \"daemon\", \"start\"], {\n detached: true,\n stdio: \"ignore\",\n cwd: process.cwd(),\n })\n child.unref()\n } catch (e: any) {\n res.writeHead(500)\n res.end(JSON.stringify({ ok: false, error: `Failed to spawn daemon: ${e.message}`, manualUrl: url }))\n return\n }\n\n // Poll for up to ~12s. Daemon boot covers .env load, config parse, mesh\n // discovery, and bot registration — usually under 4s on a clean install.\n const deadline = Date.now() + 12_000\n while (Date.now() < deadline) {\n await new Promise((ok) => setTimeout(ok, 400))\n if (await probe(url)) {\n res.writeHead(200)\n res.end(JSON.stringify({ ok: true, url, alreadyRunning: false }))\n return\n }\n }\n\n res.writeHead(504)\n res.end(JSON.stringify({\n ok: false,\n error: \"Daemon spawn succeeded but never bound the port within 12s — check `agentx daemon status` and the dotfile log for errors.\",\n manualUrl: url,\n }))\n}\n\nasync function probe(baseUrl: string): Promise<boolean> {\n try {\n const r = await fetch(baseUrl, { method: \"GET\", signal: AbortSignal.timeout(800) })\n return r.status > 0 && r.status < 600\n } catch { return false }\n}\n","import { existsSync, readFileSync, writeFileSync, copyFileSync } from \"fs\"\nimport { resolve } from \"path\"\nimport { loadDaemonConfig } from \"./config\"\n\n// --- Shared helpers for safe agentx.json mutation ---\n//\n// Multiple CLI commands and the dashboard admin UI all need to read → tweak →\n// write agentx.json without corrupting it on failure. This module owns the\n// atomic-write + backup + best-effort-reload pattern so every caller gets the\n// same guarantees.\n\nexport interface MutateOptions {\n /** Absolute path to the target agentx.json. Defaults to ./agentx.json. */\n configPath?: string\n /** When true, don't write a timestamped backup. Use for operations that are\n * intrinsically reversible (or when the caller already took a snapshot). */\n skipBackup?: boolean\n /** When true, don't POST /reload after writing. Handy in tests. */\n skipReload?: boolean\n}\n\nexport interface MutateResult<T = void> {\n summary: string\n payload?: T\n}\n\n/**\n * Read agentx.json, let the mutator tweak it in-place, then atomically write\n * the result back to disk. The mutator returns a short human-readable summary\n * of what changed and may optionally return a payload for the caller to relay.\n *\n * If the mutator throws, nothing is written. If writing succeeds but the file\n * doesn't round-trip as JSON, we restore from backup and rethrow.\n */\nexport function mutateAgentxConfig<T = void>(\n mutator: (cfg: any) => MutateResult<T> | string,\n opts: MutateOptions = {},\n): { summary: string; payload?: T; backupPath?: string } {\n const file = opts.configPath || resolve(process.cwd(), \"agentx.json\")\n if (!existsSync(file)) throw new Error(`agentx.json not found at ${file}`)\n\n const cfg = JSON.parse(readFileSync(file, \"utf-8\"))\n const raw = mutator(cfg)\n const result: MutateResult<T> = typeof raw === \"string\" ? { summary: raw } : raw\n\n const json = JSON.stringify(cfg, null, 2) + \"\\n\"\n const tmp = file + \".tmp\"\n writeFileSync(tmp, json, \"utf-8\")\n try {\n JSON.parse(readFileSync(tmp, \"utf-8\"))\n } catch (e: any) {\n throw new Error(`config did not round-trip cleanly: ${e.message}`)\n }\n\n let backupPath: string | undefined\n if (!opts.skipBackup) {\n backupPath = `${file}.bak.${Date.now()}`\n copyFileSync(file, backupPath)\n }\n writeFileSync(file, json, \"utf-8\")\n\n if (!opts.skipReload) triggerLocalReload().catch(() => { /* daemon may be off */ })\n\n return { summary: result.summary, payload: result.payload, backupPath }\n}\n\n/**\n * Write a fresh agentx.json from scratch. Used by the setup wizard on a truly\n * empty working directory. Fails if a file already exists (callers must pass\n * the overwrite flag explicitly — we don't want to silently clobber an\n * operator's hand-written config).\n */\nexport function writeAgentxConfig(\n cfg: unknown,\n opts: { configPath?: string; overwrite?: boolean } = {},\n): { file: string } {\n const file = opts.configPath || resolve(process.cwd(), \"agentx.json\")\n if (existsSync(file) && !opts.overwrite) {\n throw new Error(`agentx.json already exists at ${file}. Pass overwrite=true to replace it.`)\n }\n writeFileSync(file, JSON.stringify(cfg, null, 2) + \"\\n\", \"utf-8\")\n return { file }\n}\n\n/**\n * POST to the primary daemon's /reload endpoint so it picks up config changes\n * without a full restart. Silently no-ops if the daemon isn't running.\n */\nasync function triggerLocalReload(): Promise<void> {\n try {\n const cfg = loadDaemonConfig()\n const url = cfg.dashboard.daemonUrl?.replace(/\\/+$/, \"\") || \"http://127.0.0.1:18800\"\n await fetch(`${url}/reload`, { method: \"POST\" }).catch(() => null)\n } catch { /* config didn't load — leave it */ }\n}\n","// --- Setup wizard page ---\n//\n// First-run flow for non-technical operators: team name, first agent,\n// optional Telegram, optional Anthropic key. Writes agentx.json, scaffolds\n// the agent's workspace, writes .env, and points the operator at the next\n// step.\n//\n// The server-side state machine + form handler live in ../../setup-wizard.ts\n// — this file owns ONLY the HTML. That keeps the data flow inspectable\n// (one place) and the visual surface hot-reloadable (edit → rebuild → view).\n\nimport { renderShell, esc, stepCard, field, row, btn } from \"..\"\nimport type { WizardState } from \"../../setup-wizard\"\n\nexport function renderSetupPage(state: WizardState, defaultNode: string): string {\n const heading = state.configExists\n ? (state.agentCount === 0 ? \"Add your first agent\" : \"Add another agent\")\n : \"Set up your team\"\n\n // Custom topbar: /setup is pre-dashboard, we skip the tab nav and show\n // just brand + subtitle + theme switcher + \"Skip to dashboard\" pill.\n const customHeader = `<header class=\"ax-topbar\">\n <div class=\"ax-topbar__left\">\n <div class=\"ax-brand\">\n <span class=\"ax-brand__mark\">AX</span>\n <span class=\"ax-brand__name\">AgentX</span>\n <span class=\"ax-brand__subtitle\">Setup</span>\n </div>\n </div>\n <div class=\"ax-topbar__right\">\n <a href=\"/glossary\" class=\"ax-skip\">? Glossary</a>\n <a href=\"/live\" class=\"ax-skip\">Skip — open dashboard</a>\n <div class=\"ax-theme-switch\" role=\"tablist\" aria-label=\"Theme\">\n <button data-theme-opt=\"dark\">Dark</button>\n <button data-theme-opt=\"light\">Light</button>\n </div>\n </div>\n</header>`\n\n const step1 = stepCard(1, \"Team basics\",\n field({\n name: \"nodeName\",\n label: \"Team name\",\n hint: \"(what you'd call this AgentX install)\",\n value: defaultNode,\n placeholder: \"My Team\",\n required: true,\n })\n )\n\n const step2 = stepCard(2, \"First agent\",\n row([\n field({ name: \"agentName\", label: \"Agent name\", value: \"Assistant\", placeholder: \"Support Bot\", required: true }),\n field({ name: \"agentId\", label: \"Agent id\", hint: \"(lowercase, no spaces)\", value: \"assistant\", pattern: \"[a-z0-9][a-z0-9_-]*\", required: true }),\n ]) +\n field({\n name: \"triggerWords\",\n label: \"Trigger words\",\n hint: `(comma or space separated — e.g. <code>@support, support</code>)`,\n value: \"@assistant, assistant\",\n required: true,\n }) +\n row([\n field({\n name: \"tier\",\n label: \"AI engine\",\n type: \"select\",\n options: [\n { value: \"claude-code\", label: \"Claude Code (recommended)\", selected: true },\n { value: \"codex-cli\", label: \"Codex CLI\" },\n { value: \"opencode\", label: \"OpenCode CLI\" },\n { value: \"sdk\", label: \"Anthropic API (BYO key)\" },\n { value: \"orchestrator\", label: \"Orchestrator (any provider)\" },\n ],\n }),\n field({\n name: \"model\",\n label: \"Model\",\n hint: \"(optional)\",\n value: \"claude-sonnet-4-6\",\n placeholder: \"claude-sonnet-4-6\",\n }),\n ]) +\n field({\n name: \"personality\",\n label: \"Personality / instructions\",\n hint: \"(optional — what this agent does, in plain English)\",\n type: \"textarea\",\n placeholder: \"You are a support agent for Acme Co. Answer customer questions about our product, be friendly, keep replies short.\",\n })\n )\n\n const step3 = stepCard(3, \"First channel\", `\n <label class=\"ax-toggle\"><input type=\"checkbox\" id=\"enableTelegram\" /> Connect Telegram now</label>\n <div class=\"ax-optional\" id=\"telegramFields\">\n ${field({ name: \"telegramAccountId\", label: \"Account id\", hint: `(a label you choose — e.g. <code>support</code>)`, value: \"default\" })}\n ${field({ name: \"telegramBotToken\", label: \"Bot token\", hint: `(from <a href=\"https://t.me/BotFather\" target=\"_blank\">@BotFather</a>)`, placeholder: \"123456:ABCdef...\" })}\n ${field({ name: \"telegramBotUsername\", label: \"Bot username\", hint: `(optional — e.g. <code>my_support_bot</code>)`, placeholder: \"my_support_bot\" })}\n </div>\n `)\n\n const step4 = stepCard(4, \"Anthropic API key\",\n field({\n name: \"anthropicApiKey\",\n label: \"API key\",\n hint: \"(optional — skip if you're using Claude Code)\",\n type: \"password\",\n placeholder: \"sk-ant-…\",\n extraAttrs: `autocomplete=\"off\"`,\n }) +\n `<div class=\"ax-hint-block\">\n The key is stored in <code>.env</code> as <code>ANTHROPIC_API_KEY</code> and used to authenticate requests to Anthropic. Keep it private.\n </div>`\n )\n\n const banner = state.configExists\n ? `<div class=\"ax-banner\">Existing install: <b>${state.agentCount}</b> agent(s), <b>${state.channelCount}</b> channel(s) already configured. This wizard will add to it.</div>`\n : \"\"\n\n const body = `<div class=\"ax-wizard\">\n <h1 class=\"ax-wizard__h1\">${esc(heading)}</h1>\n <p class=\"ax-wizard__lead\">Fill in the basics below. We'll write <code>agentx.json</code>, set up a folder for your first agent, and point you at the next step.</p>\n\n ${banner}\n\n <div id=\"msg\" class=\"ax-msg\"></div>\n\n <form id=\"wizard\" autocomplete=\"off\">\n ${step1}\n ${step2}\n ${step3}\n ${step4}\n <footer class=\"ax-actions\">\n ${btn(\"Save and continue\", { type: \"submit\", primary: true, id: \"submitBtn\" })}\n ${btn(\"Skip, I'll do it later\", { onclick: \"window.location.href='/live'\" })}\n </footer>\n </form>\n</div>`\n\n return renderShell({\n title: \"AgentX — Setup\",\n activeTab: \"custom\",\n subtitle: \"Setup\",\n customHeader,\n noMain: true,\n body,\n css: SETUP_PAGE_CSS,\n scripts: SETUP_SCRIPT,\n })\n}\n\n/** CSS that's specific to the setup page — wizard layout + optional-fields\n * toggle + result messaging. Everything reusable (form fields, step cards,\n * buttons) comes from AX_COMPONENTS_CSS. */\nconst SETUP_PAGE_CSS = `\n/* Pre-dashboard topbar variant — no tab nav, the pills are the only chrome. */\n.ax-topbar__right a.ax-skip {\n padding: 4px 10px; border: 1px solid var(--ax-border-2); border-radius: 4px;\n color: var(--ax-text-2); font-size: var(--ax-fs-xs); text-decoration: none;\n}\n.ax-topbar__right a.ax-skip:hover { color: var(--ax-accent); border-color: var(--ax-accent); }\n\n/* Wizard frame */\n.ax-wizard { max-width: 680px; margin: 0 auto; padding: 36px 22px 80px; }\n.ax-wizard__h1 { font-size: 22px; font-weight: 600; margin: 0 0 4px; letter-spacing: -0.015em; }\n.ax-wizard__lead { color: var(--ax-muted); margin: 0 0 24px; font-size: var(--ax-fs); line-height: 1.55; }\n.ax-wizard__lead code { background: var(--ax-surface-2); padding: 1px 6px; border-radius: 3px; color: var(--ax-text); font-size: var(--ax-fs-sm); }\n\n/* Info banner (\"You already have N agents…\") */\n.ax-banner {\n background: color-mix(in oklch, var(--ax-accent) 10%, var(--ax-bg-elev));\n border: 1px solid color-mix(in oklch, var(--ax-accent) 30%, var(--ax-border-2));\n border-radius: var(--ax-radius);\n padding: 10px 14px; margin-bottom: 18px;\n color: var(--ax-text-2); font-size: var(--ax-fs-sm);\n}\n.ax-banner b { color: var(--ax-text); font-weight: 600; }\n\n/* \"Connect Telegram now\" toggle + collapsible fields */\n.ax-toggle { display: flex; align-items: center; gap: 8px; margin: 4px 0 6px; font-size: var(--ax-fs); color: var(--ax-text); cursor: pointer; user-select: none; }\n.ax-toggle input { width: auto; accent-color: var(--ax-accent); }\n.ax-optional { border-left: 2px solid var(--ax-border-2); padding-left: 14px; margin-top: 10px; display: none; }\n.ax-optional.is-show { display: block; }\n.ax-hint-block { font-size: var(--ax-fs-xs); color: var(--ax-muted); margin-top: 8px; line-height: 1.55; }\n.ax-hint-block code { background: var(--ax-surface-2); padding: 1px 6px; border-radius: 3px; color: var(--ax-text); font-family: var(--ax-mono); font-size: var(--ax-fs-xs); }\n\n/* Form footer */\n.ax-actions {\n display: flex; gap: 10px; padding: 20px 0 0; align-items: center;\n border-top: 1px solid var(--ax-border); margin-top: 20px;\n}\n\n/* Server-response messaging (success / error blocks) */\n.ax-msg { margin: 14px 0; padding: 12px 16px; border-radius: var(--ax-radius); font-size: var(--ax-fs); display: none; }\n.ax-msg.is-ok {\n display: block;\n background: color-mix(in oklch, var(--ax-accent) 12%, transparent);\n color: var(--ax-accent);\n border: 1px solid color-mix(in oklch, var(--ax-accent) 40%, transparent);\n}\n.ax-msg.is-err {\n display: block;\n background: color-mix(in oklch, var(--ax-err) 12%, transparent);\n color: var(--ax-err);\n border: 1px solid color-mix(in oklch, var(--ax-err) 40%, transparent);\n}\n.ax-next-steps { margin-top: 12px; padding-left: 20px; color: var(--ax-text-2); }\n.ax-next-steps li { margin: 4px 0; }\n.ax-next-steps code { background: var(--ax-surface-2); padding: 1px 6px; border-radius: 3px; color: var(--ax-text); font-family: var(--ax-mono); font-size: var(--ax-fs-sm); }\n.ax-startd { margin-top: 14px; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }\n.ax-startd__status { color: var(--ax-text-2); font-size: var(--ax-fs-sm); }\n.ax-startd__status a { color: var(--ax-accent); }`\n\nconst SETUP_SCRIPT = `<script>\ndocument.getElementById('enableTelegram').addEventListener('change', (e) => {\n document.getElementById('telegramFields').classList.toggle('is-show', e.target.checked);\n});\ndocument.getElementById('wizard').addEventListener('submit', async (e) => {\n e.preventDefault();\n const f = e.target;\n const msg = document.getElementById('msg');\n const btn = document.getElementById('submitBtn');\n msg.className = 'ax-msg'; msg.style.display = 'none';\n btn.disabled = true; btn.textContent = 'Saving…';\n const telegramEnabled = document.getElementById('enableTelegram').checked;\n const payload = {\n nodeName: f.nodeName.value.trim(),\n agent: {\n id: f.agentId.value.trim(),\n name: f.agentName.value.trim(),\n triggerWords: f.triggerWords.value.trim(),\n tier: f.tier.value,\n model: f.model.value.trim() || undefined,\n personality: f.personality.value.trim() || undefined,\n },\n anthropicApiKey: f.anthropicApiKey.value.trim() || undefined,\n };\n if (telegramEnabled) {\n payload.telegram = {\n accountId: f.telegramAccountId.value.trim() || 'default',\n botToken: f.telegramBotToken.value.trim(),\n botUsername: f.telegramBotUsername.value.trim() || undefined,\n };\n if (!payload.telegram.botToken) {\n msg.className = 'ax-msg is-err'; msg.textContent = 'Bot token is required when Telegram is enabled.';\n btn.disabled = false; btn.textContent = 'Save and continue'; return;\n }\n }\n try {\n const r = await fetch('/api/setup', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'agentx-wizard' },\n body: JSON.stringify(payload),\n });\n const data = await r.json();\n if (!r.ok) throw new Error(data.error || ('HTTP ' + r.status));\n const steps = data.nextSteps.map((s) => '<li>' + s.replace(/\\\\\\`([^\\\\\\`]+)\\\\\\`/g, '<code>$1</code>') + '</li>').join('');\n msg.className = 'ax-msg is-ok';\n msg.innerHTML = '<b>' + data.summary + '</b><ol class=\"ax-next-steps\">' + steps + '</ol>'\n + '<div class=\"ax-startd\"><button type=\"button\" id=\"startDaemonBtn\" class=\"ax-btn ax-btn--primary\">Start daemon now</button>'\n + ' <span id=\"startDaemonStatus\" class=\"ax-startd__status\"></span></div>';\n btn.textContent = 'Done';\n btn.disabled = true;\n document.getElementById('startDaemonBtn').addEventListener('click', async () => {\n const sb = document.getElementById('startDaemonBtn');\n const ss = document.getElementById('startDaemonStatus');\n sb.disabled = true; sb.textContent = 'Starting…'; ss.textContent = '';\n try {\n const r = await fetch('/api/setup/start-daemon', { method: 'POST' });\n const d = await r.json();\n if (d.ok) {\n sb.textContent = d.alreadyRunning ? 'Already running' : 'Daemon up';\n ss.innerHTML = 'Open <a href=\"' + d.url + '\" target=\"_blank\" rel=\"noopener\">' + d.url + '</a>';\n } else {\n sb.disabled = false; sb.textContent = 'Try again';\n ss.textContent = d.error + (d.manualUrl ? ' Manual: ' + d.manualUrl : '');\n }\n } catch (e) {\n sb.disabled = false; sb.textContent = 'Try again';\n ss.textContent = e.message;\n }\n });\n } catch (err) {\n msg.className = 'ax-msg is-err'; msg.textContent = err.message;\n btn.disabled = false; btn.textContent = 'Save and continue';\n }\n});\n</script>`\n","import { existsSync, readFileSync } from \"fs\"\nimport { applyConfigMutation, findConfigPath, type MutationResult } from \"@/daemon/config-mutator\"\nimport { approvalsConfigSchema, expandEnvVars } from \"@/daemon/config\"\nimport type { ApprovalSettings } from \"./sweep\"\n\n// --- Approvals settings: read and change `approvals` in agentx.json ---\n//\n// Shared by `agentx approvals settings` and the dashboard's settings form,\n// so both validate the same way (through the config schema) and both\n// hot-reload the daemon.\n\nexport function readApprovalSettings(configPath?: string): ApprovalSettings {\n const path = findConfigPath(configPath)\n let raw: any = {}\n if (existsSync(path)) {\n try { raw = expandEnvVars(JSON.parse(readFileSync(path, \"utf-8\"))) } catch { raw = {} }\n }\n const parsed = approvalsConfigSchema.safeParse(raw?.approvals)\n return (parsed.success ? parsed.data : approvalsConfigSchema.parse(undefined)) as ApprovalSettings\n}\n\n/** What can be changed. `destination: null` clears it (back to notifications.destination). */\nexport interface ApprovalSettingsPatch {\n defaultExpiryDays?: number\n maxExpiryDays?: number\n laterHours?: number\n notifyAgent?: boolean\n /** The mesh peer that takes this node's cards; null clears it (cards stay here). */\n forwardTo?: string | null\n digestEnabled?: boolean\n digestTime?: string\n digestTimezone?: string | null\n destination?: { channel: string; chatId: string; accountId?: string } | null\n popupEnabled?: boolean\n popupSpeak?: boolean\n /** null clears it (back to the system voice). */\n popupVoice?: string | null\n /** \"\" for no sound. */\n popupSound?: string\n popupTimeoutSeconds?: number\n popupStyle?: \"card\" | \"dialog\"\n popupTheme?: \"system\" | \"light\" | \"dark\"\n checkinEnabled?: boolean\n checkinTimes?: string[]\n checkinDailyAt?: string\n checkinLists?: string[]\n /** null clears it. */\n checkinAgent?: string | null\n}\n\n/** \"channel:chatId\". Everything after the first \":\" is the chat id, which may contain \":\" itself. */\nexport function parseDestination(value: string): { channel: string; chatId: string; accountId?: string } | null {\n const i = value.indexOf(\":\")\n if (i <= 0 || i === value.length - 1) return null\n return { channel: value.slice(0, i).trim(), chatId: value.slice(i + 1).trim() }\n}\n\nexport async function updateApprovalSettings(\n patch: ApprovalSettingsPatch,\n opts: { configPath?: string; reload?: boolean } = {},\n): Promise<MutationResult> {\n return applyConfigMutation((cfg) => {\n const a = (cfg.approvals ??= {})\n if (patch.defaultExpiryDays !== undefined) a.defaultExpiryDays = patch.defaultExpiryDays\n if (patch.maxExpiryDays !== undefined) a.maxExpiryDays = patch.maxExpiryDays\n if (patch.laterHours !== undefined) a.laterHours = patch.laterHours\n if (patch.notifyAgent !== undefined) a.notifyAgent = patch.notifyAgent\n if (patch.forwardTo === null) delete a.forwardTo\n else if (patch.forwardTo !== undefined) {\n const peers: Array<{ name?: string }> = Array.isArray(cfg.mesh?.peers) ? cfg.mesh.peers : []\n if (!peers.some((p) => p.name === patch.forwardTo)) {\n throw new Error(`\"${patch.forwardTo}\" is not in mesh.peers${peers.length ? ` (known: ${peers.map((p) => p.name).join(\", \")})` : \"\"}; pair the machines first`)\n }\n a.forwardTo = patch.forwardTo\n }\n const d = (a.digest ??= {})\n if (patch.digestEnabled !== undefined) d.enabled = patch.digestEnabled\n if (patch.digestTime !== undefined) d.time = patch.digestTime\n if (patch.digestTimezone === null) delete d.timezone\n else if (patch.digestTimezone !== undefined) d.timezone = patch.digestTimezone\n if (patch.destination === null) delete d.destination\n else if (patch.destination !== undefined) d.destination = patch.destination\n const p = (a.popup ??= {})\n if (patch.popupEnabled !== undefined) p.enabled = patch.popupEnabled\n if (patch.popupSpeak !== undefined) p.speak = patch.popupSpeak\n if (patch.popupVoice === null) delete p.voice\n else if (patch.popupVoice !== undefined) p.voice = patch.popupVoice\n if (patch.popupSound !== undefined) p.sound = patch.popupSound\n if (patch.popupTimeoutSeconds !== undefined) p.timeoutSeconds = patch.popupTimeoutSeconds\n if (patch.popupStyle !== undefined) p.style = patch.popupStyle\n if (patch.popupTheme !== undefined) p.theme = patch.popupTheme\n const c = (a.checkin ??= {})\n if (patch.checkinEnabled !== undefined) c.enabled = patch.checkinEnabled\n if (patch.checkinTimes !== undefined) c.times = patch.checkinTimes\n if (patch.checkinDailyAt !== undefined) c.dailyAt = patch.checkinDailyAt\n if (patch.checkinLists !== undefined) c.lists = patch.checkinLists\n if (patch.checkinAgent === null) delete c.agent\n else if (patch.checkinAgent !== undefined) c.agent = patch.checkinAgent\n const days = a.defaultExpiryDays ?? 3\n const max = a.maxExpiryDays ?? 30\n if (days > max) throw new Error(`defaultExpiryDays (${days}) can't be more than maxExpiryDays (${max})`)\n }, { configPath: opts.configPath, reload: opts.reload })\n}\n","import { createServer, type IncomingMessage, type ServerResponse } from \"http\"\nimport { markdownToHtml } from \"@/utils/markdown-html\"\nimport { WikiStore } from \"./store\"\nimport { WikiHub } from \"./hub\"\nimport { MeshWikiClient } from \"./mesh\"\nimport type { WikiPeer } from \"./article-sync\"\nimport type { AgentWikiSummary } from \"./hub\"\nimport { OntologyRoutes } from \"./ontology/routes\"\n\n// --- Lightweight Markdown → HTML (no deps) ---\n\nfunction escapeHtml(s: string): string {\n return s.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\")\n}\n\n/**\n * Strip legacy section-tag comments from the article body. The old absorb\n * prompt told the LLM to add `<!-- tags: runbook, staging -->` inside\n * sections; in the Farzapedia-aligned design, these are no longer\n * load-bearing and leak through as visible literal text once escaped.\n */\nfunction stripSectionTags(text: string): string {\n return text.replace(/<!--\\s*tags?:[^>]*-->\\s*\\n?/gi, \"\")\n}\n\n/** Render a single tag as a clickable link to the tag-filter route. */\nfunction tagLink(tag: string, agentId?: string): string {\n const href = agentId\n ? `/agent/${encodeURIComponent(agentId)}/tag/${encodeURIComponent(tag)}`\n : `/tag/${encodeURIComponent(tag)}`\n return `<a href=\"${href}\" class=\"tag\">${escapeHtml(tag)}</a>`\n}\n\n/** Render an array of tags as clickable links, space-separated. */\nfunction tagLinks(tags: string[] | undefined, agentId?: string): string {\n return (tags || []).map(t => tagLink(t, agentId)).join(\" \")\n}\n\n/**\n * Resolve the body of a `[[...]]` wikilink to a relative article path.\n *\n * Authors write wikilinks three ways: by title, by path (without `.md`), or\n * by full path (with `.md`). wikiArticles is a title→path map, so we build\n * a path-set on first call and try several normalisations:\n *\n * 1. Exact title lookup (handles [[My Article]])\n * 2. Exact path lookup (handles [[people/alex.md]])\n * 3. Path + \".md\" suffix (handles [[people/alex]])\n * 4. Case-insensitive title scan (forgives minor casing drift)\n *\n * Return the path if any matches, else undefined so the caller can render\n * a broken-link marker.\n */\nfunction resolveWikilink(target: string, wikiArticles: Map<string, string>): string | undefined {\n if (!target) return undefined\n // (1) exact title\n const byTitle = wikiArticles.get(target)\n if (byTitle) return byTitle\n\n // (2) + (3) path lookups\n const pathSet = new Set(wikiArticles.values())\n if (pathSet.has(target)) return target\n const withExt = target.endsWith('.md') ? target : `${target}.md`\n if (pathSet.has(withExt)) return withExt\n\n // (4) case-insensitive title fallback — common when the user writes\n // \"Alex Rivera\" but the canonical title is \"alex rivera\".\n const targetLower = target.toLowerCase()\n for (const [title, path] of wikiArticles) {\n if (title.toLowerCase() === targetLower) return path\n }\n return undefined\n}\n\n/** Wiki-flavoured markdown: the shared renderer plus [[wikilink]] resolution\n * and section-tag stripping, which only articles carry. */\nfunction md(text: string, wikiArticles: Map<string, string>, agentPrefix: string = \"\"): string {\n return markdownToHtml(stripSectionTags(text), {\n wikilink: (target, display) => {\n const path = resolveWikilink(target, wikiArticles)\n if (path) return `<a href=\"${agentPrefix}/article/${encodeURIComponent(path)}\" class=\"wikilink\">${display}</a>`\n return `<a href=\"${agentPrefix}/search?q=${encodeURIComponent(target)}\" class=\"wikilink broken\" title=\"Not found — click to search\">${display}</a>`\n },\n })\n}\n\n// --- CSS ---\n\nconst HEAD_FONTS = `<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n<link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n<link href=\"https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,300..600;1,6..72,300..600&family=Inter+Tight:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap\" rel=\"stylesheet\">`\n\n// Paper/ink editorial palette — warm neutrals, Newsreader display font,\n// Inter Tight for UI, JetBrains Mono for code/meta. Ported from the\n// /Users/you/Downloads/wiki mockup.\nconst CSS = `\n:root {\n --bg: #FAF8F3;\n --bg-raised: #FFFFFF;\n --bg-sunk: #F2EFE7;\n --bg-hover: #EFEBE0;\n --ink: #1A1915;\n --ink-2: #3D3A32;\n --muted: #6B6860;\n --muted-2: #96918A;\n --line: #E4DED0;\n --line-2: #D1CAB8;\n --accent: oklch(55% 0.14 45);\n --accent-soft: oklch(55% 0.14 45 / 0.10);\n --accent-hover: oklch(48% 0.14 45);\n --cool: oklch(55% 0.08 230);\n --cool-soft: oklch(55% 0.08 230 / 0.10);\n --ok: oklch(55% 0.10 145);\n --warn: oklch(60% 0.14 75);\n --err: oklch(55% 0.16 20);\n --font-display: 'Newsreader', Georgia, serif;\n --font-ui: 'Inter Tight', -apple-system, system-ui, sans-serif;\n --font-mono: 'JetBrains Mono', ui-monospace, Menlo, monospace;\n --sidebar-w: 260px;\n --topbar-h: 52px;\n --radius: 6px;\n --radius-sm: 4px;\n --radius-lg: 10px;\n --shadow-sm: 0 1px 2px rgba(26,25,21,0.04), 0 1px 1px rgba(26,25,21,0.03);\n --shadow-md: 0 4px 12px rgba(26,25,21,0.06), 0 2px 4px rgba(26,25,21,0.04);\n --shadow-lg: 0 12px 40px rgba(26,25,21,0.12), 0 4px 12px rgba(26,25,21,0.06);\n}\n[data-theme=\"dark\"] {\n --bg: #0F0E0C;\n --bg-raised: #1A1815;\n --bg-sunk: #07060A;\n --bg-hover: #22201C;\n --ink: #EBE7DD;\n --ink-2: #C9C4B7;\n --muted: #8B867B;\n --muted-2: #5E5A52;\n --line: #2A2822;\n --line-2: #3A3830;\n --accent: oklch(70% 0.16 45);\n --accent-soft: oklch(70% 0.16 45 / 0.14);\n --accent-hover: oklch(78% 0.16 45);\n --cool: oklch(70% 0.10 230);\n --cool-soft: oklch(70% 0.10 230 / 0.14);\n --ok: oklch(70% 0.14 145);\n --warn: oklch(75% 0.16 75);\n --err: oklch(68% 0.18 20);\n --shadow-sm: 0 1px 2px rgba(0,0,0,0.4);\n --shadow-md: 0 4px 12px rgba(0,0,0,0.5);\n --shadow-lg: 0 12px 40px rgba(0,0,0,0.7);\n}\n\n* { box-sizing: border-box; margin: 0; padding: 0; }\nhtml, body {\n background: var(--bg); color: var(--ink);\n font-family: var(--font-ui); font-size: 14px; line-height: 1.55;\n font-feature-settings: 'ss01','cv11';\n -webkit-font-smoothing: antialiased; min-height: 100vh;\n}\na { color: var(--accent); text-decoration: none; }\na:hover { color: var(--accent-hover); }\nbutton { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }\ninput, textarea, select { font: inherit; color: inherit; }\ncode, pre, .mono { font-family: var(--font-mono); font-size: 0.92em; }\n.display { font-family: var(--font-display); font-weight: 400; letter-spacing: -0.01em; }\n\n/* ——— App shell ——— */\n.app {\n display: grid;\n grid-template-columns: var(--sidebar-w) 1fr;\n grid-template-rows: var(--topbar-h) 1fr;\n min-height: 100vh;\n}\n.topbar {\n grid-column: 1 / -1;\n display: flex; align-items: center; gap: 16px; padding: 0 20px;\n background: var(--bg); border-bottom: 1px solid var(--line);\n position: sticky; top: 0; z-index: 20; backdrop-filter: blur(8px);\n}\n.topbar-logo {\n display: flex; align-items: center; gap: 10px;\n font-family: var(--font-display); font-size: 18px; color: var(--ink);\n width: calc(var(--sidebar-w) - 20px); padding-right: 12px;\n border-right: 1px solid var(--line); height: 100%;\n text-decoration: none;\n}\n.topbar-logo .mark {\n width: 22px; height: 22px; flex: 0 0 auto;\n display: inline-flex; align-items: center; justify-content: center;\n background: var(--accent); color: var(--bg-raised);\n border-radius: 5px; font-family: var(--font-mono);\n font-size: 11px; font-weight: 700;\n}\n.topbar-search {\n flex: 1; max-width: 520px;\n display: flex; align-items: center; gap: 8px; padding: 6px 12px;\n background: var(--bg-raised); border: 1px solid var(--line);\n border-radius: var(--radius); color: var(--muted);\n transition: border-color 0.15s, background 0.15s;\n}\n.topbar-search:focus-within { border-color: var(--line-2); background: var(--bg-hover); }\n.topbar-search input {\n flex: 1; border: 0; outline: 0; background: transparent;\n color: var(--ink); font: inherit;\n}\n.topbar-search input::placeholder { color: var(--muted); }\n.topbar-search kbd {\n font-family: var(--font-mono); font-size: 11px;\n padding: 2px 6px; border: 1px solid var(--line); border-radius: 3px;\n background: var(--bg); color: var(--muted);\n}\n.topbar-tools { margin-left: auto; display: flex; align-items: center; gap: 4px; }\n.icon-btn {\n width: 32px; height: 32px;\n display: inline-flex; align-items: center; justify-content: center;\n border-radius: var(--radius-sm); color: var(--muted);\n transition: background 0.15s, color 0.15s;\n}\n.icon-btn:hover { background: var(--bg-hover); color: var(--ink); }\n.icon-btn.active { color: var(--accent); background: var(--accent-soft); }\n.icon-btn svg { width: 16px; height: 16px; }\n\n/* ——— Sidebar ——— */\n.sidebar {\n grid-column: 1; grid-row: 2;\n background: var(--bg); border-right: 1px solid var(--line);\n padding: 16px 12px 40px; overflow-y: auto;\n position: sticky; top: var(--topbar-h);\n height: calc(100vh - var(--topbar-h));\n}\n.nav-section { margin-bottom: 20px; }\n.nav-section-title {\n display: flex; align-items: center; justify-content: space-between;\n padding: 4px 10px; font-size: 11px; font-weight: 600;\n text-transform: uppercase; letter-spacing: 0.06em;\n color: var(--muted); margin-bottom: 2px;\n}\n.nav-item {\n display: flex; align-items: center; gap: 8px;\n padding: 5px 10px; color: var(--ink-2);\n font-size: 13px; border-radius: var(--radius-sm);\n line-height: 1.35; cursor: pointer;\n transition: background 0.1s;\n text-decoration: none;\n}\n.nav-item:hover { background: var(--bg-hover); color: var(--ink); }\n.nav-item.active {\n background: var(--accent-soft); color: var(--accent); font-weight: 500;\n}\n.nav-item .count {\n margin-left: auto; font-family: var(--font-mono);\n font-size: 11px; color: var(--muted);\n}\n.nav-item.active .count { color: var(--accent); }\n.nav-agent-header {\n display: flex; align-items: center; gap: 8px;\n padding: 6px 10px; font-size: 13px; color: var(--ink);\n cursor: pointer; border-radius: var(--radius-sm);\n text-decoration: none;\n}\n.nav-agent-header:hover { color: var(--accent); background: var(--bg-hover); }\n.nav-agent-header .name { font-weight: 500; }\n.nav-agent-header .badge {\n margin-left: auto; font-family: var(--font-mono);\n font-size: 10.5px; color: var(--muted);\n}\n.nav-agent-type-label {\n padding: 6px 8px 2px; font-size: 10px;\n text-transform: uppercase; letter-spacing: 0.08em;\n color: var(--muted-2); font-weight: 600;\n}\n.nav-agent-children {\n padding-left: 14px; display: flex; flex-direction: column; gap: 1px;\n margin-top: 2px; border-left: 1px dashed var(--line); margin-left: 10px;\n}\n\n/* ——— Main ——— */\n.main {\n grid-column: 2; grid-row: 2;\n padding: 32px 48px 80px;\n max-width: 1180px; width: 100%;\n}\n.main.article { max-width: 1100px; }\n\n/* ——— Breadcrumb ——— */\n.breadcrumb {\n display: flex; align-items: center; gap: 6px;\n font-size: 12.5px; color: var(--muted);\n margin-bottom: 14px; font-family: var(--font-ui);\n}\n.breadcrumb a { color: var(--muted); }\n.breadcrumb a:hover { color: var(--accent); }\n.breadcrumb .sep { color: var(--muted-2); }\n.breadcrumb .current { color: var(--ink-2); }\n\n/* ——— Display heading ——— */\n.page-head {\n display: flex; align-items: flex-end; justify-content: space-between;\n gap: 24px; padding-bottom: 16px;\n border-bottom: 1px solid var(--line); margin-bottom: 28px;\n}\n.page-head h1 {\n font-family: var(--font-display); font-size: 38px;\n font-weight: 400; letter-spacing: -0.015em; line-height: 1.1;\n}\n.page-head .page-sub {\n font-size: 13.5px; color: var(--muted);\n margin-top: 6px; max-width: 60ch; line-height: 1.5;\n}\n.page-head .page-actions { display: flex; gap: 8px; flex: 0 0 auto; }\n\n/* ——— Buttons ——— */\n.btn {\n display: inline-flex; align-items: center; gap: 6px;\n padding: 6px 12px; font-size: 13px;\n color: var(--ink-2); background: var(--bg-raised);\n border: 1px solid var(--line); border-radius: var(--radius-sm);\n transition: all 0.1s; text-decoration: none;\n}\n.btn:hover { background: var(--bg-hover); border-color: var(--line-2); color: var(--ink); }\n.btn.primary { background: var(--ink); color: var(--bg); border-color: var(--ink); }\n.btn.primary:hover { background: var(--ink-2); color: var(--bg); }\n.btn.ghost { background: transparent; border-color: transparent; }\n.btn.ghost:hover { background: var(--bg-hover); }\n.btn svg { width: 14px; height: 14px; }\n\n/* ——— Stat strip ——— */\n.stats, .stat-strip {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));\n gap: 0;\n background: var(--bg-raised); border: 1px solid var(--line);\n border-radius: var(--radius); overflow: hidden;\n margin-bottom: 28px;\n}\n.stat-card, .stat-cell {\n padding: 16px 20px;\n border-right: 1px solid var(--line);\n display: flex; flex-direction: column; gap: 4px;\n background: transparent; text-align: left;\n}\n.stat-card:last-child, .stat-cell:last-child { border-right: none; }\n.stat-card .label, .stat-cell .label {\n font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em;\n color: var(--muted); font-weight: 600;\n}\n.stat-card .number, .stat-cell .number {\n font-family: var(--font-display); font-size: 32px; font-weight: 400;\n line-height: 1; color: var(--ink);\n}\n\n/* ——— Section heading ——— */\n.section-head, h2.section {\n display: flex; align-items: baseline; justify-content: space-between;\n margin: 40px 0 14px;\n}\n.section-head h2 {\n font-family: var(--font-display); font-size: 22px;\n font-weight: 400; letter-spacing: -0.01em; color: var(--ink);\n border: none; padding: 0;\n}\n\n/* ——— Agent grid (hub home) ——— */\n.agent-grid {\n display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));\n gap: 14px;\n}\n.agent-card {\n background: var(--bg-raised); border: 1px solid var(--line);\n border-radius: var(--radius); padding: 18px 20px;\n display: flex; flex-direction: column; gap: 12px;\n transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s;\n}\n.agent-card:hover {\n border-color: var(--line-2); box-shadow: var(--shadow-md);\n transform: translateY(-1px);\n}\n.agent-card h3 {\n font-family: var(--font-display); font-size: 20px; font-weight: 400;\n color: var(--ink); margin: 0;\n}\n.agent-card h3 a { color: inherit; text-decoration: none; }\n.agent-card h3 a:hover { color: var(--accent); }\n.agent-card .agent-stats {\n display: flex; gap: 20px; font-size: 13px; color: var(--muted);\n}\n.agent-card .agent-stats strong {\n color: var(--ink); font-weight: 600; font-family: var(--font-mono);\n}\n.agent-card .article-list {\n display: flex; flex-direction: column; gap: 4px; margin-top: 4px; font-size: 13px;\n}\n.agent-card .article-row {\n display: flex; flex-wrap: wrap; align-items: center; gap: 4px;\n padding: 2px 0;\n}\n.agent-card .article-row .article-title {\n color: var(--ink-2); text-decoration: none; margin-left: 4px; flex: 1;\n}\n.agent-card .article-row .article-title:hover { color: var(--accent); }\n\n/* ——— Tags ——— */\n.tag {\n display: inline-flex; align-items: center;\n font-family: var(--font-mono); font-size: 11.5px;\n padding: 1px 7px 2px; background: var(--bg-sunk);\n color: var(--ink-2); border-radius: 3px;\n line-height: 1.4; cursor: pointer;\n transition: background 0.1s, color 0.1s;\n text-decoration: none;\n}\n.tag:hover { background: var(--accent-soft); color: var(--accent); }\n.tag.lg { font-size: 12.5px; padding: 3px 10px; }\n\n/* ——— Article meta — inline dl below h1 ——— */\n.meta {\n background: var(--bg-raised); border: 1px solid var(--line);\n border-radius: var(--radius); padding: 14px 18px;\n margin-bottom: 24px; font-size: 13px;\n display: grid; grid-template-columns: auto 1fr;\n gap: 6px 18px;\n}\n.meta dt {\n font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.08em;\n color: var(--muted); font-weight: 600;\n align-self: center;\n}\n.meta dd { color: var(--ink-2); font-family: var(--font-mono); font-size: 12.5px; }\n\n/* ——— Prose body ——— */\n.prose {\n font-size: 15.5px; line-height: 1.65; color: var(--ink-2);\n max-width: 68ch;\n}\n.main h1, .prose h1 {\n font-family: var(--font-display); font-size: 40px;\n font-weight: 400; letter-spacing: -0.015em; line-height: 1.1;\n color: var(--ink); margin-bottom: 16px;\n border: none; padding: 0;\n}\n.main h2, .prose h2 {\n font-family: var(--font-display); font-size: 26px;\n font-weight: 400; letter-spacing: -0.01em;\n margin: 36px 0 12px; color: var(--ink);\n padding-bottom: 4px; border-bottom: 1px solid var(--line);\n}\n.main h3, .prose h3 {\n font-family: var(--font-display); font-size: 20px; font-weight: 500;\n margin: 28px 0 8px; color: var(--ink);\n}\n.main h4, .prose h4 {\n font-size: 15px; font-weight: 600; margin: 20px 0 6px; color: var(--ink);\n}\n.main p, .prose p { margin: 10px 0; }\n.main ul, .prose ul, .main ol, .prose ol { margin: 10px 0 10px 22px; }\n.main li, .prose li { margin: 4px 0; }\n.main code, .prose code {\n background: var(--bg-sunk); padding: 1px 5px; border-radius: 3px;\n font-family: var(--font-mono);\n}\n.main pre, .prose pre {\n background: var(--bg-sunk); border: 1px solid var(--line);\n border-radius: var(--radius-sm); padding: 14px 16px;\n overflow-x: auto; margin: 14px 0; font-size: 13px;\n}\n.main pre code, .prose pre code { background: none; padding: 0; }\n.main blockquote, .prose blockquote {\n border-left: 3px solid var(--accent);\n padding: 4px 0 4px 14px; color: var(--muted);\n font-style: italic; margin: 14px 0;\n}\n\n/* Wikilinks in prose */\n.prose a.wikilink, .main a.wikilink {\n color: var(--accent);\n text-decoration: underline;\n text-decoration-color: var(--accent-soft);\n text-underline-offset: 3px;\n text-decoration-thickness: 1.5px;\n}\n.prose a.wikilink:hover, .main a.wikilink:hover { text-decoration-color: var(--accent); }\n.prose a.wikilink.broken, .main a.wikilink.broken {\n color: var(--err); text-decoration-color: var(--err);\n text-decoration-style: dashed;\n}\n\n/* ——— Tables ——— */\ntable {\n width: 100%; border-collapse: collapse;\n margin: 14px 0; font-size: 14px;\n}\nth, td {\n border-bottom: 1px solid var(--line);\n padding: 8px 12px; text-align: left;\n}\nth {\n background: var(--bg-sunk); font-weight: 600;\n color: var(--ink); font-size: 12.5px;\n text-transform: uppercase; letter-spacing: 0.04em;\n}\ntr:hover td { background: var(--bg-hover); }\n\n/* ——— Entry cards ——— */\n.entry-card {\n background: var(--bg-raised); border: 1px solid var(--line);\n border-radius: var(--radius);\n padding: 14px 18px; margin: 10px 0;\n transition: border-color 0.15s, box-shadow 0.15s;\n}\n.entry-card:hover { border-color: var(--line-2); box-shadow: var(--shadow-sm); }\n.entry-card .meta-line {\n font-size: 11.5px; color: var(--muted);\n margin-bottom: 6px; font-family: var(--font-mono);\n}\n.entry-card h3 {\n font-family: var(--font-display); font-size: 19px; font-weight: 400;\n color: var(--ink); margin: 4px 0 6px;\n border: none; padding: 0;\n}\n.entry-card h3 a { color: inherit; }\n.entry-card h3 a:hover { color: var(--accent); }\n.entry-card p {\n color: var(--ink-2); font-size: 13.5px;\n line-height: 1.55; margin: 4px 0;\n}\n\n/* ——— Backlinks ——— */\n.backlinks {\n margin-top: 40px; padding: 16px 18px;\n background: var(--bg-raised); border: 1px solid var(--line);\n border-radius: var(--radius);\n}\n.backlinks h4 {\n font-size: 11px; text-transform: uppercase;\n letter-spacing: 0.08em; color: var(--muted);\n font-weight: 600; margin-bottom: 8px;\n}\n.backlinks ul { list-style: none; padding: 0; margin: 0; }\n.backlinks li { padding: 4px 0; font-size: 13.5px; }\n\n/* ——— Health issues list ——— */\n.health-list { display: flex; flex-direction: column; gap: 6px; }\n.health-row {\n display: grid; grid-template-columns: 96px 1fr 2fr;\n gap: 14px; align-items: center;\n padding: 10px 14px; background: var(--bg-raised);\n border: 1px solid var(--line); border-radius: var(--radius-sm);\n font-size: 13px;\n}\n.health-row .kind {\n font-family: var(--font-mono); font-size: 10.5px;\n text-transform: uppercase; letter-spacing: 0.06em;\n color: var(--muted);\n}\n.health-row .article { color: var(--ink); font-weight: 500; }\n.health-row .msg { color: var(--ink-2); }\n\n@media (max-width: 900px) {\n .app { grid-template-columns: 1fr; }\n .topbar-logo { width: auto; border-right: none; }\n .sidebar { display: none; }\n .main { padding: 20px; grid-column: 1; }\n}\n`\n\n// --- HTML Templates ---\n\nfunction pageLayout(title: string, sidebar: string, content: string, searchQuery: string = \"\"): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>${escapeHtml(title)} — AgentX Wiki</title>\n ${HEAD_FONTS}\n <style>${CSS}</style>\n <script>(function(){try{var t=localStorage.getItem('wiki-theme');if(t)document.documentElement.setAttribute('data-theme',t)}catch(e){}})();</script>\n</head>\n<body>\n <div class=\"app\">\n <header class=\"topbar\">\n <a href=\"/\" class=\"topbar-logo\">\n <span class=\"mark\">W</span>\n <span class=\"display\">AgentX Wiki</span>\n </a>\n <form class=\"topbar-search\" action=\"/search\" method=\"get\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"/><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"/></svg>\n <input type=\"search\" name=\"q\" placeholder=\"Search every wiki…\" value=\"${escapeHtml(searchQuery)}\" autocomplete=\"off\" />\n <kbd>⌘K</kbd>\n </form>\n <div class=\"topbar-tools\">\n <button class=\"icon-btn\" id=\"wiki-theme-toggle\" title=\"Toggle theme\" aria-label=\"Toggle theme\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z\"/></svg>\n </button>\n </div>\n </header>\n <nav class=\"sidebar\">${sidebar}</nav>\n <main class=\"main\">${content}</main>\n </div>\n <script>\n (function(){\n var btn = document.getElementById('wiki-theme-toggle');\n if (!btn) return;\n btn.addEventListener('click', function(){\n var cur = document.documentElement.getAttribute('data-theme') === 'dark' ? '' : 'dark';\n if (cur) document.documentElement.setAttribute('data-theme', 'dark');\n else document.documentElement.removeAttribute('data-theme');\n try { localStorage.setItem('wiki-theme', cur); } catch(e){}\n });\n // Cmd/Ctrl-K focuses search\n document.addEventListener('keydown', function(e){\n if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {\n e.preventDefault();\n var inp = document.querySelector('.topbar-search input');\n if (inp) inp.focus();\n }\n });\n })();\n </script>\n</body>\n</html>`\n}\n\n// --- Hub Mode (all agents) ---\n\nfunction groupByDir(articles: Array<{ title: string; path: string; tags?: string[] }>): Map<string, typeof articles> {\n const byDir = new Map<string, typeof articles>()\n for (const a of articles) {\n const dir = a.path.includes(\"/\") ? a.path.split(\"/\").slice(0, -1).join(\"/\") : \"/\"\n const list = byDir.get(dir) || []\n list.push(a)\n byDir.set(dir, list)\n }\n return new Map([...byDir].sort((a, b) => a[0].localeCompare(b[0])))\n}\n\nfunction dirLabel(dir: string): string {\n if (dir === \"/\") return \"Root\"\n return dir.split(\"/\").pop()!.replace(/-/g, \" \")\n}\n\nfunction hubSidebar(agents: AgentWikiSummary[], activePath?: string): string {\n let html = '<div class=\"nav-section\">'\n html += `<a class=\"nav-item${!activePath ? ' active' : ''}\" href=\"/\">Home</a>`\n html += `<a class=\"nav-item\" href=\"/entries\">All entries</a>`\n html += '</div>'\n\n for (const agent of agents) {\n const agentPrefix = `/agent/${encodeURIComponent(agent.agentId)}`\n html += '<div class=\"nav-section\">'\n html += `<a class=\"nav-agent-header\" href=\"${agentPrefix}\">`\n html += `<span class=\"name\">${escapeHtml(agent.agentId)}</span>`\n html += `<span class=\"badge\">${agent.totalArticles}</span>`\n html += `</a>`\n html += '<div class=\"nav-agent-children\">'\n\n const byType = groupByDir(agent.articles)\n for (const [type, articles] of byType) {\n html += `<div class=\"nav-agent-type-label\">${dirLabel(type)}</div>`\n for (const a of articles) {\n const fullPath = `${agent.agentId}/${a.path}`\n const isActive = fullPath === activePath\n html += `<a class=\"nav-item${isActive ? ' active' : ''}\" href=\"${agentPrefix}/article/${encodeURIComponent(a.path)}\">${escapeHtml(a.title)}</a>`\n }\n }\n html += '</div>'\n html += '</div>'\n }\n\n return html\n}\n\nfunction hubHome(hub: WikiHub, allAgents?: AgentWikiSummary[], remoteAgents?: Array<AgentWikiSummary & { nodeId: string }>): string {\n const agents = allAgents || hub.summary()\n const shared = hub.getSharedStore()\n const totalEntries = shared.listEntries().length\n const totalArticles = agents.reduce((s, a) => s + a.totalArticles, 0)\n const totalUnabsorbed = agents.reduce((s, a) => s + a.unabsorbed, 0)\n const remoteIds = new Set((remoteAgents || []).map(r => r.agentId))\n\n let content = `<div class=\"page-head\">\n <div>\n <h1>AgentX Wiki</h1>\n <p class=\"page-sub\">Agent-owned institutional knowledge, typed and cross-referenced. Everything here compiles from raw conversation entries through the nightly absorb pass.</p>\n </div>\n </div>`\n\n // Stat strip\n content += '<div class=\"stat-strip\">'\n content += `<div class=\"stat-cell\"><div class=\"label\">Agents</div><div class=\"number\">${agents.length}</div></div>`\n content += `<div class=\"stat-cell\"><div class=\"label\">Articles</div><div class=\"number\">${totalArticles}</div></div>`\n content += `<div class=\"stat-cell\"><div class=\"label\">Raw entries</div><div class=\"number\">${totalEntries}</div></div>`\n if (totalUnabsorbed > 0) {\n content += `<div class=\"stat-cell\"><div class=\"label\">Unabsorbed</div><div class=\"number\">${totalUnabsorbed}</div></div>`\n }\n if (remoteAgents && remoteAgents.length > 0) {\n const nodes = new Set(remoteAgents.map(r => r.nodeId))\n content += `<div class=\"stat-cell\"><div class=\"label\">Mesh nodes</div><div class=\"number\">${nodes.size}</div></div>`\n }\n content += '</div>'\n\n // Agent cards grid\n content += '<div class=\"section-head\"><h2>Agent wikis</h2></div>'\n content += '<div class=\"agent-grid\">'\n for (const agent of agents) {\n const statusChip = agent.unabsorbed > 0\n ? `<span class=\"tag\" style=\"color:var(--warn);background:color-mix(in oklch, var(--warn) 12%, transparent)\">${agent.unabsorbed} unabsorbed</span>`\n : `<span class=\"tag\" style=\"color:var(--ok);background:color-mix(in oklch, var(--ok) 12%, transparent)\">up to date</span>`\n\n const isRemote = remoteIds.has(agent.agentId) && !hub.listAgents().includes(agent.agentId)\n const remoteBadge = isRemote\n ? ` <span class=\"tag\" style=\"color:var(--cool);background:var(--cool-soft)\">remote</span>`\n : ''\n\n content += `<div class=\"agent-card\">`\n content += `<h3><a href=\"/agent/${encodeURIComponent(agent.agentId)}\">${escapeHtml(agent.agentId)}</a>${remoteBadge}</h3>`\n content += `<div class=\"agent-stats\">\n <span><strong>${agent.totalArticles}</strong> articles</span>\n <span><strong>${agent.totalEntries}</strong> entries</span>\n ${statusChip}\n </div>`\n\n if (agent.articles.length > 0) {\n content += '<div class=\"article-list\">'\n for (const a of agent.articles.slice(0, 6)) {\n const tagPart = tagLinks((a.tags || []).slice(0, 2), agent.agentId)\n content += `<div class=\"article-row\">${tagPart} <a class=\"article-title\" href=\"/agent/${encodeURIComponent(agent.agentId)}/article/${encodeURIComponent(a.path)}\">${escapeHtml(a.title)}</a></div>`\n }\n if (agent.articles.length > 6) {\n content += `<div class=\"article-row\"><a class=\"article-title\" style=\"color:var(--muted)\" href=\"/agent/${encodeURIComponent(agent.agentId)}\">+ ${agent.articles.length - 6} more →</a></div>`\n }\n content += '</div>'\n }\n content += '</div>'\n }\n content += '</div>'\n\n return pageLayout(\"Hub\", hubSidebar(agents), content)\n}\n\nfunction hubAgentOverview(hub: WikiHub, agentId: string, allAgents?: AgentWikiSummary[]): string {\n const agents = allAgents || hub.summary()\n const agentSummary = agents.find(a => a.agentId === agentId)\n if (!agentSummary) return pageLayout(\"Not Found\", hubSidebar(agents), \"<h1>Agent not found</h1>\")\n\n // Use summary articles (may come from remote peer if it has more)\n const isRemote = (agentSummary as any).peerUrl !== undefined\n const entries = hub.getAgentEntries(agentId)\n const articles = agentSummary.articles || []\n\n let content = `<nav class=\"breadcrumb\"><a href=\"/\">Hub</a> <span class=\"sep\">/</span> <span class=\"current\">${escapeHtml(agentId)}</span></nav>`\n content += `<div class=\"page-head\"><div><h1>${escapeHtml(agentId)}</h1>`\n if (isRemote) {\n content += `<p class=\"page-sub\"><span class=\"tag\" style=\"color:var(--cool);background:var(--cool-soft)\">remote @ ${escapeHtml((agentSummary as any).nodeId)}</span></p>`\n }\n content += `</div></div>`\n\n // Stats\n content += '<div class=\"stat-strip\">'\n content += `<div class=\"stat-cell\"><div class=\"label\">Articles</div><div class=\"number\">${agentSummary.totalArticles}</div></div>`\n content += `<div class=\"stat-cell\"><div class=\"label\">Entries</div><div class=\"number\">${agentSummary.totalEntries}</div></div>`\n content += `<div class=\"stat-cell\"><div class=\"label\">Unabsorbed</div><div class=\"number\">${agentSummary.unabsorbed}</div></div>`\n content += '</div>'\n\n // Articles grouped by type\n if (articles.length > 0) {\n content += '<div class=\"section-head\"><h2>Articles</h2><span class=\"mono\" style=\"font-size:12px;color:var(--muted)\">' + articles.length + ' total</span></div>'\n const byType = groupByDir(articles as Array<{ title: string; path: string; tags?: string[] }>)\n for (const [type, list] of byType) {\n content += `<h3 class=\"display\" style=\"font-size:17px;color:var(--muted);font-weight:500;margin:20px 0 8px\">${dirLabel(type)}</h3>`\n content += '<div class=\"agent-card\" style=\"padding:4px 14px\"><div class=\"article-list\">'\n for (const a of list) {\n content += `<div class=\"article-row\">${tagLinks(((a.tags || []) as string[]).slice(0, 3), agentId)} <a class=\"article-title\" href=\"/agent/${encodeURIComponent(agentId)}/article/${encodeURIComponent(a.path)}\">${escapeHtml(a.title)}</a></div>`\n }\n content += '</div></div>'\n }\n }\n\n // Recent entries\n const recent = entries.slice(-5).reverse()\n if (recent.length > 0) {\n content += '<div class=\"section-head\"><h2>Recent entries</h2><a class=\"btn ghost\" href=\"/entries\">See all →</a></div>'\n for (const e of recent) {\n content += `<div class=\"entry-card\">\n <div class=\"meta-line\">${e.date} · via ${escapeHtml(e.source)} · <code>${escapeHtml(e.id)}</code></div>\n <p>${escapeHtml(e.content.slice(0, 300))}${e.content.length > 300 ? \"…\" : \"\"}</p>\n </div>`\n }\n }\n\n // Lint\n const agentStore = hub.getAgentWiki(agentId)\n const issues = agentStore.lint()\n if (issues.length > 0) {\n content += `<div class=\"section-head\"><h2>Health issues</h2><span class=\"mono\" style=\"font-size:12px;color:var(--warn)\">${issues.length}</span></div>`\n content += '<div class=\"health-list\">'\n for (const issue of issues) {\n content += `<div class=\"health-row\">\n <span class=\"kind\">${escapeHtml(issue.type)}</span>\n <span class=\"article\">${escapeHtml(issue.article)}</span>\n <span class=\"msg\">${escapeHtml(issue.message)}</span>\n </div>`\n }\n content += '</div>'\n }\n\n return pageLayout(agentId, hubSidebar(agents, agentId), content)\n}\n\nfunction hubArticlePage(hub: WikiHub, agentId: string, articlePath: string, allAgents?: AgentWikiSummary[]): string | null {\n const store = hub.getAgentWiki(agentId)\n const article = store.readArticle(articlePath)\n if (!article) return null\n\n const agents = allAgents || hub.summary()\n const index = store.rebuildIndex()\n const titleToPath = new Map<string, string>()\n for (const a of index.articles) titleToPath.set(a.title, a.path)\n\n const prefix = `/agent/${encodeURIComponent(agentId)}`\n const backlinks = store.buildBacklinks()\n const inbound = backlinks[article.meta.title] || []\n\n let content = `<nav class=\"breadcrumb\"><a href=\"/\">Hub</a> <span class=\"sep\">/</span> <a href=\"${prefix}\">${escapeHtml(agentId)}</a> <span class=\"sep\">/</span> <span class=\"current\">${escapeHtml(article.meta.title)}</span></nav>`\n content += `<article class=\"prose\"><h1>${escapeHtml(article.meta.title)}</h1>`\n\n // Meta box\n content += '<dl class=\"meta\">'\n if (article.meta.type) {\n content += `<dt>Type</dt><dd>${tagLink(article.meta.type, agentId)}</dd>`\n }\n if (article.meta.tags?.length) {\n content += `<dt>Tags</dt><dd>${tagLinks(article.meta.tags, agentId)}</dd>`\n }\n if (article.meta.owner) content += `<dt>Owner</dt><dd>${escapeHtml(article.meta.owner)}</dd>`\n content += `<dt>Created</dt><dd>${escapeHtml(article.meta.created || '—')}</dd>`\n content += `<dt>Updated</dt><dd>${escapeHtml(article.meta.lastUpdated || '—')}</dd>`\n if (article.meta.sources?.length) {\n content += `<dt>Sources</dt><dd>${article.meta.sources.length} entries</dd>`\n }\n content += '</dl>'\n\n content += md(article.content, titleToPath, prefix)\n\n if (inbound.length > 0) {\n content += '<div class=\"backlinks\"><h4>Pages that link here</h4><ul>'\n for (const link of inbound) {\n const linked = store.readArticle(link)\n content += `<li><a href=\"${prefix}/article/${encodeURIComponent(link)}\">${escapeHtml(linked?.meta.title || link)}</a></li>`\n }\n content += '</ul></div>'\n }\n content += `</article>`\n\n return pageLayout(article.meta.title, hubSidebar(agents, `${agentId}/${articlePath}`), content)\n}\n\nfunction hubEntries(hub: WikiHub, allAgents?: AgentWikiSummary[]): string {\n const agents = allAgents || hub.summary()\n const shared = hub.getSharedStore()\n const entries = shared.listEntries()\n\n let content = '<nav class=\"breadcrumb\"><a href=\"/\">Hub</a> <span class=\"sep\">/</span> <span class=\"current\">Entries</span></nav>'\n content += `<div class=\"page-head\"><div><h1>All raw entries</h1><p class=\"page-sub\">Every conversation line that the ingest pipeline captured. Absorb compiles these into typed articles nightly.</p></div></div>`\n\n const byDate = new Map<string, typeof entries>()\n for (const e of entries) {\n const list = byDate.get(e.date) || []\n list.push(e)\n byDate.set(e.date, list)\n }\n\n for (const [date, dateEntries] of [...byDate].reverse()) {\n content += `<div class=\"section-head\"><h2>${date}</h2><span class=\"mono\" style=\"font-size:12px;color:var(--muted)\">${dateEntries.length} entries</span></div>`\n for (const e of dateEntries) {\n content += `<div class=\"entry-card\">\n <div class=\"meta-line\">\n <a href=\"/agent/${encodeURIComponent(e.agentId)}\">${escapeHtml(e.agentId)}</a>\n · via ${escapeHtml(e.source)} · <code>${escapeHtml(e.id)}</code>\n </div>\n <p>${escapeHtml(e.content.slice(0, 400))}${e.content.length > 400 ? \"…\" : \"\"}</p>\n </div>`\n }\n }\n\n return pageLayout(\"All Entries\", hubSidebar(agents), content)\n}\n\nfunction hubSearch(hub: WikiHub, query: string, allAgents?: AgentWikiSummary[]): string {\n const agents = allAgents || hub.summary()\n let content = `<nav class=\"breadcrumb\"><a href=\"/\">Hub</a> <span class=\"sep\">/</span> <span class=\"current\">Search</span></nav>`\n content += `<div class=\"page-head\"><div><h1>“${escapeHtml(query)}”</h1><p class=\"page-sub\">Full-text search across every agent's wiki.</p></div></div>`\n\n let totalResults = 0\n const blocks: string[] = []\n\n for (const agentSummary of agents) {\n const store = hub.getAgentWiki(agentSummary.agentId)\n const results = store.findRelevant(query, undefined, 10)\n\n if (results.length > 0) {\n blocks.push(`<div class=\"section-head\"><h2>${escapeHtml(agentSummary.agentId)}</h2><span class=\"mono\" style=\"font-size:12px;color:var(--muted)\">${results.length} match${results.length === 1 ? '' : 'es'}</span></div>`)\n for (const r of results) {\n const prefix = `/agent/${encodeURIComponent(agentSummary.agentId)}`\n blocks.push(`<div class=\"entry-card\">\n <div class=\"meta-line\">${tagLinks((r.meta.tags || []).slice(0, 3), agentSummary.agentId)}</div>\n <h3><a href=\"${prefix}/article/${encodeURIComponent(r.path)}\">${escapeHtml(r.meta.title)}</a></h3>\n <p>${escapeHtml(r.content.slice(0, 240))}…</p>\n </div>`)\n }\n totalResults += results.length\n }\n }\n content += blocks.join('')\n\n if (totalResults === 0) content += '<p style=\"color:var(--muted);margin-top:24px\">No matching articles found.</p>'\n\n return pageLayout(`Search: ${query}`, hubSidebar(agents), content, query)\n}\n\n/**\n * Hub-wide tag filter. Shows every article tagged with `tag` across all\n * local agents, grouped by agent. Exact-tag match (not BM25).\n */\nfunction hubTagPage(hub: WikiHub, tag: string, allAgents?: AgentWikiSummary[]): string {\n const agents = allAgents || hub.summary()\n let content = `<nav class=\"breadcrumb\"><a href=\"/\">Hub</a> <span class=\"sep\">/</span> <span class=\"current\">Tag</span></nav>`\n content += `<div class=\"page-head\"><div><h1>${escapeHtml(tag)}</h1><p class=\"page-sub\">All articles tagged <span class=\"tag\">${escapeHtml(tag)}</span>, across every agent.</p></div></div>`\n let total = 0\n for (const agentSummary of agents) {\n let store\n try { store = hub.getAgentWiki(agentSummary.agentId) } catch { continue }\n const matches = store.findByTags([tag], undefined, 100)\n if (matches.length === 0) continue\n content += `<div class=\"section-head\"><h2>${escapeHtml(agentSummary.agentId)}</h2><span class=\"mono\" style=\"font-size:12px;color:var(--muted)\">${matches.length}</span></div>`\n for (const a of matches) {\n const prefix = `/agent/${encodeURIComponent(agentSummary.agentId)}`\n content += `<div class=\"entry-card\">\n <div class=\"meta-line\">${tagLinks((a.meta.tags || []).slice(0, 6), agentSummary.agentId)}</div>\n <h3><a href=\"${prefix}/article/${encodeURIComponent(a.path)}\">${escapeHtml(a.meta.title)}</a></h3>\n </div>`\n }\n total += matches.length\n }\n if (total === 0) content += `<p style=\"color:var(--muted);margin-top:24px\">No articles tagged <code>${escapeHtml(tag)}</code>.</p>`\n return pageLayout(`Tag: ${tag}`, hubSidebar(agents), content)\n}\n\n/** Per-agent tag filter — narrows to one agent's corpus. */\nfunction hubAgentTagPage(hub: WikiHub, agentId: string, tag: string, allAgents?: AgentWikiSummary[]): string {\n const agents = allAgents || hub.summary()\n let store\n try { store = hub.getAgentWiki(agentId) } catch {\n return pageLayout(`Tag: ${tag}`, hubSidebar(agents), `<h1>Agent not found: ${escapeHtml(agentId)}</h1>`)\n }\n const matches = store.findByTags([tag], undefined, 100)\n const prefix = `/agent/${encodeURIComponent(agentId)}`\n let content = `<nav class=\"breadcrumb\"><a href=\"/\">Hub</a> <span class=\"sep\">/</span> <a href=\"${prefix}\">${escapeHtml(agentId)}</a> <span class=\"sep\">/</span> <span class=\"current\">${escapeHtml(tag)}</span></nav>`\n content += `<div class=\"page-head\"><div><h1>${escapeHtml(tag)}</h1><p class=\"page-sub\">${matches.length} article${matches.length === 1 ? \"\" : \"s\"} tagged <code>${escapeHtml(tag)}</code> in <b>${escapeHtml(agentId)}</b>.</p></div></div>`\n for (const a of matches) {\n content += `<div class=\"entry-card\">\n <div class=\"meta-line\">${tagLinks((a.meta.tags || []).slice(0, 6), agentId)}</div>\n <h3><a href=\"${prefix}/article/${encodeURIComponent(a.path)}\">${escapeHtml(a.meta.title)}</a></h3>\n </div>`\n }\n return pageLayout(`${agentId} · ${tag}`, hubSidebar(agents), content)\n}\n\n// --- Single Agent Mode ---\n\nfunction agentSidebar(store: WikiStore, agentId: string, activePath?: string): string {\n const index = store.rebuildIndex()\n const byType = groupByDir(index.articles.map(a => ({ title: a.title, path: a.path, tags: a.tags })))\n\n let html = '<div class=\"nav-section\">'\n html += `<div class=\"nav-section-title\">${escapeHtml(agentId)}</div>`\n html += `<a class=\"nav-item${!activePath ? ' active' : ''}\" href=\"/\">Home</a>`\n html += `<a class=\"nav-item\" href=\"/lint\">Health check</a>`\n html += '</div>'\n\n for (const [type, articles] of byType) {\n html += '<div class=\"nav-section\">'\n html += `<div class=\"nav-section-title\">${dirLabel(type)}</div>`\n for (const a of articles) {\n const isActive = a.path === activePath\n html += `<a class=\"nav-item${isActive ? ' active' : ''}\" href=\"/article/${encodeURIComponent(a.path)}\">${escapeHtml(a.title)}</a>`\n }\n html += '</div>'\n }\n\n return html\n}\n\n// --- Server ---\n\nexport interface WikiHandlerOpts {\n wikiDir: string\n agentFilter?: string\n peers?: WikiPeer[]\n mode?: \"flat\" | \"graph\" | \"unified\"\n /** Mount this handler under a URL prefix (e.g. \"/admin/wiki\" when\n * embedded in the dashboard). Routes are matched against the path\n * with the prefix stripped, and hrefs in the rendered HTML get the\n * prefix re-prepended so links round-trip back to the same mount. */\n pathPrefix?: string\n}\n\n/** Build the wiki HTTP request handler. Same logic as `startWikiServer`,\n * but factored out so the dashboard can mount it at `/admin/wiki/*` —\n * one HTTP listener instead of two. */\nexport function createWikiHandler(opts: WikiHandlerOpts): (req: IncomingMessage, res: ServerResponse) => Promise<void> {\n const { wikiDir, agentFilter, peers = [], mode = \"graph\", pathPrefix = \"\" } = opts\n const prefix = pathPrefix.replace(/\\/+$/, \"\")\n const hub = new WikiHub(wikiDir, undefined, mode)\n const ontologyRoutes = new OntologyRoutes(hub, wikiDir)\n const mesh = peers.length > 0 ? new MeshWikiClient(peers) : null\n\n return async (req: IncomingMessage, res: ServerResponse) => {\n const url = new URL(req.url || \"/\", `http://localhost`)\n const rawPath = decodeURIComponent(url.pathname)\n const path = prefix && rawPath.startsWith(prefix)\n ? (rawPath.slice(prefix.length) || \"/\")\n : rawPath\n\n let html: string | null = null\n let status = 200\n\n try {\n // Handle remote article fetch: /remote/:peerIdx/:agentId/article/:path\n if (path.startsWith(\"/remote/\") && mesh) {\n const parts = path.slice(\"/remote/\".length).split(\"/article/\")\n if (parts.length === 2) {\n const [peerAgent, articlePath] = parts\n const slashIdx = peerAgent.indexOf(\"/\")\n const peerUrl = decodeURIComponent(peerAgent.slice(0, slashIdx))\n const agentId = peerAgent.slice(slashIdx + 1)\n\n const article = await mesh.getRemoteArticle(peerUrl, agentId, articlePath)\n if (article) {\n const remoteAgents = await mesh.getRemoteAgents()\n const allAgents = [...hub.summary(), ...remoteAgents.map(r => ({ ...r, agentId: `${r.agentId} @${r.nodeId}` }))]\n\n let content = `<div class=\"breadcrumb\"><a href=\"/\">Hub</a> / <span class=\"tag\">remote</span> ${escapeHtml(agentId)} @ ${escapeHtml(peerUrl)}</div>`\n content += `<h1>${escapeHtml(article.meta.title)}</h1>`\n content += '<dl class=\"meta\">'\n content += `<dt>Tags</dt><dd>${(article.meta.tags||[]).map(t => `<span class=\"tag\">${t}</span>`).join(\" \")}</dd>`\n content += `<dt>Owner</dt><dd>${escapeHtml(article.meta.owner)}</dd>`\n content += `<dt>Source</dt><dd><span class=\"tag\">remote</span> ${escapeHtml(peerUrl)}</dd>`\n content += `<dt>Updated</dt><dd>${article.meta.lastUpdated}</dd>`\n content += '</dl>'\n\n const titleToPath = new Map<string, string>()\n content += md(article.content, titleToPath)\n\n html = pageLayout(article.meta.title, hubSidebar(allAgents), content)\n }\n }\n }\n\n if (!html && agentFilter) {\n // Single agent mode\n const store = hub.getAgentWiki(agentFilter)\n\n if (path === \"/\" || path === \"\") {\n const index = store.rebuildIndex()\n const entries = hub.getAgentEntries(agentFilter)\n let content = `<h1>${escapeHtml(agentFilter)}</h1>`\n content += '<div class=\"stats\">'\n content += `<div class=\"stat-card\"><div class=\"number\">${index.articles.length}</div><div class=\"label\">Articles</div></div>`\n content += `<div class=\"stat-card\"><div class=\"number\">${entries.length}</div><div class=\"label\">Entries</div></div>`\n content += '</div>'\n if (index.articles.length > 0) {\n content += '<h2>Articles</h2><table><tr><th>Title</th><th>Type</th><th>Updated</th></tr>'\n for (const a of index.articles) {\n content += `<tr><td><a href=\"/article/${encodeURIComponent(a.path)}\">${escapeHtml(a.title)}</a></td><td><span class=\"tag\">${(a.tags||[]).slice(0,3).join(\", \")}</span></td><td>${a.lastUpdated || \"\"}</td></tr>`\n }\n content += '</table>'\n }\n html = pageLayout(agentFilter, agentSidebar(store, agentFilter), content)\n } else if (path.startsWith(\"/article/\")) {\n const articlePath = path.slice(\"/article/\".length)\n const article = store.readArticle(articlePath)\n if (article) {\n const index = store.rebuildIndex()\n const titleToPath = new Map<string, string>()\n for (const a of index.articles) titleToPath.set(a.title, a.path)\n let content = `<h1>${escapeHtml(article.meta.title)}</h1>`\n content += '<dl class=\"meta\">'\n content += `<dt>Tags</dt><dd>${(article.meta.tags||[]).map(t => `<span class=\"tag\">${t}</span>`).join(\" \")}</dd>`\n content += `<dt>Updated</dt><dd>${article.meta.lastUpdated}</dd>`\n if (article.meta.sources?.length) content += `<dt>Sources</dt><dd>${article.meta.sources.length} entries</dd>`\n content += '</dl>'\n content += md(article.content, titleToPath)\n html = pageLayout(article.meta.title, agentSidebar(store, agentFilter, articlePath), content)\n }\n } else if (path === \"/lint\") {\n const issues = store.lint()\n let content = '<h1>Health Check</h1>'\n if (issues.length === 0) { content += '<p style=\"color:green;\">No issues.</p>' }\n else {\n content += `<table><tr><th>Type</th><th>Article</th><th>Issue</th></tr>`\n for (const i of issues) content += `<tr><td><span class=\"tag\">${i.type}</span></td><td>${escapeHtml(i.article)}</td><td>${escapeHtml(i.message)}</td></tr>`\n content += '</table>'\n }\n html = pageLayout(\"Health Check\", agentSidebar(store, agentFilter), content)\n } else if (path === \"/search\") {\n const q = url.searchParams.get(\"q\") || \"\"\n const results = await store.findRelevantReranked(q, undefined, 20)\n let content = `<h1>Search: \"${escapeHtml(q)}\"</h1>`\n for (const r of results) {\n content += `<div class=\"entry-card\"><h3><a href=\"/article/${encodeURIComponent(r.path)}\">${escapeHtml(r.meta.title)}</a></h3><p>${escapeHtml(r.content.slice(0, 200))}...</p></div>`\n }\n if (results.length === 0) content += '<p>No results.</p>'\n html = pageLayout(`Search: ${q}`, agentSidebar(store, agentFilter), content)\n } else if (path.startsWith(\"/tag/\")) {\n const tag = decodeURIComponent(path.slice(\"/tag/\".length))\n const matches = store.findByTags([tag], undefined, 100)\n let content = `<h1>Tag: <a class=\"tag\" href=\"#\">${escapeHtml(tag)}</a></h1>`\n content += `<p>${matches.length} article${matches.length === 1 ? \"\" : \"s\"} tagged <code>${escapeHtml(tag)}</code></p>`\n for (const a of matches) {\n content += `<div class=\"entry-card\"><h3><a href=\"/article/${encodeURIComponent(a.path)}\">${escapeHtml(a.meta.title)}</a></h3><div class=\"meta-line\">${tagLinks((a.meta.tags || []).slice(0, 6))}</div></div>`\n }\n if (matches.length === 0) content += '<p>No articles with this tag.</p>'\n html = pageLayout(`Tag: ${tag}`, agentSidebar(store, agentFilter), content)\n }\n } else if (!html && (html = ontologyRoutes.handle(path, url.searchParams)) === null) {\n // Hub mode — merge local + remote agents. The knowledge-graph\n // routes above own \"/\"; the per-agent hub moved to \"/agents\".\n const remoteAgents = mesh ? await mesh.getRemoteAgents() : []\n const localAgents = hub.summary()\n // Merge: prefer whichever has more articles (local or remote)\n const localMap = new Map(localAgents.map(a => [a.agentId, a]))\n const allAgents: AgentWikiSummary[] = []\n const seen = new Set<string>()\n\n for (const local of localAgents) {\n const remote = remoteAgents.find(r => r.agentId === local.agentId)\n if (remote && remote.totalArticles > local.totalArticles) {\n // Remote has more articles — merge: keep remote articles, combine entry counts\n allAgents.push({\n ...remote,\n totalEntries: Math.max(local.totalEntries, remote.totalEntries),\n unabsorbed: Math.max(local.unabsorbed, remote.unabsorbed),\n })\n } else {\n allAgents.push(local)\n }\n seen.add(local.agentId)\n }\n // Add remote-only agents\n for (const remote of remoteAgents) {\n if (!seen.has(remote.agentId)) {\n allAgents.push(remote)\n seen.add(remote.agentId)\n }\n }\n\n if (path === \"/agents\") {\n html = hubHome(hub, allAgents, remoteAgents)\n } else if (path === \"/entries\") {\n html = hubEntries(hub, allAgents)\n } else if (path === \"/search\") {\n html = hubSearch(hub, url.searchParams.get(\"q\") || \"\", allAgents)\n } else if (path.startsWith(\"/tag/\")) {\n html = hubTagPage(hub, decodeURIComponent(path.slice(\"/tag/\".length)), allAgents)\n } else if (path.match(/^\\/agent\\/[^/]+\\/tag\\/.+/)) {\n const m = path.match(/^\\/agent\\/([^/]+)\\/tag\\/(.+)$/)!\n html = hubAgentTagPage(hub, decodeURIComponent(m[1]), decodeURIComponent(m[2]), allAgents)\n } else if (path.startsWith(\"/agent/\")) {\n const rest = path.slice(\"/agent/\".length)\n const slashIdx = rest.indexOf(\"/article/\")\n if (slashIdx === -1) {\n // Agent overview\n html = hubAgentOverview(hub, rest, allAgents)\n } else {\n // Agent article\n const agentId = rest.slice(0, slashIdx)\n const articlePath = rest.slice(slashIdx + \"/article/\".length)\n html = hubArticlePage(hub, agentId, articlePath, allAgents)\n\n // If not found locally, try remote peers\n if (!html && mesh) {\n const remote = remoteAgents.find(r => r.agentId === agentId)\n if (remote) {\n const article = await mesh.getRemoteArticle(remote.peerUrl, agentId, articlePath)\n if (article) {\n let content = `<div class=\"breadcrumb\"><a href=\"/\">Hub</a> / <span class=\"tag\">remote @ ${escapeHtml(remote.nodeId)}</span> / ${escapeHtml(agentId)}</div>`\n content += `<h1>${escapeHtml(article.meta.title)}</h1>`\n content += '<dl class=\"meta\">'\n content += `<dt>Tags</dt><dd>${(article.meta.tags||[]).map(t => `<span class=\"tag\">${t}</span>`).join(\" \")}</dd>`\n content += `<dt>Source</dt><dd><span class=\"tag\">remote</span> ${escapeHtml(remote.nodeId)}</dd>`\n content += `<dt>Updated</dt><dd>${article.meta.lastUpdated}</dd>`\n content += '</dl>'\n content += md(article.content, new Map())\n html = pageLayout(article.meta.title, hubSidebar(allAgents), content)\n }\n }\n }\n }\n }\n }\n\n if (!html) {\n status = 404\n const sidebar = agentFilter\n ? agentSidebar(hub.getAgentWiki(agentFilter), agentFilter)\n : hubSidebar(hub.summary())\n html = pageLayout(\"Not Found\", sidebar, \"<h1>Page not found</h1>\")\n }\n } catch (err: any) {\n status = 500\n html = pageLayout(\"Error\", \"\", `<h1>Error</h1><pre>${escapeHtml(err.message)}</pre>`)\n }\n\n res.writeHead(status, { \"Content-Type\": \"text/html; charset=utf-8\" })\n res.end(prefix ? prefixHrefs(html, prefix) : html)\n }\n}\n\n/** Re-prepend the mount prefix to every absolute internal href the wiki\n * generates (`/article/...`, `/agent/...`, `/tag/...`, `/`, `/search`,\n * `/lint`, `/entries`, `/remote/...`). Skips `//` (protocol-relative)\n * and external links. Cheap: a few regexes on the rendered HTML so we\n * don't need to thread `pathPrefix` through every layout helper.\n *\n * Also injects a small \"← Dashboard\" pill so embedded users have a way\n * back to the AgentX dashboard tabs (the wiki page renders its own\n * full-screen UI and replaces the dashboard chrome). */\nfunction prefixHrefs(html: string, prefix: string): string {\n // href and form action attributes\n html = html.replace(/(\\s(?:href|action)=\")\\/(?!\\/)/g, `$1${prefix}/`)\n // de-dupe if already prefixed\n html = html.replace(new RegExp(`(${prefix})${prefix}/`, \"g\"), `${prefix}/`)\n // back-pill — fixed top-right, neutral styling so it works in any wiki theme\n const pill = `<a href=\"/admin\" style=\"position:fixed;top:10px;right:14px;z-index:9999;padding:5px 11px;background:rgba(0,0,0,0.55);color:#fff;font:12px/1.2 'IBM Plex Sans',system-ui,sans-serif;text-decoration:none;border-radius:6px;border:1px solid rgba(255,255,255,0.18);backdrop-filter:blur(6px)\">← Dashboard</a>`\n html = html.replace(/<body([^>]*)>/, `<body$1>${pill}`)\n return html\n}\n\n/** Thin wrapper that runs the handler on its own port. Kept for the\n * `agentx wiki serve` CLI; the dashboard uses `createWikiHandler`\n * directly. */\nexport function startWikiServer(wikiDir: string, port: number = 4200, agentFilter?: string, peers: WikiPeer[] = [], mode: \"flat\" | \"graph\" | \"unified\" = \"graph\"): void {\n const handler = createWikiHandler({ wikiDir, agentFilter, peers, mode })\n const server = createServer((req, res) => { void handler(req, res) })\n server.listen(port)\n}\n","import type { AgentWikiSummary } from \"./hub\"\nimport type { WikiArticle } from \"./types\"\nimport type { WikiPeer } from \"./article-sync\"\n\n/**\n * Fetches wiki data from mesh peers over HTTP.\n * Each peer exposes /wiki/agents, /wiki/entries, /wiki/articles, behind\n * its mesh token.\n */\nexport class MeshWikiClient {\n private peers: Array<WikiPeer & { nodeId?: string }>\n private cache: Map<string, { data: any; ts: number }> = new Map()\n private ttl = 30_000 // 30s cache\n\n constructor(peers: WikiPeer[]) {\n this.peers = peers.map(p => ({ ...p, url: p.url.replace(/\\/$/, \"\") }))\n }\n\n /**\n * Get agent summaries from all peers.\n * Returns remote summaries with nodeId attached.\n */\n async getRemoteAgents(): Promise<Array<AgentWikiSummary & { nodeId: string; peerUrl: string }>> {\n const results: Array<AgentWikiSummary & { nodeId: string; peerUrl: string }> = []\n\n await Promise.all(this.peers.map(async (peer) => {\n try {\n const data = await this.fetchJson(`${peer.url}/wiki/agents`)\n peer.nodeId = data.nodeId\n for (const agent of (data.agents || [])) {\n if (agent.totalEntries > 0 || agent.totalArticles > 0) {\n results.push({ ...agent, nodeId: data.nodeId, peerUrl: peer.url })\n }\n }\n } catch { /* peer unreachable */ }\n }))\n\n return results\n }\n\n /**\n * Get articles for a specific agent from a specific peer.\n */\n async getRemoteArticles(peerUrl: string, agentId: string): Promise<Array<{\n path: string; title: string; tags: string[]; lastUpdated?: string; sources?: string[]\n }>> {\n try {\n const data = await this.fetchJson(`${peerUrl}/wiki/articles?agent=${encodeURIComponent(agentId)}`)\n return data.articles || []\n } catch {\n return []\n }\n }\n\n /**\n * Fetch a specific article's content from a peer.\n */\n async getRemoteArticle(peerUrl: string, agentId: string, articlePath: string): Promise<WikiArticle | null> {\n try {\n const data = await this.fetchJson(\n `${peerUrl}/wiki/article?agent=${encodeURIComponent(agentId)}&path=${encodeURIComponent(articlePath)}`\n )\n return {\n meta: {\n title: data.title,\n tags: data.tags || [],\n owner: data.owner,\n access: \"public\",\n created: data.created,\n lastUpdated: data.lastUpdated,\n sources: data.sources || [],\n },\n content: data.content,\n path: data.path,\n }\n } catch {\n return null\n }\n }\n\n private async fetchJson(url: string): Promise<any> {\n const cached = this.cache.get(url)\n if (cached && Date.now() - cached.ts < this.ttl) return cached.data\n\n const token = this.peers.find(p => url.startsWith(`${p.url}/`))?.token\n const res = await fetch(url, {\n headers: token ? { Authorization: `Bearer ${token}` } : {},\n signal: AbortSignal.timeout(5000),\n })\n if (!res.ok) throw new Error(`HTTP ${res.status}`)\n const data = await res.json()\n this.cache.set(url, { data, ts: Date.now() })\n return data\n }\n}\n","// --- Panel contents for an entity, per its type's lens (#811) ---\n//\n// A lens lists panels; each panel reads one side of the entity from the\n// graph. At Z2 a panel shows its first few items, at Z3 all of them.\n// This file only selects and orders; the view decides how it looks.\n\nimport type { WikiEntry } from \"../types\"\nimport type { Entity, EntityStatement, WikiGraph } from \"./graph\"\nimport { panelFrom, panelSource } from \"./load\"\nimport type { Importance, LensPanel, TypeDef } from \"./types\"\n\nexport interface PanelItem {\n label: string\n /** Entity id when the item is a page. */\n entityId?: string\n /** Type of the other end, for its icon and sub-line. */\n type?: string\n /** Relation labels: property, role. */\n chips: string[]\n sub?: string\n since?: string\n until?: string\n date?: string\n importance?: Importance\n status?: string\n /** Masked at Z2 and Z3; the value shows at Z4 only. */\n private?: boolean\n /** Index in entity.statements, for the Z4 link. */\n statement?: number\n}\n\nexport interface PanelData {\n def: LensPanel\n title: string\n items: PanelItem[]\n /** Items before paging. */\n total: number\n /** History: minor events folded under the shown ones. */\n folded: PanelItem[]\n /** History: one line per recurring burst of minor events. */\n rollups: string[]\n ownerOnly: boolean\n}\n\nexport function lensFor(g: WikiGraph, type: string): LensPanel[] {\n return g.ontology.types.find((t: TypeDef) => t.id === type)?.lens ?? [{ panel: \"notes\", source: \"notes\", show: 1 }]\n}\n\nfunction propLabel(g: WikiGraph, id: string, inverse: boolean): string {\n const p = g.ontology.properties.find(x => x.id === id)\n if (!p) return id.replace(/_/g, \" \")\n return inverse ? (p.inverse ?? p.label) : p.label\n}\n\nfunction byRecent(a: PanelItem, b: PanelItem): number {\n const da = a.until ?? a.date ?? a.since ?? \"\"\n const db = b.until ?? b.date ?? b.since ?? \"\"\n if (da !== db) return db.localeCompare(da)\n return a.label.localeCompare(b.label)\n}\n\nfunction statementItem(g: WikiGraph, e: Entity, st: EntityStatement, inverse: boolean, from?: Entity): PanelItem {\n const other = inverse ? from : (st.target ? g.entities.get(st.target) : undefined)\n const chips = [propLabel(g, st.property, inverse)]\n if (st.role) chips.unshift(st.role)\n return {\n label: other?.title ?? st.value,\n entityId: other?.id,\n type: other?.type,\n chips,\n since: st.since,\n until: st.until,\n status: st.status,\n private: st.access === \"private\",\n statement: inverse ? undefined : e.statements.indexOf(st),\n sub: st.note,\n }\n}\n\nfunction statementsPanel(g: WikiGraph, e: Entity, def: LensPanel): PanelItem[] {\n const from = new Set(panelFrom(def))\n const types = def.types ? new Set(def.types) : null\n const items: PanelItem[] = []\n const seen = new Set<string>()\n const keep = (other?: Entity): boolean => !types || (!!other && types.has(other.type))\n\n for (const st of e.statements) {\n if (!from.has(st.property)) continue\n const other = st.target ? g.entities.get(st.target) : undefined\n if (!keep(other)) continue\n items.push(statementItem(g, e, st, false))\n if (other) seen.add(other.id)\n }\n for (const edge of g.incoming.get(e.id) ?? []) {\n if (!from.has(edge.property)) continue\n const other = g.entities.get(edge.from)\n if (!other || !keep(other)) continue\n if (edge.statement) items.push(statementItem(g, e, edge.statement, true, other))\n else if (!seen.has(other.id)) items.push({ label: other.title, entityId: other.id, type: other.type, chips: [propLabel(g, \"related\", true)], date: other.updated })\n seen.add(other.id)\n }\n if (from.has(\"related\")) {\n for (const edge of g.outgoing.get(e.id) ?? []) {\n if (edge.property !== \"related\" || seen.has(edge.to)) continue\n const other = g.entities.get(edge.to)\n if (!other || !keep(other)) continue\n items.push({ label: other.title, entityId: other.id, type: other.type, chips: [propLabel(g, \"related\", false)], date: other.updated })\n seen.add(other.id)\n }\n }\n // Typed relations first, then plain links; each part newest first.\n const typed = items.filter(i => !i.chips.includes(propLabel(g, \"related\", false)))\n const plain = items.filter(i => i.chips.includes(propLabel(g, \"related\", false)))\n return [...typed.sort(byRecent), ...plain.sort(byRecent)]\n}\n\n/** Entities linked to `e` either way, of the given types. */\nexport function linkedEntities(g: WikiGraph, e: Entity, types: Set<string> | null): Entity[] {\n const ids = new Set<string>()\n for (const edge of g.outgoing.get(e.id) ?? []) ids.add(edge.to)\n for (const edge of g.incoming.get(e.id) ?? []) ids.add(edge.from)\n const out: Entity[] = []\n for (const id of ids) {\n const other = g.entities.get(id)\n if (other && (!types || types.has(other.type))) out.push(other)\n }\n return out.sort((a, b) => (b.date || b.updated).localeCompare(a.date || a.updated))\n}\n\nfunction entityItem(other: Entity): PanelItem {\n return { label: other.title, entityId: other.id, type: other.type, chips: [], date: other.date, importance: other.importance }\n}\n\nfunction historyPanel(g: WikiGraph, e: Entity, def: LensPanel): { shown: PanelItem[]; folded: PanelItem[]; rollups: string[] } {\n const events = linkedEntities(g, e, new Set([\"event\"])).map(entityItem)\n const shownLevels = new Set<Importance>(def.importance ?? [\"major\", \"normal\", \"minor\"])\n const shown = events.filter(i => shownLevels.has(i.importance ?? g.ontology.importance.default))\n const folded = def.fold ? events.filter(i => i.importance === def.fold) : []\n const rollups: string[] = []\n const rule = def.rollup ?? g.ontology.importance.rollup\n if (folded.length >= rule.min && folded[0].date) {\n const newest = Date.parse(folded[0].date)\n const recent = folded.filter(i => i.date && newest - Date.parse(i.date) <= rule.days * 86_400_000)\n if (recent.length >= rule.min) rollups.push(`${recent.length} minor events in ${rule.days} days up to ${folded[0].date}`)\n }\n return { shown, folded, rollups }\n}\n\nfunction readingsPanel(e: Entity, latestOnly: boolean): PanelItem[] {\n const readings = e.statements\n .map((st, i) => ({ st, i }))\n .filter(({ st }) => st.property === \"reading\" || !!st.metric)\n .sort((a, b) => (b.st.at ?? \"\").localeCompare(a.st.at ?? \"\"))\n const seen = new Set<string>()\n const out: PanelItem[] = []\n for (const { st, i } of readings) {\n const metric = st.metric ?? \"reading\"\n if (latestOnly && seen.has(metric)) continue\n seen.add(metric)\n out.push({ label: `${metric.replace(/_/g, \" \")}: ${st.value}`, chips: [], date: st.at, statement: i, private: st.access === \"private\" })\n }\n return out\n}\n\nfunction discussedPanel(e: Entity, readEntries: (ids: string[]) => WikiEntry[]): PanelItem[] {\n return readEntries(e.sources)\n .sort((a, b) => b.date.localeCompare(a.date))\n .map(en => {\n const line = en.content.split(\"\\n\").map(l => l.trim()).find(Boolean) ?? \"\"\n return {\n label: line.length > 120 ? `${line.slice(0, 117)}…` : line,\n chips: [],\n date: en.date,\n // The panel is owner-only as a whole; its rows are not masked.\n sub: `${en.date} · ${en.agentId} · ${en.source}`,\n }\n })\n}\n\nexport interface PanelOpts {\n full: boolean\n page?: number\n pageSize?: number\n readEntries: (ids: string[]) => WikiEntry[]\n}\n\nexport function panelData(g: WikiGraph, e: Entity, def: LensPanel, opts: PanelOpts): PanelData {\n const source = panelSource(def)\n let items: PanelItem[] = []\n let folded: PanelItem[] = []\n let rollups: string[] = []\n if (source === \"statements\") items = statementsPanel(g, e, def)\n else if (source === \"linked\") items = linkedEntities(g, e, def.types ? new Set(def.types) : null).map(entityItem)\n else if (source === \"readings\") items = readingsPanel(e, !opts.full && def.latest !== false)\n else if (source === \"discussed\") items = discussedPanel(e, opts.readEntries)\n else if (source === \"history\") {\n const h = historyPanel(g, e, def)\n // Z3 shows every level, minor ones unfolded.\n items = opts.full ? linkedEntities(g, e, new Set([\"event\"])).map(entityItem) : h.shown\n folded = opts.full ? [] : h.folded\n rollups = h.rollups\n }\n const total = items.length\n if (opts.full) {\n const size = opts.pageSize ?? 50\n const page = Math.max(1, opts.page ?? 1)\n items = items.slice((page - 1) * size, page * size)\n } else {\n items = items.slice(0, def.show ?? 5)\n }\n return {\n def,\n title: def.title ?? def.panel.replace(/_/g, \" \"),\n items,\n total,\n folded,\n rollups,\n ownerOnly: def.access === \"owner\",\n }\n}\n","// --- Wiki knowledge-graph view: page frame, sidebar, icons (#811) ---\n//\n// Server-rendered HTML with no client build, like the rest of the wiki.\n// The sidebar is the widest zoom level (Z0): Home, the owner's pins and\n// the pillars, nothing deeper.\n\nimport { normName, type WikiGraph } from \"./graph\"\nimport type { Ontology } from \"./types\"\n\nexport function esc(s: string): string {\n return String(s ?? \"\").replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\")\n}\n\nconst PATHS: Record<string, string> = {\n home: '<rect x=\"3\" y=\"3\" width=\"7\" height=\"7\" rx=\"1\"/><rect x=\"14\" y=\"3\" width=\"7\" height=\"7\" rx=\"1\"/><rect x=\"3\" y=\"14\" width=\"7\" height=\"7\" rx=\"1\"/><rect x=\"14\" y=\"14\" width=\"7\" height=\"7\" rx=\"1\"/>',\n person: '<circle cx=\"12\" cy=\"8\" r=\"4\"/><path d=\"M4 21c0-4 4-6 8-6s8 2 8 6\"/>',\n org: '<rect x=\"4\" y=\"3\" width=\"16\" height=\"18\" rx=\"2\"/><path d=\"M9 7h2M13 7h2M9 11h2M13 11h2M9 15h2M13 15h2\"/>',\n pin: '<path d=\"M12 21s-7-6.2-7-11a7 7 0 0 1 14 0c0 4.8-7 11-7 11z\"/><circle cx=\"12\" cy=\"10\" r=\"2.5\"/>',\n server: '<rect x=\"3\" y=\"4\" width=\"18\" height=\"7\" rx=\"2\"/><rect x=\"3\" y=\"13\" width=\"18\" height=\"7\" rx=\"2\"/><path d=\"M7 7.5h.01M7 16.5h.01\"/>',\n device: '<rect x=\"4\" y=\"5\" width=\"16\" height=\"11\" rx=\"1.5\"/><path d=\"M2 19h20\"/>',\n app: '<rect x=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"3\"/><path d=\"M9 12h6M12 9v6\"/>',\n globe: '<circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M3 12h18M12 3c3 3.5 3 14.5 0 18M12 3c-3 3.5-3 14.5 0 18\"/>',\n key: '<circle cx=\"8\" cy=\"15\" r=\"4\"/><path d=\"M11 12l9-9M17 6l3 3\"/>',\n agent: '<rect x=\"5\" y=\"8\" width=\"14\" height=\"11\" rx=\"3\"/><path d=\"M12 4v4M9 13h.01M15 13h.01\"/>',\n project: '<path d=\"M12 3l8 4.5v9L12 21l-8-4.5v-9z\"/><path d=\"M4 7.5l8 4.5 8-4.5M12 12v9\"/>',\n contract: '<path d=\"M7 3h7l5 5v13H7z\"/><path d=\"M14 3v5h5M10 13h6M10 17h4\"/>',\n law: '<path d=\"M12 3v18M5 21h14M6 7h12M6 7l-3 7a3 3 0 0 0 6 0zM18 7l-3 7a3 3 0 0 0 6 0z\"/>',\n calendar: '<rect x=\"3\" y=\"5\" width=\"18\" height=\"16\" rx=\"2\"/><path d=\"M3 10h18M8 3v4M16 3v4\"/>',\n decision: '<path d=\"M12 3v18M12 8H6l-2 2 2 2h6M12 12h6l2 2-2 2h-6\"/>',\n steps: '<path d=\"M9 6h11M9 12h11M9 18h11M4 6l1 1 2-2M4 12l1 1 2-2M4 18l1 1 2-2\"/>',\n topic: '<path d=\"M4 7h16M4 12h10M4 17h7\"/>',\n chat: '<path d=\"M4 5h16v11H9l-5 4z\"/>',\n lock: '<rect x=\"5\" y=\"11\" width=\"14\" height=\"10\" rx=\"2\"/><path d=\"M8 11V8a4 4 0 0 1 8 0v3\"/>',\n arrow: '<path d=\"M5 12h14M13 6l6 6-6 6\"/>',\n search: '<circle cx=\"11\" cy=\"11\" r=\"7\"/><path d=\"M21 21l-4.3-4.3\"/>',\n merge: '<circle cx=\"6\" cy=\"6\" r=\"2\"/><circle cx=\"6\" cy=\"18\" r=\"2\"/><circle cx=\"18\" cy=\"12\" r=\"2\"/><path d=\"M6 8v8M8 6c6 0 8 2 8 6\"/>',\n}\n\nexport function icon(name: string | undefined): string {\n const d = PATHS[name ?? \"\"] ?? PATHS.topic\n return `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.7\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">${d}</svg>`\n}\n\nexport function typeIcon(o: Ontology, type: string | undefined): string {\n return icon(o.types.find(t => t.id === type)?.icon)\n}\n\nexport function typeLabel(o: Ontology, type: string | undefined): string {\n return o.types.find(t => t.id === type)?.label ?? type ?? \"\"\n}\n\nexport function entityHref(id: string): string {\n return `/e/${encodeURIComponent(id)}`\n}\n\nexport interface Crumb { label: string; href?: string }\n\n/** Wiki / Pillar / Kind / Page / Panel, following the zoom. */\nexport function crumbs(list: Crumb[]): string {\n const parts = [{ label: \"Wiki\", href: \"/\" }, ...list].map((c, i, all) =>\n i === all.length - 1 || !c.href ? `<b>${esc(c.label)}</b>` : `<a href=\"${c.href}\">${esc(c.label)}</a>`)\n return `<nav class=\"ox-crumbs\" aria-label=\"Breadcrumb\">${parts.join('<span aria-hidden=\"true\">/</span>')}</nav>`\n}\n\n/** The Z0–Z4 indicator. `at` is the current level. */\nexport function zoomBar(at: 1 | 2 | 3 | 4): string {\n const names = [\"\", \"Pillar\", \"Overview\", \"Panel\", \"Statement\"]\n const cells = [1, 2, 3, 4].map(z => `<span class=\"${z === at ? \"on\" : \"\"}\">Z${z}${z === at ? ` ${names[z]}` : \"\"}</span>`)\n return `<div class=\"ox-zoom\" title=\"Zoom level\">${cells.join(\"\")}</div>`\n}\n\nexport function sidebar(g: WikiGraph, active: { pillar?: string; entity?: string; home?: boolean }): string {\n const o = g.ontology\n let html = `<a class=\"ox-nav${active.home ? \" on\" : \"\"}\" href=\"/\">${icon(\"home\")}<span>Home</span></a>`\n const pins = o.sidebar.pins.slice(0, o.sidebar.pins_max)\n if (pins.length) {\n html += `<div class=\"ox-side-h\">Pinned</div>`\n for (const title of pins) {\n const id = g.names.get(normName(title))\n const e = id ? g.entities.get(id) : undefined\n if (!e) continue\n html += `<a class=\"ox-nav pin${active.entity === e.id ? \" on\" : \"\"}\" href=\"${entityHref(e.id)}\">${typeIcon(o, e.type)}<span>${esc(e.title)}</span></a>`\n }\n }\n html += `<div class=\"ox-side-h\">Pillars</div>`\n for (const p of o.pillars) {\n if (p.sidebar === false) continue\n html += `<a class=\"ox-nav${active.pillar === p.id ? \" on\" : \"\"}\" href=\"/p/${encodeURIComponent(p.id)}\">${icon(p.icon)}<span>${esc(p.label)}</span></a>`\n }\n html += `<div class=\"ox-side-foot\">Types, topics and agent wikis are one level down, on Home and the pillar pages.</div>`\n return html\n}\n\nexport function layout(title: string, side: string, main: string, rail = \"\", q = \"\"): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>${esc(title)} — Wiki</title>\n<style>${CSS}</style>\n<script>(function(){try{var t=localStorage.getItem('wiki-theme');if(t)document.documentElement.setAttribute('data-theme',t)}catch(e){}})();</script>\n</head>\n<body>\n<div class=\"ox-app\">\n <header class=\"ox-top\">\n <a class=\"ox-logo\" href=\"/\"><span class=\"mark\"><i></i></span>Wiki</a>\n <form class=\"ox-search\" action=\"/find\" method=\"get\" role=\"search\">${icon(\"search\")}<input type=\"search\" name=\"q\" value=\"${esc(q)}\" placeholder=\"Jump to any page\" aria-label=\"Search the wiki\" autocomplete=\"off\"><kbd>⌘K</kbd></form>\n <span class=\"ox-spacer\"></span>\n <a class=\"ox-btn\" href=\"/agents\">Agent wikis</a>\n <button class=\"ox-btn\" id=\"ox-theme\" type=\"button\" aria-label=\"Toggle theme\">Theme</button>\n </header>\n <div class=\"ox-layout${rail ? \" rail\" : \"\"}\">\n <nav class=\"ox-side\" aria-label=\"Wiki\">${side}</nav>\n <main class=\"ox-main\">${main}</main>\n ${rail ? `<aside class=\"ox-rail\">${rail}</aside>` : \"\"}\n </div>\n</div>\n<script>\n(function(){\n var b=document.getElementById('ox-theme');\n if(b)b.addEventListener('click',function(){var d=document.documentElement.getAttribute('data-theme')==='dark'?'':'dark';if(d)document.documentElement.setAttribute('data-theme','dark');else document.documentElement.removeAttribute('data-theme');try{localStorage.setItem('wiki-theme',d)}catch(e){}});\n document.addEventListener('keydown',function(e){if((e.metaKey||e.ctrlKey)&&e.key.toLowerCase()==='k'){e.preventDefault();var i=document.querySelector('.ox-search input');if(i)i.focus();}});\n})();\n</script>\n</body>\n</html>`\n}\n\nconst CSS = `\n:root{--paper:#fafaf9;--card:#fff;--soft:#f4f4f2;--edge:#e7e7e3;--ink:#121614;--muted:#4f5755;--subtle:#7d8684;\n--accent:#1e40af;--accent-soft:#eef3ff;--accent-edge:#c7d6fb;--ok:#0f766e;--ok-soft:#effcf9;--ok-edge:#a7eadf;\n--warn:#92400e;--warn-soft:#fffbeb;--warn-edge:#fde68a;--bad:#b91c1c;--bad-soft:#fef2f2;--bad-edge:#fecaca;\n--mono:ui-monospace,SFMono-Regular,Menlo,monospace;--sans:system-ui,-apple-system,\"Segoe UI\",sans-serif}\n[data-theme=dark]{--paper:#111413;--card:#181c1b;--soft:#1f2422;--edge:#2c3331;--ink:#e9eeec;--muted:#b3bcba;--subtle:#87918f;\n--accent:#9db7ff;--accent-soft:#1c2540;--accent-edge:#33406a;--ok:#5eead4;--ok-soft:#10302b;--ok-edge:#1d5249;\n--warn:#fcd34d;--warn-soft:#33290f;--warn-edge:#5c4a17;--bad:#fca5a5;--bad-soft:#3a1717;--bad-edge:#5e2525}\n*{box-sizing:border-box}\nbody{margin:0;background:var(--paper);color:var(--ink);font:14px/1.45 var(--sans);-webkit-font-smoothing:antialiased}\na{color:var(--accent);text-decoration:none}a:hover{text-decoration:underline}\n.ox-top{display:flex;align-items:center;gap:16px;padding:10px 18px;border-bottom:1px solid var(--edge);background:var(--card);position:sticky;top:0;z-index:5}\nbody>a[href=\"/admin\"]+.ox-app .ox-top{padding-right:130px}\n.ox-logo{display:flex;align-items:center;gap:9px;font-weight:600;color:var(--ink);width:200px}\n.ox-logo .mark{width:24px;height:24px;border-radius:7px;background:var(--ink);display:flex;align-items:center;justify-content:center}\n.ox-logo .mark i{width:8px;height:8px;border-radius:50%;background:#14b8a6}\n.ox-search{flex:0 1 440px;display:flex;align-items:center;gap:8px;border:1px solid var(--edge);border-radius:999px;padding:6px 12px;background:var(--paper)}\n.ox-search svg{width:15px;height:15px;color:var(--subtle)}\n.ox-search input{flex:1;border:0;background:transparent;color:var(--ink);font:13px var(--sans);outline:none}\n.ox-search kbd{font:11px var(--mono);color:var(--subtle)}\n.ox-spacer{flex:1}\n.ox-btn{font:12.5px var(--sans);border:1px solid var(--edge);background:var(--card);color:var(--ink);border-radius:999px;padding:5px 12px;cursor:pointer;display:inline-flex;gap:6px;align-items:center}\n.ox-layout{display:grid;grid-template-columns:230px minmax(0,1fr)}\n.ox-layout.rail{grid-template-columns:230px minmax(0,1fr) 290px}\n.ox-side{border-right:1px solid var(--edge);padding:14px 12px;min-height:calc(100vh - 50px)}\n.ox-nav{display:flex;align-items:center;gap:10px;padding:7px 10px;border-radius:10px;color:var(--ink)}\n.ox-nav:hover{background:var(--soft);text-decoration:none}\n.ox-nav svg{width:16px;height:16px;color:var(--muted);flex:none}\n.ox-nav span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.ox-nav.on{background:var(--accent-soft);color:var(--accent);font-weight:500}.ox-nav.on svg{color:var(--accent)}\n.ox-side-h{font:10.5px var(--mono);letter-spacing:.08em;text-transform:uppercase;color:var(--subtle);padding:16px 10px 6px}\n.ox-side-foot{margin-top:18px;border-top:1px solid var(--edge);padding:12px 10px 0;font:10.5px/1.6 var(--mono);color:var(--subtle)}\n.ox-main{padding:20px 28px 48px;min-width:0}\n.ox-rail{border-left:1px solid var(--edge);padding:20px 18px}\n.ox-bar{display:flex;align-items:center;justify-content:space-between;gap:12px}\n.ox-crumbs{font:11.5px var(--mono);color:var(--subtle);display:flex;gap:8px;flex-wrap:wrap}\n.ox-crumbs b{color:var(--ink);font-weight:500}\n.ox-zoom{display:inline-flex;border:1px solid var(--edge);border-radius:999px;padding:3px;background:var(--card);gap:2px}\n.ox-zoom span{font:10.5px var(--mono);letter-spacing:.05em;text-transform:uppercase;padding:4px 9px;border-radius:999px;color:var(--subtle)}\n.ox-zoom span.on{background:var(--ink);color:var(--paper)}\n.ox-head{display:flex;gap:16px;align-items:flex-start;margin:16px 0 18px}\n.ox-avatar{width:54px;height:54px;border-radius:14px;background:var(--accent-soft);border:1px solid var(--accent-edge);display:flex;align-items:center;justify-content:center;color:var(--accent);flex:none}\n.ox-avatar svg{width:26px;height:26px}\n.ox-head h1{font-size:30px;margin:2px 0 8px;letter-spacing:-.02em;font-weight:600;line-height:1.15}\n.ox-head p{margin:0;color:var(--muted)}\n.ox-chips{display:flex;gap:6px;flex-wrap:wrap;align-items:center}\n.ox-chip{font-size:12px;border:1px solid var(--edge);background:var(--card);border-radius:999px;padding:2px 10px;color:var(--muted);display:inline-flex;gap:6px;align-items:center;white-space:nowrap}\n.ox-chip svg{width:12px;height:12px}\n.ox-chip.type{background:var(--accent-soft);border-color:var(--accent-edge);color:var(--accent)}\n.ox-chip.mono{font:11px var(--mono)}\n.ox-st{font:10px var(--mono);letter-spacing:.07em;text-transform:uppercase;border-radius:999px;padding:3px 8px;border:1px solid;white-space:nowrap}\n.ox-st.ok,.ox-st.confirmed{color:var(--ok);background:var(--ok-soft);border-color:var(--ok-edge)}\n.ox-st.proposed{color:var(--accent);background:var(--accent-soft);border-color:var(--accent-edge)}\n.ox-st.warn,.ox-st.due{color:var(--warn);background:var(--warn-soft);border-color:var(--warn-edge)}\n.ox-st.bad,.ox-st.late{color:var(--bad);background:var(--bad-soft);border-color:var(--bad-edge)}\n.ox-st.major{color:var(--paper);background:var(--ink);border-color:var(--ink)}\n.ox-st.normal{color:var(--muted);background:var(--soft);border-color:var(--edge)}\n.ox-st.minor{color:var(--subtle);background:var(--card);border-color:var(--edge)}\n.ox-card{background:var(--card);border:1px solid var(--edge);border-radius:16px;padding:16px 18px;min-width:0}\n.ox-card-h{display:flex;align-items:baseline;gap:10px;margin-bottom:10px}\n.ox-card-h h2,.ox-card-h h3{font-size:15px;margin:0;font-weight:600;white-space:nowrap}\n.ox-card-h .note{font:11px var(--mono);color:var(--subtle);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}\n.ox-card-h .zin{margin-left:auto;font:11px var(--mono);white-space:nowrap}\n.ox-grid2{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:16px;margin-top:16px}\n.ox-grid2>.wide{grid-column:1/-1}\n.ox-grid3{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px;margin-top:16px}\n.ox-row{display:flex;align-items:center;gap:10px;padding:8px 0;border-top:1px solid var(--edge);font-size:13.5px;min-width:0}\n.ox-row:first-of-type{border-top:0}\n.ox-row .t{min-width:0;overflow:hidden}\n.ox-row .t a,.ox-row .t span.l{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.ox-row .r{margin-left:auto;display:flex;gap:6px;align-items:center;flex:none}\n.ox-ic{width:28px;height:28px;border-radius:8px;background:var(--soft);border:1px solid var(--edge);display:flex;align-items:center;justify-content:center;flex:none;color:var(--muted)}\n.ox-ic svg{width:14px;height:14px}\n.ox-card-h .note svg,.ox-row .l svg{width:12px;height:12px;vertical-align:-2px}\n.ox-sub{font:11px var(--mono);color:var(--subtle);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.ox-summary{font-size:15px;line-height:1.55;margin:0 0 10px}\n.ox-meta{display:flex;gap:16px;flex-wrap:wrap;font:11px var(--mono);color:var(--subtle)}\n.ox-lbl{font:10.5px var(--mono);letter-spacing:.08em;text-transform:uppercase;color:var(--subtle);display:block;margin:4px 0 10px}\n.ox-annot{border:1px dashed var(--subtle);border-radius:14px;padding:12px 14px;font-size:12.5px;color:var(--muted);line-height:1.5}\n.ox-annot ol{margin:6px 0;padding-left:18px}\n.ox-annot .ox-sub{white-space:normal;overflow-wrap:anywhere}\n.ox-rail .ox-row{font-size:13px}\n.ox-tabs{display:flex;gap:4px;border-bottom:1px solid var(--edge);margin:4px 0 0;flex-wrap:wrap}\n.ox-tabs a{padding:8px 12px;color:var(--muted);border-bottom:2px solid transparent;font-size:13.5px}\n.ox-tabs a.on{color:var(--ink);border-color:var(--ink);font-weight:500}\n.ox-tabs a small{font:11px var(--mono);color:var(--subtle);margin-left:4px}\n.ox-ev{display:grid;grid-template-columns:86px 70px minmax(0,1fr);gap:10px;align-items:center;padding:8px 0;border-top:1px solid var(--edge);font-size:13.5px}\n.ox-ev:first-of-type{border-top:0}\n.ox-ev .d{font:11px var(--mono);color:var(--subtle)}\n.ox-ev a{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block}\n.ox-fold{border:1px solid var(--edge);background:var(--soft);border-radius:12px;padding:8px 12px;margin-top:8px;font-size:13px;color:var(--muted)}\n.ox-fold summary{cursor:pointer}\n.ox-tl-axis,.ox-tl-row{display:grid;grid-template-columns:170px minmax(0,1fr);gap:8px}\n.ox-tl-axis{font:10.5px var(--mono);color:var(--subtle);margin-bottom:4px}\n.ox-tl-axis .yrs{display:flex;justify-content:space-between}\n.ox-tl-row{align-items:center;padding:6px 0;border-top:1px solid var(--edge)}\n.ox-tl-row .who{font-size:12.5px;line-height:1.3;min-width:0;overflow:hidden}\n.ox-tl-row .who small{display:block;font:10.5px var(--mono);color:var(--subtle)}\n.ox-track{position:relative;height:20px;background:var(--soft);border-radius:999px}\n.ox-track i{position:absolute;top:2px;height:16px;border-radius:999px;background:var(--accent);color:#fff;font:10px/16px var(--mono);padding:0 7px;white-space:nowrap;overflow:hidden;font-style:normal}\n.ox-track i.past{background:var(--subtle)}\n.ox-kv{display:grid;grid-template-columns:150px minmax(0,1fr);gap:10px;padding:8px 0;border-top:1px solid var(--edge);font-size:13.5px}\n.ox-kv:first-of-type{border-top:0}\n.ox-kv .k{color:var(--muted)}\n.ox-mask{letter-spacing:.15em;color:var(--muted)}\n.ox-prose{line-height:1.6;font-size:14.5px}\n.ox-prose h1,.ox-prose h2,.ox-prose h3{font-size:16px;margin:18px 0 6px}\n.ox-prose pre{background:var(--soft);padding:10px;border-radius:8px;overflow:auto}\n.ox-prose table{border-collapse:collapse}.ox-prose td,.ox-prose th{border:1px solid var(--edge);padding:4px 8px}\n.ox-pager{display:flex;gap:10px;margin-top:12px;font:12px var(--mono)}\n.ox-empty{color:var(--subtle);font-size:13px;padding:6px 0}\n.ox-err{border:1px solid var(--bad-edge);background:var(--bad-soft);color:var(--bad);border-radius:12px;padding:10px 14px;margin:12px 0;font-size:13px}\n@media (max-width:1100px){.ox-layout.rail{grid-template-columns:230px minmax(0,1fr)}.ox-rail{grid-column:2;border-left:0;border-top:1px solid var(--edge)}}\n@media (max-width:760px){.ox-layout,.ox-layout.rail{grid-template-columns:1fr}.ox-side{min-height:0;border-right:0;border-bottom:1px solid var(--edge)}.ox-rail{grid-column:1}.ox-grid2{grid-template-columns:1fr}.ox-logo{width:auto}.ox-tl-axis,.ox-tl-row{grid-template-columns:110px minmax(0,1fr)}}\n`\n","// --- Rendering one lens panel (#811) ---\n\nimport type { Entity, WikiGraph } from \"./graph\"\nimport type { PanelData, PanelItem } from \"./lens\"\nimport { entityHref, esc, icon, typeIcon, typeLabel } from \"./view-layout\"\n\nconst today = (): string => new Date().toISOString().slice(0, 10)\n\nfunction statusChip(s?: string): string {\n return s ? `<span class=\"ox-st ${esc(s)}\">${esc(s)}</span>` : \"\"\n}\n\nfunction itemTitle(it: PanelItem): string {\n if (it.private) return `<span class=\"l\"><span class=\"ox-mask\">••••</span> ${icon(\"lock\")}</span>`\n return it.entityId ? `<a href=\"${entityHref(it.entityId)}\">${esc(it.label)}</a>` : `<span class=\"l\">${esc(it.label)}</span>`\n}\n\nfunction itemSub(g: WikiGraph, it: PanelItem): string {\n if (it.sub) return it.sub\n const parts: string[] = []\n if (it.type) parts.push(typeLabel(g.ontology, it.type).toLowerCase())\n if (it.since || it.until) parts.push(`${it.since ?? \"…\"} → ${it.until ?? \"now\"}`)\n else if (it.date) parts.push(it.date)\n return parts.join(\" · \")\n}\n\nfunction rowHtml(g: WikiGraph, e: Entity, it: PanelItem): string {\n const sub = itemSub(g, it)\n const chips = it.chips.map(c => `<span class=\"ox-chip\">${esc(c)}</span>`).join(\"\")\n const z4 = it.statement !== undefined && it.statement >= 0\n ? `<a class=\"ox-sub\" href=\"${entityHref(e.id)}/s/${it.statement}\" title=\"Where this comes from (Z4)\">Z4</a>` : \"\"\n return `<div class=\"ox-row\"><span class=\"ox-ic\">${it.type ? typeIcon(g.ontology, it.type) : icon(it.private ? \"lock\" : \"topic\")}</span>`\n + `<div class=\"t\">${itemTitle(it)}${sub ? `<div class=\"ox-sub\">${esc(sub)}</div>` : \"\"}</div>`\n + `<div class=\"r\">${chips}${statusChip(it.status)}${z4}</div></div>`\n}\n\nfunction eventRow(it: PanelItem): string {\n const level = it.importance ?? \"normal\"\n return `<div class=\"ox-ev\"><span class=\"d\">${esc(it.date ?? \"\")}</span><span class=\"ox-st ${level}\">${level}</span>`\n + `<span>${it.entityId ? `<a href=\"${entityHref(it.entityId)}\">${esc(it.label)}</a>` : esc(it.label)}</span></div>`\n}\n\nfunction timeline(items: PanelItem[]): string {\n const years = items.flatMap(i => [i.since, i.until]).filter((d): d is string => !!d).map(d => Number(d.slice(0, 4))).filter(Boolean)\n const now = Number(today().slice(0, 4))\n const min = Math.min(...years, now - 1)\n const span = Math.max(1, now + 1 - min)\n const pos = (d: string | undefined, end: boolean): number => {\n if (!d) return end ? 100 : 0\n const [y, m] = [Number(d.slice(0, 4)), Number(d.slice(5, 7)) || (end ? 12 : 1)]\n return Math.min(100, Math.max(0, ((y - min) + (m - 1) / 12) / span * 100))\n }\n let html = `<div class=\"ox-tl-axis\"><span></span><span class=\"yrs\"><span>${min}</span><span>${now}</span></span></div>`\n for (const it of items) {\n const left = pos(it.since, false)\n const right = pos(it.until, true)\n const label = `${it.since ?? \"…\"} → ${it.until ?? \"now\"}`\n html += `<div class=\"ox-tl-row\"><div class=\"who\">${it.chips.map(esc).join(\", \")}<small>${it.entityId ? `<a href=\"${entityHref(it.entityId)}\">${esc(it.label)}</a>` : esc(it.label)}</small></div>`\n + `<div class=\"ox-track\"><i class=\"${it.until ? \"past\" : \"\"}\" style=\"left:${left.toFixed(1)}%;width:${Math.max(4, right - left).toFixed(1)}%\" title=\"${esc(label)}\">${esc(label)}</i></div></div>`\n }\n return html\n}\n\n/** A panel card. `full` is the Z3 view: no zoom link, minor events unfolded. */\nexport function panelCard(g: WikiGraph, e: Entity, p: PanelData, full: boolean, notesHtml = \"\"): string {\n const zin = !full && (p.total > p.items.length || p.def.source === \"notes\" || p.folded.length)\n ? `<a class=\"zin\" href=\"${entityHref(e.id)}/${encodeURIComponent(p.def.panel)}\">all ${p.total || \"\"} (Z3) →</a>` : \"\"\n const isNotes = p.def.source === \"notes\" || p.def.panel === \"notes\"\n const count = isNotes ? `${e.pages.length} page${e.pages.length === 1 ? \"\" : \"s\"}` : `${p.total} ${p.total === 1 ? \"item\" : \"items\"}`\n const note = `<span class=\"note\">${p.ownerOnly ? `${icon(\"lock\")} private to the owner · ` : \"\"}${count}</span>`\n let body = \"\"\n if (p.def.source === \"notes\" || p.def.panel === \"notes\") {\n body = notesHtml || `<div class=\"ox-empty\">No notes.</div>`\n } else if (p.items.length === 0) {\n body = `<div class=\"ox-empty\">Nothing recorded yet.</div>`\n } else if (p.def.display === \"timeline\" && p.items.some(i => i.since)) {\n body = timeline(p.items)\n } else if (p.def.source === \"history\" || p.items.every(i => i.type === \"event\")) {\n body = p.items.map(eventRow).join(\"\")\n } else {\n body = p.items.map(it => rowHtml(g, e, it)).join(\"\")\n }\n for (const r of p.rollups) body += `<div class=\"ox-fold\">↻ Recurring: ${esc(r)}</div>`\n if (p.folded.length) {\n body += `<details class=\"ox-fold\"><summary>+ ${p.folded.length} minor event${p.folded.length === 1 ? \"\" : \"s\"}</summary>${p.folded.slice(0, 20).map(eventRow).join(\"\")}</details>`\n }\n const wide = p.def.display === \"timeline\" || p.def.source === \"notes\" || p.def.panel === \"notes\" ? \" wide\" : \"\"\n return `<section class=\"ox-card${wide}\"><div class=\"ox-card-h\"><h2>${esc(p.title)}</h2>${note}${zin}</div>${body}</section>`\n}\n","// --- Entity pages: overview (Z2), one panel (Z3), one statement (Z4) ---\n\nimport { markdownToHtml } from \"@/utils/markdown-html\"\nimport type { WikiEntry } from \"../types\"\nimport { normName, type Entity, type WikiGraph } from \"./graph\"\nimport { lensFor, panelData } from \"./lens\"\nimport { panelSource } from \"./load\"\nimport type { LensPanel } from \"./types\"\nimport { panelCard } from \"./view-panels\"\nimport { crumbs, entityHref, esc, icon, layout, sidebar, typeIcon, typeLabel, zoomBar } from \"./view-layout\"\n\nexport interface EntityViewCtx {\n g: WikiGraph\n readEntries: (ids: string[]) => WikiEntry[]\n /** Saved earlier versions of one agent's page, newest first. */\n versions: (agentId: string, path: string) => Array<{ timestamp: string }>\n}\n\n/** Article markdown with [[links]] pointing at entity pages. */\nexport function wikiMd(g: WikiGraph, text: string): string {\n return markdownToHtml(text.replace(/<!--\\s*tags?:[^>]*-->\\s*\\n?/gi, \"\"), {\n wikilink: (target, display) => {\n const id = g.names.get(normName(target))\n return id\n ? `<a href=\"${entityHref(id)}\" class=\"wikilink\">${display}</a>`\n : `<a href=\"/find?q=${encodeURIComponent(target)}\" class=\"wikilink broken\" title=\"No page yet\">${display}</a>`\n },\n })\n}\n\n/** Page body without a second frontmatter block some older pages carry. */\nexport function bodyOf(content: string): string {\n return content.replace(/^---\\n[\\s\\S]*?\\n---\\n?/, \"\").trim()\n}\n\n/** First paragraph of the first page, as plain text. */\nexport function summaryOf(e: Entity, max = 360): string {\n const body = bodyOf(e.pages[0]?.article.content ?? \"\")\n const para = body.split(/\\n\\s*\\n/).map(p => p.trim()).find(p => p && !p.startsWith(\"#\") && !p.startsWith(\"|\") && !p.startsWith(\"```\")) ?? \"\"\n const plain = para\n .replace(/\\[\\[([^\\]|]+)(?:\\|([^\\]]+))?\\]\\]/g, (_m, t, d) => d ?? t)\n .replace(/\\[([^\\]]+)\\]\\([^)]*\\)/g, \"$1\")\n .replace(/^[-*]\\s+/gm, \"\")\n .replace(/[*_`]/g, \"\")\n .replace(/\\s+/g, \" \")\n .trim()\n return plain.length > max ? `${plain.slice(0, max - 1)}…` : plain\n}\n\nfunction pillarOf(g: WikiGraph, e: Entity) {\n return g.ontology.pillars.find(p => p.id === e.pillar)\n}\n\nfunction entityCrumbs(g: WikiGraph, e: Entity, tail: Array<{ label: string; href?: string }> = []): string {\n const p = pillarOf(g, e)\n return crumbs([\n { label: p?.label ?? e.pillar, href: `/p/${encodeURIComponent(e.pillar)}` },\n { label: typeLabel(g.ontology, e.type), href: `/p/${encodeURIComponent(e.pillar)}?kind=${encodeURIComponent(e.type)}` },\n { label: e.title, href: tail.length ? entityHref(e.id) : undefined },\n ...tail,\n ])\n}\n\nfunction notesHtml(g: WikiGraph, e: Entity, full: boolean): string {\n if (!full) {\n const first = e.pages[0]\n if (!first) return \"\"\n const text = bodyOf(first.article.content)\n const short = text.length > 1600 ? `${text.slice(0, 1600).replace(/\\n[^\\n]*$/, \"\")}\\n\\n…` : text\n return `<div class=\"ox-prose\">${wikiMd(g, short)}</div>`\n }\n return e.pages.map(p => `<div class=\"ox-sub\">from ${esc(p.agentId)} · ${esc(p.article.path)} · updated ${esc(p.article.meta.lastUpdated || \"—\")}</div>`\n + `<div class=\"ox-prose\">${wikiMd(g, bodyOf(p.article.content))}</div>`).join(`<hr style=\"border:0;border-top:1px solid var(--edge);margin:16px 0\">`)\n}\n\nfunction rail(g: WikiGraph, e: Entity, lens: LensPanel[]): string {\n const t = g.ontology.types.find(x => x.id === e.type)\n let html = `<span class=\"ox-lbl\">Lens for this type</span><div class=\"ox-annot\"><b>${esc(t?.label ?? e.type)}</b> opens with:<ol>`\n html += lens.map(p => `<li>${esc(p.title ?? p.panel)}</li>`).join(\"\")\n html += `</ol><span class=\"ox-sub\">from ontology.yaml · types.${esc(e.type)}.lens</span></div>`\n html += `<span class=\"ox-lbl\" style=\"margin-top:20px\">Zoom in</span>`\n for (const p of lens) {\n html += `<div class=\"ox-row\"><span class=\"ox-ic\">${icon(panelSource(p) === \"history\" ? \"calendar\" : panelSource(p) === \"discussed\" ? \"chat\" : \"arrow\")}</span><div class=\"t\"><a href=\"${entityHref(e.id)}/${encodeURIComponent(p.panel)}\">${esc(p.title ?? p.panel)}</a><div class=\"ox-sub\">Z3 · in full</div></div></div>`\n }\n html += `<span class=\"ox-lbl\" style=\"margin-top:20px\">Provenance</span>`\n const byAgent = new Map<string, number>()\n for (const p of e.pages) byAgent.set(p.agentId, (byAgent.get(p.agentId) ?? 0) + 1)\n for (const [agent, n] of byAgent) {\n const page = e.pages.find(p => p.agentId === agent)!\n html += `<div class=\"ox-row\"><span class=\"ox-ic\">${icon(\"agent\")}</span><div class=\"t\"><a href=\"/agent/${encodeURIComponent(agent)}/article/${encodeURIComponent(page.article.path)}\">${esc(agent)}</a><div class=\"ox-sub\">${n} page${n === 1 ? \"\" : \"s\"} · ${e.statements.filter(s => s.page.agentId === agent).length} statements</div></div></div>`\n }\n if (e.pages.length > 1) html += `<div class=\"ox-row\"><span class=\"ox-ic\">${icon(\"merge\")}</span><div class=\"t\"><span class=\"l\">${e.pages.length} pages merged</span><div class=\"ox-sub\">same name, one entity</div></div></div>`\n return html\n}\n\n/** Z2: one thing, through the lens of its type. */\nexport function entityPage(ctx: EntityViewCtx, e: Entity): string {\n const { g } = ctx\n const lens = lensFor(g, e.type)\n const t = g.ontology.types.find(x => x.id === e.type)\n const pinned = g.ontology.sidebar.pins.some(p => g.names.get(normName(p)) === e.id)\n let main = `<div class=\"ox-bar\">${entityCrumbs(g, e)}${zoomBar(2)}</div>`\n main += `<div class=\"ox-head\"><div class=\"ox-avatar\">${typeIcon(g.ontology, e.type)}</div><div><h1>${esc(e.title)}</h1><div class=\"ox-chips\">`\n main += `<span class=\"ox-chip type\">${typeIcon(g.ontology, e.type)}${esc(t?.label ?? e.type)}</span>`\n if (t?.schema) main += `<span class=\"ox-chip mono\">${esc(t.schema.includes(\" \") || t.schema.includes(\":\") ? t.schema : `schema.org/${t.schema}`)}</span>`\n if (e.type === \"event\") main += `<span class=\"ox-st ${e.importance}\">${e.importance}</span>`\n if (pinned) main += `<span class=\"ox-chip\">pinned</span>`\n if (e.pages.length > 1) main += `<span class=\"ox-chip\">${icon(\"merge\")}merged from ${e.pages.length} pages</span>`\n main += `</div></div></div>`\n\n const summary = summaryOf(e)\n if (summary && lens[0]?.panel !== \"notes\") {\n main += `<section class=\"ox-card\"><p class=\"ox-summary\">${esc(summary)}</p><div class=\"ox-meta\"><span>updated ${esc(e.updated || \"—\")}</span><span>sources: ${e.sources.length}</span><span>${e.statements.length} statements</span></div></section>`\n }\n main += `<div class=\"ox-grid2\">`\n for (const def of lens) {\n const data = panelData(g, e, def, { full: false, readEntries: ctx.readEntries })\n const isNotes = panelSource(def) === \"notes\"\n main += panelCard(g, e, data, false, isNotes ? notesHtml(g, e, false) : \"\")\n }\n main += `</div>`\n return layout(e.title, sidebar(g, { pillar: e.pillar, entity: e.id }), main, rail(g, e, lens))\n}\n\n/** Z3: one panel in full, paginated. */\nexport function panelPage(ctx: EntityViewCtx, e: Entity, panelId: string, page: number): string | null {\n const { g } = ctx\n const def = lensFor(g, e.type).find(p => p.panel === panelId)\n if (!def) return null\n const data = panelData(g, e, def, { full: true, page, pageSize: 50, readEntries: ctx.readEntries })\n const title = def.title ?? def.panel\n let main = `<div class=\"ox-bar\">${entityCrumbs(g, e, [{ label: title }])}${zoomBar(3)}</div>`\n main += `<div class=\"ox-head\"><div class=\"ox-avatar\">${typeIcon(g.ontology, e.type)}</div><div><h1>${esc(title)}</h1><p>${esc(e.title)} · ${data.total} item${data.total === 1 ? \"\" : \"s\"}</p></div></div>`\n const isNotes = panelSource(def) === \"notes\"\n main += panelCard(g, e, data, true, isNotes ? notesHtml(g, e, true) : \"\")\n const pages = Math.ceil(data.total / 50)\n if (pages > 1) {\n const base = `${entityHref(e.id)}/${encodeURIComponent(panelId)}`\n main += `<div class=\"ox-pager\">${page > 1 ? `<a href=\"${base}?page=${page - 1}\">← newer</a>` : \"\"}<span>page ${page} of ${pages}</span>${page < pages ? `<a href=\"${base}?page=${page + 1}\">older →</a>` : \"\"}</div>`\n }\n return layout(`${title} · ${e.title}`, sidebar(g, { pillar: e.pillar, entity: e.id }), main)\n}\n\n/** Z4: one statement with where it comes from. */\nexport function statementPage(ctx: EntityViewCtx, e: Entity, index: number): string | null {\n const { g } = ctx\n const st = e.statements[index]\n if (!st) return null\n const prop = g.ontology.properties.find(p => p.id === st.property)\n const target = st.target ? g.entities.get(st.target) : undefined\n const meta = st.page.article.meta\n const rows: Array<[string, string]> = [\n [\"Subject\", `<a href=\"${entityHref(e.id)}\">${esc(e.title)}</a>`],\n [\"Property\", `${esc(prop?.label ?? st.property)}${prop?.wikidata ? ` <span class=\"ox-sub\">wikidata ${esc(prop.wikidata)}</span>` : \"\"}`],\n [\"Value\", target ? `<a href=\"${entityHref(target.id)}\">${esc(target.title)}</a>` : esc(st.value)],\n ]\n if (st.role) rows.push([\"Role\", esc(st.role)])\n if (st.metric) rows.push([\"Metric\", esc(st.metric)])\n if (st.since || st.until) rows.push([\"True\", `${esc(st.since ?? \"…\")} → ${esc(st.until ?? \"now\")}`])\n if (st.at) rows.push([\"Measured\", esc(st.at)])\n rows.push([\"Recorded\", esc(meta.lastUpdated || meta.created || \"—\")])\n rows.push([\"Source\", esc(st.source ?? (meta.sources.length ? `${meta.sources.length} conversation entries` : \"not given\"))])\n rows.push([\"Written by\", `${esc(st.page.agentId)} · <a href=\"/agent/${encodeURIComponent(st.page.agentId)}/article/${encodeURIComponent(st.page.article.path)}\">${esc(st.page.article.path)}</a>`])\n rows.push([\"Status\", st.status ? `<span class=\"ox-st ${esc(st.status)}\">${esc(st.status)}</span>` : \"not set\"])\n if (st.confirmed_by) rows.push([\"Confirmed by\", esc(st.confirmed_by)])\n if (st.checked_at) rows.push([\"Checked\", esc(st.checked_at)])\n rows.push([\"Access\", esc(st.access ?? meta.access)])\n if (st.note) rows.push([\"Note\", esc(st.note)])\n const versions = ctx.versions(st.page.agentId, st.page.article.path)\n rows.push([\"Past versions\", versions.length ? versions.slice(0, 8).map(v => esc(v.timestamp)).join(\"<br>\") : \"none saved\"])\n\n let main = `<div class=\"ox-bar\">${entityCrumbs(g, e, [{ label: prop?.label ?? st.property }])}${zoomBar(4)}</div>`\n main += `<div class=\"ox-head\"><div class=\"ox-avatar\">${icon(\"key\")}</div><div><h1>${esc(prop?.label ?? st.property)}</h1><p>${esc(e.title)} → ${esc(target?.title ?? st.value)}</p></div></div>`\n main += `<section class=\"ox-card\">${rows.map(([k, v]) => `<div class=\"ox-kv\"><span class=\"k\">${k}</span><span>${v}</span></div>`).join(\"\")}</section>`\n return layout(`${prop?.label ?? st.property} · ${e.title}`, sidebar(g, { pillar: e.pillar, entity: e.id }), main)\n}\n","// --- Home, pillar pages (Z1), full kind lists, search, ontology page ---\n\nimport type { Entity, WikiGraph } from \"./graph\"\nimport { linkedEntities } from \"./lens\"\nimport { summaryOf } from \"./view-entity\"\nimport { IMPORTANCE_LEVELS } from \"./types\"\nimport { crumbs, entityHref, esc, icon, layout, sidebar, typeIcon, typeLabel, zoomBar } from \"./view-layout\"\n\nconst DAY = 86_400_000\n\nfunction byType(g: WikiGraph): Map<string, Entity[]> {\n const out = new Map<string, Entity[]>()\n for (const e of g.entities.values()) {\n const list = out.get(e.type) ?? []\n list.push(e)\n out.set(e.type, list)\n }\n return out\n}\n\n/** Latest activity: newest linked event, else the page's own date. */\nfunction activity(g: WikiGraph, e: Entity): string {\n if (e.type === \"event\") return e.date || e.updated\n const ev = linkedEntities(g, e, new Set([\"event\"]))[0]\n const own = e.updated || e.date\n return ev && ev.date > own ? ev.date : own\n}\n\ninterface Attention { e: Entity; chip: string; why: string }\n\n/** Things that need a person: unconfirmed, due soon, late, or a recent major event. */\nexport function needsAttention(g: WikiGraph, entities: Entity[], now = Date.now()): Attention[] {\n const out: Attention[] = []\n const soon = new Date(now + 14 * DAY).toISOString().slice(0, 10)\n const today = new Date(now).toISOString().slice(0, 10)\n for (const e of entities) {\n const due = e.statements.find(s => s.property === \"due\" && /^\\d{4}-\\d{2}-\\d{2}/.test(s.value))\n const fulfilled = e.statements.some(s => s.property === \"fulfilled_by\") || e.statements.some(s => s.property === \"status\" && /^(fulfilled|done|paid|filed)$/i.test(s.value))\n if (e.statements.some(s => s.property === \"status\" && /^late$/i.test(s.value))) {\n out.push({ e, chip: \"late\", why: \"marked late\" })\n } else if (due && !fulfilled && due.value < today) {\n out.push({ e, chip: \"late\", why: `was due ${due.value}` })\n } else if (due && !fulfilled && due.value <= soon) {\n out.push({ e, chip: \"due\", why: `due ${due.value}` })\n } else if (e.statements.some(s => s.status === \"proposed\")) {\n out.push({ e, chip: \"proposed\", why: \"statements wait for confirmation\" })\n } else if (e.type === \"event\" && e.importance === \"major\" && e.date && now - Date.parse(e.date) <= 30 * DAY) {\n out.push({ e, chip: \"major\", why: `major event ${e.date}` })\n }\n }\n const rank: Record<string, number> = { late: 0, due: 1, major: 2, proposed: 3 }\n return out.sort((a, b) => rank[a.chip] - rank[b.chip])\n}\n\nfunction entityRow(g: WikiGraph, e: Entity, right = \"\", sub?: string): string {\n return `<div class=\"ox-row\"><span class=\"ox-ic\">${typeIcon(g.ontology, e.type)}</span><div class=\"t\"><a href=\"${entityHref(e.id)}\">${esc(e.title)}</a>`\n + `<div class=\"ox-sub\">${esc(sub ?? `${typeLabel(g.ontology, e.type).toLowerCase()} · ${activity(g, e)}`)}</div></div><div class=\"r\">${right}</div></div>`\n}\n\nfunction attentionCard(g: WikiGraph, list: Attention[]): string {\n const rows = list.slice(0, 6).map(a => entityRow(g, a.e, `<span class=\"ox-st ${a.chip}\">${a.chip}</span>`, a.why)).join(\"\")\n return `<section class=\"ox-card\"><div class=\"ox-card-h\"><h2>Needs attention</h2><span class=\"note\">${list.length}</span></div>${rows || `<div class=\"ox-empty\">Nothing waits on a person.</div>`}</section>`\n}\n\nfunction errorsBox(errors: string[]): string {\n if (!errors.length) return \"\"\n return `<div class=\"ox-err\"><b>ontology.yaml has ${errors.length} problem${errors.length === 1 ? \"\" : \"s\"}</b> — the defaults are used where they apply. <a href=\"/ontology\">See them</a></div>`\n}\n\nexport function homePage(g: WikiGraph, errors: string[]): string {\n const types = byType(g)\n let main = `<div class=\"ox-bar\">${crumbs([])}</div>`\n main += `<div class=\"ox-head\"><div class=\"ox-avatar\">${icon(\"home\")}</div><div><h1>Wiki</h1><p>${g.entities.size} things, merged from every agent's pages and typed by the <a href=\"/ontology\">ontology</a>. <a href=\"/agents\">Agent wikis</a> · <a href=\"/entries\">raw entries</a></p></div></div>`\n main += errorsBox(errors)\n main += `<div class=\"ox-grid3\">`\n for (const p of g.ontology.pillars) {\n const inPillar = g.ontology.types.filter(t => t.pillar === p.id)\n const count = inPillar.reduce((n, t) => n + (types.get(t.id)?.length ?? 0), 0)\n const kinds = inPillar.filter(t => types.get(t.id)?.length).map(t => `${t.plural ?? t.label} ${types.get(t.id)!.length}`).join(\" · \")\n main += `<a class=\"ox-card\" href=\"/p/${encodeURIComponent(p.id)}\" style=\"color:inherit\"><div class=\"ox-card-h\"><span class=\"ox-ic\">${icon(p.icon)}</span><h2>${esc(p.label)}</h2><span class=\"zin\">${count}</span></div><div class=\"ox-sub\" style=\"white-space:normal\">${esc(p.description ?? \"\")}</div><div class=\"ox-sub\" style=\"margin-top:6px;white-space:normal\">${esc(kinds || \"nothing yet\")}</div></a>`\n }\n main += `</div><div class=\"ox-grid2\">`\n const events = (types.get(\"event\") ?? []).filter(e => e.importance !== \"minor\").sort((a, b) => b.date.localeCompare(a.date)).slice(0, 8)\n main += `<section class=\"ox-card\"><div class=\"ox-card-h\"><h2>Recent events</h2><span class=\"note\">major and normal</span><a class=\"zin\" href=\"/p/events\">all (Z1) →</a></div>`\n + (events.map(e => `<div class=\"ox-ev\"><span class=\"d\">${esc(e.date)}</span><span class=\"ox-st ${e.importance}\">${e.importance}</span><a href=\"${entityHref(e.id)}\">${esc(e.title)}</a></div>`).join(\"\") || `<div class=\"ox-empty\">No events yet.</div>`) + `</section>`\n main += attentionCard(g, needsAttention(g, [...g.entities.values()]))\n main += `</div>`\n return layout(\"Wiki\", sidebar(g, { home: true }), main)\n}\n\n/** Z1: the kinds inside a pillar as tabs, what needs attention, the most active pages. */\nexport function pillarPage(g: WikiGraph, pillarId: string, kind: string | null): string | null {\n const p = g.ontology.pillars.find(x => x.id === pillarId)\n if (!p) return null\n const types = byType(g)\n const kinds = g.ontology.types.filter(t => t.pillar === p.id)\n const active = kinds.find(t => t.id === kind) ?? kinds.find(t => types.get(t.id)?.length) ?? kinds[0]\n let main = `<div class=\"ox-bar\">${crumbs([{ label: p.label }])}${zoomBar(1)}</div>`\n main += `<div class=\"ox-head\"><div class=\"ox-avatar\">${icon(p.icon)}</div><div><h1>${esc(p.label)}</h1><p>${esc(p.description ?? \"\")}</p></div></div>`\n main += `<nav class=\"ox-tabs\">${kinds.map(t => `<a class=\"${t.id === active?.id ? \"on\" : \"\"}\" href=\"/p/${encodeURIComponent(p.id)}?kind=${encodeURIComponent(t.id)}\">${esc(t.plural ?? t.label)}<small>${types.get(t.id)?.length ?? 0}</small></a>`).join(\"\")}</nav>`\n const list = active ? (types.get(active.id) ?? []).map(e => ({ e, at: activity(g, e) })).sort((a, b) => b.at.localeCompare(a.at)) : []\n main += `<div class=\"ox-grid2\">`\n main += `<section class=\"ox-card\"><div class=\"ox-card-h\"><h2>${esc(active?.plural ?? active?.label ?? \"\")}</h2><span class=\"note\">${list.length} · most active first</span>`\n + (active ? `<a class=\"zin\" href=\"/p/${encodeURIComponent(p.id)}/${encodeURIComponent(active.id)}\">open list (Z3) →</a>` : \"\") + `</div>`\n + (list.slice(0, 5).map(({ e, at }) => entityRow(g, e, e.type === \"event\" ? `<span class=\"ox-st ${e.importance}\">${e.importance}</span>` : \"\", `${summaryOf(e, 90) || typeLabel(g.ontology, e.type).toLowerCase()} · ${at}`)).join(\"\") || `<div class=\"ox-empty\">No ${esc((active?.plural ?? \"pages\").toLowerCase())} yet.</div>`)\n + `</section>`\n const inPillar = kinds.flatMap(t => types.get(t.id) ?? [])\n main += attentionCard(g, needsAttention(g, inPillar))\n main += `</div>`\n return layout(p.label, sidebar(g, { pillar: p.id }), main)\n}\n\n/** Every page of one kind, paginated. */\nexport function kindListPage(g: WikiGraph, pillarId: string, typeId: string, page: number, requested: string | null): string | null {\n // Only known levels reach the filter and the pager hrefs; anything else lists every page.\n const importance = requested && (IMPORTANCE_LEVELS as readonly string[]).includes(requested) ? requested : null\n const p = g.ontology.pillars.find(x => x.id === pillarId)\n const t = g.ontology.types.find(x => x.id === typeId && x.pillar === pillarId)\n if (!p || !t) return null\n let list = [...g.entities.values()].filter(e => e.type === t.id)\n if (importance) list = list.filter(e => e.importance === importance)\n const rows = list.map(e => ({ e, at: activity(g, e) })).sort((a, b) => b.at.localeCompare(a.at))\n const size = 50\n const pages = Math.max(1, Math.ceil(rows.length / size))\n const base = `/p/${encodeURIComponent(p.id)}/${encodeURIComponent(t.id)}`\n let main = `<div class=\"ox-bar\">${crumbs([{ label: p.label, href: `/p/${encodeURIComponent(p.id)}` }, { label: t.plural ?? t.label }])}${zoomBar(3)}</div>`\n main += `<div class=\"ox-head\"><div class=\"ox-avatar\">${icon(t.icon)}</div><div><h1>${esc(t.plural ?? t.label)}</h1><p>${rows.length} page${rows.length === 1 ? \"\" : \"s\"}${importance ? ` · ${esc(importance)} only` : \"\"}</p></div></div>`\n if (t.id === \"event\") {\n main += `<nav class=\"ox-tabs\">${[\"\", \"major\", \"normal\", \"minor\"].map(lv => `<a class=\"${(importance ?? \"\") === lv ? \"on\" : \"\"}\" href=\"${base}${lv ? `?importance=${lv}` : \"\"}\">${lv || \"all\"}</a>`).join(\"\")}</nav>`\n }\n main += `<section class=\"ox-card\" style=\"margin-top:16px\">`\n + (rows.slice((page - 1) * size, page * size).map(({ e, at }) => entityRow(g, e, e.type === \"event\" ? `<span class=\"ox-st ${e.importance}\">${e.importance}</span>` : \"\", `${at} · ${e.pages.map(x => x.agentId).filter((a, i, all) => all.indexOf(a) === i).join(\", \")}`)).join(\"\") || `<div class=\"ox-empty\">None.</div>`)\n + `</section>`\n if (pages > 1) {\n const q = importance ? `importance=${importance}&` : \"\"\n main += `<div class=\"ox-pager\">${page > 1 ? `<a href=\"${base}?${q}page=${page - 1}\">← previous</a>` : \"\"}<span>page ${page} of ${pages}</span>${page < pages ? `<a href=\"${base}?${q}page=${page + 1}\">next →</a>` : \"\"}</div>`\n }\n return layout(t.plural ?? t.label, sidebar(g, { pillar: p.id }), main)\n}\n\nexport function findPage(g: WikiGraph, q: string): string {\n const needle = q.trim().toLowerCase()\n const scored: Array<{ e: Entity; s: number }> = []\n if (needle) {\n for (const e of g.entities.values()) {\n const title = e.title.toLowerCase()\n let s = title === needle ? 100 : title.startsWith(needle) ? 60 : title.includes(needle) ? 40 : 0\n if (!s && e.pages.some(p => p.article.content.toLowerCase().includes(needle))) s = 10\n if (s) scored.push({ e, s })\n }\n }\n scored.sort((a, b) => b.s - a.s || (b.e.updated).localeCompare(a.e.updated))\n let main = `<div class=\"ox-bar\">${crumbs([{ label: \"Search\" }])}</div>`\n main += `<div class=\"ox-head\"><div class=\"ox-avatar\">${icon(\"search\")}</div><div><h1>${needle ? `“${esc(q)}”` : \"Search\"}</h1><p>${scored.length} match${scored.length === 1 ? \"\" : \"es\"}</p></div></div>`\n main += `<section class=\"ox-card\">${scored.slice(0, 60).map(({ e }) => entityRow(g, e)).join(\"\") || `<div class=\"ox-empty\">No page matches.</div>`}</section>`\n return layout(`Search: ${q}`, sidebar(g, {}), main, \"\", q)\n}\n\n/** What the ontology holds, and any problems in ontology.yaml. */\nexport function ontologyPage(g: WikiGraph, errors: string[], file: string | null): string {\n const o = g.ontology\n const types = byType(g)\n let main = `<div class=\"ox-bar\">${crumbs([{ label: \"Ontology\" }])}</div>`\n main += `<div class=\"ox-head\"><div class=\"ox-avatar\">${icon(\"steps\")}</div><div><h1>Ontology</h1><p>${file ? `Read from ${esc(file)}` : \"Built-in defaults. Run <code>agentx wiki ontology init</code> to write an ontology.yaml you can edit.\"}</p></div></div>`\n if (errors.length) main += `<div class=\"ox-err\"><b>Problems</b><ul>${errors.map(e => `<li>${esc(e)}</li>`).join(\"\")}</ul></div>`\n main += `<section class=\"ox-card\"><div class=\"ox-card-h\"><h2>Types</h2><span class=\"note\">${o.types.length}</span></div>`\n for (const t of o.types) {\n const pillar = o.pillars.find(p => p.id === t.pillar)\n main += `<div class=\"ox-row\"><span class=\"ox-ic\">${icon(t.icon)}</span><div class=\"t\"><span class=\"l\">${esc(t.label)} <span class=\"ox-sub\">${esc(t.id)}</span></span><div class=\"ox-sub\">${esc(pillar?.label ?? t.pillar)} · lens: ${esc((t.lens ?? []).map(l => l.title ?? l.panel).join(\" → \"))}</div></div><div class=\"r\"><span class=\"ox-chip\">${types.get(t.id)?.length ?? 0}</span></div></div>`\n }\n main += `</section><section class=\"ox-card\" style=\"margin-top:16px\"><div class=\"ox-card-h\"><h2>Relations</h2><span class=\"note\">${o.properties.length}</span></div>`\n for (const p of o.properties) {\n main += `<div class=\"ox-kv\"><span class=\"k\">${esc(p.id)}</span><span>${esc(p.label)}${p.inverse ? ` · inverse: ${esc(p.inverse)}` : \"\"}${p.wikidata ? ` <span class=\"ox-sub\">${esc(p.wikidata)}</span>` : \"\"}</span></div>`\n }\n main += `</section><section class=\"ox-card\" style=\"margin-top:16px\"><div class=\"ox-card-h\"><h2>Event importance</h2></div><div class=\"ox-kv\"><span class=\"k\">default</span><span>${esc(o.importance.default)}</span></div><div class=\"ox-kv\"><span class=\"k\">major set by</span><span>${esc(o.importance.major_set_by)}</span></div><div class=\"ox-kv\"><span class=\"k\">roll-up</span><span>${o.importance.rollup.min} minor events in ${o.importance.rollup.days} days</span></div></section>`\n return layout(\"Ontology\", sidebar(g, {}), main)\n}\n","// --- Routes for the knowledge-graph view (#811) ---\n//\n// / Home: pillars, recent events, needs attention\n// /p/<pillar>?kind=<t> Z1 pillar, one kind open\n// /p/<pillar>/<type> every page of one kind (paginated)\n// /e/<id> Z2 entity overview, through its type's lens\n// /e/<id>/<panel> Z3 one panel in full (paginated)\n// /e/<id>/s/<n> Z4 one statement and its source\n// /find?q= search by name, then by text\n// /ontology the ontology in use and its problems\n\nimport type { WikiHub } from \"../hub\"\nimport { GraphCache } from \"./graph\"\nimport { loadOntology } from \"./load\"\nimport { entityPage, panelPage, statementPage, type EntityViewCtx } from \"./view-entity\"\nimport { findPage, homePage, kindListPage, ontologyPage, pillarPage } from \"./view-browse\"\n\nexport class OntologyRoutes {\n private cache = new GraphCache()\n\n constructor(private hub: WikiHub, private wikiDir: string) {}\n\n /** HTML for the path, or null when the path is not one of these routes\n * or names something that does not exist. */\n handle(path: string, params: URLSearchParams): string | null {\n if (!(path === \"/\" || path === \"\" || path.startsWith(\"/p/\") || path.startsWith(\"/e/\") || path === \"/find\" || path === \"/ontology\")) return null\n const { ontology, errors, file } = loadOntology(this.wikiDir)\n const g = this.cache.get(this.hub, ontology)\n const page = Math.max(1, Number(params.get(\"page\")) || 1)\n\n if (path === \"/\" || path === \"\") return homePage(g, errors)\n if (path === \"/find\") return findPage(g, params.get(\"q\") ?? \"\")\n if (path === \"/ontology\") return ontologyPage(g, errors, file)\n\n // The caller already decoded the path.\n const parts = path.split(\"/\").filter(Boolean)\n if (parts[0] === \"p\") {\n if (parts.length === 2) return pillarPage(g, parts[1], params.get(\"kind\"))\n if (parts.length === 3) return kindListPage(g, parts[1], parts[2], page, params.get(\"importance\"))\n return null\n }\n const e = g.entities.get(parts[1] ?? \"\")\n if (!e) return null\n const ctx: EntityViewCtx = {\n g,\n readEntries: ids => this.hub.getSharedStore().readEntries(ids),\n versions: (agentId, articlePath) => this.hub.getAgentWiki(agentId).getVersions(articlePath),\n }\n if (parts.length === 2) return entityPage(ctx, e)\n if (parts.length === 3) return panelPage(ctx, e, parts[2], page)\n if (parts.length === 4 && parts[2] === \"s\") return statementPage(ctx, e, Number(parts[3]))\n return null\n }\n}\n","import type Database from \"better-sqlite3\"\nimport { CLOSED_STATES, OPEN_STATES } from \"@/requests/store\"\n\n// --- What a person asked for, across every channel (#384) ---\n//\n// Reads the `person` stamp on runs (task_traces) and on open requests.\n\nexport interface PersonRun {\n taskId: string\n agentId: string\n channel: string | null\n chatId: string | null\n status: string\n startedAt: number\n finishedAt: number | null\n messagePreview: string | null\n}\n\n/** The latest turns a person started, newest first. Delegated hops are\n * left out: they carry the same person but are the agents' own work. */\nexport function runsOf(db: Database.Database, personId: string, limit = 20): PersonRun[] {\n const rows = db.prepare(\n `SELECT task_id, agent_id, channel, chat_id, status, started_at, finished_at, message_preview\n FROM task_traces\n WHERE person = ? AND (channel IS NULL OR channel != 'a2a')\n ORDER BY started_at DESC, rowid DESC LIMIT ?`,\n ).all(personId, Math.max(1, Math.min(limit, 500))) as any[]\n return rows.map((r) => ({\n taskId: r.task_id, agentId: r.agent_id, channel: r.channel, chatId: r.chat_id,\n status: r.status, startedAt: r.started_at, finishedAt: r.finished_at ?? null, messagePreview: r.message_preview,\n }))\n}\n\nexport interface PersonRequest {\n id: string\n state: string\n channel: string\n agentId: string\n text: string\n createdAt: number\n}\n\n/** Whether requests carry the person stamp. False when requests were\n * never turned on. */\nfunction requestsReady(db: Database.Database): boolean {\n const has = db.prepare(\"SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'requests'\").get()\n if (!has) return false\n const cols = db.prepare(\"PRAGMA table_info(requests)\").all() as Array<{ name: string }>\n return cols.some((c) => c.name === \"person\")\n}\n\nfunction requestsIn(db: Database.Database, personId: string, states: readonly string[], tail: string, ...args: number[]): PersonRequest[] {\n if (!requestsReady(db)) return []\n const rows = db.prepare(\n `SELECT id, state, channel, agent_id, text, created_at FROM requests\n WHERE person = ? AND state IN (${states.map(() => \"?\").join(\",\")})\n ${tail}`,\n ).all(personId, ...states, ...args) as any[]\n return rows.map((r) => ({ id: r.id, state: r.state, channel: r.channel, agentId: r.agent_id, text: r.text, createdAt: r.created_at }))\n}\n\n/** A person's requests that are still open (#356), oldest first. Empty\n * when requests were never turned on. */\nexport function openRequestsOf(db: Database.Database, personId: string): PersonRequest[] {\n return requestsIn(db, personId, OPEN_STATES, \"ORDER BY created_at\")\n}\n\n/** A person's requests, open and closed, each with the state it is in now,\n * newest first. Candidates are left out: nothing confirmed them yet. */\nexport function requestsOf(db: Database.Database, personId: string, limit = 50): PersonRequest[] {\n return requestsIn(db, personId, [...OPEN_STATES, ...CLOSED_STATES], \"ORDER BY created_at DESC, rowid DESC LIMIT ?\", Math.max(1, Math.min(limit, 500)))\n}\n","import type { IncomingMessage } from \"http\"\nimport { TokenStore, type TokenRecord } from \"@/daemon/token-store\"\nimport { CODE_TTL_MS, PairCodeStore, formatCode } from \"@/daemon/pair-codes\"\nimport type { PairAttemptLimiter } from \"@/daemon/app-pair-code\"\nimport { readJson } from \"@/daemon/app-fleet\"\nimport { createCard, readCard } from \"@/approvals/cards\"\nimport { splitIdentity, type Person } from \"@/people/people\"\nimport { MemberStore, type MemberDevice } from \"./store\"\n\n// --- Inviting a teammate and pairing their machine (#385) ---\n//\n// The phone app is the model (app-pair-code.ts): a one-time code, a key\n// per machine, a cookie the page holds. Three things are added for a\n// teammate, because a member key must never be an owner key:\n//\n// the right person the code is minted for one person from the people\n// list; the key it redeems carries `member:<person>`\n// and opens that person's own work and nothing else.\n// the right machine the owner says yes to each new machine on a decision\n// card that names the person, the machine and where it\n// came from. Until then the key is held.\n// the network's word where the private network says who is connecting\n// (tailscale serve sets Tailscale-User-Login on what it\n// proxies), the person must have that login among their\n// identities as `tailscale:<login>`; a mismatch is\n// refused and logged, and the code is spent. Only a\n// request that arrives from this computer (where the\n// proxy runs) is believed: anyone else could set the\n// header themselves.\n\nexport const MEMBER_SCOPE_PREFIX = \"member:\"\n/** How long a machine's key lives before the person must pair again. */\nexport const MEMBER_KEY_DAYS = 90\n/** Who the pairing card is raised by: not an agent, so no agent is told\n * the verdict; the member page reads it instead. */\nexport const PAIRING_CARD_BY = \"members\"\nexport const NETWORK_LOGIN_HEADER = \"tailscale-user-login\"\nconst MIN_MS = 400\nconst SEEN_EVERY_MS = 60 * 60 * 1000\n\n/** The person a member key belongs to, from its scope. */\nexport function personOfToken(rec: TokenRecord): string | null {\n const scope = rec.scopes.find((s) => s.startsWith(MEMBER_SCOPE_PREFIX))\n return scope ? scope.slice(MEMBER_SCOPE_PREFIX.length) : null\n}\n\n/** The active member key `token` names, with its person, else null. */\nexport function verifyMemberToken(token: string | null, tokens: TokenStore): { rec: TokenRecord; personId: string } | null {\n if (!token) return null\n const rec = tokens.verify(token)\n const personId = rec ? personOfToken(rec) : null\n return rec && personId ? { rec, personId } : null\n}\n\nexport interface MemberDeps {\n tokens: TokenStore\n codes: PairCodeStore\n members: MemberStore\n people: () => Person[]\n /** The install folder: where the decision cards live. */\n root: string\n limiter: PairAttemptLimiter\n now?: () => number\n minMs?: number\n log?: (line: string) => void\n}\n\nexport type InviteResult =\n | { ok: true; code: string; expiresAt: string; tokenId: string; person: Person }\n | { ok: false; error: string }\n\n/** Mint a key for one person and the one-time code that redeems it. */\nexport function inviteMember(deps: Pick<MemberDeps, \"tokens\" | \"codes\" | \"members\" | \"people\">, personId: string): InviteResult {\n const person = deps.people().find((p) => p.id === personId)\n if (!person) return { ok: false, error: `No person \"${personId}\". Add them first: agentx people add ${personId} --name \"…\"` }\n const { token, record } = deps.tokens.create({\n name: `${person.name} (machine not paired yet)`,\n scopes: [`${MEMBER_SCOPE_PREFIX}${person.id}`],\n expiresInDays: MEMBER_KEY_DAYS,\n })\n const { code, expiresAt } = deps.codes.create({ token, tokenId: record.id, name: person.id })\n deps.members.log({ person: person.id, device: record.id, event: \"invited\" })\n return { ok: true, code, expiresAt, tokenId: record.id, person }\n}\n\n/** How long a pairing code stays valid, in whole minutes. */\nexport const CODE_MINUTES = Math.round(CODE_TTL_MS / 60000)\n\n/** The page a person's paired machine opens at /member (#453): \"My work\"\n * for a teammate, \"Your project\" for a client. */\nexport function pageFor(role: string): string {\n return role === \"client\" ? \"Your project\" : \"My work\"\n}\n\n/**\n * The message the owner forwards to the person as it is, on WhatsApp,\n * Telegram or mail (#659): the page they get, named for their role; the\n * address and the code; the two steps on their side; and what happens next.\n * Plain words and no colour, and nothing to run: the person has no terminal\n * on this computer. `origin` is the address without a path.\n */\nexport function inviteMessage(p: { person: Pick<Person, \"name\" | \"role\">; origin: string; code: string }): string {\n const page = pageFor(p.person.role)\n const about = p.person.role === \"client\"\n ? `I use AgentX to keep track of the work I do for you. It has a page for you, \"${page}\": what you asked us for, and where each request stands.`\n : `I use AgentX to give our AI agents their jobs. It has a page for you, \"${page}\": what you asked the agents for, and where each request stands.`\n return [\n `Hi ${p.person.name},`,\n ``,\n about,\n ``,\n `To open it:`,\n `1. Accept the Tailscale share I sent you. Tailscale is a small program that connects your computer to mine, privately.`,\n `2. Open ${p.origin.replace(/\\/+$/, \"\")}/member in Edge or Chrome, give your computer a name and type this code: ${formatCode(p.code)}`,\n ` The code works once, for ${CODE_MINUTES} minutes. If it has stopped working, tell me and I will send you a new one.`,\n ``,\n `I then approve your machine, and the page opens by itself.`,\n ].join(\"\\n\")\n}\n\nexport type PairResult =\n | { status: 200; body: { person: string; name: string; state: \"pending\" }; token: string }\n | { status: 401 | 403 | 503; body: { error: string } }\n | { status: 429; body: { error: string; retryAfter: number }; retryAfter: number }\n\nexport const NETWORK_MISMATCH = \"The private network says someone else is connecting from this machine. Ask the person who invited you for a new code.\"\nexport const TOO_MANY_WAITING = \"Too many machines are waiting for the owner's answer. Try again later.\"\n/** A teammate or client has no terminal on the host, so the phone app's\n * \"run agentx app pair\" (PAIR_CODE_FAILED) is the wrong advice here (#453). */\nexport const MEMBER_CODE_FAILED = \"That code didn't work. Check it, or ask the person who invited you for a new one.\"\n\ntype ProxiedRequest = Pick<IncomingMessage, \"headers\"> & { socket?: { remoteAddress?: string } | null }\n\nconst header = (req: ProxiedRequest, name: string): string => {\n const v = req.headers[name]\n return (Array.isArray(v) ? v[0] : v || \"\").trim()\n}\n\n/** True when the request comes from this computer, which is where\n * `tailscale serve` proxies from. A local process can still pretend. */\nexport function viaLocalProxy(req: ProxiedRequest): boolean {\n const a = req.socket?.remoteAddress || \"\"\n return a === \"127.0.0.1\" || a === \"::1\" || a === \"::ffff:127.0.0.1\"\n}\n\n/** The login the private network reports for this request, if it does.\n * A header on a request that did not come through the local proxy is the\n * sender's own word, so it is ignored. */\nexport function networkLogin(req: ProxiedRequest): string | null {\n if (!viaLocalProxy(req)) return null\n const s = header(req, NETWORK_LOGIN_HEADER).toLowerCase()\n return s ? s.slice(0, 80) : null\n}\n\n/** Where the request came from: the address the local proxy reports\n * (X-Forwarded-For) when there is one, else the socket's. Behind\n * `tailscale serve` the socket is always this computer. The last entry is\n * the one the proxy itself saw; earlier ones are the sender's own word\n * when a proxy adds to the header instead of replacing it. */\nexport function clientAddress(req: ProxiedRequest): string {\n const socket = req.socket?.remoteAddress || \"unknown\"\n if (!viaLocalProxy(req)) return socket\n const seen = header(req, \"x-forwarded-for\").split(\",\").pop()!.trim()\n return /^[0-9a-fA-F:.]{2,45}$/.test(seen) ? seen : socket\n}\n\n/** A machine name as typed on the unpaired machine: letters, digits and a\n * few marks only, so it cannot pass for part of the question the owner reads. */\nexport function machineName(v: unknown): string {\n return typeof v === \"string\" ? v.replace(/[^\\p{L}\\p{N} ._'()-]/gu, \" \").replace(/\\s+/g, \" \").trim().slice(0, 60) : \"\"\n}\n\n/** The person's logins on the private network, from `tailscale:<login>` identities. */\nexport function networkIdentities(person: Person): string[] {\n return person.identities.map(splitIdentity).filter((i): i is { channel: string; value: string } => !!i && i.channel === \"tailscale\").map((i) => i.value)\n}\n\n/** POST /api/member/pair-code: trade the code for this machine's key, and\n * ask the owner to approve the machine. */\nexport async function pairMemberMachine(req: IncomingMessage, deps: MemberDeps): Promise<PairResult> {\n const started = Date.now()\n const now = deps.now ?? Date.now\n const log = deps.log ?? ((line: string) => console.log(line))\n const client = clientAddress(req)\n const wait = deps.limiter.retryAfter(client)\n if (wait > 0) {\n log(`[member] pair-code refused from ${client}: locked out for ${wait}s more`)\n return { status: 429, body: { error: \"too many attempts\", retryAfter: wait }, retryAfter: wait }\n }\n let code: unknown = null\n let machine = \"\"\n try {\n const body = await readJson(req, 2048)\n code = body.code\n machine = machineName(body.machine)\n } catch { /* counts as a wrong code */ }\n const redeemed = deps.codes.redeem(code)\n const verified = redeemed ? verifyMemberToken(redeemed.token, deps.tokens) : null\n await padTo(started, deps.minMs ?? MIN_MS)\n if (!redeemed || !verified) {\n deps.limiter.fail(client)\n log(`[member] pair-code failed from ${client}`)\n return { status: 401, body: { error: MEMBER_CODE_FAILED } }\n }\n deps.limiter.succeed(client)\n const { rec, personId } = verified\n const person = deps.people().find((p) => p.id === personId)\n if (!person) {\n deps.tokens.revoke(rec.id)\n deps.members.log({ person: personId, device: rec.id, event: \"refused\", address: client, detail: \"person no longer listed\" })\n log(`[member] pair-code for ${personId} refused from ${client}: person no longer listed`)\n return { status: 403, body: { error: MEMBER_CODE_FAILED } }\n }\n const login = networkLogin(req)\n const expected = networkIdentities(person)\n if (expected.length && (!login || !expected.includes(login))) {\n deps.tokens.revoke(rec.id)\n deps.members.log({ person: personId, device: rec.id, event: \"refused\", address: client, detail: `network login ${login ?? \"missing\"}; expected ${expected.join(\" or \")}` })\n log(`[member] ${personId}: pairing from ${client} refused: the network says \"${login ?? \"nobody\"}\", expected ${expected.join(\" or \")}`)\n return { status: 403, body: { error: NETWORK_MISMATCH } }\n }\n const name = machine || \"Unnamed machine\"\n // Cut so the card's 300-character question always fits.\n const who = person.name.slice(0, 40)\n const card = createCard(deps.root, {\n title: `New machine for ${who}`,\n ask: `From ${client}, ${login ? `network login ${login}` : \"no network login reported\"}. Machine name, as typed there: \"${name}\". Let it see ${who}'s own work?`,\n recommend: `Yes if ${who} told you they just paired this machine. No if you did not expect it.`,\n if_silent: \"discard\",\n raised_by: PAIRING_CARD_BY,\n }, { now: now() })\n if (!card.ok) {\n deps.tokens.revoke(rec.id)\n deps.members.log({ person: personId, device: rec.id, event: \"refused\", address: client, detail: card.error })\n log(`[member] ${personId}: pairing from ${client} refused: ${card.error}`)\n return { status: 503, body: { error: TOO_MANY_WAITING } }\n }\n deps.members.add({\n tokenId: rec.id, personId, name, state: \"pending\", cardId: card.card.id,\n address: client, ...(login ? { network: login } : {}), createdAt: new Date(now()).toISOString(),\n })\n deps.members.log({ person: personId, device: rec.id, event: \"paired\", address: client, detail: name })\n log(`[member] ${personId} paired \"${name}\" from ${client}; waiting for the owner (card ${card.card.id})`)\n return { status: 200, body: { person: personId, name, state: \"pending\" }, token: redeemed.token }\n}\n\nexport type AccessResult =\n | { ok: true; device: MemberDevice; personId: string; rec: TokenRecord }\n | { ok: false; status: 401; error: string }\n | { ok: false; status: 403; error: string; waiting: true }\n\nexport const NOT_PAIRED = \"this machine is not paired\"\nexport const WAITING = \"waiting for the owner to approve this machine\"\n\n/** The owner's answer on a pairing card: a card nobody answered in time is a\n * no, and one still waiting is null. */\nexport function cardAnswer(card: ReturnType<typeof readCard>): \"yes\" | \"no\" | null {\n return !card ? null : card.status === \"decided\" ? (card.verdict ?? null) : card.status === \"expired\" ? \"no\" : null\n}\n\n/** A waiting machine's answer, read without changing anything. The record\n * itself turns active or removed the next time that machine calls. */\nexport function pendingAnswer(root: string, device: Pick<MemberDevice, \"state\" | \"cardId\">): \"yes\" | \"no\" | null {\n return device.state === \"pending\" && device.cardId ? cardAnswer(readCard(root, device.cardId)) : null\n}\n\n/** Whether `token` opens the member page right now. Reads the owner's\n * answer on the pairing card the first time it is there. */\nexport function memberAccess(token: string | null, deps: Pick<MemberDeps, \"tokens\" | \"members\" | \"root\" | \"now\" | \"log\"> & { people?: MemberDeps[\"people\"] }, address?: string): AccessResult {\n const now = deps.now ?? Date.now\n const log = deps.log ?? ((line: string) => console.log(line))\n const verified = verifyMemberToken(token, deps.tokens)\n if (!verified) return { ok: false, status: 401, error: NOT_PAIRED }\n const { rec, personId } = verified\n let device = deps.members.byToken(rec.id)\n if (!device || device.state === \"removed\" || device.personId !== personId) return { ok: false, status: 401, error: NOT_PAIRED }\n // Taken off the people list by any road (the command, the file): the key ends.\n if (deps.people && !deps.people().some((p) => p.id === personId)) {\n removeDevice(deps, rec.id, \"person no longer listed\")\n log(`[member] ${personId}: \"${device.name}\" ended: person no longer listed`)\n return { ok: false, status: 401, error: NOT_PAIRED }\n }\n if (device.state === \"pending\") {\n const card = device.cardId ? readCard(deps.root, device.cardId) : null\n const answer = cardAnswer(card)\n if (answer === \"yes\") {\n device = deps.members.update(rec.id, { state: \"active\", approvedAt: new Date(now()).toISOString() }) ?? device\n deps.members.log({ person: personId, device: rec.id, event: \"approved\", detail: card?.decided_by })\n log(`[member] ${personId}: \"${device.name}\" approved`)\n } else if (answer === \"no\") {\n const reason = card?.status === \"expired\" ? \"the owner did not answer in time\" : \"the owner said no\"\n deps.tokens.revoke(rec.id)\n deps.members.update(rec.id, { state: \"removed\", removedAt: new Date(now()).toISOString(), removedReason: reason })\n deps.members.log({ person: personId, device: rec.id, event: \"refused\", detail: reason })\n log(`[member] ${personId}: \"${device.name}\" refused: ${reason}`)\n return { ok: false, status: 401, error: NOT_PAIRED }\n } else {\n return { ok: false, status: 403, error: WAITING, waiting: true }\n }\n }\n // Seen: once an hour per machine, or whenever it comes from somewhere new.\n const seenAt = device.lastSeenAt ? Date.parse(device.lastSeenAt) : 0\n if (address && (now() - seenAt >= SEEN_EVERY_MS || device.lastAddress !== address)) {\n device = deps.members.update(rec.id, { lastSeenAt: new Date(now()).toISOString(), lastAddress: address }) ?? device\n deps.members.log({ person: personId, device: rec.id, event: \"signed-in\", address })\n }\n return { ok: true, device, personId, rec }\n}\n\n/** The owner removes one machine: its key stops at once. */\nexport function removeDevice(deps: Pick<MemberDeps, \"tokens\" | \"members\" | \"now\">, tokenId: string, reason = \"removed by the owner\"): MemberDevice | null {\n const device = deps.members.byToken(tokenId)\n if (!device) return null\n deps.tokens.revoke(tokenId)\n const updated = deps.members.update(tokenId, { state: \"removed\", removedAt: new Date((deps.now ?? Date.now)()).toISOString(), removedReason: reason })\n deps.members.log({ person: device.personId, device: tokenId, event: \"removed\", detail: reason })\n return updated\n}\n\n/** The owner removes a person: every machine of theirs stops at once. */\nexport function removePersonDevices(deps: Pick<MemberDeps, \"tokens\" | \"members\" | \"now\">, personId: string): MemberDevice[] {\n return deps.members.devices(personId)\n .filter((d) => d.state !== \"removed\")\n .map((d) => removeDevice(deps, d.tokenId, \"person removed by the owner\"))\n .filter((d): d is MemberDevice => !!d)\n}\n\nasync function padTo(started: number, minMs: number): Promise<void> {\n const left = started + minMs - Date.now()\n if (left > 0) await new Promise((r) => setTimeout(r, left))\n}\n","import { mutateAgentxConfig } from \"@/daemon/config-mutate\"\n\n// --- Request status setting: `requestStatus.channels` in agentx.json (#383) ---\n//\n// Shared by `agentx request-status` and the dashboard's Channels tab, so\n// both accept the same channels and write the same shape.\n\n/** Channels that can show request status today. */\nexport const STATUS_CHANNELS = [\"gitlab\", \"github\"] as const\n\n/** Turn request status on or off for one channel, in the raw config\n * object. Returns what changed, in words. */\nexport function setStatusChannel(cfg: any, channel: string, on: boolean): string {\n const name = String(channel || \"\").trim().toLowerCase()\n if (!(STATUS_CHANNELS as readonly string[]).includes(name)) {\n throw new Error(`Request status works on ${STATUS_CHANNELS.join(\" and \")}, not on \"${channel}\".`)\n }\n cfg.requestStatus = cfg.requestStatus && typeof cfg.requestStatus === \"object\" ? cfg.requestStatus : {}\n const current: string[] = Array.isArray(cfg.requestStatus.channels) ? cfg.requestStatus.channels.map((c: unknown) => String(c).toLowerCase()) : []\n cfg.requestStatus.channels = on ? [...new Set([...current, name])] : current.filter((c) => c !== name)\n return `request status on ${name} is ${on ? \"on\" : \"off\"}`\n}\n\nexport function statusChannelsOf(cfg: any): string[] {\n return Array.isArray(cfg?.requestStatus?.channels) ? cfg.requestStatus.channels.map((c: unknown) => String(c).toLowerCase()) : []\n}\n\n/** Dashboard: POST /api/admin/channels/request-status { channel, enabled }. */\nexport function toggleRequestStatus(body: any): { summary: string } {\n const { summary } = mutateAgentxConfig((cfg) => setStatusChannel(cfg, body?.channel, !!body?.enabled))\n return { summary }\n}\n","// `channels.ntfy` as the CLI and the dashboard edit it: one write rule for\n// both, and a read-back that never echoes the topic or token. On the\n// public ntfy.sh the topic IS the credential, so the dashboard learns only\n// whether one is set.\n\nexport interface NtfyBlock {\n enabled?: boolean\n server?: string\n topic?: string\n token?: string\n [key: string]: unknown\n}\n\nexport interface NtfyStatus {\n enabled: boolean\n server: string\n topicSet: boolean\n tokenSet: boolean\n}\n\nconst DEFAULT_SERVER = \"https://ntfy.sh\"\n\nexport function ntfyStatus(block: NtfyBlock | undefined): NtfyStatus {\n return {\n enabled: !!block?.enabled,\n server: block?.server || DEFAULT_SERVER,\n topicSet: !!block?.topic,\n tokenSet: !!block?.token,\n }\n}\n\n/**\n * Apply a change to a stored `channels.ntfy` block. A topic or token may\n * be a `${VAR}` placeholder, which the daemon expands from the\n * environment. An empty token removes it; an empty topic is refused,\n * because the channel cannot deliver without one.\n */\nexport function patchNtfy(current: NtfyBlock | undefined, patch: Record<string, unknown>): NtfyBlock {\n const next: NtfyBlock = { ...(current ?? {}) }\n if (\"enabled\" in patch) next.enabled = Boolean(patch.enabled)\n if (\"server\" in patch) {\n const server = String(patch.server).trim().replace(/\\/+$/, \"\")\n if (!/^https?:\\/\\/\\S+$/.test(server)) throw new Error(\"ntfy server must be an http(s) URL\")\n next.server = server\n }\n if (\"topic\" in patch) {\n const topic = String(patch.topic).trim()\n if (!topic) throw new Error(\"ntfy topic cannot be empty\")\n next.topic = topic\n }\n if (\"token\" in patch) {\n const token = String(patch.token ?? \"\").trim()\n if (token) next.token = token\n else delete next.token\n }\n if (next.enabled && !next.topic) throw new Error(\"set a topic before enabling ntfy\")\n return next\n}\n"],"mappings":"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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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","names":["existsSync","readFileSync","writeFileSync","appendFileSync","mkdirSync","dirname","resolve","fileURLToPath","hostname","spawn","init_config","existsSync","readFileSync","writeFileSync","copyFileSync","resolve","mutateAgentxConfig","mutator","opts","file","cfg","raw","result","json","tmp","e","backupPath","triggerLocalReload","writeAgentxConfig","url","loadDaemonConfig","renderSetupPage","state","defaultNode","heading","customHeader","step1","stepCard","field","step2","row","step3","step4","banner","body","esc","btn","renderShell","SETUP_PAGE_CSS","SETUP_SCRIPT","init_config","wizardState","baseDir","file","resolve","existsSync","cfg","readFileSync","agents","channels","c","runWizard","payload","mentions","splitMentions","configPath","envPath","workspaceDir","state","mkdirSync","claudeMd","personality","writeFileSync","telegramTokenRef","backupPath","mutateAgentxConfig","slugify","agentBlock","telegramAccountBlock","buildFreshConfig","writeAgentxConfig","ensureEnvEntries","nextSteps","s","m","i","block","tokenRef","existing","lines","sep","appendFileSync","handleWizardGet","_req","res","defaultNode","hostname","html","renderSetupPage","handleWizardPost","req","raw","ok","result","e","handleStartDaemonPost","bind","loadDaemonConfig","url","probe","cli","dirname","fileURLToPath","spawn","deadline","baseUrl","r","existsSync","readFileSync","init_config","readApprovalSettings","configPath","path","findConfigPath","raw","existsSync","expandEnvVars","readFileSync","parsed","approvalsConfigSchema","parseDestination","value","i","updateApprovalSettings","patch","opts","applyConfigMutation","cfg","peers","p","d","c","days","max","createServer","MeshWikiClient","peers","p","results","peer","data","agent","peerUrl","agentId","articlePath","url","cached","token","res","lensFor","g","type","t","propLabel","id","inverse","p","x","byRecent","a","b","da","db","statementItem","e","st","from","other","chips","statementsPanel","def","panelFrom","types","items","seen","keep","edge","typed","i","plain","linkedEntities","ids","out","entityItem","historyPanel","events","shownLevels","shown","folded","rollups","rule","newest","recent","readingsPanel","latestOnly","readings","metric","discussedPanel","readEntries","en","line","l","panelData","opts","source","panelSource","h","total","size","page","esc","s","PATHS","icon","name","typeIcon","o","type","t","typeLabel","entityHref","id","crumbs","list","c","i","all","zoomBar","at","names","z","sidebar","g","active","html","pins","title","normName","e","p","layout","side","main","rail","q","CSS","today","statusChip","s","esc","itemTitle","it","icon","entityHref","itemSub","g","parts","typeLabel","rowHtml","e","sub","chips","c","z4","typeIcon","eventRow","level","timeline","items","years","i","d","now","min","span","pos","end","y","m","html","left","right","label","panelCard","p","full","notesHtml","zin","count","note","body","r","wikiMd","g","text","markdownToHtml","target","display","id","normName","entityHref","bodyOf","content","summaryOf","max","plain","p","_m","t","d","pillarOf","e","entityCrumbs","tail","crumbs","typeLabel","notesHtml","full","first","short","esc","rail","lens","x","html","icon","panelSource","byAgent","agent","n","page","s","entityPage","ctx","lensFor","pinned","main","zoomBar","typeIcon","summary","def","data","panelData","isNotes","panelCard","layout","sidebar","panelPage","panelId","title","pages","base","statementPage","index","st","prop","meta","rows","versions","v","k","DAY","byType","g","out","e","list","activity","ev","linkedEntities","own","needsAttention","entities","now","soon","today","due","s","fulfilled","rank","a","b","entityRow","right","sub","typeIcon","entityHref","esc","typeLabel","attentionCard","rows","errorsBox","errors","homePage","types","main","crumbs","icon","p","inPillar","t","count","n","kinds","events","layout","sidebar","pillarPage","pillarId","kind","x","active","zoomBar","at","summaryOf","kindListPage","typeId","page","requested","importance","IMPORTANCE_LEVELS","size","pages","base","lv","i","all","q","findPage","needle","scored","title","ontologyPage","file","o","pillar","OntologyRoutes","hub","wikiDir","GraphCache","path","params","ontology","errors","file","loadOntology","g","page","homePage","findPage","ontologyPage","parts","pillarPage","kindListPage","e","ctx","ids","agentId","articlePath","entityPage","panelPage","statementPage","escapeHtml","s","stripSectionTags","text","tagLink","tag","agentId","tagLinks","tags","t","resolveWikilink","target","wikiArticles","byTitle","pathSet","withExt","targetLower","title","path","md","agentPrefix","markdownToHtml","display","HEAD_FONTS","CSS","pageLayout","sidebar","content","searchQuery","groupByDir","articles","byDir","a","dir","list","b","dirLabel","hubSidebar","agents","activePath","html","agent","byType","type","isActive","hubHome","hub","allAgents","remoteAgents","totalEntries","totalArticles","totalUnabsorbed","remoteIds","r","nodes","statusChip","remoteBadge","tagPart","hubAgentOverview","agentSummary","isRemote","entries","recent","e","issues","issue","hubArticlePage","articlePath","store","article","index","titleToPath","prefix","inbound","link","linked","hubEntries","byDate","date","dateEntries","hubSearch","query","totalResults","blocks","results","hubTagPage","total","matches","hubAgentTagPage","agentSidebar","createWikiHandler","opts","wikiDir","agentFilter","peers","mode","pathPrefix","WikiHub","ontologyRoutes","OntologyRoutes","mesh","MeshWikiClient","req","res","url","rawPath","status","parts","peerAgent","slashIdx","peerUrl","i","q","localAgents","localMap","seen","local","remote","m","rest","err","prefixHrefs","pill","startWikiServer","port","handler","createServer","init_store","runsOf","db","personId","limit","requestsReady","c","requestsIn","states","tail","args","r","openRequestsOf","OPEN_STATES","requestsOf","CLOSED_STATES","init_people","MEMBER_SCOPE_PREFIX","MEMBER_KEY_DAYS","PAIRING_CARD_BY","NETWORK_LOGIN_HEADER","MIN_MS","SEEN_EVERY_MS","personOfToken","rec","scope","s","verifyMemberToken","token","tokens","personId","inviteMember","deps","person","p","record","code","expiresAt","CODE_MINUTES","CODE_TTL_MS","pageFor","role","inviteMessage","page","about","formatCode","NETWORK_MISMATCH","TOO_MANY_WAITING","MEMBER_CODE_FAILED","header","req","name","v","viaLocalProxy","a","networkLogin","clientAddress","socket","seen","machineName","networkIdentities","splitIdentity","i","pairMemberMachine","started","now","log","line","client","wait","machine","body","readJson","redeemed","verified","padTo","login","expected","who","card","createCard","NOT_PAIRED","WAITING","cardAnswer","pendingAnswer","root","device","readCard","memberAccess","address","removeDevice","answer","reason","seenAt","tokenId","updated","removePersonDevices","d","minMs","left","r","STATUS_CHANNELS","setStatusChannel","cfg","channel","on","name","current","c","statusChannelsOf","toggleRequestStatus","body","summary","mutateAgentxConfig","DEFAULT_SERVER","ntfyStatus","block","patchNtfy","current","patch","next","server","topic","token"]}