titan-agent 5.4.2 → 5.5.6

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 (302) hide show
  1. package/README.md +1 -1
  2. package/dist/agent/agent.js +9 -5
  3. package/dist/agent/agent.js.map +1 -1
  4. package/dist/agent/agentLoop.js +7 -3
  5. package/dist/agent/agentLoop.js.map +1 -1
  6. package/dist/agent/checkpoint.js +2 -2
  7. package/dist/agent/checkpoint.js.map +1 -1
  8. package/dist/agent/commandPost.js +3 -3
  9. package/dist/agent/commandPost.js.map +1 -1
  10. package/dist/agent/goalProposer.js +2 -2
  11. package/dist/agent/goalProposer.js.map +1 -1
  12. package/dist/agent/goals.js +3 -3
  13. package/dist/agent/goals.js.map +1 -1
  14. package/dist/agent/peerAdvise.js +1 -1
  15. package/dist/agent/peerAdvise.js.map +1 -1
  16. package/dist/agent/planner.js +4 -4
  17. package/dist/agent/planner.js.map +1 -1
  18. package/dist/agent/userProfile.js +2 -2
  19. package/dist/agent/userProfile.js.map +1 -1
  20. package/dist/cli/doctor.js +33 -0
  21. package/dist/cli/doctor.js.map +1 -1
  22. package/dist/cli/onboard.js +4 -4
  23. package/dist/cli/onboard.js.map +1 -1
  24. package/dist/config/config.js +3 -3
  25. package/dist/config/config.js.map +1 -1
  26. package/dist/config/schema.js +8 -1
  27. package/dist/config/schema.js.map +1 -1
  28. package/dist/gateway/routes/adminRouter.js +500 -0
  29. package/dist/gateway/routes/adminRouter.js.map +1 -0
  30. package/dist/gateway/routes/agents.js +231 -0
  31. package/dist/gateway/routes/agents.js.map +1 -0
  32. package/dist/gateway/routes/agentsRouter.js +32 -0
  33. package/dist/gateway/routes/agentsRouter.js.map +1 -0
  34. package/dist/gateway/routes/checkpoints.js +41 -0
  35. package/dist/gateway/routes/checkpoints.js.map +1 -0
  36. package/dist/gateway/routes/commandPost.js +755 -0
  37. package/dist/gateway/routes/commandPost.js.map +1 -0
  38. package/dist/gateway/routes/companies.js +166 -0
  39. package/dist/gateway/routes/companies.js.map +1 -0
  40. package/dist/gateway/routes/files.js +295 -0
  41. package/dist/gateway/routes/files.js.map +1 -0
  42. package/dist/gateway/routes/hardwareRouter.js +151 -0
  43. package/dist/gateway/routes/hardwareRouter.js.map +1 -0
  44. package/dist/gateway/routes/mcpRouter.js +88 -0
  45. package/dist/gateway/routes/mcpRouter.js.map +1 -0
  46. package/dist/gateway/routes/mesh.js +464 -0
  47. package/dist/gateway/routes/mesh.js.map +1 -0
  48. package/dist/gateway/routes/metricsRouter.js +131 -0
  49. package/dist/gateway/routes/metricsRouter.js.map +1 -0
  50. package/dist/gateway/routes/organism.js +82 -0
  51. package/dist/gateway/routes/organism.js.map +1 -0
  52. package/dist/gateway/routes/paperclip.js +101 -0
  53. package/dist/gateway/routes/paperclip.js.map +1 -0
  54. package/dist/gateway/routes/sessions.js +227 -0
  55. package/dist/gateway/routes/sessions.js.map +1 -0
  56. package/dist/gateway/routes/skills.js +295 -0
  57. package/dist/gateway/routes/skills.js.map +1 -0
  58. package/dist/gateway/routes/socialRouter.js +145 -0
  59. package/dist/gateway/routes/socialRouter.js.map +1 -0
  60. package/dist/gateway/routes/systemRouter.js +220 -0
  61. package/dist/gateway/routes/systemRouter.js.map +1 -0
  62. package/dist/gateway/routes/teamsRecipes.js +297 -0
  63. package/dist/gateway/routes/teamsRecipes.js.map +1 -0
  64. package/dist/gateway/routes/tests.js +401 -0
  65. package/dist/gateway/routes/tests.js.map +1 -0
  66. package/dist/gateway/routes/traces.js +33 -0
  67. package/dist/gateway/routes/traces.js.map +1 -0
  68. package/dist/gateway/routes/voiceRouter.js +770 -0
  69. package/dist/gateway/routes/voiceRouter.js.map +1 -0
  70. package/dist/gateway/routes/watchRouter.js +131 -0
  71. package/dist/gateway/routes/watchRouter.js.map +1 -0
  72. package/dist/gateway/server.js +1179 -7379
  73. package/dist/gateway/server.js.map +1 -1
  74. package/dist/mcp/registry.js +2 -2
  75. package/dist/mcp/registry.js.map +1 -1
  76. package/dist/memory/episodic.js +2 -2
  77. package/dist/memory/episodic.js.map +1 -1
  78. package/dist/memory/learning.js +3 -3
  79. package/dist/memory/learning.js.map +1 -1
  80. package/dist/memory/memory.js +3 -3
  81. package/dist/memory/memory.js.map +1 -1
  82. package/dist/organism/drives.js +2 -2
  83. package/dist/organism/drives.js.map +1 -1
  84. package/dist/providers/errorTaxonomy.js +13 -0
  85. package/dist/providers/errorTaxonomy.js.map +1 -1
  86. package/dist/providers/ollama.js +3 -1
  87. package/dist/providers/ollama.js.map +1 -1
  88. package/dist/providers/openai_compat.js +4 -3
  89. package/dist/providers/openai_compat.js.map +1 -1
  90. package/dist/providers/router.js +13 -0
  91. package/dist/providers/router.js.map +1 -1
  92. package/dist/safety/fixOscillation.js +15 -0
  93. package/dist/safety/fixOscillation.js.map +1 -1
  94. package/dist/safety/killSwitch.js +2 -2
  95. package/dist/safety/killSwitch.js.map +1 -1
  96. package/dist/safety/selfRepair.js +7 -3
  97. package/dist/safety/selfRepair.js.map +1 -1
  98. package/dist/skills/builtin/agent_debate.js +2 -2
  99. package/dist/skills/builtin/agent_debate.js.map +1 -1
  100. package/dist/skills/builtin/apply_patch.js +3 -3
  101. package/dist/skills/builtin/apply_patch.js.map +1 -1
  102. package/dist/skills/builtin/shell.js +2 -2
  103. package/dist/skills/builtin/shell.js.map +1 -1
  104. package/dist/skills/builtin/voice_control.js +49 -0
  105. package/dist/skills/builtin/voice_control.js.map +1 -0
  106. package/dist/skills/builtin/widget_gallery.js +6 -1
  107. package/dist/skills/builtin/widget_gallery.js.map +1 -1
  108. package/dist/skills/registry.js +15 -4
  109. package/dist/skills/registry.js.map +1 -1
  110. package/dist/storage/JsonStorage.js +4 -4
  111. package/dist/storage/JsonStorage.js.map +1 -1
  112. package/dist/utils/constants.js +1 -1
  113. package/dist/utils/constants.js.map +1 -1
  114. package/dist/utils/helpers.js +3 -1
  115. package/dist/utils/helpers.js.map +1 -1
  116. package/dist/utils/lifecycle.js +86 -0
  117. package/dist/utils/lifecycle.js.map +1 -0
  118. package/dist/voice/bridge.js +136 -0
  119. package/dist/voice/bridge.js.map +1 -0
  120. package/docs/COO-MASTER-PLAN-2026-05-02.md +474 -0
  121. package/docs/HANDOFF/2026-04-29.md +141 -0
  122. package/docs/HANDOFF-2026-04-30.md +144 -0
  123. package/docs/HANDOFF-2026-05-03.md +114 -0
  124. package/docs/adr/2026-04-29-widget-pipeline-traceability.md +49 -0
  125. package/docs/agent-memory/README.md +45 -0
  126. package/docs/agent-memory/commands.md +100 -0
  127. package/docs/agent-memory/context-tree.md +101 -0
  128. package/docs/agent-memory/current-state.md +54 -0
  129. package/docs/agent-memory/decisions.md +78 -0
  130. package/docs/agent-memory/known-issues.md +76 -0
  131. package/docs/agent-memory/reflections.md +52 -0
  132. package/docs/agent-memory/skills-candidates.md +80 -0
  133. package/docs/superpowers/plans/2026-04-29-comprehensive-audit.md +256 -0
  134. package/docs/superpowers/plans/2026-04-29-comprehensive-test-plan.md +396 -0
  135. package/docs/superpowers/plans/2026-04-29-fix-all-prs.md +251 -0
  136. package/docs/superpowers/plans/2026-04-29-gitnexus-gap-remediation.md +969 -0
  137. package/package.json +5 -2
  138. package/ui/dist/assets/{AuditPanel-CM6Wg9hO.js → AuditPanel-VzSndmDN.js} +2 -2
  139. package/ui/dist/assets/{AutonomyPanel-CESx3ANg.js → AutonomyPanel-BiFouzAV.js} +2 -2
  140. package/ui/dist/assets/AutopilotPanel-fjOfM668.js +1 -0
  141. package/ui/dist/assets/{AutoresearchPanel-DR47NqT5.js → AutoresearchPanel-CVCxzAH3.js} +2 -2
  142. package/ui/dist/assets/BackupPanel-CHVTG--q.js +1 -0
  143. package/ui/dist/assets/{BrowserPanel-C15x9bLn.js → BrowserPanel-D5mvMKFU.js} +2 -2
  144. package/ui/dist/assets/CPActivity-B12mt35m.js +1 -0
  145. package/ui/dist/assets/CPAgentDetail-DsdShc-1.js +1 -0
  146. package/ui/dist/assets/CPAgents-j_7C-oQV.js +1 -0
  147. package/ui/dist/assets/CPApprovals-BShKSX9X.js +1 -0
  148. package/ui/dist/assets/CPCosts-CKPlhBDs.js +1 -0
  149. package/ui/dist/assets/CPDashboard-11c0nkxK.js +1 -0
  150. package/ui/dist/assets/CPFiles-BhLEOnXy.js +1 -0
  151. package/ui/dist/assets/CPGoals-Bi3t1b2P.js +1 -0
  152. package/ui/dist/assets/CPInbox-Bbr7khp6.js +11 -0
  153. package/ui/dist/assets/CPIssueDetail-DSdgNK8r.js +1 -0
  154. package/ui/dist/assets/CPIssues-DDEVKhX6.js +1 -0
  155. package/ui/dist/assets/CPLayout-DgPOfyGv.js +17 -0
  156. package/ui/dist/assets/CPOrg-Df73RrRJ.js +8 -0
  157. package/ui/dist/assets/CPRuns-ByioAz8w.js +1 -0
  158. package/ui/dist/assets/{CPSocial-nb-j7sOE.js → CPSocial-Dlnr_w1X.js} +2 -2
  159. package/ui/dist/assets/ChannelsPanel-DQjQCTK5.js +1 -0
  160. package/ui/dist/assets/CheckpointsPanel-C4vKjlAJ.js +1 -0
  161. package/ui/dist/assets/CommandPostHub-C9pp5Giq.js +24 -0
  162. package/ui/dist/assets/CronPanel-C6bzUfrD.js +1 -0
  163. package/ui/dist/assets/DaemonPanel-BA5Tb_UO.js +1 -0
  164. package/ui/dist/assets/{DataTable-B2Ma8hfi.js → DataTable-CH7IYJJh.js} +1 -1
  165. package/ui/dist/assets/{EmptyState-CcKyk5Yn.js → EmptyState-jU6yNDnF.js} +1 -1
  166. package/ui/dist/assets/{EvalHarnessPanel-BqtMc1ZM.js → EvalHarnessPanel-DnYqredY.js} +2 -2
  167. package/ui/dist/assets/EvalPanel-ChO7CD1r.js +1 -0
  168. package/ui/dist/assets/{FilesPanel-3QKvrWPo.js → FilesPanel-CaUkv2is.js} +2 -2
  169. package/ui/dist/assets/FleetPanel-DC_5uj0N.js +1 -0
  170. package/ui/dist/assets/{HomelabPanel-DhrjTX9m.js → HomelabPanel-CE5PGRpL.js} +2 -2
  171. package/ui/dist/assets/InfraView-C-uSlvb9.js +2 -0
  172. package/ui/dist/assets/InlineEditableField-BMQjiE6-.js +1 -0
  173. package/ui/dist/assets/Input-Bu_b3qmY.js +1 -0
  174. package/ui/dist/assets/IntegrationsPanel-DsYpAq43.js +1 -0
  175. package/ui/dist/assets/IntelligenceView-DUdIO1K7.js +2 -0
  176. package/ui/dist/assets/LearningPanel-UpQZC-mA.js +1 -0
  177. package/ui/dist/assets/LogsPanel-ClXJ4fcr.js +1 -0
  178. package/ui/dist/assets/McpPanel-JKgtIERQ.js +1 -0
  179. package/ui/dist/assets/{MemoryGraphPanel-Bzvjmzvk.js → MemoryGraphPanel-Bo2OrvA6.js} +2 -2
  180. package/ui/dist/assets/MemoryWikiPanel-BqJ1AmYm.js +11 -0
  181. package/ui/dist/assets/{MeshPanel-C3LJSlht.js → MeshPanel-BJVGYvwk.js} +2 -2
  182. package/ui/dist/assets/Modal-CAAooiZU.js +1 -0
  183. package/ui/dist/assets/NvidiaPanel-BtCg3G4w.js +1 -0
  184. package/ui/dist/assets/OrganismPanel-DgrTTzcF.js +1 -0
  185. package/ui/dist/assets/OverviewPanel-rVav1Hox.js +1 -0
  186. package/ui/dist/assets/{PageHeader-BimceqQo.js → PageHeader-CnZtP8ek.js} +1 -1
  187. package/ui/dist/assets/PaperclipPanel-C-FKdhiF.js +1 -0
  188. package/ui/dist/assets/{PersonasPanel-L1j78p6H.js → PersonasPanel-BmlxokfB.js} +1 -1
  189. package/ui/dist/assets/RecipesPanel-BNKKChis.js +1 -0
  190. package/ui/dist/assets/SecurityPanel-I7JRHiNy.js +1 -0
  191. package/ui/dist/assets/SelfImprovePanel-u9h0Lt3p.js +1 -0
  192. package/ui/dist/assets/{SelfProposalsPanel-lNmiDThB.js → SelfProposalsPanel-DKl9iBjM.js} +2 -2
  193. package/ui/dist/assets/SessionsPanel-BhRiWI_g.js +1 -0
  194. package/ui/dist/assets/{SessionsTab-JQbltWww.js → SessionsTab-Bk08wyeY.js} +1 -1
  195. package/ui/dist/assets/SettingsPanel-haLfmG2k.js +1 -0
  196. package/ui/dist/assets/SettingsView--gi3fxI8.js +2 -0
  197. package/ui/dist/assets/{SkeletonLoader-atQtpcF5.js → SkeletonLoader-B5v09EF_.js} +1 -1
  198. package/ui/dist/assets/{SkillsPanel-DlFs2ih7.js → SkillsPanel-BlAHFLcQ.js} +1 -1
  199. package/ui/dist/assets/SomaView-CExtS3zw.js +5 -0
  200. package/ui/dist/assets/{StatCard-DciE_Iqc.js → StatCard-BIsyMybM.js} +1 -1
  201. package/ui/dist/assets/{StatusBadge-BtfSPoW2.js → StatusBadge-D5nU7El8.js} +1 -1
  202. package/ui/dist/assets/Tabs-BBYZrBI8.js +1 -0
  203. package/ui/dist/assets/TeamsPanel-LPXJg823.js +1 -0
  204. package/ui/dist/assets/TelemetryPanel-EqpRBmOI.js +1 -0
  205. package/ui/dist/assets/TitanCanvas-BCbWnLMd.js +985 -0
  206. package/ui/dist/assets/ToolsView-CeP0Zz-N.js +2 -0
  207. package/ui/dist/assets/{Tooltip-70UK0E2I.js → Tooltip-BSO2XVpF.js} +1 -1
  208. package/ui/dist/assets/TraceViewer-BKI7o5B0.js +1 -0
  209. package/ui/dist/assets/TrainingPanel-c-RhjdE1.js +1 -0
  210. package/ui/dist/assets/VoiceOverlay-D-gc58b0.js +27 -0
  211. package/ui/dist/assets/VramPanel-C6xc7zgd.js +1 -0
  212. package/ui/dist/assets/{WatchView-C-sGFpVy.js → WatchView-dqBVCVH0.js} +1 -1
  213. package/ui/dist/assets/WorkTab-CBoLNrTM.js +1 -0
  214. package/ui/dist/assets/{WorkflowsPanel-CvgQU1xI.js → WorkflowsPanel-BAnSTOYe.js} +2 -2
  215. package/ui/dist/assets/approvalHeadline-DB9SgR-9.js +1 -0
  216. package/ui/dist/assets/{arrow-left-DwqHtJiU.js → arrow-left-5chqas7J.js} +1 -1
  217. package/ui/dist/assets/briefcase-D4vLzudp.js +6 -0
  218. package/ui/dist/assets/{chart-column-BtNO6sRy.js → chart-column-CdFlBpoP.js} +1 -1
  219. package/ui/dist/assets/check-Bpm1IONe.js +6 -0
  220. package/ui/dist/assets/chevron-down-D7OLjvuD.js +6 -0
  221. package/ui/dist/assets/chevron-right-aQEw2mUW.js +6 -0
  222. package/ui/dist/assets/chevron-up-C5g6pEj8.js +6 -0
  223. package/ui/dist/assets/{circle-check-big-DZRE_MbN.js → circle-check-big-fPhEdP88.js} +1 -1
  224. package/ui/dist/assets/clock-CTsgP_Sn.js +6 -0
  225. package/ui/dist/assets/{dollar-sign-aVG3a5eL.js → dollar-sign-CudFVYFc.js} +1 -1
  226. package/ui/dist/assets/{download-BxiWJU4G.js → download-DZRxDn67.js} +1 -1
  227. package/ui/dist/assets/external-link-BZ0y_Ahx.js +6 -0
  228. package/ui/dist/assets/{eye-off-CkgfFYhm.js → eye-off-BmJF0YYx.js} +1 -1
  229. package/ui/dist/assets/folder-DA43TRCm.js +11 -0
  230. package/ui/dist/assets/{funnel-PkLdxKyC.js → funnel-J3mULzrz.js} +1 -1
  231. package/ui/dist/assets/{git-branch-BM-Gw95X.js → git-branch-oHibJqDq.js} +1 -1
  232. package/ui/dist/assets/{index-D0RJ8701.css → index-BR0vfkIi.css} +1 -1
  233. package/ui/dist/assets/{index-CahJbWSR.js → index-DzwowwSI.js} +20 -20
  234. package/ui/dist/assets/{layers-BuGf4FIJ.js → layers-DsyEyu7z.js} +1 -1
  235. package/ui/dist/assets/{legacy-CR6o4t-y.js → legacy-8ITl64sV.js} +1 -1
  236. package/ui/dist/assets/{lightbulb-n8gc_XAL.js → lightbulb-C54Ske-p.js} +1 -1
  237. package/ui/dist/assets/list-todo-Cnd4rdoK.js +6 -0
  238. package/ui/dist/assets/loader-circle-1YOBsoQp.js +6 -0
  239. package/ui/dist/assets/network-DbGDAdrn.js +6 -0
  240. package/ui/dist/assets/{pause-DCV52koX.js → pause-CYhO_uQo.js} +1 -1
  241. package/ui/dist/assets/{play-CcJ9BnCh.js → play-DVY9c5Ck.js} +1 -1
  242. package/ui/dist/assets/{plug-CfWBXfCl.js → plug-BcXjlPUL.js} +1 -1
  243. package/ui/dist/assets/plus-Csu2v9GN.js +6 -0
  244. package/ui/dist/assets/{proxy-CzZDfLmm.js → proxy-DxS2_9D7.js} +1 -1
  245. package/ui/dist/assets/rotate-ccw-Co-_W04j.js +6 -0
  246. package/ui/dist/assets/save-Btx-kpoW.js +6 -0
  247. package/ui/dist/assets/search-0hXTwEZR.js +6 -0
  248. package/ui/dist/assets/send-TEpapzQR.js +6 -0
  249. package/ui/dist/assets/shield-check-DjBJXZUr.js +6 -0
  250. package/ui/dist/assets/{square-DJpUhlxi.js → square-OweUvjP-.js} +1 -1
  251. package/ui/dist/assets/{target-DWcmM_9m.js → target-BRW80Xer.js} +1 -1
  252. package/ui/dist/assets/terminal-BtiqJ628.js +16 -0
  253. package/ui/dist/assets/{toggle-right-YusFQ69L.js → toggle-right-CKtSrl28.js} +1 -1
  254. package/ui/dist/assets/{trash-2-CK7yQ55V.js → trash-2-DgWrHVax.js} +1 -1
  255. package/ui/dist/assets/{trending-up-DGjFyubC.js → trending-up-MpIrE4j6.js} +1 -1
  256. package/ui/dist/assets/{trophy-uQv_NgDB.js → trophy-CECuZNhX.js} +1 -1
  257. package/ui/dist/assets/users-dZgv4ePG.js +16 -0
  258. package/ui/dist/assets/wrench-CDz3xYve.js +11 -0
  259. package/ui/dist/index.html +2 -2
  260. package/ui/dist/assets/AutopilotPanel-DtEet1hJ.js +0 -1
  261. package/ui/dist/assets/BackupPanel-BGP8p3l3.js +0 -1
  262. package/ui/dist/assets/CPAgents-DYUtPzSq.js +0 -1
  263. package/ui/dist/assets/CPDashboard-Bf0-SyCh.js +0 -6
  264. package/ui/dist/assets/CPFiles-CxgxjQcO.js +0 -1
  265. package/ui/dist/assets/CPGoals-BsmCMTvT.js +0 -1
  266. package/ui/dist/assets/CPInbox-tMSbmQ9H.js +0 -11
  267. package/ui/dist/assets/ChannelsPanel-DP5C2OKd.js +0 -1
  268. package/ui/dist/assets/CheckpointsPanel-DlranVLZ.js +0 -1
  269. package/ui/dist/assets/CommandPostHub-BgxIa4Ev.js +0 -29
  270. package/ui/dist/assets/CronPanel-LoT5yKwJ.js +0 -1
  271. package/ui/dist/assets/DaemonPanel-DBGMqaE_.js +0 -1
  272. package/ui/dist/assets/EvalPanel-Bc33j0pN.js +0 -1
  273. package/ui/dist/assets/FleetPanel-CSsXuQYj.js +0 -1
  274. package/ui/dist/assets/InfraView-CR6HyrL6.js +0 -2
  275. package/ui/dist/assets/InlineEditableField-CnvF-yFR.js +0 -1
  276. package/ui/dist/assets/Input-GTHp2Rkr.js +0 -1
  277. package/ui/dist/assets/IntegrationsPanel-CymCRE3T.js +0 -1
  278. package/ui/dist/assets/IntelligenceView-C1IHxJRC.js +0 -2
  279. package/ui/dist/assets/LearningPanel-DOCES3lH.js +0 -1
  280. package/ui/dist/assets/LogsPanel-BLnAqEaZ.js +0 -1
  281. package/ui/dist/assets/McpPanel-ChUzmr3z.js +0 -1
  282. package/ui/dist/assets/MemoryWikiPanel-Dwk3Aqwd.js +0 -11
  283. package/ui/dist/assets/NvidiaPanel-CeZK_-CV.js +0 -1
  284. package/ui/dist/assets/OrganismPanel-BB6YOiQV.js +0 -1
  285. package/ui/dist/assets/OverviewPanel-BmtBhQnv.js +0 -1
  286. package/ui/dist/assets/PaperclipPanel-C-brgwA3.js +0 -1
  287. package/ui/dist/assets/RecipesPanel-34lCfynJ.js +0 -1
  288. package/ui/dist/assets/SecurityPanel-CBTPWLj6.js +0 -1
  289. package/ui/dist/assets/SelfImprovePanel-BrPbFHhG.js +0 -1
  290. package/ui/dist/assets/SessionsPanel-DAEYIn83.js +0 -1
  291. package/ui/dist/assets/SettingsPanel-CzRROAYQ.js +0 -1
  292. package/ui/dist/assets/SettingsView-CN7ii2uw.js +0 -2
  293. package/ui/dist/assets/SomaView-Ba642Oqb.js +0 -5
  294. package/ui/dist/assets/TeamsPanel-DKQ5z2Qe.js +0 -1
  295. package/ui/dist/assets/TelemetryPanel-B6KAc55Q.js +0 -1
  296. package/ui/dist/assets/TitanCanvas-C-s0A-lv.js +0 -1092
  297. package/ui/dist/assets/ToolsView-Dei0KMP0.js +0 -2
  298. package/ui/dist/assets/TraceViewer-BniolyBx.js +0 -1
  299. package/ui/dist/assets/TrainingPanel-Bz4CTPGW.js +0 -1
  300. package/ui/dist/assets/VoiceOverlay-CmNCrLcd.js +0 -37
  301. package/ui/dist/assets/VramPanel-Xh_OtRDR.js +0 -1
  302. package/ui/dist/assets/WorkTab-BjLNmgIK.js +0 -1
