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,220 @@
1
+ #!/usr/bin/env node
2
+ import { Router } from "express";
3
+ import { join } from "path";
4
+ import { existsSync, readFileSync } from "fs";
5
+ import { randomUUID } from "crypto";
6
+ import { getDb } from "../../memory/memory.js";
7
+ import { loadConfig } from "../../config/config.js";
8
+ import { TITAN_HOME } from "../../utils/constants.js";
9
+ const COMPONENT = "SystemRouter";
10
+ function createSystemRouter() {
11
+ const router = Router();
12
+ router.get("/cron", (_req, res) => {
13
+ const store = getDb();
14
+ res.json({ jobs: store.cronJobs });
15
+ });
16
+ router.post("/cron", (req, res) => {
17
+ const { name, schedule, command } = req.body;
18
+ if (!name || !schedule || !command) {
19
+ res.status(400).json({ error: "name, schedule, and command are required" });
20
+ return;
21
+ }
22
+ const store = getDb();
23
+ const id = randomUUID();
24
+ store.cronJobs.push({ id, name, schedule, command, enabled: true, created_at: (/* @__PURE__ */ new Date()).toISOString() });
25
+ res.status(201).json({ job: { id, name, schedule, command, enabled: true } });
26
+ });
27
+ router.post("/cron/:id/toggle", (req, res) => {
28
+ const store = getDb();
29
+ const job = store.cronJobs.find((j) => j.id === req.params.id);
30
+ if (!job) {
31
+ res.status(404).json({ error: "Cron job not found" });
32
+ return;
33
+ }
34
+ job.enabled = typeof req.body.enabled === "boolean" ? req.body.enabled : !job.enabled;
35
+ res.json({ job });
36
+ });
37
+ router.delete("/cron/:id", (req, res) => {
38
+ const store = getDb();
39
+ const idx = store.cronJobs.findIndex((j) => j.id === req.params.id);
40
+ if (idx === -1) {
41
+ res.status(404).json({ error: "Cron job not found" });
42
+ return;
43
+ }
44
+ store.cronJobs.splice(idx, 1);
45
+ res.json({ deleted: true });
46
+ });
47
+ router.get("/self-improve/history", async (_req, res) => {
48
+ try {
49
+ const { existsSync: existsSync2, readFileSync: readFileSync2 } = await import("fs");
50
+ const { join: join2 } = await import("path");
51
+ const { TITAN_HOME: TITAN_HOME2 } = await import("../../utils/constants.js");
52
+ const historyPath = join2(TITAN_HOME2, "self-improve", "history.jsonl");
53
+ if (!existsSync2(historyPath)) {
54
+ res.json({ sessions: [] });
55
+ return;
56
+ }
57
+ const lines = readFileSync2(historyPath, "utf-8").split("\n").filter((l) => l.trim());
58
+ const sessions = lines.map((l) => {
59
+ try {
60
+ return JSON.parse(l);
61
+ } catch {
62
+ return null;
63
+ }
64
+ }).filter(Boolean);
65
+ res.json({ sessions });
66
+ } catch (e) {
67
+ res.json({ sessions: [] });
68
+ }
69
+ });
70
+ router.get("/self-improve/config", (_req, res) => {
71
+ const cfg = loadConfig();
72
+ res.json(cfg.selfImprove || {});
73
+ });
74
+ router.get("/training/stream", async (req, res) => {
75
+ res.writeHead(200, {
76
+ "Content-Type": "text/event-stream",
77
+ "Cache-Control": "no-cache",
78
+ Connection: "keep-alive",
79
+ "X-Accel-Buffering": "no"
80
+ });
81
+ res.write('data: {"type":"connected","message":"Training progress stream connected"}\n\n');
82
+ let handler = null;
83
+ try {
84
+ const { trainingEvents } = await import("../../skills/builtin/model_trainer.js");
85
+ handler = (event) => {
86
+ try {
87
+ res.write(`data: ${JSON.stringify(event)}
88
+
89
+ `);
90
+ } catch {
91
+ }
92
+ };
93
+ trainingEvents.on("progress", handler);
94
+ } catch {
95
+ }
96
+ try {
97
+ const { existsSync: existsSync2, readFileSync: readFileSync2 } = await import("fs");
98
+ const { join: join2 } = await import("path");
99
+ const { TITAN_HOME: TITAN_HOME2 } = await import("../../utils/constants.js");
100
+ const logPath = join2(TITAN_HOME2, "training-progress.jsonl");
101
+ if (existsSync2(logPath)) {
102
+ const lines = readFileSync2(logPath, "utf-8").split("\n").filter((l) => l.trim());
103
+ const recent = lines.slice(-50);
104
+ for (const line of recent) {
105
+ try {
106
+ res.write(`data: ${line}
107
+
108
+ `);
109
+ } catch {
110
+ break;
111
+ }
112
+ }
113
+ }
114
+ } catch {
115
+ }
116
+ const keepAlive = setInterval(() => {
117
+ try {
118
+ res.write(": keepalive\n\n");
119
+ } catch {
120
+ clearInterval(keepAlive);
121
+ }
122
+ }, 15e3);
123
+ req.on("close", () => {
124
+ clearInterval(keepAlive);
125
+ if (handler) {
126
+ import("../../skills/builtin/model_trainer.js").then((m) => m.trainingEvents.off("progress", handler)).catch(() => {
127
+ });
128
+ }
129
+ });
130
+ });
131
+ router.get("/training/progress", async (req, res) => {
132
+ try {
133
+ const { existsSync: existsSync2, readFileSync: readFileSync2 } = await import("fs");
134
+ const { join: join2 } = await import("path");
135
+ const { TITAN_HOME: TITAN_HOME2 } = await import("../../utils/constants.js");
136
+ const logPath = join2(TITAN_HOME2, "training-progress.jsonl");
137
+ if (!existsSync2(logPath)) {
138
+ res.json({ events: [] });
139
+ return;
140
+ }
141
+ const lines = readFileSync2(logPath, "utf-8").split("\n").filter((l) => l.trim());
142
+ const since = req.query.since;
143
+ let events = lines.map((l) => {
144
+ try {
145
+ return JSON.parse(l);
146
+ } catch {
147
+ return null;
148
+ }
149
+ }).filter(Boolean);
150
+ if (since) {
151
+ events = events.filter((e) => e.timestamp && e.timestamp > since);
152
+ }
153
+ res.json({ events: events.slice(-100) });
154
+ } catch {
155
+ res.json({ events: [] });
156
+ }
157
+ });
158
+ router.delete("/training/progress", async (_req, res) => {
159
+ try {
160
+ const { writeFileSync } = await import("fs");
161
+ const { join: join2 } = await import("path");
162
+ const { TITAN_HOME: TITAN_HOME2 } = await import("../../utils/constants.js");
163
+ writeFileSync(join2(TITAN_HOME2, "training-progress.jsonl"), "", "utf-8");
164
+ res.json({ cleared: true });
165
+ } catch {
166
+ res.status(500).json({ error: "Failed to clear" });
167
+ }
168
+ });
169
+ router.get("/training/runs", async (_req, res) => {
170
+ try {
171
+ const { existsSync: existsSync2, readdirSync, readFileSync: readFileSync2 } = await import("fs");
172
+ const { join: join2 } = await import("path");
173
+ const { TITAN_HOME: TITAN_HOME2 } = await import("../../utils/constants.js");
174
+ const runsDir = join2(TITAN_HOME2, "training-runs");
175
+ if (!existsSync2(runsDir)) {
176
+ res.json({ runs: [] });
177
+ return;
178
+ }
179
+ const dirs = readdirSync(runsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
180
+ const runs = dirs.map((dir) => {
181
+ const metaPath = join2(runsDir, dir, "meta.json");
182
+ const resultsPath = join2(runsDir, dir, "results.json");
183
+ if (!existsSync2(metaPath)) return null;
184
+ const meta = JSON.parse(readFileSync2(metaPath, "utf-8"));
185
+ if (existsSync2(resultsPath)) {
186
+ const results = JSON.parse(readFileSync2(resultsPath, "utf-8"));
187
+ meta.status = results.status || "completed";
188
+ meta.finalLoss = results.final_loss;
189
+ }
190
+ return meta;
191
+ }).filter(Boolean);
192
+ res.json({ runs });
193
+ } catch {
194
+ res.json({ runs: [] });
195
+ }
196
+ });
197
+ router.get("/autoresearch/results", (req, res) => {
198
+ try {
199
+ const type = req.query.type || "tool_router";
200
+ const resultsFile = type === "agent" ? "agent_results.json" : "results.json";
201
+ const resultsPath = join(TITAN_HOME, "autoresearch", "output", resultsFile);
202
+ if (!existsSync(resultsPath)) {
203
+ res.json({ runs: [] });
204
+ return;
205
+ }
206
+ const data = JSON.parse(readFileSync(resultsPath, "utf-8"));
207
+ res.json({ runs: Array.isArray(data) ? data : [] });
208
+ } catch {
209
+ res.json({ runs: [] });
210
+ }
211
+ });
212
+ router.get("/autoresearch/status", (_req, res) => {
213
+ res.json({ status: "idle" });
214
+ });
215
+ return router;
216
+ }
217
+ export {
218
+ createSystemRouter
219
+ };
220
+ //# sourceMappingURL=systemRouter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/gateway/routes/systemRouter.ts"],"sourcesContent":["/**\n * System Router\n *\n * Extracted from gateway/server.ts.\n * Consolidates cron, self-improvement, training, and autoresearch routes.\n */\n\nimport { Router, type Request, type Response } from 'express';\nimport { join } from 'path';\nimport { existsSync, readFileSync } from 'fs';\nimport { randomUUID } from 'crypto';\nimport { getDb } from '../../memory/memory.js';\nimport { loadConfig } from '../../config/config.js';\nimport { TITAN_HOME } from '../../utils/constants.js';\n\nconst COMPONENT = 'SystemRouter';\n\nexport function createSystemRouter(): Router {\n const router = Router();\n\n // ── Cron API ──────────────────────────────────────────────\n router.get('/cron', (_req, res) => {\n const store = getDb();\n res.json({ jobs: store.cronJobs });\n });\n\n router.post('/cron', (req, res) => {\n const { name, schedule, command } = req.body;\n if (!name || !schedule || !command) {\n res.status(400).json({ error: 'name, schedule, and command are required' }); return;\n }\n const store = getDb();\n const id = randomUUID();\n store.cronJobs.push({ id, name, schedule, command, enabled: true, created_at: new Date().toISOString() });\n res.status(201).json({ job: { id, name, schedule, command, enabled: true } });\n });\n\n router.post('/cron/:id/toggle', (req, res) => {\n const store = getDb();\n const job = store.cronJobs.find(j => j.id === req.params.id);\n if (!job) { res.status(404).json({ error: 'Cron job not found' }); return; }\n job.enabled = typeof req.body.enabled === 'boolean' ? req.body.enabled : !job.enabled;\n res.json({ job });\n });\n\n router.delete('/cron/:id', (req, res) => {\n const store = getDb();\n const idx = store.cronJobs.findIndex(j => j.id === req.params.id);\n if (idx === -1) { res.status(404).json({ error: 'Cron job not found' }); return; }\n store.cronJobs.splice(idx, 1);\n res.json({ deleted: true });\n });\n\n // ── Self-Improvement API ────────────────────────────────────\n router.get('/self-improve/history', async (_req, res) => {\n try {\n const { existsSync, readFileSync } = await import('fs');\n const { join } = await import('path');\n const { TITAN_HOME } = await import('../../utils/constants.js');\n const historyPath = join(TITAN_HOME, 'self-improve', 'history.jsonl');\n if (!existsSync(historyPath)) {\n res.json({ sessions: [] });\n return;\n }\n const lines = readFileSync(historyPath, 'utf-8').split('\\n').filter((l: string) => l.trim());\n const sessions = lines.map((l: string) => {\n try { return JSON.parse(l); } catch { return null; }\n }).filter(Boolean);\n res.json({ sessions });\n } catch (e) {\n res.json({ sessions: [] });\n }\n });\n\n router.get('/self-improve/config', (_req, res) => {\n const cfg = loadConfig();\n res.json((cfg as Record<string, unknown>).selfImprove || {});\n });\n\n // ── Training Progress SSE Stream ─────────────────────────────────\n router.get('/training/stream', async (req, res) => {\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n 'X-Accel-Buffering': 'no',\n });\n res.write('data: {\"type\":\"connected\",\"message\":\"Training progress stream connected\"}\\n\\n');\n\n // Import training events emitter\n let handler: ((event: unknown) => void) | null = null;\n try {\n const { trainingEvents } = await import('../../skills/builtin/model_trainer.js');\n handler = (event: unknown) => {\n try {\n res.write(`data: ${JSON.stringify(event)}\\n\\n`);\n } catch { /* client disconnected */ }\n };\n trainingEvents.on('progress', handler);\n } catch { /* model_trainer not loaded */ }\n\n // Send recent progress log as catch-up (last 50 entries)\n try {\n const { existsSync, readFileSync } = await import('fs');\n const { join } = await import('path');\n const { TITAN_HOME } = await import('../../utils/constants.js');\n const logPath = join(TITAN_HOME, 'training-progress.jsonl');\n if (existsSync(logPath)) {\n const lines = readFileSync(logPath, 'utf-8').split('\\n').filter((l: string) => l.trim());\n const recent = lines.slice(-50);\n for (const line of recent) {\n try { res.write(`data: ${line}\\n\\n`); } catch { break; }\n }\n }\n } catch { /* best-effort */ }\n\n // Keep alive\n const keepAlive = setInterval(() => {\n try { res.write(': keepalive\\n\\n'); } catch { clearInterval(keepAlive); }\n }, 15_000);\n\n req.on('close', () => {\n clearInterval(keepAlive);\n if (handler) {\n import('../../skills/builtin/model_trainer.js')\n .then(m => m.trainingEvents.off('progress', handler!))\n .catch(() => {});\n }\n });\n });\n\n // ── Training Progress Log (poll fallback) ──────────────────────\n router.get('/training/progress', async (req, res) => {\n try {\n const { existsSync, readFileSync } = await import('fs');\n const { join } = await import('path');\n const { TITAN_HOME } = await import('../../utils/constants.js');\n const logPath = join(TITAN_HOME, 'training-progress.jsonl');\n if (!existsSync(logPath)) {\n res.json({ events: [] });\n return;\n }\n const lines = readFileSync(logPath, 'utf-8').split('\\n').filter((l: string) => l.trim());\n const since = req.query.since as string | undefined;\n let events = lines.map((l: string) => { try { return JSON.parse(l); } catch { return null; } }).filter(Boolean);\n if (since) {\n events = events.filter((e: { timestamp?: string }) => e.timestamp && e.timestamp > since);\n }\n // Return last 100\n res.json({ events: events.slice(-100) });\n } catch {\n res.json({ events: [] });\n }\n });\n\n // ── Clear training progress log ────────────────────────────────\n router.delete('/training/progress', async (_req, res) => {\n try {\n const { writeFileSync } = await import('fs');\n const { join } = await import('path');\n const { TITAN_HOME } = await import('../../utils/constants.js');\n writeFileSync(join(TITAN_HOME, 'training-progress.jsonl'), '', 'utf-8');\n res.json({ cleared: true });\n } catch {\n res.status(500).json({ error: 'Failed to clear' });\n }\n });\n\n router.get('/training/runs', async (_req, res) => {\n try {\n const { existsSync, readdirSync, readFileSync } = await import('fs');\n const { join } = await import('path');\n const { TITAN_HOME } = await import('../../utils/constants.js');\n const runsDir = join(TITAN_HOME, 'training-runs');\n if (!existsSync(runsDir)) {\n res.json({ runs: [] });\n return;\n }\n const dirs = readdirSync(runsDir, { withFileTypes: true })\n .filter((d: { isDirectory: () => boolean }) => d.isDirectory())\n .map((d: { name: string }) => d.name);\n const runs = dirs.map((dir: string) => {\n const metaPath = join(runsDir, dir, 'meta.json');\n const resultsPath = join(runsDir, dir, 'results.json');\n if (!existsSync(metaPath)) return null;\n const meta = JSON.parse(readFileSync(metaPath, 'utf-8'));\n if (existsSync(resultsPath)) {\n const results = JSON.parse(readFileSync(resultsPath, 'utf-8'));\n meta.status = results.status || 'completed';\n meta.finalLoss = results.final_loss;\n }\n return meta;\n }).filter(Boolean);\n res.json({ runs });\n } catch {\n res.json({ runs: [] });\n }\n });\n\n // ── Autoresearch API ──────────────────────────────────────────\n router.get('/autoresearch/results', (req, res) => {\n try {\n const type = req.query.type as string || 'tool_router';\n const resultsFile = type === 'agent' ? 'agent_results.json' : 'results.json';\n const resultsPath = join(TITAN_HOME, 'autoresearch', 'output', resultsFile);\n if (!existsSync(resultsPath)) {\n res.json({ runs: [] });\n return;\n }\n const data = JSON.parse(readFileSync(resultsPath, 'utf-8'));\n res.json({ runs: Array.isArray(data) ? data : [] });\n } catch {\n res.json({ runs: [] });\n }\n });\n\n router.get('/autoresearch/status', (_req, res) => {\n res.json({ status: 'idle' });\n });\n\n return router;\n}\n"],"mappings":"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","names":["existsSync","readFileSync","join","TITAN_HOME"]}
@@ -0,0 +1,297 @@
1
+ #!/usr/bin/env node
2
+ import { Router } from "express";
3
+ import express from "express";
4
+ import logger from "../../utils/logger.js";
5
+ import {
6
+ listTeams,
7
+ getTeam,
8
+ createTeam,
9
+ updateTeam,
10
+ deleteTeam,
11
+ getTeamStats,
12
+ addMember,
13
+ removeMember,
14
+ updateMemberRole,
15
+ createInvite,
16
+ acceptInvite,
17
+ getEffectivePermissions,
18
+ getUserRole,
19
+ setRolePermissions,
20
+ isToolAllowed
21
+ } from "../../security/teams.js";
22
+ import {
23
+ listRecipes,
24
+ getRecipe,
25
+ saveRecipe,
26
+ deleteRecipe,
27
+ getBuiltinRecipes,
28
+ importRecipeYaml
29
+ } from "../../recipes/store.js";
30
+ import { runRecipe } from "../../recipes/runner.js";
31
+ import {
32
+ getGraphData,
33
+ getGraphStats,
34
+ clearGraph,
35
+ cleanupGraph,
36
+ listEntities
37
+ } from "../../memory/graph.js";
38
+ const COMPONENT = "TeamsRecipesRouter";
39
+ function createTeamsRecipesRouter() {
40
+ const router = Router();
41
+ router.get("/teams", (_req, res) => {
42
+ res.json({ teams: listTeams().map((t) => ({ id: t.id, name: t.name, description: t.description, memberCount: t.members.filter((m) => m.status === "active").length, createdAt: t.createdAt })) });
43
+ });
44
+ router.post("/teams", (req, res) => {
45
+ try {
46
+ const { name, description, ownerId = "api-user" } = req.body;
47
+ if (!name) {
48
+ res.status(400).json({ error: "name is required" });
49
+ return;
50
+ }
51
+ const team = createTeam(name, ownerId, description);
52
+ res.status(201).json({ team: { id: team.id, name: team.name } });
53
+ } catch (e) {
54
+ res.status(400).json({ error: e.message });
55
+ }
56
+ });
57
+ router.get("/teams/:teamId", (req, res) => {
58
+ const team = getTeam(req.params.teamId);
59
+ if (!team) {
60
+ res.status(404).json({ error: "Team not found" });
61
+ return;
62
+ }
63
+ res.json({ team, stats: getTeamStats(req.params.teamId) });
64
+ });
65
+ router.patch("/teams/:teamId", (req, res) => {
66
+ try {
67
+ const { name, description, actorId = "api-user" } = req.body;
68
+ const team = updateTeam(req.params.teamId, actorId, { name, description });
69
+ res.json({ team: { id: team.id, name: team.name, description: team.description } });
70
+ } catch (e) {
71
+ res.status(400).json({ error: e.message });
72
+ }
73
+ });
74
+ router.delete("/teams/:teamId", (req, res) => {
75
+ try {
76
+ const actorId = req.query.actorId || "api-user";
77
+ const deleted = deleteTeam(req.params.teamId, actorId);
78
+ res.json({ deleted });
79
+ } catch (e) {
80
+ res.status(403).json({ error: e.message });
81
+ }
82
+ });
83
+ router.get("/teams/:teamId/members", (req, res) => {
84
+ const team = getTeam(req.params.teamId);
85
+ if (!team) {
86
+ res.status(404).json({ error: "Team not found" });
87
+ return;
88
+ }
89
+ res.json({ members: team.members });
90
+ });
91
+ router.post("/teams/:teamId/members", (req, res) => {
92
+ try {
93
+ const { userId, role = "operator", displayName, actorId = "api-user" } = req.body;
94
+ if (!userId) {
95
+ res.status(400).json({ error: "userId is required" });
96
+ return;
97
+ }
98
+ const member = addMember(req.params.teamId, actorId, userId, role, displayName);
99
+ res.status(201).json({ member });
100
+ } catch (e) {
101
+ res.status(400).json({ error: e.message });
102
+ }
103
+ });
104
+ router.delete("/teams/:teamId/members/:userId", (req, res) => {
105
+ try {
106
+ const actorId = req.query.actorId || "api-user";
107
+ const removed = removeMember(req.params.teamId, actorId, req.params.userId);
108
+ res.json({ removed });
109
+ } catch (e) {
110
+ res.status(403).json({ error: e.message });
111
+ }
112
+ });
113
+ router.patch("/teams/:teamId/members/:userId/role", (req, res) => {
114
+ try {
115
+ const { role, actorId = "api-user" } = req.body;
116
+ if (!role) {
117
+ res.status(400).json({ error: "role is required" });
118
+ return;
119
+ }
120
+ const member = updateMemberRole(req.params.teamId, actorId, req.params.userId, role);
121
+ res.json({ member });
122
+ } catch (e) {
123
+ res.status(400).json({ error: e.message });
124
+ }
125
+ });
126
+ router.post("/teams/:teamId/invites", (req, res) => {
127
+ try {
128
+ const { role = "operator", expiresInHours = 48, actorId = "api-user" } = req.body;
129
+ const code = createInvite(req.params.teamId, actorId, role, expiresInHours);
130
+ res.status(201).json({ code, expiresInHours });
131
+ } catch (e) {
132
+ res.status(400).json({ error: e.message });
133
+ }
134
+ });
135
+ router.post("/teams/join", (req, res) => {
136
+ try {
137
+ const { code, userId, displayName } = req.body;
138
+ if (!code || !userId) {
139
+ res.status(400).json({ error: "code and userId are required" });
140
+ return;
141
+ }
142
+ const result = acceptInvite(code, userId, displayName);
143
+ res.json({ teamId: result.team.id, teamName: result.team.name, role: result.member.role });
144
+ } catch (e) {
145
+ res.status(400).json({ error: e.message });
146
+ }
147
+ });
148
+ router.get("/teams/:teamId/permissions/:userId", (req, res) => {
149
+ const perms = getEffectivePermissions(req.params.teamId, req.params.userId);
150
+ const role = getUserRole(req.params.teamId, req.params.userId);
151
+ res.json({ role, permissions: perms });
152
+ });
153
+ router.put("/teams/:teamId/roles/:role/permissions", (req, res) => {
154
+ try {
155
+ const { actorId = "api-user", ...perms } = req.body;
156
+ setRolePermissions(req.params.teamId, actorId, req.params.role, perms);
157
+ res.json({ updated: true });
158
+ } catch (e) {
159
+ res.status(400).json({ error: e.message });
160
+ }
161
+ });
162
+ router.get("/teams/:teamId/tools/:toolName/check/:userId", (req, res) => {
163
+ const allowed = isToolAllowed(req.params.teamId, req.params.userId, req.params.toolName);
164
+ res.json({ allowed, tool: req.params.toolName, userId: req.params.userId });
165
+ });
166
+ router.get("/recipes", (_req, res) => {
167
+ res.json({ recipes: listRecipes() });
168
+ });
169
+ router.get("/recipes/:id", (req, res) => {
170
+ const recipe = getRecipe(req.params.id);
171
+ if (!recipe) {
172
+ res.status(404).json({ error: "Recipe not found" });
173
+ return;
174
+ }
175
+ res.json({ recipe });
176
+ });
177
+ router.post("/recipes", (req, res) => {
178
+ const recipe = req.body;
179
+ if (!recipe.id || !recipe.name || !recipe.steps) {
180
+ res.status(400).json({ error: "id, name, and steps are required" });
181
+ return;
182
+ }
183
+ if (!recipe.createdAt) recipe.createdAt = (/* @__PURE__ */ new Date()).toISOString();
184
+ saveRecipe(recipe);
185
+ res.status(201).json({ recipe });
186
+ });
187
+ router.put("/recipes/:id", (req, res) => {
188
+ const existing = getRecipe(req.params.id);
189
+ if (!existing) {
190
+ res.status(404).json({ error: "Recipe not found" });
191
+ return;
192
+ }
193
+ const updated = { ...existing, ...req.body, id: req.params.id };
194
+ saveRecipe(updated);
195
+ res.json({ recipe: updated });
196
+ });
197
+ router.delete("/recipes/:id", (req, res) => {
198
+ if (!getRecipe(req.params.id)) {
199
+ res.status(404).json({ error: "Recipe not found" });
200
+ return;
201
+ }
202
+ deleteRecipe(req.params.id);
203
+ res.json({ deleted: true });
204
+ });
205
+ router.get("/recipes/builtin/templates", (_req, res) => {
206
+ res.json({ templates: getBuiltinRecipes() });
207
+ });
208
+ router.post("/recipes/import", express.text({ type: "text/*" }), (req, res) => {
209
+ try {
210
+ const recipe = importRecipeYaml(req.body);
211
+ saveRecipe(recipe);
212
+ res.status(201).json({ recipe });
213
+ } catch (e) {
214
+ res.status(400).json({ error: e.message });
215
+ }
216
+ });
217
+ router.post("/recipes/:id/run", async (req, res) => {
218
+ const recipe = getRecipe(req.params.id);
219
+ if (!recipe) {
220
+ res.status(404).json({ error: "Recipe not found" });
221
+ return;
222
+ }
223
+ try {
224
+ const params = req.body.params || {};
225
+ const steps = [];
226
+ for await (const step of runRecipe(req.params.id, params)) {
227
+ steps.push({ stepIndex: step.stepIndex, prompt: step.prompt });
228
+ }
229
+ res.json({ recipe: recipe.name, stepsExecuted: steps.length, steps });
230
+ } catch (e) {
231
+ logger.error(COMPONENT, `Endpoint error: ${e.message}`);
232
+ res.status(500).json({ error: "Something went wrong on our end. Please try again in a moment." });
233
+ }
234
+ });
235
+ router.get("/plugins", async (_req, res) => {
236
+ const { getPlugins } = await import("../../plugins/registry.js");
237
+ const plugins = getPlugins().map((p) => ({
238
+ name: p.name,
239
+ version: p.version
240
+ }));
241
+ res.json({ plugins });
242
+ });
243
+ router.get("/graphiti", (_req, res) => {
244
+ try {
245
+ const { nodes, edges } = getGraphData();
246
+ const { episodeCount } = getGraphStats();
247
+ res.json({
248
+ graphReady: true,
249
+ episodeCount,
250
+ nodeCount: nodes.length,
251
+ edgeCount: edges.length,
252
+ nodes,
253
+ edges
254
+ });
255
+ } catch (e) {
256
+ logger.error(COMPONENT, `Endpoint error: ${e.message}`);
257
+ res.status(500).json({ error: "Something went wrong on our end. Please try again in a moment." });
258
+ }
259
+ });
260
+ router.get("/graph/entities", (req, res) => {
261
+ try {
262
+ const q = req.query.q || "";
263
+ const type = req.query.type || void 0;
264
+ const entities = listEntities(type);
265
+ const filtered = q ? entities.filter((e) => e.name.toLowerCase().includes(q.toLowerCase()) || (e.type || "").toLowerCase().includes(q.toLowerCase())) : entities;
266
+ res.json(filtered);
267
+ } catch (e) {
268
+ logger.error(COMPONENT, `Endpoint error: ${e.message}`);
269
+ res.status(500).json({ error: "Something went wrong on our end. Please try again in a moment." });
270
+ }
271
+ });
272
+ router.delete("/graphiti", (_req, res) => {
273
+ try {
274
+ clearGraph();
275
+ logger.info(COMPONENT, "Memory graph cleared via API");
276
+ res.json({ success: true, message: "Graph cleared" });
277
+ } catch (e) {
278
+ logger.error(COMPONENT, `Endpoint error: ${e.message}`);
279
+ res.status(500).json({ error: "Something went wrong on our end. Please try again in a moment." });
280
+ }
281
+ });
282
+ router.post("/graphiti/cleanup", (_req, res) => {
283
+ try {
284
+ const result = cleanupGraph();
285
+ logger.info(COMPONENT, `Graph cleanup: removed ${result.removedEntities} entities, ${result.removedEdges} edges`);
286
+ res.json({ success: true, ...result });
287
+ } catch (e) {
288
+ logger.error(COMPONENT, `Endpoint error: ${e.message}`);
289
+ res.status(500).json({ error: "Something went wrong on our end. Please try again in a moment." });
290
+ }
291
+ });
292
+ return router;
293
+ }
294
+ export {
295
+ createTeamsRecipesRouter
296
+ };
297
+ //# sourceMappingURL=teamsRecipes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/gateway/routes/teamsRecipes.ts"],"sourcesContent":["/**\n * Teams, Recipes, Plugins, and Graph Router\n *\n * Extracted from gateway/server.ts.\n * Consolidates all /api/teams/*, /api/recipes/*, /api/plugins, and /api/graphiti/* routes.\n */\nimport { Router, type Request, type Response } from 'express';\nimport express from 'express';\nimport logger from '../../utils/logger.js';\n\nimport {\n listTeams,\n getTeam,\n createTeam,\n updateTeam,\n deleteTeam,\n getTeamStats,\n addMember,\n removeMember,\n updateMemberRole,\n createInvite,\n acceptInvite,\n getEffectivePermissions,\n getUserRole,\n setRolePermissions,\n isToolAllowed,\n} from '../../security/teams.js';\n\nimport {\n listRecipes,\n getRecipe,\n saveRecipe,\n deleteRecipe,\n getBuiltinRecipes,\n importRecipeYaml,\n} from '../../recipes/store.js';\n\nimport { runRecipe } from '../../recipes/runner.js';\n\nimport {\n getGraphData,\n getGraphStats,\n clearGraph,\n cleanupGraph,\n listEntities,\n} from '../../memory/graph.js';\n\nconst COMPONENT = 'TeamsRecipesRouter';\n\nexport function createTeamsRecipesRouter(): Router {\n const router = Router();\n\n // ── Teams RBAC API ──────────────────────────────────────────\n router.get('/teams', (_req, res) => {\n res.json({ teams: listTeams().map(t => ({ id: t.id, name: t.name, description: t.description, memberCount: t.members.filter(m => m.status === 'active').length, createdAt: t.createdAt })) });\n });\n\n router.post('/teams', (req, res) => {\n try {\n const { name, description, ownerId = 'api-user' } = req.body;\n if (!name) { res.status(400).json({ error: 'name is required' }); return; }\n const team = createTeam(name, ownerId, description);\n res.status(201).json({ team: { id: team.id, name: team.name } });\n } catch (e) { res.status(400).json({ error: (e as Error).message }); }\n });\n\n router.get('/teams/:teamId', (req, res) => {\n const team = getTeam(req.params.teamId);\n if (!team) { res.status(404).json({ error: 'Team not found' }); return; }\n res.json({ team, stats: getTeamStats(req.params.teamId) });\n });\n\n router.patch('/teams/:teamId', (req, res) => {\n try {\n const { name, description, actorId = 'api-user' } = req.body;\n const team = updateTeam(req.params.teamId, actorId, { name, description });\n res.json({ team: { id: team.id, name: team.name, description: team.description } });\n } catch (e) { res.status(400).json({ error: (e as Error).message }); }\n });\n\n router.delete('/teams/:teamId', (req, res) => {\n try {\n const actorId = (req.query.actorId as string) || 'api-user';\n const deleted = deleteTeam(req.params.teamId, actorId);\n res.json({ deleted });\n } catch (e) { res.status(403).json({ error: (e as Error).message }); }\n });\n\n router.get('/teams/:teamId/members', (req, res) => {\n const team = getTeam(req.params.teamId);\n if (!team) { res.status(404).json({ error: 'Team not found' }); return; }\n res.json({ members: team.members });\n });\n\n router.post('/teams/:teamId/members', (req, res) => {\n try {\n const { userId, role = 'operator', displayName, actorId = 'api-user' } = req.body;\n if (!userId) { res.status(400).json({ error: 'userId is required' }); return; }\n const member = addMember(req.params.teamId, actorId, userId, role, displayName);\n res.status(201).json({ member });\n } catch (e) { res.status(400).json({ error: (e as Error).message }); }\n });\n\n router.delete('/teams/:teamId/members/:userId', (req, res) => {\n try {\n const actorId = (req.query.actorId as string) || 'api-user';\n const removed = removeMember(req.params.teamId, actorId, req.params.userId);\n res.json({ removed });\n } catch (e) { res.status(403).json({ error: (e as Error).message }); }\n });\n\n router.patch('/teams/:teamId/members/:userId/role', (req, res) => {\n try {\n const { role, actorId = 'api-user' } = req.body;\n if (!role) { res.status(400).json({ error: 'role is required' }); return; }\n const member = updateMemberRole(req.params.teamId, actorId, req.params.userId, role);\n res.json({ member });\n } catch (e) { res.status(400).json({ error: (e as Error).message }); }\n });\n\n router.post('/teams/:teamId/invites', (req, res) => {\n try {\n const { role = 'operator', expiresInHours = 48, actorId = 'api-user' } = req.body;\n const code = createInvite(req.params.teamId, actorId, role, expiresInHours);\n res.status(201).json({ code, expiresInHours });\n } catch (e) { res.status(400).json({ error: (e as Error).message }); }\n });\n\n router.post('/teams/join', (req, res) => {\n try {\n const { code, userId, displayName } = req.body;\n if (!code || !userId) { res.status(400).json({ error: 'code and userId are required' }); return; }\n const result = acceptInvite(code, userId, displayName);\n res.json({ teamId: result.team.id, teamName: result.team.name, role: result.member.role });\n } catch (e) { res.status(400).json({ error: (e as Error).message }); }\n });\n\n router.get('/teams/:teamId/permissions/:userId', (req, res) => {\n const perms = getEffectivePermissions(req.params.teamId, req.params.userId);\n const role = getUserRole(req.params.teamId, req.params.userId);\n res.json({ role, permissions: perms });\n });\n\n router.put('/teams/:teamId/roles/:role/permissions', (req, res) => {\n try {\n const { actorId = 'api-user', ...perms } = req.body;\n setRolePermissions(req.params.teamId, actorId, req.params.role as 'admin' | 'operator' | 'viewer', perms);\n res.json({ updated: true });\n } catch (e) { res.status(400).json({ error: (e as Error).message }); }\n });\n\n router.get('/teams/:teamId/tools/:toolName/check/:userId', (req, res) => {\n const allowed = isToolAllowed(req.params.teamId, req.params.userId, req.params.toolName);\n res.json({ allowed, tool: req.params.toolName, userId: req.params.userId });\n });\n\n // ── Recipes / Workflow API ───────────────────────────────────\n router.get('/recipes', (_req, res) => {\n res.json({ recipes: listRecipes() });\n });\n\n router.get('/recipes/:id', (req, res) => {\n const recipe = getRecipe(req.params.id);\n if (!recipe) { res.status(404).json({ error: 'Recipe not found' }); return; }\n res.json({ recipe });\n });\n\n router.post('/recipes', (req, res) => {\n const recipe = req.body;\n if (!recipe.id || !recipe.name || !recipe.steps) {\n res.status(400).json({ error: 'id, name, and steps are required' }); return;\n }\n if (!recipe.createdAt) recipe.createdAt = new Date().toISOString();\n saveRecipe(recipe);\n res.status(201).json({ recipe });\n });\n\n router.put('/recipes/:id', (req, res) => {\n const existing = getRecipe(req.params.id);\n if (!existing) { res.status(404).json({ error: 'Recipe not found' }); return; }\n const updated = { ...existing, ...req.body, id: req.params.id };\n saveRecipe(updated);\n res.json({ recipe: updated });\n });\n\n router.delete('/recipes/:id', (req, res) => {\n if (!getRecipe(req.params.id)) { res.status(404).json({ error: 'Recipe not found' }); return; }\n deleteRecipe(req.params.id);\n res.json({ deleted: true });\n });\n\n router.get('/recipes/builtin/templates', (_req, res) => {\n res.json({ templates: getBuiltinRecipes() });\n });\n\n router.post('/recipes/import', express.text({ type: 'text/*' }), (req, res) => {\n try {\n const recipe = importRecipeYaml(req.body);\n saveRecipe(recipe);\n res.status(201).json({ recipe });\n } catch (e) { res.status(400).json({ error: (e as Error).message }); }\n });\n\n router.post('/recipes/:id/run', async (req, res) => {\n const recipe = getRecipe(req.params.id);\n if (!recipe) { res.status(404).json({ error: 'Recipe not found' }); return; }\n try {\n const params = req.body.params || {};\n const steps: Array<{ stepIndex: number; prompt: string }> = [];\n for await (const step of runRecipe(req.params.id, params)) {\n steps.push({ stepIndex: step.stepIndex, prompt: step.prompt });\n }\n res.json({ recipe: recipe.name, stepsExecuted: steps.length, steps });\n } catch (e) {\n logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`);\n res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' });\n }\n });\n\n // ── Plugins API ─────────────────────────────────────────────\n router.get('/plugins', async (_req, res) => {\n const { getPlugins } = await import('../../plugins/registry.js');\n const plugins = getPlugins().map((p: { name: string; version: string }) => ({\n name: p.name,\n version: p.version,\n }));\n res.json({ plugins });\n });\n\n // ── Graph API ─────────────────────────────────────────────────\n router.get('/graphiti', (_req, res) => {\n try {\n const { nodes, edges } = getGraphData();\n const { episodeCount } = getGraphStats();\n res.json({\n graphReady: true,\n episodeCount,\n nodeCount: nodes.length,\n edgeCount: edges.length,\n nodes,\n edges,\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.get('/graph/entities', (req, res) => {\n try {\n const q = (req.query.q as string) || '';\n const type = (req.query.type as string) || undefined;\n const entities = listEntities(type);\n const filtered = q\n ? entities.filter(e => e.name.toLowerCase().includes(q.toLowerCase()) || (e.type || '').toLowerCase().includes(q.toLowerCase()))\n : entities;\n res.json(filtered);\n } catch (e) {\n logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`);\n res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' });\n }\n });\n\n router.delete('/graphiti', (_req, res) => {\n try {\n clearGraph();\n logger.info(COMPONENT, 'Memory graph cleared via API');\n res.json({ success: true, message: 'Graph cleared' });\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('/graphiti/cleanup', (_req, res) => {\n try {\n const result = cleanupGraph();\n logger.info(COMPONENT, `Graph cleanup: removed ${result.removedEntities} entities, ${result.removedEdges} edges`);\n res.json({ success: true, ...result });\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 return router;\n}\n"],"mappings":"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","names":[]}