@@ -0,0 +1,464 @@
1
+ #!/usr/bin/env node
2
+ import { Router } from "express";
3
+ import { join, dirname } from "path";
4
+ import { fileURLToPath } from "url";
5
+ import { loadavg, cpus } from "os";
6
+ import fs from "fs";
7
+ import { spawn } from "child_process";
8
+ import { loadConfig } from "../../config/config.js";
9
+ import { TITAN_VERSION, TITAN_WORKSPACE } from "../../utils/constants.js";
10
+ import logger from "../../utils/logger.js";
11
+ import { listEntities, getEntity, getGraphData, getEntityEpisodes } from "../../memory/graph.js";
12
+ const COMPONENT = "MeshRouter";
13
+ function getCpuLoad() {
14
+ const avg = loadavg()[0];
15
+ const cores = cpus().length || 1;
16
+ return Math.min(1, avg / cores);
17
+ }
18
+ function createMeshRouter(broadcast) {
19
+ const router = Router();
20
+ router.get("/mesh/hello", async (_req, res) => {
21
+ const cfg = loadConfig();
22
+ if (!cfg.mesh.enabled) {
23
+ res.json({ titan: false, enabled: false });
24
+ return;
25
+ }
26
+ const { getOrCreateNodeId } = await import("../../mesh/identity.js");
27
+ const { getActiveRemoteTaskCount } = await import("../../mesh/transport.js");
28
+ const { discoverAllModels: discoverModels } = await import("../../providers/router.js");
29
+ const models = await discoverModels();
30
+ const { listAgents: meshListAgents } = await import("../../agent/multiAgent.js");
31
+ const cpuLoad = getCpuLoad();
32
+ const activeTasks = getActiveRemoteTaskCount();
33
+ const taskLoad = activeTasks / Math.max(cfg.mesh.maxRemoteTasks, 1);
34
+ const load = Math.min(1, cpuLoad * 0.4 + taskLoad * 0.6);
35
+ res.json({
36
+ titan: true,
37
+ nodeId: getOrCreateNodeId(),
38
+ version: TITAN_VERSION,
39
+ models: models.map((m) => m.id),
40
+ agentCount: meshListAgents().length,
41
+ load: Math.round(load * 100) / 100
42
+ });
43
+ });
44
+ router.get("/mesh/peers", async (_req, res) => {
45
+ const cfg = loadConfig();
46
+ if (!cfg.mesh.enabled) {
47
+ res.json({ peers: [], enabled: false });
48
+ return;
49
+ }
50
+ const { getPeers } = await import("../../mesh/discovery.js");
51
+ res.json({ peers: getPeers(), enabled: true });
52
+ });
53
+ router.get("/mesh/models", async (_req, res) => {
54
+ const cfg = loadConfig();
55
+ if (!cfg.mesh.enabled) {
56
+ res.json({ models: [] });
57
+ return;
58
+ }
59
+ const { getMeshModels } = await import("../../mesh/registry.js");
60
+ res.json({ models: getMeshModels() });
61
+ });
62
+ router.get("/mesh/pending", async (_req, res) => {
63
+ const cfg = loadConfig();
64
+ if (!cfg.mesh.enabled) {
65
+ res.json({ pending: [], enabled: false });
66
+ return;
67
+ }
68
+ const { getPendingPeers } = await import("../../mesh/discovery.js");
69
+ res.json({ pending: getPendingPeers(), enabled: true });
70
+ });
71
+ router.post("/mesh/approve/:nodeId", async (req, res) => {
72
+ const cfg = loadConfig();
73
+ if (!cfg.mesh.enabled) {
74
+ res.status(400).json({ error: "Mesh not enabled" });
75
+ return;
76
+ }
77
+ const { approvePeer } = await import("../../mesh/discovery.js");
78
+ const peer = approvePeer(req.params.nodeId);
79
+ if (peer) {
80
+ broadcast({ type: "mesh_peer_approved", peer });
81
+ res.json({ approved: true, peer });
82
+ } else {
83
+ res.status(404).json({ error: "Peer not found in pending list or at max capacity" });
84
+ }
85
+ });
86
+ router.post("/mesh/reject/:nodeId", async (req, res) => {
87
+ const cfg = loadConfig();
88
+ if (!cfg.mesh.enabled) {
89
+ res.status(400).json({ error: "Mesh not enabled" });
90
+ return;
91
+ }
92
+ const { rejectPeer } = await import("../../mesh/discovery.js");
93
+ const rejected = rejectPeer(req.params.nodeId);
94
+ res.json({ rejected });
95
+ });
96
+ router.post("/mesh/revoke/:nodeId", async (req, res) => {
97
+ const cfg = loadConfig();
98
+ if (!cfg.mesh.enabled) {
99
+ res.status(400).json({ error: "Mesh not enabled" });
100
+ return;
101
+ }
102
+ const { revokePeer } = await import("../../mesh/discovery.js");
103
+ const revoked = revokePeer(req.params.nodeId);
104
+ if (revoked) {
105
+ broadcast({ type: "mesh_peer_revoked", nodeId: req.params.nodeId });
106
+ }
107
+ res.json({ revoked });
108
+ });
109
+ router.get("/mesh/status", async (_req, res) => {
110
+ const cfg = loadConfig();
111
+ if (!cfg.mesh.enabled) {
112
+ res.json({ enabled: false, status: "disabled" });
113
+ return;
114
+ }
115
+ const { getOrCreateNodeId } = await import("../../mesh/identity.js");
116
+ const { getPeers, getPendingPeers } = await import("../../mesh/discovery.js");
117
+ const { getConnectedPeerCount } = await import("../../mesh/transport.js");
118
+ const { getOrCreateNodeId: localNodeId } = await import("../../mesh/identity.js");
119
+ const nodeId = getOrCreateNodeId();
120
+ const approvedPeers = getPeers();
121
+ const pendingPeers = getPendingPeers();
122
+ const connectedCount = getConnectedPeerCount();
123
+ const connectedPeerIds = /* @__PURE__ */ new Set();
124
+ const peerDetails = approvedPeers.map((p) => {
125
+ const isConnected = p.lastSeen > Date.now() - 1e4;
126
+ if (isConnected) connectedPeerIds.add(p.nodeId);
127
+ return {
128
+ nodeId: p.nodeId,
129
+ hostname: p.hostname,
130
+ address: p.address,
131
+ port: p.port,
132
+ discoveredVia: p.discoveredVia,
133
+ lastSeen: p.lastSeen,
134
+ models: p.models,
135
+ agentCount: p.agentCount,
136
+ load: p.load,
137
+ isConnected
138
+ };
139
+ });
140
+ const totalApproved = approvedPeers.length;
141
+ const unreachableCount = totalApproved - connectedCount;
142
+ const healthScore = totalApproved > 0 ? Math.round((totalApproved - unreachableCount) / totalApproved * 100) / 100 : 1;
143
+ const discoveryModes = [];
144
+ if (cfg.mesh.mdns) discoveryModes.push("mdns");
145
+ if (cfg.mesh.tailscale) discoveryModes.push("tailscale");
146
+ if ((cfg.mesh.staticPeers || []).length > 0) discoveryModes.push("manual");
147
+ const status = unreachableCount === 0 && totalApproved > 0 ? "healthy" : unreachableCount > 0 && connectedCount > 0 ? "degraded" : totalApproved === 0 ? "empty" : "unreachable";
148
+ res.json({
149
+ enabled: true,
150
+ status,
151
+ nodeId,
152
+ discoveryModes,
153
+ peers: {
154
+ total: totalApproved,
155
+ connected: connectedCount,
156
+ unreachable: unreachableCount,
157
+ pending: pendingPeers.length
158
+ },
159
+ peerDetails,
160
+ healthScore,
161
+ maxPeers: cfg.mesh.maxPeers,
162
+ autoApprove: cfg.mesh.autoApprove
163
+ });
164
+ });
165
+ router.get("/mesh/routes", async (_req, res) => {
166
+ const cfg = loadConfig();
167
+ if (!cfg.mesh.enabled) {
168
+ res.json({ enabled: false, routes: [] });
169
+ return;
170
+ }
171
+ const { getRoutingTable } = await import("../../mesh/transport.js");
172
+ res.json({ routes: getRoutingTable() });
173
+ });
174
+ router.get("/homelab/machines", async (_req, res) => {
175
+ try {
176
+ const cfg = loadConfig();
177
+ const machines = cfg.homelab?.machines ?? [
178
+ { name: "Titan PC", ip: "192.168.1.11", role: "Primary GPU (RTX 5090)", port: 48420, protocol: "https", path: "/api/health" },
179
+ { name: "Mini PC", ip: "192.168.1.95", role: "Docker Host", port: 48420, protocol: "https", path: "/api/health" },
180
+ { name: "T610 Server", ip: "192.168.1.67", role: "Always-on Backbone", port: 48420, protocol: "https", path: "/api/health" }
181
+ ];
182
+ const https = await import("https");
183
+ const http = await import("http");
184
+ const probe = (protocol, ip, port, path) => {
185
+ return new Promise((resolve, reject) => {
186
+ const started = Date.now();
187
+ const lib = protocol === "https" ? https : http;
188
+ const req = lib.request({
189
+ host: ip,
190
+ port,
191
+ path,
192
+ method: "GET",
193
+ timeout: 3e3,
194
+ ...protocol === "https" ? { rejectUnauthorized: false } : {}
195
+ }, (r) => {
196
+ let body = "";
197
+ r.on("data", (c) => body += c);
198
+ r.on("end", () => resolve({ ok: (r.statusCode ?? 0) >= 200 && (r.statusCode ?? 0) < 400, body, latencyMs: Date.now() - started }));
199
+ });
200
+ req.on("timeout", () => {
201
+ req.destroy(new Error("timeout"));
202
+ });
203
+ req.on("error", reject);
204
+ req.end();
205
+ });
206
+ };
207
+ const results = await Promise.all(machines.map(async (m) => {
208
+ const protocol = m.protocol ?? "https";
209
+ const port = m.port ?? 48420;
210
+ const path = m.path ?? "/api/health";
211
+ const started = Date.now();
212
+ try {
213
+ const r = await probe(protocol, m.ip, port, path);
214
+ let version;
215
+ try {
216
+ const parsed = JSON.parse(r.body);
217
+ version = parsed?.version;
218
+ } catch {
219
+ }
220
+ return { name: m.name, ip: m.ip, role: m.role ?? "", online: r.ok, latencyMs: r.latencyMs, version };
221
+ } catch (err) {
222
+ return { name: m.name, ip: m.ip, role: m.role ?? "", online: false, latencyMs: Date.now() - started, error: err.message };
223
+ }
224
+ }));
225
+ res.json({ machines: results });
226
+ } catch (err) {
227
+ res.status(500).json({ error: err.message });
228
+ }
229
+ });
230
+ router.get("/dependencies/scan", async (_req, res) => {
231
+ try {
232
+ const reportPath = join(TITAN_WORKSPACE, "dependency-scan-report.json");
233
+ if (fs.existsSync(reportPath)) {
234
+ const report = JSON.parse(fs.readFileSync(reportPath, "utf-8"));
235
+ res.json(report);
236
+ } else {
237
+ res.status(404).json({ error: "No scan report found. Run a scan first." });
238
+ }
239
+ } catch (e) {
240
+ logger.error(COMPONENT, `Endpoint error: ${e.message}`);
241
+ res.status(500).json({ error: "Something went wrong on our end. Please try again in a moment." });
242
+ }
243
+ });
244
+ router.post("/dependencies/scan", async (req, res) => {
245
+ try {
246
+ const { fix = false } = req.body;
247
+ const scriptPath = join(dirname(fileURLToPath(import.meta.url)), "../../scripts/dependency-scan.cjs");
248
+ const proc = spawn("node", [scriptPath, ...fix ? ["--fix"] : []], {
249
+ cwd: TITAN_WORKSPACE,
250
+ stdio: "pipe",
251
+ detached: false
252
+ });
253
+ let output = "";
254
+ proc.stdout?.on("data", (data) => {
255
+ output += data.toString();
256
+ });
257
+ proc.stderr?.on("data", (data) => {
258
+ output += data.toString();
259
+ });
260
+ proc.on("close", (code) => {
261
+ if (code === 0) {
262
+ logger.info(COMPONENT, "Dependency scan completed successfully");
263
+ } else {
264
+ logger.warn(COMPONENT, `Dependency scan exited with code ${code}`);
265
+ }
266
+ });
267
+ res.json({ success: true, message: "Dependency scan started in background" });
268
+ } catch (e) {
269
+ logger.error(COMPONENT, `Endpoint error: ${e.message}`);
270
+ res.status(500).json({ error: "Something went wrong on our end. Please try again in a moment." });
271
+ }
272
+ });
273
+ router.get("/dependencies/status", (_req, res) => {
274
+ try {
275
+ const reportPath = join(TITAN_WORKSPACE, "dependency-scan-report.json");
276
+ if (fs.existsSync(reportPath)) {
277
+ const stats = fs.statSync(reportPath);
278
+ const report = JSON.parse(fs.readFileSync(reportPath, "utf-8"));
279
+ const summary = {
280
+ lastScan: report.timestamp,
281
+ lastScanAge: Date.now() - new Date(report.timestamp).getTime(),
282
+ vulnerabilities: report.vulnerabilities.total,
283
+ critical: report.vulnerabilities.critical,
284
+ high: report.vulnerabilities.high,
285
+ outdated: report.outdated?.length || 0,
286
+ deprecated: report.deprecated?.length || 0,
287
+ licenseIssues: report.licenseIssues?.length || 0,
288
+ health: report.vulnerabilities.critical === 0 && report.vulnerabilities.high === 0 ? "healthy" : "warning"
289
+ };
290
+ res.json(summary);
291
+ } else {
292
+ res.json({
293
+ lastScan: null,
294
+ health: "unknown",
295
+ message: "No scan has been run yet"
296
+ });
297
+ }
298
+ } catch (e) {
299
+ logger.error(COMPONENT, `Endpoint error: ${e.message}`);
300
+ res.status(500).json({ error: "Something went wrong on our end. Please try again in a moment." });
301
+ }
302
+ });
303
+ router.get("/wiki/entities", (req, res) => {
304
+ try {
305
+ const type = req.query.type;
306
+ const q = req.query.q;
307
+ let entities = listEntities(type || void 0);
308
+ if (q) {
309
+ const query = q.toLowerCase();
310
+ entities = entities.filter(
311
+ (e) => e.name.toLowerCase().includes(query) || e.facts.some((f) => f.toLowerCase().includes(query)) || (e.summary || "").toLowerCase().includes(query)
312
+ );
313
+ }
314
+ res.json(entities.map((e) => ({
315
+ id: e.id,
316
+ name: e.name,
317
+ type: e.type,
318
+ summary: e.summary,
319
+ factCount: e.facts.length,
320
+ aliases: e.aliases,
321
+ firstSeen: e.firstSeen,
322
+ lastSeen: e.lastSeen
323
+ })));
324
+ } catch (e) {
325
+ logger.error(COMPONENT, `Endpoint error: ${e.message}`);
326
+ res.status(500).json({ error: "Something went wrong on our end. Please try again in a moment." });
327
+ }
328
+ });
329
+ router.get("/wiki/entity/:name", (req, res) => {
330
+ try {
331
+ const entity = getEntity(decodeURIComponent(req.params.name));
332
+ if (!entity) {
333
+ res.status(404).json({ error: "Entity not found" });
334
+ return;
335
+ }
336
+ const graphData = getGraphData();
337
+ const relatedEdges = graphData.edges.filter((e) => e.from === entity.id || e.to === entity.id);
338
+ const relatedIds = new Set(relatedEdges.map((e) => e.from === entity.id ? e.to : e.from));
339
+ const related = graphData.nodes.filter((n) => relatedIds.has(n.id)).map((n) => ({
340
+ id: n.id,
341
+ name: n.label,
342
+ type: n.type,
343
+ relation: relatedEdges.find((e) => e.from === entity.id && e.to === n.id || e.to === entity.id && e.from === n.id)?.label || "co_mentioned"
344
+ }));
345
+ const episodes = getEntityEpisodes(entity.id, 20).map((ep) => ({
346
+ id: ep.id,
347
+ content: ep.content.slice(0, 300),
348
+ source: ep.source,
349
+ createdAt: ep.createdAt
350
+ }));
351
+ res.json({ ...entity, related, episodes });
352
+ } catch (e) {
353
+ logger.error(COMPONENT, `Endpoint error: ${e.message}`);
354
+ res.status(500).json({ error: "Something went wrong on our end. Please try again in a moment." });
355
+ }
356
+ });
357
+ router.get("/agent-templates", async (_req, res) => {
358
+ try {
359
+ const { listTemplates, BUILTIN_TEMPLATES } = await import("../../skills/agentTemplates.js");
360
+ const installed = listTemplates();
361
+ res.json({ builtin: BUILTIN_TEMPLATES, installed });
362
+ } catch (e) {
363
+ logger.error(COMPONENT, `Endpoint error: ${e.message}`);
364
+ res.status(500).json({ error: "Something went wrong on our end. Please try again in a moment." });
365
+ }
366
+ });
367
+ router.post("/agent-templates", async (req, res) => {
368
+ try {
369
+ const { saveTemplate } = await import("../../skills/agentTemplates.js");
370
+ saveTemplate(req.body);
371
+ res.json({ success: true });
372
+ } catch (e) {
373
+ logger.error(COMPONENT, `Endpoint error: ${e.message}`);
374
+ res.status(500).json({ error: "Something went wrong on our end. Please try again in a moment." });
375
+ }
376
+ });
377
+ router.get("/training/stats", async (_req, res) => {
378
+ try {
379
+ const { getTrainingStats } = await import("../../agent/trajectoryCapture.js");
380
+ res.json(getTrainingStats());
381
+ } catch (e) {
382
+ logger.error(COMPONENT, `Endpoint error: ${e.message}`);
383
+ res.status(500).json({ error: "Something went wrong on our end. Please try again in a moment." });
384
+ }
385
+ });
386
+ router.get("/training/export", async (_req, res) => {
387
+ try {
388
+ const { exportTrainingData } = await import("../../agent/trajectoryCapture.js");
389
+ res.setHeader("Content-Type", "application/jsonl");
390
+ res.setHeader("Content-Disposition", 'attachment; filename="titan-training-data.jsonl"');
391
+ res.send(exportTrainingData());
392
+ } catch (e) {
393
+ logger.error(COMPONENT, `Endpoint error: ${e.message}`);
394
+ res.status(500).json({ error: "Something went wrong on our end. Please try again in a moment." });
395
+ }
396
+ });
397
+ router.get("/dreaming/status", async (_req, res) => {
398
+ try {
399
+ const { getDreamingStatus } = await import("../../memory/dreaming.js");
400
+ res.json(getDreamingStatus());
401
+ } catch (e) {
402
+ logger.error(COMPONENT, `Endpoint error: ${e.message}`);
403
+ res.status(500).json({ error: "Something went wrong on our end. Please try again in a moment." });
404
+ }
405
+ });
406
+ router.post("/dreaming/run", async (_req, res) => {
407
+ try {
408
+ const { runConsolidation } = await import("../../memory/dreaming.js");
409
+ const result = await runConsolidation();
410
+ res.json({ success: true, ...result });
411
+ } catch (e) {
412
+ logger.error(COMPONENT, `Endpoint error: ${e.message}`);
413
+ res.status(500).json({ error: "Something went wrong on our end. Please try again in a moment." });
414
+ }
415
+ });
416
+ router.get("/dreaming/history", async (_req, res) => {
417
+ try {
418
+ const { getConsolidationHistory } = await import("../../memory/dreaming.js");
419
+ res.json(getConsolidationHistory());
420
+ } catch (e) {
421
+ logger.error(COMPONENT, `Endpoint error: ${e.message}`);
422
+ res.status(500).json({ error: "Something went wrong on our end. Please try again in a moment." });
423
+ }
424
+ });
425
+ router.post("/backup/create", async (_req, res) => {
426
+ try {
427
+ const { createBackup } = await import("../../storage/backup.js");
428
+ const info = await createBackup();
429
+ res.json({ success: true, ...info });
430
+ } catch (e) {
431
+ logger.error(COMPONENT, `Endpoint error: ${e.message}`);
432
+ res.status(500).json({ error: "Something went wrong on our end. Please try again in a moment." });
433
+ }
434
+ });
435
+ router.get("/backup/list", async (_req, res) => {
436
+ try {
437
+ const { listBackups } = await import("../../storage/backup.js");
438
+ res.json({ backups: listBackups() });
439
+ } catch (e) {
440
+ logger.error(COMPONENT, `Endpoint error: ${e.message}`);
441
+ res.status(500).json({ error: "Something went wrong on our end. Please try again in a moment." });
442
+ }
443
+ });
444
+ router.post("/backup/verify", async (req, res) => {
445
+ try {
446
+ const { verifyBackup, listBackups } = await import("../../storage/backup.js");
447
+ const path = req.body?.path || listBackups()[0]?.path;
448
+ if (!path) {
449
+ res.status(400).json({ error: "No backup path specified and no backups found" });
450
+ return;
451
+ }
452
+ const result = await verifyBackup(path);
453
+ res.json(result);
454
+ } catch (e) {
455
+ logger.error(COMPONENT, `Endpoint error: ${e.message}`);
456
+ res.status(500).json({ error: "Something went wrong on our end. Please try again in a moment." });
457
+ }
458
+ });
459
+ return router;
460
+ }
461
+ export {
462
+ createMeshRouter
463
+ };
464
+ //# sourceMappingURL=mesh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/gateway/routes/mesh.ts"],"sourcesContent":["/**\n * Mesh Router + Misc Routes\n *\n * Extracted from gateway/server.ts.\n * Consolidates /api/mesh/* and several miscellaneous endpoints.\n */\n\nimport { Router } from 'express';\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport { homedir } from 'os';\nimport { loadavg, cpus } from 'os';\nimport fs from 'fs';\nimport { spawn } from 'child_process';\nimport { loadConfig } from '../../config/config.js';\nimport { TITAN_VERSION, TITAN_WORKSPACE, TITAN_HOME } from '../../utils/constants.js';\nimport logger from '../../utils/logger.js';\nimport { listEntities, getEntity, getGraphData, getEntityEpisodes } from '../../memory/graph.js';\n\nconst COMPONENT = 'MeshRouter';\n\n/** Get normalized CPU load (0.0–1.0) using 1-minute load average */\nfunction getCpuLoad(): number {\n const avg = loadavg()[0]; // 1-minute load average\n const cores = cpus().length || 1;\n return Math.min(1, avg / cores);\n}\n\nexport function createMeshRouter(broadcast: (data: Record<string, unknown>, userId?: string) => void): Router {\n const router = Router();\n\n // ── Mesh Networking Endpoints ─────────────────────────────────\n router.get('/mesh/hello', async (_req, res) => {\n const cfg = loadConfig();\n if (!cfg.mesh.enabled) { res.json({ titan: false, enabled: false }); return; }\n const { getOrCreateNodeId } = await import('../../mesh/identity.js');\n const { getActiveRemoteTaskCount } = await import('../../mesh/transport.js');\n const { discoverAllModels: discoverModels } = await import('../../providers/router.js');\n const models = await discoverModels();\n const { listAgents: meshListAgents } = await import('../../agent/multiAgent.js');\n const cpuLoad = getCpuLoad();\n const activeTasks = getActiveRemoteTaskCount();\n // Load score: 0.0 (idle) to 1.0 (maxed). Blend CPU + task saturation.\n const taskLoad = activeTasks / Math.max(cfg.mesh.maxRemoteTasks, 1);\n const load = Math.min(1, cpuLoad * 0.4 + taskLoad * 0.6);\n res.json({\n titan: true,\n nodeId: getOrCreateNodeId(),\n version: TITAN_VERSION,\n models: models.map(m => m.id),\n agentCount: meshListAgents().length,\n load: Math.round(load * 100) / 100,\n });\n });\n\n router.get('/mesh/peers', async (_req, res) => {\n const cfg = loadConfig();\n if (!cfg.mesh.enabled) { res.json({ peers: [], enabled: false }); return; }\n const { getPeers } = await import('../../mesh/discovery.js');\n res.json({ peers: getPeers(), enabled: true });\n });\n\n router.get('/mesh/models', async (_req, res) => {\n const cfg = loadConfig();\n if (!cfg.mesh.enabled) { res.json({ models: [] }); return; }\n const { getMeshModels } = await import('../../mesh/registry.js');\n res.json({ models: getMeshModels() });\n });\n\n router.get('/mesh/pending', async (_req, res) => {\n const cfg = loadConfig();\n if (!cfg.mesh.enabled) { res.json({ pending: [], enabled: false }); return; }\n const { getPendingPeers } = await import('../../mesh/discovery.js');\n res.json({ pending: getPendingPeers(), enabled: true });\n });\n\n router.post('/mesh/approve/:nodeId', async (req, res) => {\n const cfg = loadConfig();\n if (!cfg.mesh.enabled) { res.status(400).json({ error: 'Mesh not enabled' }); return; }\n const { approvePeer } = await import('../../mesh/discovery.js');\n const peer = approvePeer(req.params.nodeId);\n if (peer) {\n broadcast({ type: 'mesh_peer_approved', peer });\n res.json({ approved: true, peer });\n } else {\n res.status(404).json({ error: 'Peer not found in pending list or at max capacity' });\n }\n });\n\n router.post('/mesh/reject/:nodeId', async (req, res) => {\n const cfg = loadConfig();\n if (!cfg.mesh.enabled) { res.status(400).json({ error: 'Mesh not enabled' }); return; }\n const { rejectPeer } = await import('../../mesh/discovery.js');\n const rejected = rejectPeer(req.params.nodeId);\n res.json({ rejected });\n });\n\n router.post('/mesh/revoke/:nodeId', async (req, res) => {\n const cfg = loadConfig();\n if (!cfg.mesh.enabled) { res.status(400).json({ error: 'Mesh not enabled' }); return; }\n const { revokePeer } = await import('../../mesh/discovery.js');\n const revoked = revokePeer(req.params.nodeId);\n if (revoked) {\n broadcast({ type: 'mesh_peer_revoked', nodeId: req.params.nodeId });\n }\n res.json({ revoked });\n });\n\n // ── Mesh Health / Status Endpoint ─────────────────────────────\n router.get('/mesh/status', async (_req, res) => {\n const cfg = loadConfig();\n if (!cfg.mesh.enabled) { res.json({ enabled: false, status: 'disabled' }); return; }\n\n const { getOrCreateNodeId } = await import('../../mesh/identity.js');\n const { getPeers, getPendingPeers } = await import('../../mesh/discovery.js');\n const { getConnectedPeerCount } = await import('../../mesh/transport.js');\n const { getOrCreateNodeId: localNodeId } = await import('../../mesh/identity.js');\n\n const nodeId = getOrCreateNodeId();\n const approvedPeers = getPeers();\n const pendingPeers = getPendingPeers();\n const connectedCount = getConnectedPeerCount();\n const connectedPeerIds = new Set<string>();\n\n // Collect per-peer connection detail from approved list + transport\n const peerDetails = approvedPeers.map(p => {\n const isConnected = p.lastSeen > Date.now() - 10_000; // Consider connected if seen in last 10s\n if (isConnected) connectedPeerIds.add(p.nodeId);\n return {\n nodeId: p.nodeId,\n hostname: p.hostname,\n address: p.address,\n port: p.port,\n discoveredVia: p.discoveredVia,\n lastSeen: p.lastSeen,\n models: p.models,\n agentCount: p.agentCount,\n load: p.load,\n isConnected,\n };\n });\n\n // Composite health score\n const totalApproved = approvedPeers.length;\n const unreachableCount = totalApproved - connectedCount;\n const healthScore = totalApproved > 0\n ? Math.round(((totalApproved - unreachableCount) / totalApproved) * 100) / 100\n : 1.0;\n\n // Discovery mode detection\n const discoveryModes: string[] = [];\n if (cfg.mesh.mdns) discoveryModes.push('mdns');\n if (cfg.mesh.tailscale) discoveryModes.push('tailscale');\n if ((cfg.mesh.staticPeers || []).length > 0) discoveryModes.push('manual');\n\n const status = unreachableCount === 0 && totalApproved > 0\n ? 'healthy'\n : unreachableCount > 0 && connectedCount > 0\n ? 'degraded'\n : totalApproved === 0\n ? 'empty'\n : 'unreachable';\n\n res.json({\n enabled: true,\n status,\n nodeId,\n discoveryModes,\n peers: {\n total: totalApproved,\n connected: connectedCount,\n unreachable: unreachableCount,\n pending: pendingPeers.length,\n },\n peerDetails,\n healthScore,\n maxPeers: cfg.mesh.maxPeers,\n autoApprove: cfg.mesh.autoApprove,\n });\n });\n\n // ── Mesh Routes Endpoint ───────────────────────────────────────\n router.get('/mesh/routes', async (_req, res) => {\n const cfg = loadConfig();\n if (!cfg.mesh.enabled) { res.json({ enabled: false, routes: [] }); return; }\n const { getRoutingTable } = await import('../../mesh/transport.js');\n res.json({ routes: getRoutingTable() });\n });\n\n // ── Homelab machine health (v4.8.4) ───────────────────────────\n router.get('/homelab/machines', async (_req, res) => {\n try {\n const cfg = loadConfig() as unknown as {\n homelab?: { machines?: Array<{ name: string; ip: string; role?: string; port?: number; protocol?: 'http' | 'https'; path?: string }> };\n };\n const machines = cfg.homelab?.machines ?? [\n { name: 'Titan PC', ip: '192.168.1.11', role: 'Primary GPU (RTX 5090)', port: 48420, protocol: 'https' as const, path: '/api/health' },\n { name: 'Mini PC', ip: '192.168.1.95', role: 'Docker Host', port: 48420, protocol: 'https' as const, path: '/api/health' },\n { name: 'T610 Server', ip: '192.168.1.67', role: 'Always-on Backbone', port: 48420, protocol: 'https' as const, path: '/api/health' },\n ];\n const https = await import('https');\n const http = await import('http');\n const probe = (protocol: 'http' | 'https', ip: string, port: number, path: string): Promise<{ ok: boolean; body: string; latencyMs: number }> => {\n return new Promise((resolve, reject) => {\n const started = Date.now();\n const lib = protocol === 'https' ? https : http;\n const req = lib.request({\n host: ip,\n port,\n path,\n method: 'GET',\n timeout: 3000,\n ...(protocol === 'https' ? { rejectUnauthorized: false } : {}),\n }, (r) => {\n let body = '';\n r.on('data', (c) => body += c);\n r.on('end', () => resolve({ ok: (r.statusCode ?? 0) >= 200 && (r.statusCode ?? 0) < 400, body, latencyMs: Date.now() - started }));\n });\n req.on('timeout', () => { req.destroy(new Error('timeout')); });\n req.on('error', reject);\n req.end();\n });\n };\n const results = await Promise.all(machines.map(async (m) => {\n const protocol = m.protocol ?? 'https';\n const port = m.port ?? 48420;\n const path = m.path ?? '/api/health';\n const started = Date.now();\n try {\n const r = await probe(protocol, m.ip, port, path);\n let version: string | undefined;\n try {\n const parsed = JSON.parse(r.body) as { version?: string };\n version = parsed?.version;\n } catch { /* not JSON — still online */ }\n return { name: m.name, ip: m.ip, role: m.role ?? '', online: r.ok, latencyMs: r.latencyMs, version };\n } catch (err) {\n return { name: m.name, ip: m.ip, role: m.role ?? '', online: false, latencyMs: Date.now() - started, error: (err as Error).message };\n }\n }));\n res.json({ machines: results });\n } catch (err) {\n res.status(500).json({ error: (err as Error).message });\n }\n });\n\n // ── Dependency Scan API ────────────────────────────────────────\n router.get('/dependencies/scan', async (_req, res) => {\n try {\n const reportPath = join(TITAN_WORKSPACE, 'dependency-scan-report.json');\n if (fs.existsSync(reportPath)) {\n const report = JSON.parse(fs.readFileSync(reportPath, 'utf-8'));\n res.json(report);\n } else {\n res.status(404).json({ error: 'No scan report found. Run a scan first.' });\n }\n } catch (e) {\n logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' });\n }\n });\n\n router.post('/dependencies/scan', async (req, res) => {\n try {\n const { fix = false } = req.body;\n const scriptPath = join(dirname(fileURLToPath(import.meta.url)), '../../scripts/dependency-scan.cjs');\n\n const proc = spawn('node', [scriptPath, ...(fix ? ['--fix'] : [])], {\n cwd: TITAN_WORKSPACE,\n stdio: 'pipe',\n detached: false,\n });\n\n let output = '';\n proc.stdout?.on('data', (data) => { output += data.toString(); });\n proc.stderr?.on('data', (data) => { output += data.toString(); });\n\n proc.on('close', (code) => {\n if (code === 0) {\n logger.info(COMPONENT, 'Dependency scan completed successfully');\n } else {\n logger.warn(COMPONENT, `Dependency scan exited with code ${code}`);\n }\n });\n\n res.json({ success: true, message: 'Dependency scan started in background' });\n } catch (e) {\n logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' });\n }\n });\n\n router.get('/dependencies/status', (_req, res) => {\n try {\n const reportPath = join(TITAN_WORKSPACE, 'dependency-scan-report.json');\n if (fs.existsSync(reportPath)) {\n const stats = fs.statSync(reportPath);\n const report = JSON.parse(fs.readFileSync(reportPath, 'utf-8'));\n\n const summary = {\n lastScan: report.timestamp,\n lastScanAge: Date.now() - new Date(report.timestamp).getTime(),\n vulnerabilities: report.vulnerabilities.total,\n critical: report.vulnerabilities.critical,\n high: report.vulnerabilities.high,\n outdated: report.outdated?.length || 0,\n deprecated: report.deprecated?.length || 0,\n licenseIssues: report.licenseIssues?.length || 0,\n health: report.vulnerabilities.critical === 0 && report.vulnerabilities.high === 0 ? 'healthy' : 'warning',\n };\n\n res.json(summary);\n } else {\n res.json({\n lastScan: null,\n health: 'unknown',\n message: 'No scan has been run yet',\n });\n }\n } catch (e) {\n logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' });\n }\n });\n\n // Memory Wiki API — browseable knowledge base\n router.get('/wiki/entities', (req, res) => {\n try {\n const type = req.query.type as string | undefined;\n const q = req.query.q as string | undefined;\n let entities = listEntities(type || undefined);\n if (q) {\n const query = q.toLowerCase();\n entities = entities.filter(e =>\n e.name.toLowerCase().includes(query) ||\n e.facts.some(f => f.toLowerCase().includes(query)) ||\n (e.summary || '').toLowerCase().includes(query)\n );\n }\n res.json(entities.map(e => ({\n id: e.id,\n name: e.name,\n type: e.type,\n summary: e.summary,\n factCount: e.facts.length,\n aliases: e.aliases,\n firstSeen: e.firstSeen,\n lastSeen: e.lastSeen,\n })));\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.get('/wiki/entity/:name', (req, res) => {\n try {\n const entity = getEntity(decodeURIComponent(req.params.name));\n if (!entity) { res.status(404).json({ error: 'Entity not found' }); return; }\n const graphData = getGraphData();\n const relatedEdges = graphData.edges.filter(e => e.from === entity.id || e.to === entity.id);\n const relatedIds = new Set(relatedEdges.map(e => e.from === entity.id ? e.to : e.from));\n const related = graphData.nodes.filter(n => relatedIds.has(n.id)).map(n => ({\n id: n.id,\n name: n.label,\n type: n.type,\n relation: relatedEdges.find(e => (e.from === entity.id && e.to === n.id) || (e.to === entity.id && e.from === n.id))?.label || 'co_mentioned',\n }));\n const episodes = getEntityEpisodes(entity.id, 20).map(ep => ({\n id: ep.id,\n content: ep.content.slice(0, 300),\n source: ep.source,\n createdAt: ep.createdAt,\n }));\n res.json({ ...entity, related, episodes });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n // Agent Templates (marketplace)\n router.get('/agent-templates', async (_req, res) => {\n try {\n const { listTemplates, BUILTIN_TEMPLATES } = await import('../../skills/agentTemplates.js');\n const installed = listTemplates();\n res.json({ builtin: BUILTIN_TEMPLATES, installed });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.post('/agent-templates', async (req, res) => {\n try {\n const { saveTemplate } = await import('../../skills/agentTemplates.js');\n saveTemplate(req.body);\n res.json({ success: true });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n // Training data (RL trajectory capture)\n router.get('/training/stats', async (_req, res) => {\n try {\n const { getTrainingStats } = await import('../../agent/trajectoryCapture.js');\n res.json(getTrainingStats());\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.get('/training/export', async (_req, res) => {\n try {\n const { exportTrainingData } = await import('../../agent/trajectoryCapture.js');\n res.setHeader('Content-Type', 'application/jsonl');\n res.setHeader('Content-Disposition', 'attachment; filename=\"titan-training-data.jsonl\"');\n res.send(exportTrainingData());\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n // Dreaming memory (sleep-cycle consolidation)\n router.get('/dreaming/status', async (_req, res) => {\n try {\n const { getDreamingStatus } = await import('../../memory/dreaming.js');\n res.json(getDreamingStatus());\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.post('/dreaming/run', async (_req, res) => {\n try {\n const { runConsolidation } = await import('../../memory/dreaming.js');\n const result = await runConsolidation();\n res.json({ success: true, ...result });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.get('/dreaming/history', async (_req, res) => {\n try {\n const { getConsolidationHistory } = await import('../../memory/dreaming.js');\n res.json(getConsolidationHistory());\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n // Backup system\n router.post('/backup/create', async (_req, res) => {\n try {\n const { createBackup } = await import('../../storage/backup.js');\n const info = await createBackup();\n res.json({ success: true, ...info });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.get('/backup/list', async (_req, res) => {\n try {\n const { listBackups } = await import('../../storage/backup.js');\n res.json({ backups: listBackups() });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.post('/backup/verify', async (req, res) => {\n try {\n const { verifyBackup, listBackups } = await import('../../storage/backup.js');\n const path = req.body?.path || listBackups()[0]?.path;\n if (!path) { res.status(400).json({ error: 'No backup path specified and no backups found' }); return; }\n const result = await verifyBackup(path);\n res.json(result);\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n return router;\n}\n"],"mappings":";AAOA,SAAS,cAAc;AACvB,SAAS,MAAM,eAAe;AAC9B,SAAS,qBAAqB;AAE9B,SAAS,SAAS,YAAY;AAC9B,OAAO,QAAQ;AACf,SAAS,aAAa;AACtB,SAAS,kBAAkB;AAC3B,SAAS,eAAe,uBAAmC;AAC3D,OAAO,YAAY;AACnB,SAAS,cAAc,WAAW,cAAc,yBAAyB;AAEzE,MAAM,YAAY;AAGlB,SAAS,aAAqB;AAC1B,QAAM,MAAM,QAAQ,EAAE,CAAC;AACvB,QAAM,QAAQ,KAAK,EAAE,UAAU;AAC/B,SAAO,KAAK,IAAI,GAAG,MAAM,KAAK;AAClC;AAEO,SAAS,iBAAiB,WAA6E;AAC5G,QAAM,SAAS,OAAO;AAGtB,SAAO,IAAI,eAAe,OAAO,MAAM,QAAQ;AAC7C,UAAM,MAAM,WAAW;AACvB,QAAI,CAAC,IAAI,KAAK,SAAS;AAAE,UAAI,KAAK,EAAE,OAAO,OAAO,SAAS,MAAM,CAAC;AAAG;AAAA,IAAQ;AAC7E,UAAM,EAAE,kBAAkB,IAAI,MAAM,OAAO,wBAAwB;AACnE,UAAM,EAAE,yBAAyB,IAAI,MAAM,OAAO,yBAAyB;AAC3E,UAAM,EAAE,mBAAmB,eAAe,IAAI,MAAM,OAAO,2BAA2B;AACtF,UAAM,SAAS,MAAM,eAAe;AACpC,UAAM,EAAE,YAAY,eAAe,IAAI,MAAM,OAAO,2BAA2B;AAC/E,UAAM,UAAU,WAAW;AAC3B,UAAM,cAAc,yBAAyB;AAE7C,UAAM,WAAW,cAAc,KAAK,IAAI,IAAI,KAAK,gBAAgB,CAAC;AAClE,UAAM,OAAO,KAAK,IAAI,GAAG,UAAU,MAAM,WAAW,GAAG;AACvD,QAAI,KAAK;AAAA,MACP,OAAO;AAAA,MACP,QAAQ,kBAAkB;AAAA,MAC1B,SAAS;AAAA,MACT,QAAQ,OAAO,IAAI,OAAK,EAAE,EAAE;AAAA,MAC5B,YAAY,eAAe,EAAE;AAAA,MAC7B,MAAM,KAAK,MAAM,OAAO,GAAG,IAAI;AAAA,IACjC,CAAC;AAAA,EACH,CAAC;AAED,SAAO,IAAI,eAAe,OAAO,MAAM,QAAQ;AAC7C,UAAM,MAAM,WAAW;AACvB,QAAI,CAAC,IAAI,KAAK,SAAS;AAAE,UAAI,KAAK,EAAE,OAAO,CAAC,GAAG,SAAS,MAAM,CAAC;AAAG;AAAA,IAAQ;AAC1E,UAAM,EAAE,SAAS,IAAI,MAAM,OAAO,yBAAyB;AAC3D,QAAI,KAAK,EAAE,OAAO,SAAS,GAAG,SAAS,KAAK,CAAC;AAAA,EAC/C,CAAC;AAED,SAAO,IAAI,gBAAgB,OAAO,MAAM,QAAQ;AAC9C,UAAM,MAAM,WAAW;AACvB,QAAI,CAAC,IAAI,KAAK,SAAS;AAAE,UAAI,KAAK,EAAE,QAAQ,CAAC,EAAE,CAAC;AAAG;AAAA,IAAQ;AAC3D,UAAM,EAAE,cAAc,IAAI,MAAM,OAAO,wBAAwB;AAC/D,QAAI,KAAK,EAAE,QAAQ,cAAc,EAAE,CAAC;AAAA,EACtC,CAAC;AAED,SAAO,IAAI,iBAAiB,OAAO,MAAM,QAAQ;AAC/C,UAAM,MAAM,WAAW;AACvB,QAAI,CAAC,IAAI,KAAK,SAAS;AAAE,UAAI,KAAK,EAAE,SAAS,CAAC,GAAG,SAAS,MAAM,CAAC;AAAG;AAAA,IAAQ;AAC5E,UAAM,EAAE,gBAAgB,IAAI,MAAM,OAAO,yBAAyB;AAClE,QAAI,KAAK,EAAE,SAAS,gBAAgB,GAAG,SAAS,KAAK,CAAC;AAAA,EACxD,CAAC;AAED,SAAO,KAAK,yBAAyB,OAAO,KAAK,QAAQ;AACvD,UAAM,MAAM,WAAW;AACvB,QAAI,CAAC,IAAI,KAAK,SAAS;AAAE,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,mBAAmB,CAAC;AAAG;AAAA,IAAQ;AACtF,UAAM,EAAE,YAAY,IAAI,MAAM,OAAO,yBAAyB;AAC9D,UAAM,OAAO,YAAY,IAAI,OAAO,MAAM;AAC1C,QAAI,MAAM;AACR,gBAAU,EAAE,MAAM,sBAAsB,KAAK,CAAC;AAC9C,UAAI,KAAK,EAAE,UAAU,MAAM,KAAK,CAAC;AAAA,IACnC,OAAO;AACL,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,oDAAoD,CAAC;AAAA,IACrF;AAAA,EACF,CAAC;AAED,SAAO,KAAK,wBAAwB,OAAO,KAAK,QAAQ;AACtD,UAAM,MAAM,WAAW;AACvB,QAAI,CAAC,IAAI,KAAK,SAAS;AAAE,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,mBAAmB,CAAC;AAAG;AAAA,IAAQ;AACtF,UAAM,EAAE,WAAW,IAAI,MAAM,OAAO,yBAAyB;AAC7D,UAAM,WAAW,WAAW,IAAI,OAAO,MAAM;AAC7C,QAAI,KAAK,EAAE,SAAS,CAAC;AAAA,EACvB,CAAC;AAED,SAAO,KAAK,wBAAwB,OAAO,KAAK,QAAQ;AACtD,UAAM,MAAM,WAAW;AACvB,QAAI,CAAC,IAAI,KAAK,SAAS;AAAE,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,mBAAmB,CAAC;AAAG;AAAA,IAAQ;AACtF,UAAM,EAAE,WAAW,IAAI,MAAM,OAAO,yBAAyB;AAC7D,UAAM,UAAU,WAAW,IAAI,OAAO,MAAM;AAC5C,QAAI,SAAS;AACX,gBAAU,EAAE,MAAM,qBAAqB,QAAQ,IAAI,OAAO,OAAO,CAAC;AAAA,IACpE;AACA,QAAI,KAAK,EAAE,QAAQ,CAAC;AAAA,EACtB,CAAC;AAGD,SAAO,IAAI,gBAAgB,OAAO,MAAM,QAAQ;AAC9C,UAAM,MAAM,WAAW;AACvB,QAAI,CAAC,IAAI,KAAK,SAAS;AAAE,UAAI,KAAK,EAAE,SAAS,OAAO,QAAQ,WAAW,CAAC;AAAG;AAAA,IAAQ;AAEnF,UAAM,EAAE,kBAAkB,IAAI,MAAM,OAAO,wBAAwB;AACnE,UAAM,EAAE,UAAU,gBAAgB,IAAI,MAAM,OAAO,yBAAyB;AAC5E,UAAM,EAAE,sBAAsB,IAAI,MAAM,OAAO,yBAAyB;AACxE,UAAM,EAAE,mBAAmB,YAAY,IAAI,MAAM,OAAO,wBAAwB;AAEhF,UAAM,SAAS,kBAAkB;AACjC,UAAM,gBAAgB,SAAS;AAC/B,UAAM,eAAe,gBAAgB;AACrC,UAAM,iBAAiB,sBAAsB;AAC7C,UAAM,mBAAmB,oBAAI,IAAY;AAGzC,UAAM,cAAc,cAAc,IAAI,OAAK;AACzC,YAAM,cAAc,EAAE,WAAW,KAAK,IAAI,IAAI;AAC9C,UAAI,YAAa,kBAAiB,IAAI,EAAE,MAAM;AAC9C,aAAO;AAAA,QACL,QAAQ,EAAE;AAAA,QACV,UAAU,EAAE;AAAA,QACZ,SAAS,EAAE;AAAA,QACX,MAAM,EAAE;AAAA,QACR,eAAe,EAAE;AAAA,QACjB,UAAU,EAAE;AAAA,QACZ,QAAQ,EAAE;AAAA,QACV,YAAY,EAAE;AAAA,QACd,MAAM,EAAE;AAAA,QACR;AAAA,MACF;AAAA,IACF,CAAC;AAGD,UAAM,gBAAgB,cAAc;AACpC,UAAM,mBAAmB,gBAAgB;AACzC,UAAM,cAAc,gBAAgB,IAChC,KAAK,OAAQ,gBAAgB,oBAAoB,gBAAiB,GAAG,IAAI,MACzE;AAGJ,UAAM,iBAA2B,CAAC;AAClC,QAAI,IAAI,KAAK,KAAM,gBAAe,KAAK,MAAM;AAC7C,QAAI,IAAI,KAAK,UAAW,gBAAe,KAAK,WAAW;AACvD,SAAK,IAAI,KAAK,eAAe,CAAC,GAAG,SAAS,EAAG,gBAAe,KAAK,QAAQ;AAEzE,UAAM,SAAS,qBAAqB,KAAK,gBAAgB,IACrD,YACA,mBAAmB,KAAK,iBAAiB,IACvC,aACA,kBAAkB,IAChB,UACA;AAER,QAAI,KAAK;AAAA,MACP,SAAS;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO;AAAA,QACL,OAAO;AAAA,QACP,WAAW;AAAA,QACX,aAAa;AAAA,QACb,SAAS,aAAa;AAAA,MACxB;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU,IAAI,KAAK;AAAA,MACnB,aAAa,IAAI,KAAK;AAAA,IACxB,CAAC;AAAA,EACH,CAAC;AAGD,SAAO,IAAI,gBAAgB,OAAO,MAAM,QAAQ;AAC9C,UAAM,MAAM,WAAW;AACvB,QAAI,CAAC,IAAI,KAAK,SAAS;AAAE,UAAI,KAAK,EAAE,SAAS,OAAO,QAAQ,CAAC,EAAE,CAAC;AAAG;AAAA,IAAQ;AAC3E,UAAM,EAAE,gBAAgB,IAAI,MAAM,OAAO,yBAAyB;AAClE,QAAI,KAAK,EAAE,QAAQ,gBAAgB,EAAE,CAAC;AAAA,EACxC,CAAC;AAGD,SAAO,IAAI,qBAAqB,OAAO,MAAM,QAAQ;AACnD,QAAI;AACF,YAAM,MAAM,WAAW;AAGvB,YAAM,WAAW,IAAI,SAAS,YAAY;AAAA,QACxC,EAAE,MAAM,YAAY,IAAI,gBAAgB,MAAM,0BAA0B,MAAM,OAAO,UAAU,SAAkB,MAAM,cAAc;AAAA,QACrI,EAAE,MAAM,WAAW,IAAI,gBAAgB,MAAM,eAAe,MAAM,OAAO,UAAU,SAAkB,MAAM,cAAc;AAAA,QACzH,EAAE,MAAM,eAAe,IAAI,gBAAgB,MAAM,sBAAsB,MAAM,OAAO,UAAU,SAAkB,MAAM,cAAc;AAAA,MACtI;AACA,YAAM,QAAQ,MAAM,OAAO,OAAO;AAClC,YAAM,OAAO,MAAM,OAAO,MAAM;AAChC,YAAM,QAAQ,CAAC,UAA4B,IAAY,MAAc,SAA4E;AAC/I,eAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,gBAAM,UAAU,KAAK,IAAI;AACzB,gBAAM,MAAM,aAAa,UAAU,QAAQ;AAC3C,gBAAM,MAAM,IAAI,QAAQ;AAAA,YACtB,MAAM;AAAA,YACN;AAAA,YACA;AAAA,YACA,QAAQ;AAAA,YACR,SAAS;AAAA,YACT,GAAI,aAAa,UAAU,EAAE,oBAAoB,MAAM,IAAI,CAAC;AAAA,UAC9D,GAAG,CAAC,MAAM;AACR,gBAAI,OAAO;AACX,cAAE,GAAG,QAAQ,CAAC,MAAM,QAAQ,CAAC;AAC7B,cAAE,GAAG,OAAO,MAAM,QAAQ,EAAE,KAAK,EAAE,cAAc,MAAM,QAAQ,EAAE,cAAc,KAAK,KAAK,MAAM,WAAW,KAAK,IAAI,IAAI,QAAQ,CAAC,CAAC;AAAA,UACnI,CAAC;AACD,cAAI,GAAG,WAAW,MAAM;AAAE,gBAAI,QAAQ,IAAI,MAAM,SAAS,CAAC;AAAA,UAAG,CAAC;AAC9D,cAAI,GAAG,SAAS,MAAM;AACtB,cAAI,IAAI;AAAA,QACV,CAAC;AAAA,MACH;AACA,YAAM,UAAU,MAAM,QAAQ,IAAI,SAAS,IAAI,OAAO,MAAM;AAC1D,cAAM,WAAW,EAAE,YAAY;AAC/B,cAAM,OAAO,EAAE,QAAQ;AACvB,cAAM,OAAO,EAAE,QAAQ;AACvB,cAAM,UAAU,KAAK,IAAI;AACzB,YAAI;AACF,gBAAM,IAAI,MAAM,MAAM,UAAU,EAAE,IAAI,MAAM,IAAI;AAChD,cAAI;AACJ,cAAI;AACF,kBAAM,SAAS,KAAK,MAAM,EAAE,IAAI;AAChC,sBAAU,QAAQ;AAAA,UACpB,QAAQ;AAAA,UAAgC;AACxC,iBAAO,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE,IAAI,MAAM,EAAE,QAAQ,IAAI,QAAQ,EAAE,IAAI,WAAW,EAAE,WAAW,QAAQ;AAAA,QACrG,SAAS,KAAK;AACZ,iBAAO,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE,IAAI,MAAM,EAAE,QAAQ,IAAI,QAAQ,OAAO,WAAW,KAAK,IAAI,IAAI,SAAS,OAAQ,IAAc,QAAQ;AAAA,QACrI;AAAA,MACF,CAAC,CAAC;AACF,UAAI,KAAK,EAAE,UAAU,QAAQ,CAAC;AAAA,IAChC,SAAS,KAAK;AACZ,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAQ,IAAc,QAAQ,CAAC;AAAA,IACxD;AAAA,EACF,CAAC;AAGD,SAAO,IAAI,sBAAsB,OAAO,MAAM,QAAQ;AACpD,QAAI;AACF,YAAM,aAAa,KAAK,iBAAiB,6BAA6B;AACtE,UAAI,GAAG,WAAW,UAAU,GAAG;AAC7B,cAAM,SAAS,KAAK,MAAM,GAAG,aAAa,YAAY,OAAO,CAAC;AAC9D,YAAI,KAAK,MAAM;AAAA,MACjB,OAAO;AACL,YAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,0CAA0C,CAAC;AAAA,MAC3E;AAAA,IACF,SAAS,GAAG;AACV,aAAO,MAAM,WAAW,mBAAoB,EAAY,OAAO,EAAE;AAAG,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,iEAAiE,CAAC;AAAA,IACtK;AAAA,EACF,CAAC;AAED,SAAO,KAAK,sBAAsB,OAAO,KAAK,QAAQ;AACpD,QAAI;AACF,YAAM,EAAE,MAAM,MAAM,IAAI,IAAI;AAC5B,YAAM,aAAa,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC,GAAG,mCAAmC;AAEpG,YAAM,OAAO,MAAM,QAAQ,CAAC,YAAY,GAAI,MAAM,CAAC,OAAO,IAAI,CAAC,CAAE,GAAG;AAAA,QAClE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,UAAU;AAAA,MACZ,CAAC;AAED,UAAI,SAAS;AACb,WAAK,QAAQ,GAAG,QAAQ,CAAC,SAAS;AAAE,kBAAU,KAAK,SAAS;AAAA,MAAG,CAAC;AAChE,WAAK,QAAQ,GAAG,QAAQ,CAAC,SAAS;AAAE,kBAAU,KAAK,SAAS;AAAA,MAAG,CAAC;AAEhE,WAAK,GAAG,SAAS,CAAC,SAAS;AACzB,YAAI,SAAS,GAAG;AACd,iBAAO,KAAK,WAAW,wCAAwC;AAAA,QACjE,OAAO;AACL,iBAAO,KAAK,WAAW,oCAAoC,IAAI,EAAE;AAAA,QACnE;AAAA,MACF,CAAC;AAED,UAAI,KAAK,EAAE,SAAS,MAAM,SAAS,wCAAwC,CAAC;AAAA,IAC9E,SAAS,GAAG;AACV,aAAO,MAAM,WAAW,mBAAoB,EAAY,OAAO,EAAE;AAAG,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,iEAAiE,CAAC;AAAA,IACtK;AAAA,EACF,CAAC;AAED,SAAO,IAAI,wBAAwB,CAAC,MAAM,QAAQ;AAChD,QAAI;AACF,YAAM,aAAa,KAAK,iBAAiB,6BAA6B;AACtE,UAAI,GAAG,WAAW,UAAU,GAAG;AAC7B,cAAM,QAAQ,GAAG,SAAS,UAAU;AACpC,cAAM,SAAS,KAAK,MAAM,GAAG,aAAa,YAAY,OAAO,CAAC;AAE9D,cAAM,UAAU;AAAA,UACd,UAAU,OAAO;AAAA,UACjB,aAAa,KAAK,IAAI,IAAI,IAAI,KAAK,OAAO,SAAS,EAAE,QAAQ;AAAA,UAC7D,iBAAiB,OAAO,gBAAgB;AAAA,UACxC,UAAU,OAAO,gBAAgB;AAAA,UACjC,MAAM,OAAO,gBAAgB;AAAA,UAC7B,UAAU,OAAO,UAAU,UAAU;AAAA,UACrC,YAAY,OAAO,YAAY,UAAU;AAAA,UACzC,eAAe,OAAO,eAAe,UAAU;AAAA,UAC/C,QAAQ,OAAO,gBAAgB,aAAa,KAAK,OAAO,gBAAgB,SAAS,IAAI,YAAY;AAAA,QACnG;AAEA,YAAI,KAAK,OAAO;AAAA,MAClB,OAAO;AACL,YAAI,KAAK;AAAA,UACP,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AAAA,IACF,SAAS,GAAG;AACV,aAAO,MAAM,WAAW,mBAAoB,EAAY,OAAO,EAAE;AAAG,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,iEAAiE,CAAC;AAAA,IACtK;AAAA,EACF,CAAC;AAGD,SAAO,IAAI,kBAAkB,CAAC,KAAK,QAAQ;AACzC,QAAI;AACF,YAAM,OAAO,IAAI,MAAM;AACvB,YAAM,IAAI,IAAI,MAAM;AACpB,UAAI,WAAW,aAAa,QAAQ,MAAS;AAC7C,UAAI,GAAG;AACL,cAAM,QAAQ,EAAE,YAAY;AAC5B,mBAAW,SAAS;AAAA,UAAO,OACzB,EAAE,KAAK,YAAY,EAAE,SAAS,KAAK,KACnC,EAAE,MAAM,KAAK,OAAK,EAAE,YAAY,EAAE,SAAS,KAAK,CAAC,MAChD,EAAE,WAAW,IAAI,YAAY,EAAE,SAAS,KAAK;AAAA,QAChD;AAAA,MACF;AACA,UAAI,KAAK,SAAS,IAAI,QAAM;AAAA,QAC1B,IAAI,EAAE;AAAA,QACN,MAAM,EAAE;AAAA,QACR,MAAM,EAAE;AAAA,QACR,SAAS,EAAE;AAAA,QACX,WAAW,EAAE,MAAM;AAAA,QACnB,SAAS,EAAE;AAAA,QACX,WAAW,EAAE;AAAA,QACb,UAAU,EAAE;AAAA,MACd,EAAE,CAAC;AAAA,IACL,SAAS,GAAG;AAAE,aAAO,MAAM,WAAW,mBAAoB,EAAY,OAAO,EAAE;AAAG,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,iEAAiE,CAAC;AAAA,IAAG;AAAA,EACvL,CAAC;AAED,SAAO,IAAI,sBAAsB,CAAC,KAAK,QAAQ;AAC7C,QAAI;AACF,YAAM,SAAS,UAAU,mBAAmB,IAAI,OAAO,IAAI,CAAC;AAC5D,UAAI,CAAC,QAAQ;AAAE,YAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,mBAAmB,CAAC;AAAG;AAAA,MAAQ;AAC5E,YAAM,YAAY,aAAa;AAC/B,YAAM,eAAe,UAAU,MAAM,OAAO,OAAK,EAAE,SAAS,OAAO,MAAM,EAAE,OAAO,OAAO,EAAE;AAC3F,YAAM,aAAa,IAAI,IAAI,aAAa,IAAI,OAAK,EAAE,SAAS,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC;AACtF,YAAM,UAAU,UAAU,MAAM,OAAO,OAAK,WAAW,IAAI,EAAE,EAAE,CAAC,EAAE,IAAI,QAAM;AAAA,QAC1E,IAAI,EAAE;AAAA,QACN,MAAM,EAAE;AAAA,QACR,MAAM,EAAE;AAAA,QACR,UAAU,aAAa,KAAK,OAAM,EAAE,SAAS,OAAO,MAAM,EAAE,OAAO,EAAE,MAAQ,EAAE,OAAO,OAAO,MAAM,EAAE,SAAS,EAAE,EAAG,GAAG,SAAS;AAAA,MACjI,EAAE;AACF,YAAM,WAAW,kBAAkB,OAAO,IAAI,EAAE,EAAE,IAAI,SAAO;AAAA,QAC3D,IAAI,GAAG;AAAA,QACP,SAAS,GAAG,QAAQ,MAAM,GAAG,GAAG;AAAA,QAChC,QAAQ,GAAG;AAAA,QACX,WAAW,GAAG;AAAA,MAChB,EAAE;AACF,UAAI,KAAK,EAAE,GAAG,QAAQ,SAAS,SAAS,CAAC;AAAA,IAC3C,SAAS,GAAG;AAAE,aAAO,MAAM,WAAW,mBAAoB,EAAY,OAAO,EAAE;AAAG,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,iEAAiE,CAAC;AAAA,IAAG;AAAA,EACvL,CAAC;AAGD,SAAO,IAAI,oBAAoB,OAAO,MAAM,QAAQ;AAClD,QAAI;AACF,YAAM,EAAE,eAAe,kBAAkB,IAAI,MAAM,OAAO,gCAAgC;AAC1F,YAAM,YAAY,cAAc;AAChC,UAAI,KAAK,EAAE,SAAS,mBAAmB,UAAU,CAAC;AAAA,IACpD,SAAS,GAAG;AAAE,aAAO,MAAM,WAAW,mBAAoB,EAAY,OAAO,EAAE;AAAG,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,iEAAiE,CAAC;AAAA,IAAG;AAAA,EACvL,CAAC;AAED,SAAO,KAAK,oBAAoB,OAAO,KAAK,QAAQ;AAClD,QAAI;AACF,YAAM,EAAE,aAAa,IAAI,MAAM,OAAO,gCAAgC;AACtE,mBAAa,IAAI,IAAI;AACrB,UAAI,KAAK,EAAE,SAAS,KAAK,CAAC;AAAA,IAC5B,SAAS,GAAG;AAAE,aAAO,MAAM,WAAW,mBAAoB,EAAY,OAAO,EAAE;AAAG,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,iEAAiE,CAAC;AAAA,IAAG;AAAA,EACvL,CAAC;AAGD,SAAO,IAAI,mBAAmB,OAAO,MAAM,QAAQ;AACjD,QAAI;AACF,YAAM,EAAE,iBAAiB,IAAI,MAAM,OAAO,kCAAkC;AAC5E,UAAI,KAAK,iBAAiB,CAAC;AAAA,IAC7B,SAAS,GAAG;AAAE,aAAO,MAAM,WAAW,mBAAoB,EAAY,OAAO,EAAE;AAAG,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,iEAAiE,CAAC;AAAA,IAAG;AAAA,EACvL,CAAC;AAED,SAAO,IAAI,oBAAoB,OAAO,MAAM,QAAQ;AAClD,QAAI;AACF,YAAM,EAAE,mBAAmB,IAAI,MAAM,OAAO,kCAAkC;AAC9E,UAAI,UAAU,gBAAgB,mBAAmB;AACjD,UAAI,UAAU,uBAAuB,kDAAkD;AACvF,UAAI,KAAK,mBAAmB,CAAC;AAAA,IAC/B,SAAS,GAAG;AAAE,aAAO,MAAM,WAAW,mBAAoB,EAAY,OAAO,EAAE;AAAG,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,iEAAiE,CAAC;AAAA,IAAG;AAAA,EACvL,CAAC;AAGD,SAAO,IAAI,oBAAoB,OAAO,MAAM,QAAQ;AAClD,QAAI;AACF,YAAM,EAAE,kBAAkB,IAAI,MAAM,OAAO,0BAA0B;AACrE,UAAI,KAAK,kBAAkB,CAAC;AAAA,IAC9B,SAAS,GAAG;AAAE,aAAO,MAAM,WAAW,mBAAoB,EAAY,OAAO,EAAE;AAAG,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,iEAAiE,CAAC;AAAA,IAAG;AAAA,EACvL,CAAC;AAED,SAAO,KAAK,iBAAiB,OAAO,MAAM,QAAQ;AAChD,QAAI;AACF,YAAM,EAAE,iBAAiB,IAAI,MAAM,OAAO,0BAA0B;AACpE,YAAM,SAAS,MAAM,iBAAiB;AACtC,UAAI,KAAK,EAAE,SAAS,MAAM,GAAG,OAAO,CAAC;AAAA,IACvC,SAAS,GAAG;AAAE,aAAO,MAAM,WAAW,mBAAoB,EAAY,OAAO,EAAE;AAAG,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,iEAAiE,CAAC;AAAA,IAAG;AAAA,EACvL,CAAC;AAED,SAAO,IAAI,qBAAqB,OAAO,MAAM,QAAQ;AACnD,QAAI;AACF,YAAM,EAAE,wBAAwB,IAAI,MAAM,OAAO,0BAA0B;AAC3E,UAAI,KAAK,wBAAwB,CAAC;AAAA,IACpC,SAAS,GAAG;AAAE,aAAO,MAAM,WAAW,mBAAoB,EAAY,OAAO,EAAE;AAAG,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,iEAAiE,CAAC;AAAA,IAAG;AAAA,EACvL,CAAC;AAGD,SAAO,KAAK,kBAAkB,OAAO,MAAM,QAAQ;AACjD,QAAI;AACF,YAAM,EAAE,aAAa,IAAI,MAAM,OAAO,yBAAyB;AAC/D,YAAM,OAAO,MAAM,aAAa;AAChC,UAAI,KAAK,EAAE,SAAS,MAAM,GAAG,KAAK,CAAC;AAAA,IACrC,SAAS,GAAG;AAAE,aAAO,MAAM,WAAW,mBAAoB,EAAY,OAAO,EAAE;AAAG,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,iEAAiE,CAAC;AAAA,IAAG;AAAA,EACvL,CAAC;AAED,SAAO,IAAI,gBAAgB,OAAO,MAAM,QAAQ;AAC9C,QAAI;AACF,YAAM,EAAE,YAAY,IAAI,MAAM,OAAO,yBAAyB;AAC9D,UAAI,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;AAAA,IACrC,SAAS,GAAG;AAAE,aAAO,MAAM,WAAW,mBAAoB,EAAY,OAAO,EAAE;AAAG,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,iEAAiE,CAAC;AAAA,IAAG;AAAA,EACvL,CAAC;AAED,SAAO,KAAK,kBAAkB,OAAO,KAAK,QAAQ;AAChD,QAAI;AACF,YAAM,EAAE,cAAc,YAAY,IAAI,MAAM,OAAO,yBAAyB;AAC5E,YAAM,OAAO,IAAI,MAAM,QAAQ,YAAY,EAAE,CAAC,GAAG;AACjD,UAAI,CAAC,MAAM;AAAE,YAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,gDAAgD,CAAC;AAAG;AAAA,MAAQ;AACvG,YAAM,SAAS,MAAM,aAAa,IAAI;AACtC,UAAI,KAAK,MAAM;AAAA,IACjB,SAAS,GAAG;AAAE,aAAO,MAAM,WAAW,mBAAoB,EAAY,OAAO,EAAE;AAAG,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,iEAAiE,CAAC;AAAA,IAAG;AAAA,EACvL,CAAC;AAED,SAAO;AACT;","names":[]}
@@ -0,0 +1,131 @@
1
+ #!/usr/bin/env node
2
+ import { Router } from "express";
3
+ import { serializePrometheus, getMetricsSummary } from "../metrics.js";
4
+ import { loadConfig, updateConfig } from "../../config/config.js";
5
+ import { collectSystemProfile, getRemoteAnalyticsStatus } from "../../analytics/collector.js";
6
+ import { TITAN_VERSION } from "../../utils/constants.js";
7
+ function getUserIdFromReq(req) {
8
+ const token = req.headers.authorization?.replace("Bearer ", "");
9
+ if (token) {
10
+ return token;
11
+ }
12
+ return "default-user";
13
+ }
14
+ function createMetricsRouter() {
15
+ const router = Router();
16
+ router.get("/metrics", (_req, res) => {
17
+ res.setHeader("Content-Type", "text/plain; version=0.0.4");
18
+ res.send(serializePrometheus());
19
+ });
20
+ router.get("/metrics/summary", (_req, res) => {
21
+ res.json(getMetricsSummary());
22
+ });
23
+ router.post("/telemetry", (req, res) => {
24
+ const cfg = loadConfig();
25
+ if (!cfg.telemetry?.enabled) {
26
+ res.status(204).end();
27
+ return;
28
+ }
29
+ const { event, properties, timestamp } = req.body || {};
30
+ if (!event || typeof event !== "string") {
31
+ res.status(400).json({ error: "event is required" });
32
+ return;
33
+ }
34
+ const entry = {
35
+ event,
36
+ properties: properties || {},
37
+ timestamp: timestamp || (/* @__PURE__ */ new Date()).toISOString(),
38
+ sessionId: getUserIdFromReq(req)
39
+ };
40
+ import("../../storage/index.js").then(({ getStorage }) => getStorage()).then((storage) => storage.appendTelemetryEvent?.(entry)).catch(() => {
41
+ });
42
+ res.status(204).end();
43
+ });
44
+ router.get("/telemetry/events", async (_req, res) => {
45
+ const cfg = loadConfig();
46
+ if (!cfg.telemetry?.enabled) {
47
+ res.json({ enabled: false, events: [] });
48
+ return;
49
+ }
50
+ const limit = Math.min(parseInt(_req.query.limit || "100", 10), 1e3);
51
+ try {
52
+ const { getStorage } = await import("../../storage/index.js");
53
+ const storage = await getStorage();
54
+ const events = await storage.queryTelemetryEvents?.({ limit }) ?? [];
55
+ res.json({ enabled: true, events });
56
+ } catch (err) {
57
+ res.status(500).json({ error: err.message });
58
+ }
59
+ });
60
+ router.get("/analytics/profile", async (_req, res) => {
61
+ try {
62
+ const profile = await collectSystemProfile();
63
+ res.json(profile);
64
+ } catch (err) {
65
+ res.status(500).json({ error: err.message });
66
+ }
67
+ });
68
+ router.post("/telemetry/consent", async (req, res) => {
69
+ try {
70
+ const body = req.body || {};
71
+ const enabled = body.enabled === true;
72
+ const crashReports = body.crashReports !== false;
73
+ const patch = {
74
+ telemetry: {
75
+ enabled,
76
+ crashReports,
77
+ consentedAt: enabled ? (/* @__PURE__ */ new Date()).toISOString() : void 0,
78
+ consentedVersion: enabled ? TITAN_VERSION : void 0
79
+ }
80
+ };
81
+ updateConfig(patch);
82
+ if (enabled) {
83
+ (async () => {
84
+ try {
85
+ const { recordStartupAnalytics: record } = await import("../../analytics/collector.js");
86
+ await record();
87
+ } catch {
88
+ }
89
+ })();
90
+ }
91
+ res.json({ ok: true, enabled, crashReports });
92
+ } catch (err) {
93
+ res.status(500).json({ error: err.message });
94
+ }
95
+ });
96
+ router.get("/telemetry/consent", (_req, res) => {
97
+ const cfg = loadConfig();
98
+ const t = cfg.telemetry;
99
+ res.json({
100
+ enabled: Boolean(t?.enabled),
101
+ crashReports: t?.crashReports !== false,
102
+ consentedAt: t?.consentedAt,
103
+ consentedVersion: t?.consentedVersion,
104
+ remoteUrl: t?.remoteUrl
105
+ });
106
+ });
107
+ router.get("/telemetry/status", async (_req, res) => {
108
+ try {
109
+ const cfg = loadConfig();
110
+ const t = cfg.telemetry;
111
+ const remote = getRemoteAnalyticsStatus();
112
+ res.json({
113
+ consent: {
114
+ enabled: Boolean(t?.enabled),
115
+ crashReports: t?.crashReports !== false,
116
+ consentedAt: t?.consentedAt,
117
+ consentedVersion: t?.consentedVersion,
118
+ remoteUrl: t?.remoteUrl
119
+ },
120
+ remote
121
+ });
122
+ } catch (err) {
123
+ res.status(500).json({ error: err.message });
124
+ }
125
+ });
126
+ return router;
127
+ }
128
+ export {
129
+ createMetricsRouter
130
+ };
131
+ //# sourceMappingURL=metricsRouter.js.map