titan-agent 5.4.2 → 5.5.5

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 (296) 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/planner.js +4 -4
  15. package/dist/agent/planner.js.map +1 -1
  16. package/dist/agent/userProfile.js +2 -2
  17. package/dist/agent/userProfile.js.map +1 -1
  18. package/dist/cli/doctor.js +33 -0
  19. package/dist/cli/doctor.js.map +1 -1
  20. package/dist/cli/onboard.js +4 -4
  21. package/dist/cli/onboard.js.map +1 -1
  22. package/dist/config/config.js +3 -3
  23. package/dist/config/config.js.map +1 -1
  24. package/dist/config/schema.js +8 -1
  25. package/dist/config/schema.js.map +1 -1
  26. package/dist/gateway/routes/adminRouter.js +500 -0
  27. package/dist/gateway/routes/adminRouter.js.map +1 -0
  28. package/dist/gateway/routes/agents.js +231 -0
  29. package/dist/gateway/routes/agents.js.map +1 -0
  30. package/dist/gateway/routes/agentsRouter.js +32 -0
  31. package/dist/gateway/routes/agentsRouter.js.map +1 -0
  32. package/dist/gateway/routes/checkpoints.js +41 -0
  33. package/dist/gateway/routes/checkpoints.js.map +1 -0
  34. package/dist/gateway/routes/commandPost.js +755 -0
  35. package/dist/gateway/routes/commandPost.js.map +1 -0
  36. package/dist/gateway/routes/companies.js +166 -0
  37. package/dist/gateway/routes/companies.js.map +1 -0
  38. package/dist/gateway/routes/files.js +295 -0
  39. package/dist/gateway/routes/files.js.map +1 -0
  40. package/dist/gateway/routes/hardwareRouter.js +151 -0
  41. package/dist/gateway/routes/hardwareRouter.js.map +1 -0
  42. package/dist/gateway/routes/mcpRouter.js +88 -0
  43. package/dist/gateway/routes/mcpRouter.js.map +1 -0
  44. package/dist/gateway/routes/mesh.js +464 -0
  45. package/dist/gateway/routes/mesh.js.map +1 -0
  46. package/dist/gateway/routes/metricsRouter.js +131 -0
  47. package/dist/gateway/routes/metricsRouter.js.map +1 -0
  48. package/dist/gateway/routes/organism.js +82 -0
  49. package/dist/gateway/routes/organism.js.map +1 -0
  50. package/dist/gateway/routes/paperclip.js +101 -0
  51. package/dist/gateway/routes/paperclip.js.map +1 -0
  52. package/dist/gateway/routes/sessions.js +227 -0
  53. package/dist/gateway/routes/sessions.js.map +1 -0
  54. package/dist/gateway/routes/skills.js +295 -0
  55. package/dist/gateway/routes/skills.js.map +1 -0
  56. package/dist/gateway/routes/socialRouter.js +145 -0
  57. package/dist/gateway/routes/socialRouter.js.map +1 -0
  58. package/dist/gateway/routes/systemRouter.js +220 -0
  59. package/dist/gateway/routes/systemRouter.js.map +1 -0
  60. package/dist/gateway/routes/teamsRecipes.js +297 -0
  61. package/dist/gateway/routes/teamsRecipes.js.map +1 -0
  62. package/dist/gateway/routes/tests.js +401 -0
  63. package/dist/gateway/routes/tests.js.map +1 -0
  64. package/dist/gateway/routes/traces.js +33 -0
  65. package/dist/gateway/routes/traces.js.map +1 -0
  66. package/dist/gateway/routes/voiceRouter.js +770 -0
  67. package/dist/gateway/routes/voiceRouter.js.map +1 -0
  68. package/dist/gateway/routes/watchRouter.js +131 -0
  69. package/dist/gateway/routes/watchRouter.js.map +1 -0
  70. package/dist/gateway/server.js +1179 -7379
  71. package/dist/gateway/server.js.map +1 -1
  72. package/dist/mcp/registry.js +2 -2
  73. package/dist/mcp/registry.js.map +1 -1
  74. package/dist/memory/episodic.js +2 -2
  75. package/dist/memory/episodic.js.map +1 -1
  76. package/dist/memory/learning.js +3 -3
  77. package/dist/memory/learning.js.map +1 -1
  78. package/dist/memory/memory.js +3 -3
  79. package/dist/memory/memory.js.map +1 -1
  80. package/dist/organism/drives.js +2 -2
  81. package/dist/organism/drives.js.map +1 -1
  82. package/dist/providers/errorTaxonomy.js +13 -0
  83. package/dist/providers/errorTaxonomy.js.map +1 -1
  84. package/dist/providers/ollama.js +3 -1
  85. package/dist/providers/ollama.js.map +1 -1
  86. package/dist/providers/openai_compat.js +4 -3
  87. package/dist/providers/openai_compat.js.map +1 -1
  88. package/dist/providers/router.js +13 -0
  89. package/dist/providers/router.js.map +1 -1
  90. package/dist/safety/killSwitch.js +2 -2
  91. package/dist/safety/killSwitch.js.map +1 -1
  92. package/dist/skills/builtin/agent_debate.js +2 -2
  93. package/dist/skills/builtin/agent_debate.js.map +1 -1
  94. package/dist/skills/builtin/apply_patch.js +3 -3
  95. package/dist/skills/builtin/apply_patch.js.map +1 -1
  96. package/dist/skills/builtin/shell.js +2 -2
  97. package/dist/skills/builtin/shell.js.map +1 -1
  98. package/dist/skills/builtin/voice_control.js +49 -0
  99. package/dist/skills/builtin/voice_control.js.map +1 -0
  100. package/dist/skills/builtin/widget_gallery.js +6 -1
  101. package/dist/skills/builtin/widget_gallery.js.map +1 -1
  102. package/dist/skills/registry.js +15 -4
  103. package/dist/skills/registry.js.map +1 -1
  104. package/dist/storage/JsonStorage.js +4 -4
  105. package/dist/storage/JsonStorage.js.map +1 -1
  106. package/dist/utils/constants.js +1 -1
  107. package/dist/utils/constants.js.map +1 -1
  108. package/dist/utils/helpers.js +3 -1
  109. package/dist/utils/helpers.js.map +1 -1
  110. package/dist/utils/lifecycle.js +86 -0
  111. package/dist/utils/lifecycle.js.map +1 -0
  112. package/dist/voice/bridge.js +136 -0
  113. package/dist/voice/bridge.js.map +1 -0
  114. package/docs/COO-MASTER-PLAN-2026-05-02.md +474 -0
  115. package/docs/HANDOFF/2026-04-29.md +141 -0
  116. package/docs/HANDOFF-2026-04-30.md +144 -0
  117. package/docs/HANDOFF-2026-05-03.md +114 -0
  118. package/docs/adr/2026-04-29-widget-pipeline-traceability.md +49 -0
  119. package/docs/agent-memory/README.md +45 -0
  120. package/docs/agent-memory/commands.md +100 -0
  121. package/docs/agent-memory/context-tree.md +101 -0
  122. package/docs/agent-memory/current-state.md +54 -0
  123. package/docs/agent-memory/decisions.md +78 -0
  124. package/docs/agent-memory/known-issues.md +76 -0
  125. package/docs/agent-memory/reflections.md +52 -0
  126. package/docs/agent-memory/skills-candidates.md +80 -0
  127. package/docs/superpowers/plans/2026-04-29-comprehensive-audit.md +256 -0
  128. package/docs/superpowers/plans/2026-04-29-comprehensive-test-plan.md +396 -0
  129. package/docs/superpowers/plans/2026-04-29-fix-all-prs.md +251 -0
  130. package/docs/superpowers/plans/2026-04-29-gitnexus-gap-remediation.md +969 -0
  131. package/package.json +5 -2
  132. package/ui/dist/assets/{AuditPanel-CM6Wg9hO.js → AuditPanel-VzSndmDN.js} +2 -2
  133. package/ui/dist/assets/{AutonomyPanel-CESx3ANg.js → AutonomyPanel-BiFouzAV.js} +2 -2
  134. package/ui/dist/assets/AutopilotPanel-fjOfM668.js +1 -0
  135. package/ui/dist/assets/{AutoresearchPanel-DR47NqT5.js → AutoresearchPanel-CVCxzAH3.js} +2 -2
  136. package/ui/dist/assets/BackupPanel-CHVTG--q.js +1 -0
  137. package/ui/dist/assets/{BrowserPanel-C15x9bLn.js → BrowserPanel-D5mvMKFU.js} +2 -2
  138. package/ui/dist/assets/CPActivity-B12mt35m.js +1 -0
  139. package/ui/dist/assets/CPAgentDetail-DsdShc-1.js +1 -0
  140. package/ui/dist/assets/CPAgents-j_7C-oQV.js +1 -0
  141. package/ui/dist/assets/CPApprovals-BShKSX9X.js +1 -0
  142. package/ui/dist/assets/CPCosts-CKPlhBDs.js +1 -0
  143. package/ui/dist/assets/CPDashboard-11c0nkxK.js +1 -0
  144. package/ui/dist/assets/CPFiles-BhLEOnXy.js +1 -0
  145. package/ui/dist/assets/CPGoals-Bi3t1b2P.js +1 -0
  146. package/ui/dist/assets/CPInbox-Bbr7khp6.js +11 -0
  147. package/ui/dist/assets/CPIssueDetail-DSdgNK8r.js +1 -0
  148. package/ui/dist/assets/CPIssues-DDEVKhX6.js +1 -0
  149. package/ui/dist/assets/CPLayout-DgPOfyGv.js +17 -0
  150. package/ui/dist/assets/CPOrg-Df73RrRJ.js +8 -0
  151. package/ui/dist/assets/CPRuns-ByioAz8w.js +1 -0
  152. package/ui/dist/assets/{CPSocial-nb-j7sOE.js → CPSocial-Dlnr_w1X.js} +2 -2
  153. package/ui/dist/assets/ChannelsPanel-DQjQCTK5.js +1 -0
  154. package/ui/dist/assets/CheckpointsPanel-C4vKjlAJ.js +1 -0
  155. package/ui/dist/assets/CommandPostHub-C9pp5Giq.js +24 -0
  156. package/ui/dist/assets/CronPanel-C6bzUfrD.js +1 -0
  157. package/ui/dist/assets/DaemonPanel-BA5Tb_UO.js +1 -0
  158. package/ui/dist/assets/{DataTable-B2Ma8hfi.js → DataTable-CH7IYJJh.js} +1 -1
  159. package/ui/dist/assets/{EmptyState-CcKyk5Yn.js → EmptyState-jU6yNDnF.js} +1 -1
  160. package/ui/dist/assets/{EvalHarnessPanel-BqtMc1ZM.js → EvalHarnessPanel-DnYqredY.js} +2 -2
  161. package/ui/dist/assets/EvalPanel-ChO7CD1r.js +1 -0
  162. package/ui/dist/assets/{FilesPanel-3QKvrWPo.js → FilesPanel-CaUkv2is.js} +2 -2
  163. package/ui/dist/assets/FleetPanel-DC_5uj0N.js +1 -0
  164. package/ui/dist/assets/{HomelabPanel-DhrjTX9m.js → HomelabPanel-CE5PGRpL.js} +2 -2
  165. package/ui/dist/assets/InfraView-C-uSlvb9.js +2 -0
  166. package/ui/dist/assets/InlineEditableField-BMQjiE6-.js +1 -0
  167. package/ui/dist/assets/Input-Bu_b3qmY.js +1 -0
  168. package/ui/dist/assets/IntegrationsPanel-DsYpAq43.js +1 -0
  169. package/ui/dist/assets/IntelligenceView-DUdIO1K7.js +2 -0
  170. package/ui/dist/assets/LearningPanel-UpQZC-mA.js +1 -0
  171. package/ui/dist/assets/LogsPanel-ClXJ4fcr.js +1 -0
  172. package/ui/dist/assets/McpPanel-JKgtIERQ.js +1 -0
  173. package/ui/dist/assets/{MemoryGraphPanel-Bzvjmzvk.js → MemoryGraphPanel-Bo2OrvA6.js} +2 -2
  174. package/ui/dist/assets/MemoryWikiPanel-BqJ1AmYm.js +11 -0
  175. package/ui/dist/assets/{MeshPanel-C3LJSlht.js → MeshPanel-BJVGYvwk.js} +2 -2
  176. package/ui/dist/assets/Modal-CAAooiZU.js +1 -0
  177. package/ui/dist/assets/NvidiaPanel-BtCg3G4w.js +1 -0
  178. package/ui/dist/assets/OrganismPanel-DgrTTzcF.js +1 -0
  179. package/ui/dist/assets/OverviewPanel-rVav1Hox.js +1 -0
  180. package/ui/dist/assets/{PageHeader-BimceqQo.js → PageHeader-CnZtP8ek.js} +1 -1
  181. package/ui/dist/assets/PaperclipPanel-C-FKdhiF.js +1 -0
  182. package/ui/dist/assets/{PersonasPanel-L1j78p6H.js → PersonasPanel-BmlxokfB.js} +1 -1
  183. package/ui/dist/assets/RecipesPanel-BNKKChis.js +1 -0
  184. package/ui/dist/assets/SecurityPanel-I7JRHiNy.js +1 -0
  185. package/ui/dist/assets/SelfImprovePanel-u9h0Lt3p.js +1 -0
  186. package/ui/dist/assets/{SelfProposalsPanel-lNmiDThB.js → SelfProposalsPanel-DKl9iBjM.js} +2 -2
  187. package/ui/dist/assets/SessionsPanel-BhRiWI_g.js +1 -0
  188. package/ui/dist/assets/{SessionsTab-JQbltWww.js → SessionsTab-Bk08wyeY.js} +1 -1
  189. package/ui/dist/assets/SettingsPanel-haLfmG2k.js +1 -0
  190. package/ui/dist/assets/SettingsView--gi3fxI8.js +2 -0
  191. package/ui/dist/assets/{SkeletonLoader-atQtpcF5.js → SkeletonLoader-B5v09EF_.js} +1 -1
  192. package/ui/dist/assets/{SkillsPanel-DlFs2ih7.js → SkillsPanel-BlAHFLcQ.js} +1 -1
  193. package/ui/dist/assets/SomaView-CExtS3zw.js +5 -0
  194. package/ui/dist/assets/{StatCard-DciE_Iqc.js → StatCard-BIsyMybM.js} +1 -1
  195. package/ui/dist/assets/{StatusBadge-BtfSPoW2.js → StatusBadge-D5nU7El8.js} +1 -1
  196. package/ui/dist/assets/Tabs-BBYZrBI8.js +1 -0
  197. package/ui/dist/assets/TeamsPanel-LPXJg823.js +1 -0
  198. package/ui/dist/assets/TelemetryPanel-EqpRBmOI.js +1 -0
  199. package/ui/dist/assets/TitanCanvas-BCbWnLMd.js +985 -0
  200. package/ui/dist/assets/ToolsView-CeP0Zz-N.js +2 -0
  201. package/ui/dist/assets/{Tooltip-70UK0E2I.js → Tooltip-BSO2XVpF.js} +1 -1
  202. package/ui/dist/assets/TraceViewer-BKI7o5B0.js +1 -0
  203. package/ui/dist/assets/TrainingPanel-c-RhjdE1.js +1 -0
  204. package/ui/dist/assets/VoiceOverlay-D-gc58b0.js +27 -0
  205. package/ui/dist/assets/VramPanel-C6xc7zgd.js +1 -0
  206. package/ui/dist/assets/{WatchView-C-sGFpVy.js → WatchView-dqBVCVH0.js} +1 -1
  207. package/ui/dist/assets/WorkTab-CBoLNrTM.js +1 -0
  208. package/ui/dist/assets/{WorkflowsPanel-CvgQU1xI.js → WorkflowsPanel-BAnSTOYe.js} +2 -2
  209. package/ui/dist/assets/approvalHeadline-DB9SgR-9.js +1 -0
  210. package/ui/dist/assets/{arrow-left-DwqHtJiU.js → arrow-left-5chqas7J.js} +1 -1
  211. package/ui/dist/assets/briefcase-D4vLzudp.js +6 -0
  212. package/ui/dist/assets/{chart-column-BtNO6sRy.js → chart-column-CdFlBpoP.js} +1 -1
  213. package/ui/dist/assets/check-Bpm1IONe.js +6 -0
  214. package/ui/dist/assets/chevron-down-D7OLjvuD.js +6 -0
  215. package/ui/dist/assets/chevron-right-aQEw2mUW.js +6 -0
  216. package/ui/dist/assets/chevron-up-C5g6pEj8.js +6 -0
  217. package/ui/dist/assets/{circle-check-big-DZRE_MbN.js → circle-check-big-fPhEdP88.js} +1 -1
  218. package/ui/dist/assets/clock-CTsgP_Sn.js +6 -0
  219. package/ui/dist/assets/{dollar-sign-aVG3a5eL.js → dollar-sign-CudFVYFc.js} +1 -1
  220. package/ui/dist/assets/{download-BxiWJU4G.js → download-DZRxDn67.js} +1 -1
  221. package/ui/dist/assets/external-link-BZ0y_Ahx.js +6 -0
  222. package/ui/dist/assets/{eye-off-CkgfFYhm.js → eye-off-BmJF0YYx.js} +1 -1
  223. package/ui/dist/assets/folder-DA43TRCm.js +11 -0
  224. package/ui/dist/assets/{funnel-PkLdxKyC.js → funnel-J3mULzrz.js} +1 -1
  225. package/ui/dist/assets/{git-branch-BM-Gw95X.js → git-branch-oHibJqDq.js} +1 -1
  226. package/ui/dist/assets/{index-D0RJ8701.css → index-BR0vfkIi.css} +1 -1
  227. package/ui/dist/assets/{index-CahJbWSR.js → index-DzwowwSI.js} +20 -20
  228. package/ui/dist/assets/{layers-BuGf4FIJ.js → layers-DsyEyu7z.js} +1 -1
  229. package/ui/dist/assets/{legacy-CR6o4t-y.js → legacy-8ITl64sV.js} +1 -1
  230. package/ui/dist/assets/{lightbulb-n8gc_XAL.js → lightbulb-C54Ske-p.js} +1 -1
  231. package/ui/dist/assets/list-todo-Cnd4rdoK.js +6 -0
  232. package/ui/dist/assets/loader-circle-1YOBsoQp.js +6 -0
  233. package/ui/dist/assets/network-DbGDAdrn.js +6 -0
  234. package/ui/dist/assets/{pause-DCV52koX.js → pause-CYhO_uQo.js} +1 -1
  235. package/ui/dist/assets/{play-CcJ9BnCh.js → play-DVY9c5Ck.js} +1 -1
  236. package/ui/dist/assets/{plug-CfWBXfCl.js → plug-BcXjlPUL.js} +1 -1
  237. package/ui/dist/assets/plus-Csu2v9GN.js +6 -0
  238. package/ui/dist/assets/{proxy-CzZDfLmm.js → proxy-DxS2_9D7.js} +1 -1
  239. package/ui/dist/assets/rotate-ccw-Co-_W04j.js +6 -0
  240. package/ui/dist/assets/save-Btx-kpoW.js +6 -0
  241. package/ui/dist/assets/search-0hXTwEZR.js +6 -0
  242. package/ui/dist/assets/send-TEpapzQR.js +6 -0
  243. package/ui/dist/assets/shield-check-DjBJXZUr.js +6 -0
  244. package/ui/dist/assets/{square-DJpUhlxi.js → square-OweUvjP-.js} +1 -1
  245. package/ui/dist/assets/{target-DWcmM_9m.js → target-BRW80Xer.js} +1 -1
  246. package/ui/dist/assets/terminal-BtiqJ628.js +16 -0
  247. package/ui/dist/assets/{toggle-right-YusFQ69L.js → toggle-right-CKtSrl28.js} +1 -1
  248. package/ui/dist/assets/{trash-2-CK7yQ55V.js → trash-2-DgWrHVax.js} +1 -1
  249. package/ui/dist/assets/{trending-up-DGjFyubC.js → trending-up-MpIrE4j6.js} +1 -1
  250. package/ui/dist/assets/{trophy-uQv_NgDB.js → trophy-CECuZNhX.js} +1 -1
  251. package/ui/dist/assets/users-dZgv4ePG.js +16 -0
  252. package/ui/dist/assets/wrench-CDz3xYve.js +11 -0
  253. package/ui/dist/index.html +2 -2
  254. package/ui/dist/assets/AutopilotPanel-DtEet1hJ.js +0 -1
  255. package/ui/dist/assets/BackupPanel-BGP8p3l3.js +0 -1
  256. package/ui/dist/assets/CPAgents-DYUtPzSq.js +0 -1
  257. package/ui/dist/assets/CPDashboard-Bf0-SyCh.js +0 -6
  258. package/ui/dist/assets/CPFiles-CxgxjQcO.js +0 -1
  259. package/ui/dist/assets/CPGoals-BsmCMTvT.js +0 -1
  260. package/ui/dist/assets/CPInbox-tMSbmQ9H.js +0 -11
  261. package/ui/dist/assets/ChannelsPanel-DP5C2OKd.js +0 -1
  262. package/ui/dist/assets/CheckpointsPanel-DlranVLZ.js +0 -1
  263. package/ui/dist/assets/CommandPostHub-BgxIa4Ev.js +0 -29
  264. package/ui/dist/assets/CronPanel-LoT5yKwJ.js +0 -1
  265. package/ui/dist/assets/DaemonPanel-DBGMqaE_.js +0 -1
  266. package/ui/dist/assets/EvalPanel-Bc33j0pN.js +0 -1
  267. package/ui/dist/assets/FleetPanel-CSsXuQYj.js +0 -1
  268. package/ui/dist/assets/InfraView-CR6HyrL6.js +0 -2
  269. package/ui/dist/assets/InlineEditableField-CnvF-yFR.js +0 -1
  270. package/ui/dist/assets/Input-GTHp2Rkr.js +0 -1
  271. package/ui/dist/assets/IntegrationsPanel-CymCRE3T.js +0 -1
  272. package/ui/dist/assets/IntelligenceView-C1IHxJRC.js +0 -2
  273. package/ui/dist/assets/LearningPanel-DOCES3lH.js +0 -1
  274. package/ui/dist/assets/LogsPanel-BLnAqEaZ.js +0 -1
  275. package/ui/dist/assets/McpPanel-ChUzmr3z.js +0 -1
  276. package/ui/dist/assets/MemoryWikiPanel-Dwk3Aqwd.js +0 -11
  277. package/ui/dist/assets/NvidiaPanel-CeZK_-CV.js +0 -1
  278. package/ui/dist/assets/OrganismPanel-BB6YOiQV.js +0 -1
  279. package/ui/dist/assets/OverviewPanel-BmtBhQnv.js +0 -1
  280. package/ui/dist/assets/PaperclipPanel-C-brgwA3.js +0 -1
  281. package/ui/dist/assets/RecipesPanel-34lCfynJ.js +0 -1
  282. package/ui/dist/assets/SecurityPanel-CBTPWLj6.js +0 -1
  283. package/ui/dist/assets/SelfImprovePanel-BrPbFHhG.js +0 -1
  284. package/ui/dist/assets/SessionsPanel-DAEYIn83.js +0 -1
  285. package/ui/dist/assets/SettingsPanel-CzRROAYQ.js +0 -1
  286. package/ui/dist/assets/SettingsView-CN7ii2uw.js +0 -2
  287. package/ui/dist/assets/SomaView-Ba642Oqb.js +0 -5
  288. package/ui/dist/assets/TeamsPanel-DKQ5z2Qe.js +0 -1
  289. package/ui/dist/assets/TelemetryPanel-B6KAc55Q.js +0 -1
  290. package/ui/dist/assets/TitanCanvas-C-s0A-lv.js +0 -1092
  291. package/ui/dist/assets/ToolsView-Dei0KMP0.js +0 -2
  292. package/ui/dist/assets/TraceViewer-BniolyBx.js +0 -1
  293. package/ui/dist/assets/TrainingPanel-Bz4CTPGW.js +0 -1
  294. package/ui/dist/assets/VoiceOverlay-CmNCrLcd.js +0 -37
  295. package/ui/dist/assets/VramPanel-Xh_OtRDR.js +0 -1
  296. package/ui/dist/assets/WorkTab-BjLNmgIK.js +0 -1
@@ -4,7 +4,7 @@ import { join, dirname } from "path";
4
4
  import vm from "vm";
5
5
  import { TITAN_HOME, TITAN_SKILLS_DIR } from "../utils/constants.js";
6
6
  import { registerTool } from "../agent/toolRunner.js";
7
- import { ensureDir } from "../utils/helpers.js";
7
+ import { mkdirIfNotExists } from "../utils/helpers.js";
8
8
  import logger from "../utils/logger.js";
9
9
  import { loadConfig } from "../config/config.js";
10
10
  const COMPONENT = "Skills";
@@ -77,16 +77,27 @@ function setSkillEnabled(skillName, enabled) {
77
77
  }
78
78
  saveDisabledSkills(disabled);
79
79
  }
80
+ let _disabledSkillsCache = null;
81
+ let _disabledSkillsCacheAt = 0;
82
+ const DISABLED_SKILLS_CACHE_TTL_MS = 3e4;
80
83
  function loadDisabledSkills() {
84
+ const now = Date.now();
85
+ if (_disabledSkillsCache !== null && now - _disabledSkillsCacheAt < DISABLED_SKILLS_CACHE_TTL_MS) {
86
+ return _disabledSkillsCache;
87
+ }
88
+ let result = [];
81
89
  try {
82
90
  if (existsSync(DISABLED_SKILLS_PATH)) {
83
- return JSON.parse(readFileSync(DISABLED_SKILLS_PATH, "utf-8"));
91
+ result = JSON.parse(readFileSync(DISABLED_SKILLS_PATH, "utf-8"));
84
92
  }
85
93
  } catch {
86
94
  }
87
- return [];
95
+ _disabledSkillsCache = result;
96
+ _disabledSkillsCacheAt = now;
97
+ return result;
88
98
  }
89
99
  function saveDisabledSkills(disabled) {
100
+ _disabledSkillsCache = null;
90
101
  try {
91
102
  const dir = dirname(DISABLED_SKILLS_PATH);
92
103
  if (!existsSync(dir)) {
@@ -98,7 +109,7 @@ function saveDisabledSkills(disabled) {
98
109
  }
99
110
  }
100
111
  function discoverWorkspaceSkills() {
101
- ensureDir(TITAN_SKILLS_DIR);
112
+ mkdirIfNotExists(TITAN_SKILLS_DIR);
102
113
  const discovered = [];
103
114
  if (!existsSync(TITAN_SKILLS_DIR)) return discovered;
104
115
  const entries = readdirSync(TITAN_SKILLS_DIR, { withFileTypes: true });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/skills/registry.ts"],"sourcesContent":["/**\n * TITAN — Skills Registry\n * Discovers, loads, and manages skills from bundled, workspace, and marketplace sources.\n */\nimport { existsSync, readdirSync, readFileSync, writeFileSync, mkdirSync } from 'fs';\nimport { join, dirname } from 'path';\nimport vm from 'vm';\nimport { TITAN_HOME, TITAN_SKILLS_DIR } from '../utils/constants.js';\nimport { registerTool, type ToolHandler } from '../agent/toolRunner.js';\nimport { ensureDir } from '../utils/helpers.js';\nimport logger from '../utils/logger.js';\nimport { loadConfig } from '../config/config.js';\n\nconst COMPONENT = 'Skills';\nconst DISABLED_SKILLS_PATH = join(TITAN_HOME, 'disabled-skills.json');\n\nexport interface SkillMeta {\n name: string;\n description: string;\n version: string;\n author?: string;\n source: 'bundled' | 'workspace' | 'marketplace' | 'frontmatter';\n enabled: boolean;\n}\n\nconst registeredSkills: Map<string, SkillMeta> = new Map();\n\n/** Maps skill name → tool names belonging to that skill */\nconst skillToolMap: Map<string, Set<string>> = new Map();\n\n/** Register a built-in skill (tool handler + metadata) */\nexport function registerSkill(meta: SkillMeta, handler: ToolHandler): void {\n registeredSkills.set(meta.name, meta);\n // Track which tools belong to this skill\n if (!skillToolMap.has(meta.name)) {\n skillToolMap.set(meta.name, new Set());\n }\n skillToolMap.get(meta.name)!.add(handler.name);\n registerTool(handler);\n logger.debug(COMPONENT, `Registered skill: ${meta.name} (${meta.source})`);\n}\n\n/** Get all registered skills (with persisted enabled/disabled state applied) */\nexport function getSkills(): SkillMeta[] {\n const disabled = loadDisabledSkills();\n return Array.from(registeredSkills.values()).map(s => ({\n ...s,\n enabled: !disabled.includes(s.name),\n }));\n}\n\n/** Get a skill by name */\nexport function getSkill(name: string): SkillMeta | undefined {\n return registeredSkills.get(name);\n}\n\n/** Get tool names belonging to a skill */\nexport function getSkillTools(skillName: string): string[] {\n return Array.from(skillToolMap.get(skillName) || []);\n}\n\n/** Check if a skill is enabled */\nexport function isSkillEnabled(skillName: string): boolean {\n return !loadDisabledSkills().includes(skillName);\n}\n\n/** Check if a specific tool's parent skill is enabled */\nexport function isToolSkillEnabled(toolName: string): boolean {\n for (const [skillName, tools] of skillToolMap.entries()) {\n if (tools.has(toolName)) {\n return isSkillEnabled(skillName);\n }\n }\n return true; // Tools not belonging to any skill are always enabled\n}\n\n/** Toggle a skill on/off. Returns the new enabled state. */\nexport function toggleSkill(skillName: string): boolean {\n const skill = registeredSkills.get(skillName);\n if (!skill) {\n throw new Error(`Skill \"${skillName}\" not found`);\n }\n\n const disabled = loadDisabledSkills();\n const idx = disabled.indexOf(skillName);\n let nowEnabled: boolean;\n\n if (idx >= 0) {\n disabled.splice(idx, 1);\n nowEnabled = true;\n } else {\n disabled.push(skillName);\n nowEnabled = false;\n }\n\n saveDisabledSkills(disabled);\n logger.info(COMPONENT, `Skill \"${skillName}\" ${nowEnabled ? 'enabled' : 'disabled'}`);\n return nowEnabled;\n}\n\n/** Set a skill's enabled state explicitly */\nexport function setSkillEnabled(skillName: string, enabled: boolean): void {\n const skill = registeredSkills.get(skillName);\n if (!skill) {\n throw new Error(`Skill \"${skillName}\" not found`);\n }\n\n const disabled = loadDisabledSkills();\n const idx = disabled.indexOf(skillName);\n\n if (enabled && idx >= 0) {\n disabled.splice(idx, 1);\n } else if (!enabled && idx < 0) {\n disabled.push(skillName);\n }\n\n saveDisabledSkills(disabled);\n}\n\n/** Load disabled skills list from disk */\nfunction loadDisabledSkills(): string[] {\n try {\n if (existsSync(DISABLED_SKILLS_PATH)) {\n return JSON.parse(readFileSync(DISABLED_SKILLS_PATH, 'utf-8')) as string[];\n }\n } catch {\n // Corrupt file — treat as empty\n }\n return [];\n}\n\n/** Save disabled skills list to disk */\nfunction saveDisabledSkills(disabled: string[]): void {\n try {\n const dir = dirname(DISABLED_SKILLS_PATH);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(DISABLED_SKILLS_PATH, JSON.stringify(disabled, null, 2), 'utf-8');\n } catch (e) {\n logger.warn(COMPONENT, `Failed to save disabled skills: ${(e as Error).message}`);\n }\n}\n\n/** Discover workspace skills from ~/.titan/workspace/skills/ */\nexport function discoverWorkspaceSkills(): SkillMeta[] {\n ensureDir(TITAN_SKILLS_DIR);\n const discovered: SkillMeta[] = [];\n\n if (!existsSync(TITAN_SKILLS_DIR)) return discovered;\n\n const entries = readdirSync(TITAN_SKILLS_DIR, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n const skillDir = join(TITAN_SKILLS_DIR, entry.name);\n const skillMdPath = join(skillDir, 'SKILL.md');\n\n if (!existsSync(skillMdPath)) continue;\n\n try {\n const content = readFileSync(skillMdPath, 'utf-8');\n const meta = parseSkillMd(content, entry.name);\n if (meta) {\n discovered.push({ ...meta, source: 'workspace', enabled: true });\n }\n } catch (error) {\n logger.warn(COMPONENT, `Failed to load skill ${entry.name}: ${(error as Error).message}`);\n }\n }\n\n logger.info(COMPONENT, `Discovered ${discovered.length} workspace skills`);\n return discovered;\n}\n\n/** Parse SKILL.md frontmatter to extract metadata */\nfunction parseSkillMd(content: string, fallbackName: string): Omit<SkillMeta, 'source' | 'enabled'> | null {\n const frontmatterMatch = content.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (!frontmatterMatch) {\n return {\n name: fallbackName,\n description: content.split('\\n')[0] || 'No description',\n version: '1.0.0',\n };\n }\n\n const frontmatter = frontmatterMatch[1];\n const name = frontmatter.match(/name:\\s*(.+)/)?.[1]?.trim() || fallbackName;\n const description = frontmatter.match(/description:\\s*(.+)/)?.[1]?.trim() || 'No description';\n const version = frontmatter.match(/version:\\s*(.+)/)?.[1]?.trim() || '1.0.0';\n const author = frontmatter.match(/author:\\s*(.+)/)?.[1]?.trim();\n\n return { name, description, version, author };\n}\n\n/** Initialize all built-in skills */\nexport async function initBuiltinSkills(): Promise<void> {\n logger.info(COMPONENT, 'Loading built-in skills...');\n\n // Import and register built-in skills\n const { registerShellSkill } = await import('./builtin/shell.js');\n const { registerFilesystemSkill } = await import('./builtin/filesystem.js');\n const { registerWebSearchSkill } = await import('./builtin/web_search.js');\n const { registerCronSkill } = await import('./builtin/cron.js');\n const { registerWebhookSkill } = await import('./builtin/webhook.js');\n const { registerMemorySkill } = await import('./builtin/memory_skill.js');\n const { registerBrowserSkill } = await import('./builtin/browser.js');\n const { registerSessionsSkill } = await import('./builtin/sessions.js');\n const { registerProcessSkill } = await import('./builtin/process.js');\n const { registerWebFetchSkill } = await import('./builtin/web_fetch.js');\n const { registerApplyPatchSkill } = await import('./builtin/apply_patch.js');\n const { registerAutoGenerateSkill } = await import('./builtin/auto_generate.js');\n const { registerVisionSkill } = await import('./builtin/vision.js');\n const { registerVoiceSkills } = await import('./builtin/voice.js');\n const { registerMemoryGraphSkill } = await import('./builtin/memory_graph.js');\n const { initWebBrowserTool } = await import('./builtin/web_browser.js');\n const { registerGitHubSkill } = await import('./builtin/github.js');\n const { registerEmailSkill } = await import('./builtin/email.js');\n const { registerComputerUseSkill } = await import('./builtin/computer_use.js');\n const { registerImageGenSkill } = await import('./builtin/image_gen.js');\n const { registerPdfSkill } = await import('./builtin/pdf.js');\n const { registerCalendarSkill } = await import('./builtin/calendar.js');\n const { registerSmartHomeSkill } = await import('./builtin/smart_home.js');\n const { registerDataAnalysisSkill } = await import('./builtin/data_analysis.js');\n const { registerSkyvernSkill } = await import('./builtin/skyvern.js');\n const { registerWebBrowseLlmSkill } = await import('./builtin/web_browse_llm.js');\n const { registerIncomeTrackerSkill } = await import('./builtin/income_tracker.js');\n const { registerFreelanceMonitorSkill } = await import('./builtin/freelance_monitor.js');\n const { registerContentPublisherSkill } = await import('./builtin/content_publisher.js');\n const { registerLeadScorerSkill } = await import('./builtin/lead_scorer.js');\n const { registerHunterSkill } = await import('./builtin/hunter.js');\n const { registerCodeExecSkill } = await import('./builtin/code_exec.js');\n const { registerExecuteCodeSkill } = await import('./builtin/executeCode.js');\n const { registerWeatherSkill } = await import('./builtin/weather.js');\n const { registerGoalsSkill } = await import('./builtin/goals.js');\n const { registerXPosterSkill } = await import('./builtin/x_poster.js');\n const { initModelSwitchTool } = await import('./builtin/model_switch.js');\n const { registerRagSkill } = await import('./builtin/rag.js');\n const { registerDeepResearchSkill } = await import('./builtin/deep_research.js');\n const { registerSystemInfoSkill } = await import('./builtin/system_info.js');\n const { registerPersonaManagerSkill } = await import('./builtin/persona_manager.js');\n const { registerResearchPipelineSkill } = await import('./builtin/research_pipeline.js');\n const { registerAutoresearchSkill } = await import('./builtin/autoresearch.js');\n const { registerSelfDoctorSkill } = await import('./builtin/self_doctor.js');\n const { registerInteractionTrackerSkill } = await import('./builtin/interaction_tracker.js');\n const { registerFeedbackTrackerSkill } = await import('./builtin/feedback_tracker.js');\n const { registerGrowthExperimentsSkill } = await import('./builtin/growth_experiments.js');\n const { registerContentCalendarSkill } = await import('./builtin/content_calendar.js');\n const { registerSlackSkill } = await import('./builtin/slack.js');\n const { registerRevenueCatKBSkill } = await import('./builtin/revenuecat_kb.js');\n const { registerWeeklyReportSkill } = await import('./builtin/weekly_report.js');\n const { registerSelfImproveSkill } = await import('./builtin/self_improve.js');\n const { registerGepaSkill } = await import('./builtin/gepa.js');\n const { registerModelTrainerSkill } = await import('./builtin/model_trainer.js');\n const { registerSocialSchedulerSkill } = await import('./builtin/social_scheduler.js');\n const { registerStructuredOutputSkill } = await import('./builtin/structured_output.js');\n const { registerWorkflowsSkill } = await import('./builtin/workflows.js');\n const { registerAgentHandoffSkill } = await import('./builtin/agent_handoff.js');\n const { registerKnowledgeBaseSkill } = await import('./builtin/knowledge_base.js');\n const { registerEventTriggersSkill } = await import('./builtin/event_triggers.js');\n const { registerA2AProtocolSkill } = await import('./builtin/a2a_protocol.js');\n const { registerEvalsSkill } = await import('./builtin/evals.js');\n const { registerApprovalGatesSkill } = await import('./builtin/approval_gates.js');\n const { registerVRAMSkills } = await import('./builtin/vram.js');\n const { registerSecurityScanSkill } = await import('./builtin/security_scan.js');\n const { registerChangelogGenSkill } = await import('./builtin/changelog_gen.js');\n const { registerJiraLinearSkill } = await import('./builtin/jira_linear.js');\n const { registerAuditTrailSkill } = await import('./builtin/audit_trail.js');\n const { registerVisualPlanSkill } = await import('./builtin/visual_plan.js');\n const { registerScreenRecordSkill } = await import('./builtin/screen_record.js');\n const { registerSessionTeleportSkill } = await import('./builtin/session_teleport.js');\n const { registerCrossProviderSkill } = await import('./builtin/cross_provider.js');\n const { registerSentrySkill } = await import('./builtin/sentry.js');\n const { registerVideoSkill } = await import('./builtin/video.js');\n const { registerMixtureOfAgentsSkill } = await import('./builtin/mixture_of_agents.js');\n const { registerAgentDebateSkill } = await import('./builtin/agent_debate.js');\n const { registerFileCheckpointsSkill } = await import('./builtin/file_checkpoints.js');\n const { registerVerifyPageSkill } = await import('./builtin/verify_page.js');\n const { registerAgentMessagingSkill } = await import('./builtin/agent_messaging.js');\n const { registerFacebookSkill } = await import('./builtin/facebook.js');\n const { registerFBAutopilotSkill } = await import('./builtin/fb_autopilot.js');\n const { registerWidgetGallerySkill } = await import('./builtin/widget_gallery.js');\n\n const config = loadConfig();\n const primitiveMode = config.skills.primitiveMode;\n\n if (primitiveMode) {\n logger.info(COMPONENT, 'PRIMITIVE MODE ENABLED — loading only shell, filesystem, web_search');\n }\n\n const registrations: [string, () => void][] = [\n ['shell', registerShellSkill],\n ['filesystem', registerFilesystemSkill],\n ['web_search', registerWebSearchSkill],\n ];\n\n if (!primitiveMode) {\n registrations.push(\n ['cron', registerCronSkill],\n ['webhook', registerWebhookSkill],\n ['memory', registerMemorySkill],\n ['browser', registerBrowserSkill],\n ['sessions', registerSessionsSkill],\n ['process', registerProcessSkill],\n ['web_fetch', registerWebFetchSkill],\n ['apply_patch', registerApplyPatchSkill],\n ['auto_generate', registerAutoGenerateSkill],\n ['vision', registerVisionSkill],\n ['voice', registerVoiceSkills],\n ['memory_graph', registerMemoryGraphSkill],\n ['web_browser', initWebBrowserTool],\n ['github', registerGitHubSkill],\n ['email', registerEmailSkill],\n ['computer_use', registerComputerUseSkill],\n ['image_gen', registerImageGenSkill],\n ['pdf', registerPdfSkill],\n ['calendar', registerCalendarSkill],\n ['smart_home', registerSmartHomeSkill],\n ['data_analysis', registerDataAnalysisSkill],\n ['skyvern', registerSkyvernSkill],\n ['web_browse_llm', registerWebBrowseLlmSkill],\n ['income_tracker', registerIncomeTrackerSkill],\n ['freelance_monitor', registerFreelanceMonitorSkill],\n ['content_publisher', registerContentPublisherSkill],\n ['lead_scorer', registerLeadScorerSkill],\n ['hunter', registerHunterSkill],\n ['code_exec', registerCodeExecSkill],\n ['execute_code', registerExecuteCodeSkill],\n ['weather', registerWeatherSkill],\n ['goals', registerGoalsSkill],\n ['x_poster', registerXPosterSkill],\n ['model_switch', initModelSwitchTool],\n ['rag', registerRagSkill],\n ['deep_research', registerDeepResearchSkill],\n ['system_info', registerSystemInfoSkill],\n ['persona_manager', registerPersonaManagerSkill],\n ['research_pipeline', registerResearchPipelineSkill],\n ['autoresearch', registerAutoresearchSkill],\n ['self_doctor', registerSelfDoctorSkill],\n ['interaction_tracker', registerInteractionTrackerSkill],\n ['feedback_tracker', registerFeedbackTrackerSkill],\n ['growth_experiments', registerGrowthExperimentsSkill],\n ['content_calendar', registerContentCalendarSkill],\n ['slack', registerSlackSkill],\n ['revenuecat_kb', registerRevenueCatKBSkill],\n ['weekly_report', registerWeeklyReportSkill],\n ['self_improve', registerSelfImproveSkill],\n ['gepa', registerGepaSkill],\n ['model_trainer', registerModelTrainerSkill],\n ['social_scheduler', registerSocialSchedulerSkill],\n ['structured_output', registerStructuredOutputSkill],\n ['workflows', registerWorkflowsSkill],\n ['agent_handoff', registerAgentHandoffSkill],\n ['knowledge_base', registerKnowledgeBaseSkill],\n ['event_triggers', registerEventTriggersSkill],\n ['evals', registerEvalsSkill],\n ['a2a_protocol', registerA2AProtocolSkill],\n ['approval_gates', registerApprovalGatesSkill],\n ['vram', registerVRAMSkills],\n ['security_scan', registerSecurityScanSkill],\n ['changelog_gen', registerChangelogGenSkill],\n ['jira_linear', registerJiraLinearSkill],\n ['audit_trail', registerAuditTrailSkill],\n ['visual_plan', registerVisualPlanSkill],\n ['screen_record', registerScreenRecordSkill],\n ['session_teleport', registerSessionTeleportSkill],\n ['cross_provider', registerCrossProviderSkill],\n ['sentry', registerSentrySkill],\n ['video', registerVideoSkill],\n ['mixture_of_agents', registerMixtureOfAgentsSkill],\n ['agent_debate', registerAgentDebateSkill],\n ['file_checkpoints', registerFileCheckpointsSkill],\n ['verify_page', registerVerifyPageSkill],\n ['agent_messaging', registerAgentMessagingSkill],\n ['facebook', registerFacebookSkill],\n ['fb_autopilot', registerFBAutopilotSkill],\n ['widget_gallery', registerWidgetGallerySkill],\n ['widget_gallery', registerWidgetGallerySkill],\n );\n }\n for (const [name, fn] of registrations) {\n try { fn(); } catch (e) { logger.warn(COMPONENT, `Failed to register skill \"${name}\": ${(e as Error).message}`); }\n }\n\n if (!primitiveMode) {\n // Register planner as an LLM-invocable tool\n const { registerPlannerTool } = await import('../agent/planner.js');\n try { registerPlannerTool(); } catch (e) { logger.warn(COMPONENT, `Failed to register planner: ${(e as Error).message}`); }\n\n // Register TopFacts context engine plugin (DeerFlow-inspired persistent memory)\n try {\n const { createTopFactsPlugin } = await import('../plugins/topFacts.js');\n const { createMemoryRetrievalPlugin } = await import('../plugins/memoryRetrieval.js');\n const { registerPlugin } = await import('../plugins/registry.js');\n const topFacts = createTopFactsPlugin();\n registerPlugin(topFacts);\n if (topFacts.bootstrap) await topFacts.bootstrap({});\n const memoryRetrieval = createMemoryRetrievalPlugin();\n registerPlugin(memoryRetrieval);\n if (memoryRetrieval.bootstrap) await memoryRetrieval.bootstrap({});\n } catch (e) { logger.warn(COMPONENT, `Failed to register TopFacts plugin: ${(e as Error).message}`); }\n\n // Register SmartCompress context engine plugin (task-type-aware compression)\n try {\n const { createSmartCompressPlugin } = await import('../plugins/smartCompress.js');\n const { registerPlugin: regPlugin } = await import('../plugins/registry.js');\n const smartCompress = createSmartCompressPlugin();\n regPlugin(smartCompress);\n if (smartCompress.bootstrap) await smartCompress.bootstrap({});\n } catch (e) { logger.warn(COMPONENT, `Failed to register SmartCompress plugin: ${(e as Error).message}`); }\n\n // Register tool_search + tool_expand — meta-tools for discovering tools on demand\n // tool_expand is the progressive disclosure extension (Hermes competitive gap fix)\n const { getToolSearchHandler, getToolExpandHandler } = await import('../agent/toolSearch.js');\n try { registerTool(getToolSearchHandler()); } catch (e) { logger.warn(COMPONENT, `Failed to register tool_search: ${(e as Error).message}`); }\n try { registerTool(getToolExpandHandler()); } catch (e) { logger.warn(COMPONENT, `Failed to register tool_expand: ${(e as Error).message}`); }\n\n // F3: Register procedural memory tools (Hermes-inspired skill learning)\n try {\n const { saveSkill, searchSkills } = await import('./proceduralMemory.js');\n registerTool({\n name: 'save_skill',\n description: 'Save a reusable approach/technique as a procedural skill for future tasks. Use this when you discover an effective approach that could help in similar future situations.',\n parameters: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'Short descriptive name for the skill (e.g., \"Deploy Node.js app to Docker\")' },\n tags: { type: 'array', items: { type: 'string' }, description: 'Tags for searchability (e.g., [\"docker\", \"deployment\", \"nodejs\"])' },\n content: { type: 'string', description: 'The reusable approach/technique in markdown format. Include key steps, commands, and gotchas.' },\n },\n required: ['name', 'tags', 'content'],\n },\n execute: async (args: Record<string, unknown>) => {\n const name = args.name as string;\n const tags = (args.tags as string[]) || [];\n const content = args.content as string;\n if (!name || !content) return 'Error: name and content are required';\n const skill = saveSkill(name, tags, content);\n return `Skill saved: \"${skill.name}\" (tags: ${skill.tags.join(', ')}). It will be auto-recalled in future tasks matching these tags.`;\n },\n });\n registerTool({\n name: 'recall_skill',\n description: 'Search for previously saved procedural skills by keyword or tag. Returns reusable approaches from past tasks.',\n parameters: {\n type: 'object',\n properties: {\n query: { type: 'string', description: 'Search query — keywords or tags to find relevant skills' },\n },\n required: ['query'],\n },\n execute: async (args: Record<string, unknown>) => {\n const query = args.query as string;\n if (!query) return 'Error: query is required';\n const results = searchSkills(query, 5);\n if (results.length === 0) return 'No matching skills found. Consider saving useful approaches with save_skill.';\n return results.map(s =>\n `### ${s.name}\\nTags: ${s.tags.join(', ')} | Used ${s.useCount}x\\n${s.content.slice(0, 800)}`\n ).join('\\n\\n---\\n\\n');\n },\n });\n logger.info(COMPONENT, 'Registered procedural memory tools (save_skill, recall_skill)');\n } catch (e) { logger.warn(COMPONENT, `Failed to register procedural memory tools: ${(e as Error).message}`); }\n }\n\n logger.info(COMPONENT, `Loaded ${registeredSkills.size} built-in skills`);\n\n // Load dev skills (only in dev mode — skip import entirely in production)\n if (process.env.NODE_ENV !== 'production' || process.env.TITAN_DEV) {\n const { initDevSkills } = await import('./dev/loader.js');\n await initDevSkills();\n }\n\n // Load NVIDIA skills (optional — only when TITAN_NVIDIA=1 or nvidia.enabled in config)\n try {\n let nvidiaEnabled = process.env.TITAN_NVIDIA === '1';\n if (!nvidiaEnabled) {\n try {\n const { loadConfig: _loadConfig } = await import('../config/config.js');\n const cfg = _loadConfig() as Record<string, unknown>;\n const nvCfg = cfg.nvidia as Record<string, unknown> | undefined;\n nvidiaEnabled = nvCfg?.enabled === true;\n } catch { /* config not available in test env */ }\n }\n if (nvidiaEnabled) {\n const { initNvidiaSkills } = await import('./nvidia/loader.js');\n await initNvidiaSkills();\n }\n } catch (err) {\n logger.warn(COMPONENT, `NVIDIA skills failed to load: ${(err as Error).message}`);\n }\n\n // Load personal skills (private, gitignored — only when TITAN_PERSONAL=1)\n // Primary location: dist/skills/personal/loader.js (co-located with dist/skills/registry.js\n // so `../registry` resolves to the SAME module instance — tools register into the correct registry)\n // Fallback: ~/.titan/personal/loader.js (legacy / TITAN_PERSONAL_DIR override)\n if (process.env.TITAN_PERSONAL === '1') {\n try {\n const { pathToFileURL, fileURLToPath } = await import('node:url');\n const { join: _join, dirname: _dirname } = await import('node:path');\n // Compute dist/skills/ dir from this file's location (works on any machine)\n const thisDir = _dirname(fileURLToPath(import.meta.url));\n const distPersonalDir = _join(thisDir, 'personal');\n // TITAN_PERSONAL_DIR env var overrides; otherwise try dist-local first, then ~/.titan/personal/\n const personalDir = process.env.TITAN_PERSONAL_DIR\n || (existsSync(_join(distPersonalDir, 'loader.js')) ? distPersonalDir : _join(TITAN_HOME, 'personal'));\n const loaderPath = _join(personalDir, 'loader.js');\n if (existsSync(loaderPath)) {\n // Inject the main app's registerSkill into a global so the personal bundle\n // (which has its own bundled copy) uses the correct shared toolRegistry instance.\n (globalThis as Record<string, unknown>).__titanRegisterSkill = registerSkill;\n const { initPersonalSkills } = await import(pathToFileURL(loaderPath).href) as { initPersonalSkills: () => Promise<void> };\n await initPersonalSkills();\n } else {\n logger.warn(COMPONENT, `TITAN_PERSONAL=1 but ${loaderPath} not found — run: npm run build:personal`);\n }\n } catch (err) {\n logger.warn(COMPONENT, `Personal skills failed to load: ${(err as Error).message}`);\n }\n }\n}\n\n/**\n * Discover and load user skills from ~/.titan/skills/ (all subdirs).\n * Supports:\n * 1. JavaScript files (.js) that export default { name, description, parameters, execute }\n * 2. YAML skill definitions (.yaml/.yml) with inline scripts\n * 3. Auto-generated skills from ~/.titan/skills/auto/\n */\nexport async function loadAutoSkills(): Promise<void> {\n const skillsRoot = join(TITAN_HOME, 'skills');\n if (!existsSync(skillsRoot)) return;\n\n logger.info(COMPONENT, 'Scanning for user skills...');\n let loadedCount = 0;\n\n // Scan both root and all subdirectories\n const dirsToScan = [skillsRoot];\n const entries = readdirSync(skillsRoot, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory()) dirsToScan.push(join(skillsRoot, entry.name));\n }\n\n for (const dir of dirsToScan) {\n const files = readdirSync(dir).filter(f =>\n f.endsWith('.js') || f.endsWith('.yaml') || f.endsWith('.yml')\n );\n\n for (const file of files) {\n const filePath = join(dir, file);\n try {\n if (file.endsWith('.js')) {\n // JavaScript skill — export default { name, description, parameters, execute }\n const modulePath = `file://${filePath}?t=${Date.now()}`;\n const mod = await import(modulePath);\n if (mod.default && mod.default.name && mod.default.execute) {\n const handler = mod.default as ToolHandler;\n if (registeredSkills.has(handler.name)) continue; // Skip duplicates\n registerSkill({\n name: handler.name,\n description: handler.description || 'User skill',\n version: '1.0.0',\n source: 'workspace',\n enabled: true,\n }, handler);\n loadedCount++;\n }\n } else {\n // YAML skill definition\n const loaded = loadYamlSkill(filePath);\n if (loaded && !registeredSkills.has(loaded.name)) {\n registerSkill({\n name: loaded.name,\n description: loaded.description,\n version: '1.0.0',\n source: 'workspace',\n enabled: true,\n }, loaded);\n loadedCount++;\n }\n }\n } catch (e: unknown) {\n logger.warn(COMPONENT, `Failed to load skill ${file}: ${(e as Error).message}`);\n }\n }\n }\n\n if (loadedCount > 0) {\n logger.info(COMPONENT, `Loaded ${loadedCount} user skill(s) from ~/.titan/skills/`);\n }\n\n // Load frontmatter skills (*.skill.md) — Space Agent / Hermes parity\n try {\n const { getFrontmatterToolHandlers } = await import('./frontmatterLoader.js');\n const fmHandlers = getFrontmatterToolHandlers();\n for (const { name, handler } of fmHandlers) {\n if (registeredSkills.has(name)) continue;\n registerSkill({\n name: handler.name,\n description: handler.description,\n version: '1.0.0',\n source: 'frontmatter',\n enabled: true,\n }, handler);\n loadedCount++;\n }\n if (fmHandlers.length > 0) {\n logger.info(COMPONENT, `Loaded ${fmHandlers.length} frontmatter skill(s)`);\n }\n } catch (e) {\n logger.warn(COMPONENT, `Frontmatter skills failed to load: ${(e as Error).message}`);\n }\n}\n\n/**\n * Load a YAML skill definition.\n * Format:\n * name: my_tool\n * description: What it does\n * parameters:\n * myParam:\n * type: string\n * description: A parameter\n * required: true\n * script: |\n * // JavaScript code. Use `args.myParam` for inputs.\n * // Return a string result.\n * return \"Hello \" + args.myParam;\n */\nfunction loadYamlSkill(filePath: string): ToolHandler | null {\n const content = readFileSync(filePath, 'utf-8');\n\n // Simple YAML parser (no dependency needed for this basic format)\n const name = content.match(/^name:\\s*(.+)$/m)?.[1]?.trim();\n const description = content.match(/^description:\\s*(.+)$/m)?.[1]?.trim();\n const scriptMatch = content.match(/^script:\\s*\\|\\n([\\s\\S]+?)(?=\\n\\w|\\n$|$)/m);\n const script = scriptMatch?.[1]?.replace(/^ {2}/gm, ''); // Remove YAML indent\n\n if (!name || !description || !script) {\n logger.debug(COMPONENT, `Skipping ${filePath}: missing name, description, or script`);\n return null;\n }\n\n // Parse parameters section\n const paramsSection = content.match(/^parameters:\\n((?:\\s{2}\\w[\\s\\S]*?)(?=\\nscript:|\\n\\w|\\n$))/m);\n const properties: Record<string, Record<string, unknown>> = {};\n const required: string[] = [];\n\n if (paramsSection) {\n const paramLines = paramsSection[1].split('\\n');\n let currentParam = '';\n for (const line of paramLines) {\n const paramMatch = line.match(/^\\s{2}(\\w+):\\s*$/);\n if (paramMatch) {\n currentParam = paramMatch[1];\n properties[currentParam] = {};\n continue;\n }\n if (currentParam) {\n const typeMatch = line.match(/^\\s{4}type:\\s*(.+)$/);\n const descMatch = line.match(/^\\s{4}description:\\s*(.+)$/);\n const reqMatch = line.match(/^\\s{4}required:\\s*true$/);\n const defMatch = line.match(/^\\s{4}default:\\s*(.+)$/);\n if (typeMatch) properties[currentParam].type = typeMatch[1].trim();\n if (descMatch) properties[currentParam].description = descMatch[1].trim();\n if (reqMatch) required.push(currentParam);\n if (defMatch) properties[currentParam].default = defMatch[1].trim();\n }\n }\n }\n\n // Create the execute function from the script\n const handler: ToolHandler = {\n name,\n description,\n parameters: {\n type: 'object',\n properties,\n required: required.length > 0 ? required : undefined,\n },\n execute: async (args: Record<string, unknown>) => {\n try {\n // Run in a restricted VM context — no access to globalThis, process, eval, or Function\n const safeRequire = (mod: string) => {\n // SECURITY: child_process, http, https removed — YAML skills must use builtin tools for shell/network\n const allowed = ['fs', 'path', 'os', 'crypto', 'url', 'util'];\n if (!allowed.includes(mod)) throw new Error(`Module \"${mod}\" not allowed in YAML skills`);\n return require(mod); // eslint-disable-line @typescript-eslint/no-require-imports\n };\n const sandbox: Record<string, unknown> = {\n args,\n require: safeRequire,\n console: { log: console.log },\n JSON,\n Math,\n Date,\n String,\n Number,\n Array,\n Object,\n RegExp,\n Map,\n Set,\n Promise,\n setTimeout,\n Buffer,\n };\n // Wrap the user script in an async IIFE so `return` works and we can await it\n const wrapped = `(async function() { ${script} })()`;\n const result = await vm.runInNewContext(wrapped, sandbox, { timeout: 10000 });\n return typeof result === 'string' ? result : JSON.stringify(result, null, 2);\n } catch (err) {\n return `Error: ${(err as Error).message}`;\n }\n },\n };\n\n logger.debug(COMPONENT, `Loaded YAML skill: ${name} from ${filePath}`);\n return handler;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/skills/registry.ts"],"sourcesContent":["/**\n * TITAN — Skills Registry\n * Discovers, loads, and manages skills from bundled, workspace, and marketplace sources.\n */\nimport { existsSync, readdirSync, readFileSync, writeFileSync, mkdirSync } from 'fs';\nimport { join, dirname } from 'path';\nimport vm from 'vm';\nimport { TITAN_HOME, TITAN_SKILLS_DIR } from '../utils/constants.js';\nimport { registerTool, type ToolHandler } from '../agent/toolRunner.js';\nimport { mkdirIfNotExists } from '../utils/helpers.js';\nimport logger from '../utils/logger.js';\nimport { loadConfig } from '../config/config.js';\n\nconst COMPONENT = 'Skills';\nconst DISABLED_SKILLS_PATH = join(TITAN_HOME, 'disabled-skills.json');\n\nexport interface SkillMeta {\n name: string;\n description: string;\n version: string;\n author?: string;\n source: 'bundled' | 'workspace' | 'marketplace' | 'frontmatter';\n enabled: boolean;\n}\n\nconst registeredSkills: Map<string, SkillMeta> = new Map();\n\n/** Maps skill name → tool names belonging to that skill */\nconst skillToolMap: Map<string, Set<string>> = new Map();\n\n/** Register a built-in skill (tool handler + metadata) */\nexport function registerSkill(meta: SkillMeta, handler: ToolHandler): void {\n registeredSkills.set(meta.name, meta);\n // Track which tools belong to this skill\n if (!skillToolMap.has(meta.name)) {\n skillToolMap.set(meta.name, new Set());\n }\n skillToolMap.get(meta.name)!.add(handler.name);\n registerTool(handler);\n logger.debug(COMPONENT, `Registered skill: ${meta.name} (${meta.source})`);\n}\n\n/** Get all registered skills (with persisted enabled/disabled state applied) */\nexport function getSkills(): SkillMeta[] {\n const disabled = loadDisabledSkills();\n return Array.from(registeredSkills.values()).map(s => ({\n ...s,\n enabled: !disabled.includes(s.name),\n }));\n}\n\n/** Get a skill by name */\nexport function getSkill(name: string): SkillMeta | undefined {\n return registeredSkills.get(name);\n}\n\n/** Get tool names belonging to a skill */\nexport function getSkillTools(skillName: string): string[] {\n return Array.from(skillToolMap.get(skillName) || []);\n}\n\n/** Check if a skill is enabled */\nexport function isSkillEnabled(skillName: string): boolean {\n return !loadDisabledSkills().includes(skillName);\n}\n\n/** Check if a specific tool's parent skill is enabled */\nexport function isToolSkillEnabled(toolName: string): boolean {\n for (const [skillName, tools] of skillToolMap.entries()) {\n if (tools.has(toolName)) {\n return isSkillEnabled(skillName);\n }\n }\n return true; // Tools not belonging to any skill are always enabled\n}\n\n/** Toggle a skill on/off. Returns the new enabled state. */\nexport function toggleSkill(skillName: string): boolean {\n const skill = registeredSkills.get(skillName);\n if (!skill) {\n throw new Error(`Skill \"${skillName}\" not found`);\n }\n\n const disabled = loadDisabledSkills();\n const idx = disabled.indexOf(skillName);\n let nowEnabled: boolean;\n\n if (idx >= 0) {\n disabled.splice(idx, 1);\n nowEnabled = true;\n } else {\n disabled.push(skillName);\n nowEnabled = false;\n }\n\n saveDisabledSkills(disabled);\n logger.info(COMPONENT, `Skill \"${skillName}\" ${nowEnabled ? 'enabled' : 'disabled'}`);\n return nowEnabled;\n}\n\n/** Set a skill's enabled state explicitly */\nexport function setSkillEnabled(skillName: string, enabled: boolean): void {\n const skill = registeredSkills.get(skillName);\n if (!skill) {\n throw new Error(`Skill \"${skillName}\" not found`);\n }\n\n const disabled = loadDisabledSkills();\n const idx = disabled.indexOf(skillName);\n\n if (enabled && idx >= 0) {\n disabled.splice(idx, 1);\n } else if (!enabled && idx < 0) {\n disabled.push(skillName);\n }\n\n saveDisabledSkills(disabled);\n}\n\n// ── Disabled-skills disk cache (30s TTL) ─────────────────────────\nlet _disabledSkillsCache: string[] | null = null;\nlet _disabledSkillsCacheAt = 0;\nconst DISABLED_SKILLS_CACHE_TTL_MS = 30_000;\n\n/** Load disabled skills list from disk (cached for 30 s to avoid ~7 k reads/req) */\nfunction loadDisabledSkills(): string[] {\n const now = Date.now();\n if (_disabledSkillsCache !== null && now - _disabledSkillsCacheAt < DISABLED_SKILLS_CACHE_TTL_MS) {\n return _disabledSkillsCache;\n }\n let result: string[] = [];\n try {\n if (existsSync(DISABLED_SKILLS_PATH)) {\n result = JSON.parse(readFileSync(DISABLED_SKILLS_PATH, 'utf-8')) as string[];\n }\n } catch {\n // Corrupt file — treat as empty\n }\n _disabledSkillsCache = result;\n _disabledSkillsCacheAt = now;\n return result;\n}\n\n/** Save disabled skills list to disk and invalidate the in-memory cache */\nfunction saveDisabledSkills(disabled: string[]): void {\n _disabledSkillsCache = null; // Invalidate cache on write\n try {\n const dir = dirname(DISABLED_SKILLS_PATH);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(DISABLED_SKILLS_PATH, JSON.stringify(disabled, null, 2), 'utf-8');\n } catch (e) {\n logger.warn(COMPONENT, `Failed to save disabled skills: ${(e as Error).message}`);\n }\n}\n\n/** Discover workspace skills from ~/.titan/workspace/skills/ */\nexport function discoverWorkspaceSkills(): SkillMeta[] {\n mkdirIfNotExists(TITAN_SKILLS_DIR);\n const discovered: SkillMeta[] = [];\n\n if (!existsSync(TITAN_SKILLS_DIR)) return discovered;\n\n const entries = readdirSync(TITAN_SKILLS_DIR, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n const skillDir = join(TITAN_SKILLS_DIR, entry.name);\n const skillMdPath = join(skillDir, 'SKILL.md');\n\n if (!existsSync(skillMdPath)) continue;\n\n try {\n const content = readFileSync(skillMdPath, 'utf-8');\n const meta = parseSkillMd(content, entry.name);\n if (meta) {\n discovered.push({ ...meta, source: 'workspace', enabled: true });\n }\n } catch (error) {\n logger.warn(COMPONENT, `Failed to load skill ${entry.name}: ${(error as Error).message}`);\n }\n }\n\n logger.info(COMPONENT, `Discovered ${discovered.length} workspace skills`);\n return discovered;\n}\n\n/** Parse SKILL.md frontmatter to extract metadata */\nfunction parseSkillMd(content: string, fallbackName: string): Omit<SkillMeta, 'source' | 'enabled'> | null {\n const frontmatterMatch = content.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (!frontmatterMatch) {\n return {\n name: fallbackName,\n description: content.split('\\n')[0] || 'No description',\n version: '1.0.0',\n };\n }\n\n const frontmatter = frontmatterMatch[1];\n const name = frontmatter.match(/name:\\s*(.+)/)?.[1]?.trim() || fallbackName;\n const description = frontmatter.match(/description:\\s*(.+)/)?.[1]?.trim() || 'No description';\n const version = frontmatter.match(/version:\\s*(.+)/)?.[1]?.trim() || '1.0.0';\n const author = frontmatter.match(/author:\\s*(.+)/)?.[1]?.trim();\n\n return { name, description, version, author };\n}\n\n/** Initialize all built-in skills */\nexport async function initBuiltinSkills(): Promise<void> {\n logger.info(COMPONENT, 'Loading built-in skills...');\n\n // Import and register built-in skills\n const { registerShellSkill } = await import('./builtin/shell.js');\n const { registerFilesystemSkill } = await import('./builtin/filesystem.js');\n const { registerWebSearchSkill } = await import('./builtin/web_search.js');\n const { registerCronSkill } = await import('./builtin/cron.js');\n const { registerWebhookSkill } = await import('./builtin/webhook.js');\n const { registerMemorySkill } = await import('./builtin/memory_skill.js');\n const { registerBrowserSkill } = await import('./builtin/browser.js');\n const { registerSessionsSkill } = await import('./builtin/sessions.js');\n const { registerProcessSkill } = await import('./builtin/process.js');\n const { registerWebFetchSkill } = await import('./builtin/web_fetch.js');\n const { registerApplyPatchSkill } = await import('./builtin/apply_patch.js');\n const { registerAutoGenerateSkill } = await import('./builtin/auto_generate.js');\n const { registerVisionSkill } = await import('./builtin/vision.js');\n const { registerVoiceSkills } = await import('./builtin/voice.js');\n const { registerMemoryGraphSkill } = await import('./builtin/memory_graph.js');\n const { initWebBrowserTool } = await import('./builtin/web_browser.js');\n const { registerGitHubSkill } = await import('./builtin/github.js');\n const { registerEmailSkill } = await import('./builtin/email.js');\n const { registerComputerUseSkill } = await import('./builtin/computer_use.js');\n const { registerImageGenSkill } = await import('./builtin/image_gen.js');\n const { registerPdfSkill } = await import('./builtin/pdf.js');\n const { registerCalendarSkill } = await import('./builtin/calendar.js');\n const { registerSmartHomeSkill } = await import('./builtin/smart_home.js');\n const { registerDataAnalysisSkill } = await import('./builtin/data_analysis.js');\n const { registerSkyvernSkill } = await import('./builtin/skyvern.js');\n const { registerWebBrowseLlmSkill } = await import('./builtin/web_browse_llm.js');\n const { registerIncomeTrackerSkill } = await import('./builtin/income_tracker.js');\n const { registerFreelanceMonitorSkill } = await import('./builtin/freelance_monitor.js');\n const { registerContentPublisherSkill } = await import('./builtin/content_publisher.js');\n const { registerLeadScorerSkill } = await import('./builtin/lead_scorer.js');\n const { registerHunterSkill } = await import('./builtin/hunter.js');\n const { registerCodeExecSkill } = await import('./builtin/code_exec.js');\n const { registerExecuteCodeSkill } = await import('./builtin/executeCode.js');\n const { registerWeatherSkill } = await import('./builtin/weather.js');\n const { registerGoalsSkill } = await import('./builtin/goals.js');\n const { registerXPosterSkill } = await import('./builtin/x_poster.js');\n const { initModelSwitchTool } = await import('./builtin/model_switch.js');\n const { registerRagSkill } = await import('./builtin/rag.js');\n const { registerDeepResearchSkill } = await import('./builtin/deep_research.js');\n const { registerSystemInfoSkill } = await import('./builtin/system_info.js');\n const { registerPersonaManagerSkill } = await import('./builtin/persona_manager.js');\n const { registerResearchPipelineSkill } = await import('./builtin/research_pipeline.js');\n const { registerAutoresearchSkill } = await import('./builtin/autoresearch.js');\n const { registerSelfDoctorSkill } = await import('./builtin/self_doctor.js');\n const { registerInteractionTrackerSkill } = await import('./builtin/interaction_tracker.js');\n const { registerFeedbackTrackerSkill } = await import('./builtin/feedback_tracker.js');\n const { registerGrowthExperimentsSkill } = await import('./builtin/growth_experiments.js');\n const { registerContentCalendarSkill } = await import('./builtin/content_calendar.js');\n const { registerSlackSkill } = await import('./builtin/slack.js');\n const { registerRevenueCatKBSkill } = await import('./builtin/revenuecat_kb.js');\n const { registerWeeklyReportSkill } = await import('./builtin/weekly_report.js');\n const { registerSelfImproveSkill } = await import('./builtin/self_improve.js');\n const { registerGepaSkill } = await import('./builtin/gepa.js');\n const { registerModelTrainerSkill } = await import('./builtin/model_trainer.js');\n const { registerSocialSchedulerSkill } = await import('./builtin/social_scheduler.js');\n const { registerStructuredOutputSkill } = await import('./builtin/structured_output.js');\n const { registerWorkflowsSkill } = await import('./builtin/workflows.js');\n const { registerAgentHandoffSkill } = await import('./builtin/agent_handoff.js');\n const { registerKnowledgeBaseSkill } = await import('./builtin/knowledge_base.js');\n const { registerEventTriggersSkill } = await import('./builtin/event_triggers.js');\n const { registerA2AProtocolSkill } = await import('./builtin/a2a_protocol.js');\n const { registerEvalsSkill } = await import('./builtin/evals.js');\n const { registerApprovalGatesSkill } = await import('./builtin/approval_gates.js');\n const { registerVRAMSkills } = await import('./builtin/vram.js');\n const { registerSecurityScanSkill } = await import('./builtin/security_scan.js');\n const { registerChangelogGenSkill } = await import('./builtin/changelog_gen.js');\n const { registerJiraLinearSkill } = await import('./builtin/jira_linear.js');\n const { registerAuditTrailSkill } = await import('./builtin/audit_trail.js');\n const { registerVisualPlanSkill } = await import('./builtin/visual_plan.js');\n const { registerScreenRecordSkill } = await import('./builtin/screen_record.js');\n const { registerSessionTeleportSkill } = await import('./builtin/session_teleport.js');\n const { registerCrossProviderSkill } = await import('./builtin/cross_provider.js');\n const { registerSentrySkill } = await import('./builtin/sentry.js');\n const { registerVideoSkill } = await import('./builtin/video.js');\n const { registerMixtureOfAgentsSkill } = await import('./builtin/mixture_of_agents.js');\n const { registerAgentDebateSkill } = await import('./builtin/agent_debate.js');\n const { registerFileCheckpointsSkill } = await import('./builtin/file_checkpoints.js');\n const { registerVerifyPageSkill } = await import('./builtin/verify_page.js');\n const { registerAgentMessagingSkill } = await import('./builtin/agent_messaging.js');\n const { registerFacebookSkill } = await import('./builtin/facebook.js');\n const { registerFBAutopilotSkill } = await import('./builtin/fb_autopilot.js');\n const { registerWidgetGallerySkill } = await import('./builtin/widget_gallery.js');\n\n const config = loadConfig();\n const primitiveMode = config.skills.primitiveMode;\n\n if (primitiveMode) {\n logger.info(COMPONENT, 'PRIMITIVE MODE ENABLED — loading only shell, filesystem, web_search');\n }\n\n const registrations: [string, () => void][] = [\n ['shell', registerShellSkill],\n ['filesystem', registerFilesystemSkill],\n ['web_search', registerWebSearchSkill],\n ];\n\n if (!primitiveMode) {\n registrations.push(\n ['cron', registerCronSkill],\n ['webhook', registerWebhookSkill],\n ['memory', registerMemorySkill],\n ['browser', registerBrowserSkill],\n ['sessions', registerSessionsSkill],\n ['process', registerProcessSkill],\n ['web_fetch', registerWebFetchSkill],\n ['apply_patch', registerApplyPatchSkill],\n ['auto_generate', registerAutoGenerateSkill],\n ['vision', registerVisionSkill],\n ['voice', registerVoiceSkills],\n ['memory_graph', registerMemoryGraphSkill],\n ['web_browser', initWebBrowserTool],\n ['github', registerGitHubSkill],\n ['email', registerEmailSkill],\n ['computer_use', registerComputerUseSkill],\n ['image_gen', registerImageGenSkill],\n ['pdf', registerPdfSkill],\n ['calendar', registerCalendarSkill],\n ['smart_home', registerSmartHomeSkill],\n ['data_analysis', registerDataAnalysisSkill],\n ['skyvern', registerSkyvernSkill],\n ['web_browse_llm', registerWebBrowseLlmSkill],\n ['income_tracker', registerIncomeTrackerSkill],\n ['freelance_monitor', registerFreelanceMonitorSkill],\n ['content_publisher', registerContentPublisherSkill],\n ['lead_scorer', registerLeadScorerSkill],\n ['hunter', registerHunterSkill],\n ['code_exec', registerCodeExecSkill],\n ['execute_code', registerExecuteCodeSkill],\n ['weather', registerWeatherSkill],\n ['goals', registerGoalsSkill],\n ['x_poster', registerXPosterSkill],\n ['model_switch', initModelSwitchTool],\n ['rag', registerRagSkill],\n ['deep_research', registerDeepResearchSkill],\n ['system_info', registerSystemInfoSkill],\n ['persona_manager', registerPersonaManagerSkill],\n ['research_pipeline', registerResearchPipelineSkill],\n ['autoresearch', registerAutoresearchSkill],\n ['self_doctor', registerSelfDoctorSkill],\n ['interaction_tracker', registerInteractionTrackerSkill],\n ['feedback_tracker', registerFeedbackTrackerSkill],\n ['growth_experiments', registerGrowthExperimentsSkill],\n ['content_calendar', registerContentCalendarSkill],\n ['slack', registerSlackSkill],\n ['revenuecat_kb', registerRevenueCatKBSkill],\n ['weekly_report', registerWeeklyReportSkill],\n ['self_improve', registerSelfImproveSkill],\n ['gepa', registerGepaSkill],\n ['model_trainer', registerModelTrainerSkill],\n ['social_scheduler', registerSocialSchedulerSkill],\n ['structured_output', registerStructuredOutputSkill],\n ['workflows', registerWorkflowsSkill],\n ['agent_handoff', registerAgentHandoffSkill],\n ['knowledge_base', registerKnowledgeBaseSkill],\n ['event_triggers', registerEventTriggersSkill],\n ['evals', registerEvalsSkill],\n ['a2a_protocol', registerA2AProtocolSkill],\n ['approval_gates', registerApprovalGatesSkill],\n ['vram', registerVRAMSkills],\n ['security_scan', registerSecurityScanSkill],\n ['changelog_gen', registerChangelogGenSkill],\n ['jira_linear', registerJiraLinearSkill],\n ['audit_trail', registerAuditTrailSkill],\n ['visual_plan', registerVisualPlanSkill],\n ['screen_record', registerScreenRecordSkill],\n ['session_teleport', registerSessionTeleportSkill],\n ['cross_provider', registerCrossProviderSkill],\n ['sentry', registerSentrySkill],\n ['video', registerVideoSkill],\n ['mixture_of_agents', registerMixtureOfAgentsSkill],\n ['agent_debate', registerAgentDebateSkill],\n ['file_checkpoints', registerFileCheckpointsSkill],\n ['verify_page', registerVerifyPageSkill],\n ['agent_messaging', registerAgentMessagingSkill],\n ['facebook', registerFacebookSkill],\n ['fb_autopilot', registerFBAutopilotSkill],\n ['widget_gallery', registerWidgetGallerySkill],\n ['widget_gallery', registerWidgetGallerySkill],\n );\n }\n for (const [name, fn] of registrations) {\n try { fn(); } catch (e) { logger.warn(COMPONENT, `Failed to register skill \"${name}\": ${(e as Error).message}`); }\n }\n\n if (!primitiveMode) {\n // Register planner as an LLM-invocable tool\n const { registerPlannerTool } = await import('../agent/planner.js');\n try { registerPlannerTool(); } catch (e) { logger.warn(COMPONENT, `Failed to register planner: ${(e as Error).message}`); }\n\n // Register TopFacts context engine plugin (DeerFlow-inspired persistent memory)\n try {\n const { createTopFactsPlugin } = await import('../plugins/topFacts.js');\n const { createMemoryRetrievalPlugin } = await import('../plugins/memoryRetrieval.js');\n const { registerPlugin } = await import('../plugins/registry.js');\n const topFacts = createTopFactsPlugin();\n registerPlugin(topFacts);\n if (topFacts.bootstrap) await topFacts.bootstrap({});\n const memoryRetrieval = createMemoryRetrievalPlugin();\n registerPlugin(memoryRetrieval);\n if (memoryRetrieval.bootstrap) await memoryRetrieval.bootstrap({});\n } catch (e) { logger.warn(COMPONENT, `Failed to register TopFacts plugin: ${(e as Error).message}`); }\n\n // Register SmartCompress context engine plugin (task-type-aware compression)\n try {\n const { createSmartCompressPlugin } = await import('../plugins/smartCompress.js');\n const { registerPlugin: regPlugin } = await import('../plugins/registry.js');\n const smartCompress = createSmartCompressPlugin();\n regPlugin(smartCompress);\n if (smartCompress.bootstrap) await smartCompress.bootstrap({});\n } catch (e) { logger.warn(COMPONENT, `Failed to register SmartCompress plugin: ${(e as Error).message}`); }\n\n // Register tool_search + tool_expand — meta-tools for discovering tools on demand\n // tool_expand is the progressive disclosure extension (Hermes competitive gap fix)\n const { getToolSearchHandler, getToolExpandHandler } = await import('../agent/toolSearch.js');\n try { registerTool(getToolSearchHandler()); } catch (e) { logger.warn(COMPONENT, `Failed to register tool_search: ${(e as Error).message}`); }\n try { registerTool(getToolExpandHandler()); } catch (e) { logger.warn(COMPONENT, `Failed to register tool_expand: ${(e as Error).message}`); }\n\n // F3: Register procedural memory tools (Hermes-inspired skill learning)\n try {\n const { saveSkill, searchSkills } = await import('./proceduralMemory.js');\n registerTool({\n name: 'save_skill',\n description: 'Save a reusable approach/technique as a procedural skill for future tasks. Use this when you discover an effective approach that could help in similar future situations.',\n parameters: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'Short descriptive name for the skill (e.g., \"Deploy Node.js app to Docker\")' },\n tags: { type: 'array', items: { type: 'string' }, description: 'Tags for searchability (e.g., [\"docker\", \"deployment\", \"nodejs\"])' },\n content: { type: 'string', description: 'The reusable approach/technique in markdown format. Include key steps, commands, and gotchas.' },\n },\n required: ['name', 'tags', 'content'],\n },\n execute: async (args: Record<string, unknown>) => {\n const name = args.name as string;\n const tags = (args.tags as string[]) || [];\n const content = args.content as string;\n if (!name || !content) return 'Error: name and content are required';\n const skill = saveSkill(name, tags, content);\n return `Skill saved: \"${skill.name}\" (tags: ${skill.tags.join(', ')}). It will be auto-recalled in future tasks matching these tags.`;\n },\n });\n registerTool({\n name: 'recall_skill',\n description: 'Search for previously saved procedural skills by keyword or tag. Returns reusable approaches from past tasks.',\n parameters: {\n type: 'object',\n properties: {\n query: { type: 'string', description: 'Search query — keywords or tags to find relevant skills' },\n },\n required: ['query'],\n },\n execute: async (args: Record<string, unknown>) => {\n const query = args.query as string;\n if (!query) return 'Error: query is required';\n const results = searchSkills(query, 5);\n if (results.length === 0) return 'No matching skills found. Consider saving useful approaches with save_skill.';\n return results.map(s =>\n `### ${s.name}\\nTags: ${s.tags.join(', ')} | Used ${s.useCount}x\\n${s.content.slice(0, 800)}`\n ).join('\\n\\n---\\n\\n');\n },\n });\n logger.info(COMPONENT, 'Registered procedural memory tools (save_skill, recall_skill)');\n } catch (e) { logger.warn(COMPONENT, `Failed to register procedural memory tools: ${(e as Error).message}`); }\n }\n\n logger.info(COMPONENT, `Loaded ${registeredSkills.size} built-in skills`);\n\n // Load dev skills (only in dev mode — skip import entirely in production)\n if (process.env.NODE_ENV !== 'production' || process.env.TITAN_DEV) {\n const { initDevSkills } = await import('./dev/loader.js');\n await initDevSkills();\n }\n\n // Load NVIDIA skills (optional — only when TITAN_NVIDIA=1 or nvidia.enabled in config)\n try {\n let nvidiaEnabled = process.env.TITAN_NVIDIA === '1';\n if (!nvidiaEnabled) {\n try {\n const { loadConfig: _loadConfig } = await import('../config/config.js');\n const cfg = _loadConfig() as Record<string, unknown>;\n const nvCfg = cfg.nvidia as Record<string, unknown> | undefined;\n nvidiaEnabled = nvCfg?.enabled === true;\n } catch { /* config not available in test env */ }\n }\n if (nvidiaEnabled) {\n const { initNvidiaSkills } = await import('./nvidia/loader.js');\n await initNvidiaSkills();\n }\n } catch (err) {\n logger.warn(COMPONENT, `NVIDIA skills failed to load: ${(err as Error).message}`);\n }\n\n // Load personal skills (private, gitignored — only when TITAN_PERSONAL=1)\n // Primary location: dist/skills/personal/loader.js (co-located with dist/skills/registry.js\n // so `../registry` resolves to the SAME module instance — tools register into the correct registry)\n // Fallback: ~/.titan/personal/loader.js (legacy / TITAN_PERSONAL_DIR override)\n if (process.env.TITAN_PERSONAL === '1') {\n try {\n const { pathToFileURL, fileURLToPath } = await import('node:url');\n const { join: _join, dirname: _dirname } = await import('node:path');\n // Compute dist/skills/ dir from this file's location (works on any machine)\n const thisDir = _dirname(fileURLToPath(import.meta.url));\n const distPersonalDir = _join(thisDir, 'personal');\n // TITAN_PERSONAL_DIR env var overrides; otherwise try dist-local first, then ~/.titan/personal/\n const personalDir = process.env.TITAN_PERSONAL_DIR\n || (existsSync(_join(distPersonalDir, 'loader.js')) ? distPersonalDir : _join(TITAN_HOME, 'personal'));\n const loaderPath = _join(personalDir, 'loader.js');\n if (existsSync(loaderPath)) {\n // Inject the main app's registerSkill into a global so the personal bundle\n // (which has its own bundled copy) uses the correct shared toolRegistry instance.\n (globalThis as Record<string, unknown>).__titanRegisterSkill = registerSkill;\n const { initPersonalSkills } = await import(pathToFileURL(loaderPath).href) as { initPersonalSkills: () => Promise<void> };\n await initPersonalSkills();\n } else {\n logger.warn(COMPONENT, `TITAN_PERSONAL=1 but ${loaderPath} not found — run: npm run build:personal`);\n }\n } catch (err) {\n logger.warn(COMPONENT, `Personal skills failed to load: ${(err as Error).message}`);\n }\n }\n}\n\n/**\n * Discover and load user skills from ~/.titan/skills/ (all subdirs).\n * Supports:\n * 1. JavaScript files (.js) that export default { name, description, parameters, execute }\n * 2. YAML skill definitions (.yaml/.yml) with inline scripts\n * 3. Auto-generated skills from ~/.titan/skills/auto/\n */\nexport async function loadAutoSkills(): Promise<void> {\n const skillsRoot = join(TITAN_HOME, 'skills');\n if (!existsSync(skillsRoot)) return;\n\n logger.info(COMPONENT, 'Scanning for user skills...');\n let loadedCount = 0;\n\n // Scan both root and all subdirectories\n const dirsToScan = [skillsRoot];\n const entries = readdirSync(skillsRoot, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory()) dirsToScan.push(join(skillsRoot, entry.name));\n }\n\n for (const dir of dirsToScan) {\n const files = readdirSync(dir).filter(f =>\n f.endsWith('.js') || f.endsWith('.yaml') || f.endsWith('.yml')\n );\n\n for (const file of files) {\n const filePath = join(dir, file);\n try {\n if (file.endsWith('.js')) {\n // JavaScript skill — export default { name, description, parameters, execute }\n const modulePath = `file://${filePath}?t=${Date.now()}`;\n const mod = await import(modulePath);\n if (mod.default && mod.default.name && mod.default.execute) {\n const handler = mod.default as ToolHandler;\n if (registeredSkills.has(handler.name)) continue; // Skip duplicates\n registerSkill({\n name: handler.name,\n description: handler.description || 'User skill',\n version: '1.0.0',\n source: 'workspace',\n enabled: true,\n }, handler);\n loadedCount++;\n }\n } else {\n // YAML skill definition\n const loaded = loadYamlSkill(filePath);\n if (loaded && !registeredSkills.has(loaded.name)) {\n registerSkill({\n name: loaded.name,\n description: loaded.description,\n version: '1.0.0',\n source: 'workspace',\n enabled: true,\n }, loaded);\n loadedCount++;\n }\n }\n } catch (e: unknown) {\n logger.warn(COMPONENT, `Failed to load skill ${file}: ${(e as Error).message}`);\n }\n }\n }\n\n if (loadedCount > 0) {\n logger.info(COMPONENT, `Loaded ${loadedCount} user skill(s) from ~/.titan/skills/`);\n }\n\n // Load frontmatter skills (*.skill.md) — Space Agent / Hermes parity\n try {\n const { getFrontmatterToolHandlers } = await import('./frontmatterLoader.js');\n const fmHandlers = getFrontmatterToolHandlers();\n for (const { name, handler } of fmHandlers) {\n if (registeredSkills.has(name)) continue;\n registerSkill({\n name: handler.name,\n description: handler.description,\n version: '1.0.0',\n source: 'frontmatter',\n enabled: true,\n }, handler);\n loadedCount++;\n }\n if (fmHandlers.length > 0) {\n logger.info(COMPONENT, `Loaded ${fmHandlers.length} frontmatter skill(s)`);\n }\n } catch (e) {\n logger.warn(COMPONENT, `Frontmatter skills failed to load: ${(e as Error).message}`);\n }\n}\n\n/**\n * Load a YAML skill definition.\n * Format:\n * name: my_tool\n * description: What it does\n * parameters:\n * myParam:\n * type: string\n * description: A parameter\n * required: true\n * script: |\n * // JavaScript code. Use `args.myParam` for inputs.\n * // Return a string result.\n * return \"Hello \" + args.myParam;\n */\nfunction loadYamlSkill(filePath: string): ToolHandler | null {\n const content = readFileSync(filePath, 'utf-8');\n\n // Simple YAML parser (no dependency needed for this basic format)\n const name = content.match(/^name:\\s*(.+)$/m)?.[1]?.trim();\n const description = content.match(/^description:\\s*(.+)$/m)?.[1]?.trim();\n const scriptMatch = content.match(/^script:\\s*\\|\\n([\\s\\S]+?)(?=\\n\\w|\\n$|$)/m);\n const script = scriptMatch?.[1]?.replace(/^ {2}/gm, ''); // Remove YAML indent\n\n if (!name || !description || !script) {\n logger.debug(COMPONENT, `Skipping ${filePath}: missing name, description, or script`);\n return null;\n }\n\n // Parse parameters section\n const paramsSection = content.match(/^parameters:\\n((?:\\s{2}\\w[\\s\\S]*?)(?=\\nscript:|\\n\\w|\\n$))/m);\n const properties: Record<string, Record<string, unknown>> = {};\n const required: string[] = [];\n\n if (paramsSection) {\n const paramLines = paramsSection[1].split('\\n');\n let currentParam = '';\n for (const line of paramLines) {\n const paramMatch = line.match(/^\\s{2}(\\w+):\\s*$/);\n if (paramMatch) {\n currentParam = paramMatch[1];\n properties[currentParam] = {};\n continue;\n }\n if (currentParam) {\n const typeMatch = line.match(/^\\s{4}type:\\s*(.+)$/);\n const descMatch = line.match(/^\\s{4}description:\\s*(.+)$/);\n const reqMatch = line.match(/^\\s{4}required:\\s*true$/);\n const defMatch = line.match(/^\\s{4}default:\\s*(.+)$/);\n if (typeMatch) properties[currentParam].type = typeMatch[1].trim();\n if (descMatch) properties[currentParam].description = descMatch[1].trim();\n if (reqMatch) required.push(currentParam);\n if (defMatch) properties[currentParam].default = defMatch[1].trim();\n }\n }\n }\n\n // Create the execute function from the script\n const handler: ToolHandler = {\n name,\n description,\n parameters: {\n type: 'object',\n properties,\n required: required.length > 0 ? required : undefined,\n },\n execute: async (args: Record<string, unknown>) => {\n try {\n // Run in a restricted VM context — no access to globalThis, process, eval, or Function\n const safeRequire = (mod: string) => {\n // SECURITY: child_process, http, https removed — YAML skills must use builtin tools for shell/network\n const allowed = ['fs', 'path', 'os', 'crypto', 'url', 'util'];\n if (!allowed.includes(mod)) throw new Error(`Module \"${mod}\" not allowed in YAML skills`);\n return require(mod); // eslint-disable-line @typescript-eslint/no-require-imports\n };\n const sandbox: Record<string, unknown> = {\n args,\n require: safeRequire,\n console: { log: console.log },\n JSON,\n Math,\n Date,\n String,\n Number,\n Array,\n Object,\n RegExp,\n Map,\n Set,\n Promise,\n setTimeout,\n Buffer,\n };\n // Wrap the user script in an async IIFE so `return` works and we can await it\n const wrapped = `(async function() { ${script} })()`;\n const result = await vm.runInNewContext(wrapped, sandbox, { timeout: 10000 });\n return typeof result === 'string' ? result : JSON.stringify(result, null, 2);\n } catch (err) {\n return `Error: ${(err as Error).message}`;\n }\n },\n };\n\n logger.debug(COMPONENT, `Loaded YAML skill: ${name} from ${filePath}`);\n return handler;\n}\n"],"mappings":"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","names":[]}
@@ -3,7 +3,7 @@ import { existsSync, readFileSync, appendFileSync } from "fs";
3
3
  import { atomicWriteJsonFile } from "../utils/helpers.js";
4
4
  import { join } from "path";
5
5
  import { TITAN_HOME, TELEMETRY_EVENTS_PATH } from "../utils/constants.js";
6
- import { ensureDir } from "../utils/helpers.js";
6
+ import { mkdirIfNotExists } from "../utils/helpers.js";
7
7
  import logger from "../utils/logger.js";
8
8
  const COMPONENT = "JsonStorage";
9
9
  const GOALS_PATH = join(TITAN_HOME, "goals.json");
@@ -25,7 +25,7 @@ class JsonStorage {
25
25
  goalsLoaded = false;
26
26
  // ── Lifecycle ────────────────────────────────────────────────────────
27
27
  async init() {
28
- ensureDir(TITAN_HOME);
28
+ mkdirIfNotExists(TITAN_HOME);
29
29
  this.loadGoals();
30
30
  this.loadState();
31
31
  logger.info(COMPONENT, "JSON storage initialized");
@@ -55,7 +55,7 @@ class JsonStorage {
55
55
  saveGoals() {
56
56
  const goals = this.goalsCache || [];
57
57
  try {
58
- ensureDir(TITAN_HOME);
58
+ mkdirIfNotExists(TITAN_HOME);
59
59
  const store = {
60
60
  goals,
61
61
  lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
@@ -92,7 +92,7 @@ class JsonStorage {
92
92
  }
93
93
  saveState() {
94
94
  try {
95
- ensureDir(TITAN_HOME);
95
+ mkdirIfNotExists(TITAN_HOME);
96
96
  const state = {
97
97
  checkouts: Array.from(this.checkouts.values()),
98
98
  budgetPolicies: this.budgetPolicies,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/storage/JsonStorage.ts"],"sourcesContent":["/**\n * TITAN — JSON File Storage Implementation\n * Implements StorageProvider using the same file paths, in-memory Maps,\n * and read/write patterns extracted from commandPost.ts and goals.ts.\n *\n * Drop-in replacement: commandPost.ts calls getStorage() and uses this interface\n * instead of its module-level Maps and bare fs calls.\n */\nimport { existsSync, readFileSync, writeFileSync, appendFileSync } from 'fs';\nimport { atomicWriteJsonFile } from '../utils/helpers.js';\nimport { join } from 'path';\nimport { TITAN_HOME, TELEMETRY_EVENTS_PATH } from '../utils/constants.js';\nimport { ensureDir } from '../utils/helpers.js';\nimport logger from '../utils/logger.js';\nimport type {\n StorageProvider,\n IssueFilters,\n ActivityQueryOpts,\n BudgetReservation,\n Transaction,\n TelemetryEvent,\n} from './StorageProvider.js';\nimport type {\n TaskCheckout,\n BudgetPolicy,\n RegisteredAgent,\n ActivityEntry,\n CPIssue,\n CPComment,\n CPApproval,\n CPRun,\n} from '../agent/commandPost.js';\nimport type { Goal, Subtask } from '../agent/goals.js';\n\nconst COMPONENT = 'JsonStorage';\n\n// ─── Disk Paths (mirrors commandPost.ts / goals.ts) ───────────────────────\n\nconst GOALS_PATH = join(TITAN_HOME, 'goals.json');\nconst STATE_PATH = join(TITAN_HOME, 'command-post.json');\nconst ACTIVITY_PATH = join(TITAN_HOME, 'command-post-activity.jsonl');\n\n// ─── On-disk Shapes ───────────────────────────────────────────────────────\n\ninterface GoalsStore {\n goals: Goal[];\n lastUpdated: string;\n}\n\ninterface CommandPostState {\n checkouts: TaskCheckout[];\n budgetPolicies: BudgetPolicy[];\n agents: RegisteredAgent[];\n issues: CPIssue[];\n approvals: CPApproval[];\n runs: CPRun[];\n comments: CPComment[];\n issueCounter: number;\n lastSaved: string;\n}\n\n// ─── JsonStorage Class ────────────────────────────────────────────────────\n\nexport class JsonStorage implements StorageProvider {\n\n // ── In-memory caches ────────────────────────────────────────────────\n\n private goalsCache: Goal[] | null = null;\n\n private checkouts = new Map<string, TaskCheckout>();\n private budgetPolicies: BudgetPolicy[] = [];\n private agents = new Map<string, RegisteredAgent>();\n private issues = new Map<string, CPIssue>();\n private approvals = new Map<string, CPApproval>();\n private runs: CPRun[] = [];\n private comments: CPComment[] = [];\n private activityBuffer: ActivityEntry[] = [];\n private issueCounter = 0;\n\n private stateLoaded = false;\n private goalsLoaded = false;\n\n // ── Lifecycle ────────────────────────────────────────────────────────\n\n async init(): Promise<void> {\n ensureDir(TITAN_HOME);\n this.loadGoals();\n this.loadState();\n logger.info(COMPONENT, 'JSON storage initialized');\n }\n\n async shutdown(): Promise<void> {\n this.saveGoals();\n this.saveState();\n logger.info(COMPONENT, 'JSON storage shut down');\n }\n\n // ── Internal: Goals persistence ───────────────────────────────────\n\n private loadGoals(): void {\n if (this.goalsLoaded) return;\n this.goalsLoaded = true;\n\n if (!existsSync(GOALS_PATH)) {\n this.goalsCache = [];\n return;\n }\n try {\n const raw = readFileSync(GOALS_PATH, 'utf-8');\n const store = JSON.parse(raw) as GoalsStore;\n this.goalsCache = store.goals || [];\n } catch (err) {\n logger.warn(COMPONENT, `Failed to load goals: ${(err as Error).message}`);\n this.goalsCache = [];\n }\n }\n\n private saveGoals(): void {\n const goals = this.goalsCache || [];\n try {\n ensureDir(TITAN_HOME);\n const store: GoalsStore = {\n goals,\n lastUpdated: new Date().toISOString(),\n };\n atomicWriteJsonFile(GOALS_PATH, store);\n } catch (err) {\n logger.error(COMPONENT, `Failed to save goals: ${(err as Error).message}`);\n }\n }\n\n // ── Internal: Command Post persistence ───────────────────────────\n\n private loadState(): void {\n if (this.stateLoaded) return;\n this.stateLoaded = true;\n\n if (!existsSync(STATE_PATH)) return;\n try {\n const raw = readFileSync(STATE_PATH, 'utf-8');\n const state = JSON.parse(raw) as CommandPostState;\n\n for (const c of state.checkouts || []) {\n if (c.status === 'locked') this.checkouts.set(c.subtaskId, c);\n }\n this.budgetPolicies = state.budgetPolicies || [];\n for (const a of state.agents || []) {\n if (!a.role) a.role = 'general'; // backcompat\n this.agents.set(a.id, a);\n }\n for (const i of state.issues || []) this.issues.set(i.id, i);\n for (const ap of state.approvals || []) this.approvals.set(ap.id, ap);\n this.runs.push(...(state.runs || []).slice(-200)); // keep last 200\n this.comments.push(...(state.comments || []));\n this.issueCounter = state.issueCounter || (state.issues?.length || 0);\n } catch (err) {\n logger.warn(COMPONENT, `Failed to load state: ${(err as Error).message}`);\n }\n }\n\n private saveState(): void {\n try {\n ensureDir(TITAN_HOME);\n const state: CommandPostState = {\n checkouts: Array.from(this.checkouts.values()),\n budgetPolicies: this.budgetPolicies,\n agents: Array.from(this.agents.values()),\n issues: Array.from(this.issues.values()),\n approvals: Array.from(this.approvals.values()),\n runs: this.runs.slice(-200),\n comments: this.comments,\n issueCounter: this.issueCounter,\n lastSaved: new Date().toISOString(),\n };\n atomicWriteJsonFile(STATE_PATH, state);\n } catch (err) {\n logger.error(COMPONENT, `Failed to save state: ${(err as Error).message}`);\n }\n }\n\n // ── Goals ────────────────────────────────────────────────────────────\n\n async getGoals(): Promise<Goal[]> {\n this.loadGoals();\n return [...(this.goalsCache || [])];\n }\n\n async getGoal(id: string): Promise<Goal | undefined> {\n this.loadGoals();\n return this.goalsCache?.find(g => g.id === id);\n }\n\n async saveGoal(goal: Goal): Promise<void> {\n this.loadGoals();\n const goals = this.goalsCache!;\n const idx = goals.findIndex(g => g.id === goal.id);\n if (idx === -1) {\n goals.push(goal);\n } else {\n goals[idx] = goal;\n }\n this.saveGoals();\n }\n\n async deleteGoal(id: string): Promise<boolean> {\n this.loadGoals();\n const goals = this.goalsCache!;\n const idx = goals.findIndex(g => g.id === id);\n if (idx === -1) return false;\n goals.splice(idx, 1);\n this.saveGoals();\n return true;\n }\n\n async saveSubtask(goalId: string, subtask: Subtask): Promise<void> {\n // Subtasks are stored inline on the parent Goal in JSON mode.\n const goal = await this.getGoal(goalId);\n if (!goal) return;\n const idx = goal.subtasks.findIndex(st => st.id === subtask.id);\n if (idx === -1) {\n goal.subtasks.push(subtask);\n } else {\n goal.subtasks[idx] = subtask;\n }\n await this.saveGoal(goal);\n }\n\n // ── Agents ───────────────────────────────────────────────────────────\n\n async getAgents(): Promise<RegisteredAgent[]> {\n this.loadState();\n return Array.from(this.agents.values());\n }\n\n async getAgent(id: string): Promise<RegisteredAgent | undefined> {\n this.loadState();\n return this.agents.get(id);\n }\n\n async saveAgent(agent: RegisteredAgent): Promise<void> {\n this.loadState();\n this.agents.set(agent.id, agent);\n this.saveState();\n }\n\n async deleteAgent(id: string): Promise<boolean> {\n this.loadState();\n const existed = this.agents.has(id);\n this.agents.delete(id);\n if (existed) this.saveState();\n return existed;\n }\n\n // ── Task Checkouts ────────────────────────────────────────────────────\n\n async getCheckouts(): Promise<TaskCheckout[]> {\n this.loadState();\n return Array.from(this.checkouts.values());\n }\n\n async getCheckout(subtaskId: string): Promise<TaskCheckout | undefined> {\n this.loadState();\n return this.checkouts.get(subtaskId);\n }\n\n async saveCheckout(checkout: TaskCheckout): Promise<void> {\n this.loadState();\n this.checkouts.set(checkout.subtaskId, checkout);\n this.saveState();\n }\n\n async deleteCheckout(subtaskId: string): Promise<void> {\n this.loadState();\n this.checkouts.delete(subtaskId);\n this.saveState();\n }\n\n // ── Budget Policies ───────────────────────────────────────────────────\n\n async getBudgetPolicies(): Promise<BudgetPolicy[]> {\n this.loadState();\n return [...this.budgetPolicies];\n }\n\n async getBudgetPolicy(id: string): Promise<BudgetPolicy | undefined> {\n this.loadState();\n return this.budgetPolicies.find(p => p.id === id);\n }\n\n async saveBudgetPolicy(policy: BudgetPolicy): Promise<void> {\n this.loadState();\n const idx = this.budgetPolicies.findIndex(p => p.id === policy.id);\n if (idx === -1) {\n this.budgetPolicies.push(policy);\n } else {\n this.budgetPolicies[idx] = policy;\n }\n this.saveState();\n }\n\n async deleteBudgetPolicy(id: string): Promise<boolean> {\n this.loadState();\n const idx = this.budgetPolicies.findIndex(p => p.id === id);\n if (idx === -1) return false;\n this.budgetPolicies.splice(idx, 1);\n this.saveState();\n return true;\n }\n\n // ── Issues ────────────────────────────────────────────────────────────\n\n async getIssues(): Promise<CPIssue[]> {\n this.loadState();\n return Array.from(this.issues.values());\n }\n\n async getIssue(id: string): Promise<CPIssue | undefined> {\n this.loadState();\n return this.issues.get(id);\n }\n\n async saveIssue(issue: CPIssue): Promise<void> {\n this.loadState();\n this.issues.set(issue.id, issue);\n this.saveState();\n }\n\n async deleteIssue(id: string): Promise<boolean> {\n this.loadState();\n const existed = this.issues.has(id);\n this.issues.delete(id);\n if (existed) this.saveState();\n return existed;\n }\n\n async queryIssues(filters: IssueFilters): Promise<CPIssue[]> {\n this.loadState();\n let result = Array.from(this.issues.values());\n if (filters.status) result = result.filter(i => i.status === filters.status);\n if (filters.assigneeAgentId) result = result.filter(i => i.assigneeAgentId === filters.assigneeAgentId);\n if (filters.goalId) result = result.filter(i => i.goalId === filters.goalId);\n return result.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());\n }\n\n // ── Issue Counter ─────────────────────────────────────────────────────\n\n async getIssueCounter(): Promise<number> {\n this.loadState();\n return this.issueCounter;\n }\n\n async incrementIssueCounter(): Promise<number> {\n this.loadState();\n this.issueCounter++;\n this.saveState();\n return this.issueCounter;\n }\n\n // ── Comments ──────────────────────────────────────────────────────────\n\n async getComments(issueId: string): Promise<CPComment[]> {\n this.loadState();\n return this.comments.filter(c => c.issueId === issueId);\n }\n\n async saveComment(comment: CPComment): Promise<void> {\n this.loadState();\n this.comments.push(comment);\n this.saveState();\n }\n\n // ── Approvals ─────────────────────────────────────────────────────────\n\n async getApprovals(): Promise<CPApproval[]> {\n this.loadState();\n return Array.from(this.approvals.values());\n }\n\n async getApproval(id: string): Promise<CPApproval | undefined> {\n this.loadState();\n return this.approvals.get(id);\n }\n\n async saveApproval(approval: CPApproval): Promise<void> {\n this.loadState();\n this.approvals.set(approval.id, approval);\n this.saveState();\n }\n\n // ── Runs ──────────────────────────────────────────────────────────────\n\n async getRuns(): Promise<CPRun[]> {\n this.loadState();\n return [...this.runs];\n }\n\n async getRun(id: string): Promise<CPRun | undefined> {\n this.loadState();\n return this.runs.find(r => r.id === id);\n }\n\n async saveRun(run: CPRun): Promise<void> {\n this.loadState();\n const idx = this.runs.findIndex(r => r.id === run.id);\n if (idx === -1) {\n this.runs.push(run);\n // Mirror the hard cap from commandPost.ts\n if (this.runs.length > 500) this.runs.splice(0, this.runs.length - 500);\n } else {\n this.runs[idx] = run;\n }\n this.saveState();\n }\n\n async queryRuns(agentId?: string, limit = 50): Promise<CPRun[]> {\n this.loadState();\n let result = [...this.runs];\n if (agentId) result = result.filter(r => r.agentId === agentId);\n return result.slice(-limit).reverse();\n }\n\n // ── Activity ──────────────────────────────────────────────────────────\n\n async appendActivity(entry: ActivityEntry): Promise<void> {\n // In-memory buffer (non-blocking; size managed by CommandPost)\n this.activityBuffer.push(entry);\n // JSONL append — non-critical, same as commandPost.ts original\n try {\n appendFileSync(ACTIVITY_PATH, JSON.stringify(entry) + '\\n', 'utf-8');\n } catch { /* non-critical */ }\n }\n\n async queryActivity(opts: ActivityQueryOpts): Promise<ActivityEntry[]> {\n let entries = [...this.activityBuffer];\n if (opts.type) entries = entries.filter(e => e.type === opts.type);\n if (opts.limit) entries = entries.slice(-opts.limit);\n return entries;\n }\n\n /** Expose internal buffer so CommandPost can manage its own size cap */\n getActivityBuffer(): ActivityEntry[] {\n return this.activityBuffer;\n }\n\n // ── Budget Reservations (no-op in JSON mode) ──────────────────────────\n\n async saveBudgetReservation(_reservation: BudgetReservation): Promise<void> {\n // JSON mode: reservations are not persisted separately.\n // Budget spend is tracked directly on BudgetPolicy.currentSpend.\n }\n\n async getBudgetReservation(_id: string): Promise<BudgetReservation | undefined> {\n return undefined;\n }\n\n // ── Transactions (no-op — event-loop guarantee is sufficient in JSON mode) ─\n\n async beginTransaction(): Promise<Transaction> {\n return {\n async commit() { /* no-op */ },\n async rollback() { /* no-op */ },\n };\n }\n\n // ── Telemetry ─────────────────────────────────────────────────────────\n\n async appendTelemetryEvent(entry: TelemetryEvent): Promise<void> {\n try {\n appendFileSync(TELEMETRY_EVENTS_PATH, JSON.stringify(entry) + '\\n', 'utf-8');\n } catch { /* non-critical */ }\n }\n\n async queryTelemetryEvents(opts: { limit?: number }): Promise<TelemetryEvent[]> {\n const limit = opts.limit ?? 100;\n try {\n if (!existsSync(TELEMETRY_EVENTS_PATH)) return [];\n const raw = readFileSync(TELEMETRY_EVENTS_PATH, 'utf-8');\n const lines = raw.trim().split('\\n').filter(Boolean);\n const events = lines\n .slice(-limit)\n .map((line) => {\n try { return JSON.parse(line) as TelemetryEvent; } catch { return null; }\n })\n .filter((e): e is TelemetryEvent => e !== null);\n return events;\n } catch {\n return [];\n }\n }\n}\n"],"mappings":";AAQA,SAAS,YAAY,cAA6B,sBAAsB;AACxE,SAAS,2BAA2B;AACpC,SAAS,YAAY;AACrB,SAAS,YAAY,6BAA6B;AAClD,SAAS,iBAAiB;AAC1B,OAAO,YAAY;AAqBnB,MAAM,YAAY;AAIlB,MAAM,aAAiB,KAAK,YAAY,YAAY;AACpD,MAAM,aAAiB,KAAK,YAAY,mBAAmB;AAC3D,MAAM,gBAAiB,KAAK,YAAY,6BAA6B;AAuB9D,MAAM,YAAuC;AAAA;AAAA,EAIxC,aAA4B;AAAA,EAE5B,YAAgB,oBAAI,IAA0B;AAAA,EAC9C,iBAAiC,CAAC;AAAA,EAClC,SAAgB,oBAAI,IAA6B;AAAA,EACjD,SAAgB,oBAAI,IAAqB;AAAA,EACzC,YAAgB,oBAAI,IAAwB;AAAA,EAC5C,OAAgB,CAAC;AAAA,EACjB,WAAwB,CAAC;AAAA,EACzB,iBAAkC,CAAC;AAAA,EACnC,eAAe;AAAA,EAEf,cAAc;AAAA,EACd,cAAc;AAAA;AAAA,EAItB,MAAM,OAAsB;AACxB,cAAU,UAAU;AACpB,SAAK,UAAU;AACf,SAAK,UAAU;AACf,WAAO,KAAK,WAAW,0BAA0B;AAAA,EACrD;AAAA,EAEA,MAAM,WAA0B;AAC5B,SAAK,UAAU;AACf,SAAK,UAAU;AACf,WAAO,KAAK,WAAW,wBAAwB;AAAA,EACnD;AAAA;AAAA,EAIQ,YAAkB;AACtB,QAAI,KAAK,YAAa;AACtB,SAAK,cAAc;AAEnB,QAAI,CAAC,WAAW,UAAU,GAAG;AACzB,WAAK,aAAa,CAAC;AACnB;AAAA,IACJ;AACA,QAAI;AACA,YAAM,MAAM,aAAa,YAAY,OAAO;AAC5C,YAAM,QAAQ,KAAK,MAAM,GAAG;AAC5B,WAAK,aAAa,MAAM,SAAS,CAAC;AAAA,IACtC,SAAS,KAAK;AACV,aAAO,KAAK,WAAW,yBAA0B,IAAc,OAAO,EAAE;AACxE,WAAK,aAAa,CAAC;AAAA,IACvB;AAAA,EACJ;AAAA,EAEQ,YAAkB;AACtB,UAAM,QAAQ,KAAK,cAAc,CAAC;AAClC,QAAI;AACA,gBAAU,UAAU;AACpB,YAAM,QAAoB;AAAA,QACtB;AAAA,QACA,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACxC;AACA,0BAAoB,YAAY,KAAK;AAAA,IACzC,SAAS,KAAK;AACV,aAAO,MAAM,WAAW,yBAA0B,IAAc,OAAO,EAAE;AAAA,IAC7E;AAAA,EACJ;AAAA;AAAA,EAIQ,YAAkB;AACtB,QAAI,KAAK,YAAa;AACtB,SAAK,cAAc;AAEnB,QAAI,CAAC,WAAW,UAAU,EAAG;AAC7B,QAAI;AACA,YAAM,MAAM,aAAa,YAAY,OAAO;AAC5C,YAAM,QAAQ,KAAK,MAAM,GAAG;AAE5B,iBAAW,KAAK,MAAM,aAAa,CAAC,GAAG;AACnC,YAAI,EAAE,WAAW,SAAU,MAAK,UAAU,IAAI,EAAE,WAAW,CAAC;AAAA,MAChE;AACA,WAAK,iBAAiB,MAAM,kBAAkB,CAAC;AAC/C,iBAAW,KAAK,MAAM,UAAU,CAAC,GAAG;AAChC,YAAI,CAAC,EAAE,KAAM,GAAE,OAAO;AACtB,aAAK,OAAO,IAAI,EAAE,IAAI,CAAC;AAAA,MAC3B;AACA,iBAAW,KAAK,MAAM,UAAU,CAAC,EAAG,MAAK,OAAO,IAAI,EAAE,IAAI,CAAC;AAC3D,iBAAW,MAAM,MAAM,aAAa,CAAC,EAAG,MAAK,UAAU,IAAI,GAAG,IAAI,EAAE;AACpE,WAAK,KAAK,KAAK,IAAI,MAAM,QAAQ,CAAC,GAAG,MAAM,IAAI,CAAC;AAChD,WAAK,SAAS,KAAK,GAAI,MAAM,YAAY,CAAC,CAAE;AAC5C,WAAK,eAAe,MAAM,iBAAiB,MAAM,QAAQ,UAAU;AAAA,IACvE,SAAS,KAAK;AACV,aAAO,KAAK,WAAW,yBAA0B,IAAc,OAAO,EAAE;AAAA,IAC5E;AAAA,EACJ;AAAA,EAEQ,YAAkB;AACtB,QAAI;AACA,gBAAU,UAAU;AACpB,YAAM,QAA0B;AAAA,QAC5B,WAAW,MAAM,KAAK,KAAK,UAAU,OAAO,CAAC;AAAA,QAC7C,gBAAgB,KAAK;AAAA,QACrB,QAAQ,MAAM,KAAK,KAAK,OAAO,OAAO,CAAC;AAAA,QACvC,QAAQ,MAAM,KAAK,KAAK,OAAO,OAAO,CAAC;AAAA,QACvC,WAAW,MAAM,KAAK,KAAK,UAAU,OAAO,CAAC;AAAA,QAC7C,MAAM,KAAK,KAAK,MAAM,IAAI;AAAA,QAC1B,UAAU,KAAK;AAAA,QACf,cAAc,KAAK;AAAA,QACnB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACtC;AACA,0BAAoB,YAAY,KAAK;AAAA,IACzC,SAAS,KAAK;AACV,aAAO,MAAM,WAAW,yBAA0B,IAAc,OAAO,EAAE;AAAA,IAC7E;AAAA,EACJ;AAAA;AAAA,EAIA,MAAM,WAA4B;AAC9B,SAAK,UAAU;AACf,WAAO,CAAC,GAAI,KAAK,cAAc,CAAC,CAAE;AAAA,EACtC;AAAA,EAEA,MAAM,QAAQ,IAAuC;AACjD,SAAK,UAAU;AACf,WAAO,KAAK,YAAY,KAAK,OAAK,EAAE,OAAO,EAAE;AAAA,EACjD;AAAA,EAEA,MAAM,SAAS,MAA2B;AACtC,SAAK,UAAU;AACf,UAAM,QAAQ,KAAK;AACnB,UAAM,MAAM,MAAM,UAAU,OAAK,EAAE,OAAO,KAAK,EAAE;AACjD,QAAI,QAAQ,IAAI;AACZ,YAAM,KAAK,IAAI;AAAA,IACnB,OAAO;AACH,YAAM,GAAG,IAAI;AAAA,IACjB;AACA,SAAK,UAAU;AAAA,EACnB;AAAA,EAEA,MAAM,WAAW,IAA8B;AAC3C,SAAK,UAAU;AACf,UAAM,QAAQ,KAAK;AACnB,UAAM,MAAM,MAAM,UAAU,OAAK,EAAE,OAAO,EAAE;AAC5C,QAAI,QAAQ,GAAI,QAAO;AACvB,UAAM,OAAO,KAAK,CAAC;AACnB,SAAK,UAAU;AACf,WAAO;AAAA,EACX;AAAA,EAEA,MAAM,YAAY,QAAgB,SAAiC;AAE/D,UAAM,OAAO,MAAM,KAAK,QAAQ,MAAM;AACtC,QAAI,CAAC,KAAM;AACX,UAAM,MAAM,KAAK,SAAS,UAAU,QAAM,GAAG,OAAO,QAAQ,EAAE;AAC9D,QAAI,QAAQ,IAAI;AACZ,WAAK,SAAS,KAAK,OAAO;AAAA,IAC9B,OAAO;AACH,WAAK,SAAS,GAAG,IAAI;AAAA,IACzB;AACA,UAAM,KAAK,SAAS,IAAI;AAAA,EAC5B;AAAA;AAAA,EAIA,MAAM,YAAwC;AAC1C,SAAK,UAAU;AACf,WAAO,MAAM,KAAK,KAAK,OAAO,OAAO,CAAC;AAAA,EAC1C;AAAA,EAEA,MAAM,SAAS,IAAkD;AAC7D,SAAK,UAAU;AACf,WAAO,KAAK,OAAO,IAAI,EAAE;AAAA,EAC7B;AAAA,EAEA,MAAM,UAAU,OAAuC;AACnD,SAAK,UAAU;AACf,SAAK,OAAO,IAAI,MAAM,IAAI,KAAK;AAC/B,SAAK,UAAU;AAAA,EACnB;AAAA,EAEA,MAAM,YAAY,IAA8B;AAC5C,SAAK,UAAU;AACf,UAAM,UAAU,KAAK,OAAO,IAAI,EAAE;AAClC,SAAK,OAAO,OAAO,EAAE;AACrB,QAAI,QAAS,MAAK,UAAU;AAC5B,WAAO;AAAA,EACX;AAAA;AAAA,EAIA,MAAM,eAAwC;AAC1C,SAAK,UAAU;AACf,WAAO,MAAM,KAAK,KAAK,UAAU,OAAO,CAAC;AAAA,EAC7C;AAAA,EAEA,MAAM,YAAY,WAAsD;AACpE,SAAK,UAAU;AACf,WAAO,KAAK,UAAU,IAAI,SAAS;AAAA,EACvC;AAAA,EAEA,MAAM,aAAa,UAAuC;AACtD,SAAK,UAAU;AACf,SAAK,UAAU,IAAI,SAAS,WAAW,QAAQ;AAC/C,SAAK,UAAU;AAAA,EACnB;AAAA,EAEA,MAAM,eAAe,WAAkC;AACnD,SAAK,UAAU;AACf,SAAK,UAAU,OAAO,SAAS;AAC/B,SAAK,UAAU;AAAA,EACnB;AAAA;AAAA,EAIA,MAAM,oBAA6C;AAC/C,SAAK,UAAU;AACf,WAAO,CAAC,GAAG,KAAK,cAAc;AAAA,EAClC;AAAA,EAEA,MAAM,gBAAgB,IAA+C;AACjE,SAAK,UAAU;AACf,WAAO,KAAK,eAAe,KAAK,OAAK,EAAE,OAAO,EAAE;AAAA,EACpD;AAAA,EAEA,MAAM,iBAAiB,QAAqC;AACxD,SAAK,UAAU;AACf,UAAM,MAAM,KAAK,eAAe,UAAU,OAAK,EAAE,OAAO,OAAO,EAAE;AACjE,QAAI,QAAQ,IAAI;AACZ,WAAK,eAAe,KAAK,MAAM;AAAA,IACnC,OAAO;AACH,WAAK,eAAe,GAAG,IAAI;AAAA,IAC/B;AACA,SAAK,UAAU;AAAA,EACnB;AAAA,EAEA,MAAM,mBAAmB,IAA8B;AACnD,SAAK,UAAU;AACf,UAAM,MAAM,KAAK,eAAe,UAAU,OAAK,EAAE,OAAO,EAAE;AAC1D,QAAI,QAAQ,GAAI,QAAO;AACvB,SAAK,eAAe,OAAO,KAAK,CAAC;AACjC,SAAK,UAAU;AACf,WAAO;AAAA,EACX;AAAA;AAAA,EAIA,MAAM,YAAgC;AAClC,SAAK,UAAU;AACf,WAAO,MAAM,KAAK,KAAK,OAAO,OAAO,CAAC;AAAA,EAC1C;AAAA,EAEA,MAAM,SAAS,IAA0C;AACrD,SAAK,UAAU;AACf,WAAO,KAAK,OAAO,IAAI,EAAE;AAAA,EAC7B;AAAA,EAEA,MAAM,UAAU,OAA+B;AAC3C,SAAK,UAAU;AACf,SAAK,OAAO,IAAI,MAAM,IAAI,KAAK;AAC/B,SAAK,UAAU;AAAA,EACnB;AAAA,EAEA,MAAM,YAAY,IAA8B;AAC5C,SAAK,UAAU;AACf,UAAM,UAAU,KAAK,OAAO,IAAI,EAAE;AAClC,SAAK,OAAO,OAAO,EAAE;AACrB,QAAI,QAAS,MAAK,UAAU;AAC5B,WAAO;AAAA,EACX;AAAA,EAEA,MAAM,YAAY,SAA2C;AACzD,SAAK,UAAU;AACf,QAAI,SAAS,MAAM,KAAK,KAAK,OAAO,OAAO,CAAC;AAC5C,QAAI,QAAQ,OAAQ,UAAS,OAAO,OAAO,OAAK,EAAE,WAAW,QAAQ,MAAM;AAC3E,QAAI,QAAQ,gBAAiB,UAAS,OAAO,OAAO,OAAK,EAAE,oBAAoB,QAAQ,eAAe;AACtG,QAAI,QAAQ,OAAQ,UAAS,OAAO,OAAO,OAAK,EAAE,WAAW,QAAQ,MAAM;AAC3E,WAAO,OAAO,KAAK,CAAC,GAAG,MAAM,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC;AAAA,EAClG;AAAA;AAAA,EAIA,MAAM,kBAAmC;AACrC,SAAK,UAAU;AACf,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,MAAM,wBAAyC;AAC3C,SAAK,UAAU;AACf,SAAK;AACL,SAAK,UAAU;AACf,WAAO,KAAK;AAAA,EAChB;AAAA;AAAA,EAIA,MAAM,YAAY,SAAuC;AACrD,SAAK,UAAU;AACf,WAAO,KAAK,SAAS,OAAO,OAAK,EAAE,YAAY,OAAO;AAAA,EAC1D;AAAA,EAEA,MAAM,YAAY,SAAmC;AACjD,SAAK,UAAU;AACf,SAAK,SAAS,KAAK,OAAO;AAC1B,SAAK,UAAU;AAAA,EACnB;AAAA;AAAA,EAIA,MAAM,eAAsC;AACxC,SAAK,UAAU;AACf,WAAO,MAAM,KAAK,KAAK,UAAU,OAAO,CAAC;AAAA,EAC7C;AAAA,EAEA,MAAM,YAAY,IAA6C;AAC3D,SAAK,UAAU;AACf,WAAO,KAAK,UAAU,IAAI,EAAE;AAAA,EAChC;AAAA,EAEA,MAAM,aAAa,UAAqC;AACpD,SAAK,UAAU;AACf,SAAK,UAAU,IAAI,SAAS,IAAI,QAAQ;AACxC,SAAK,UAAU;AAAA,EACnB;AAAA;AAAA,EAIA,MAAM,UAA4B;AAC9B,SAAK,UAAU;AACf,WAAO,CAAC,GAAG,KAAK,IAAI;AAAA,EACxB;AAAA,EAEA,MAAM,OAAO,IAAwC;AACjD,SAAK,UAAU;AACf,WAAO,KAAK,KAAK,KAAK,OAAK,EAAE,OAAO,EAAE;AAAA,EAC1C;AAAA,EAEA,MAAM,QAAQ,KAA2B;AACrC,SAAK,UAAU;AACf,UAAM,MAAM,KAAK,KAAK,UAAU,OAAK,EAAE,OAAO,IAAI,EAAE;AACpD,QAAI,QAAQ,IAAI;AACZ,WAAK,KAAK,KAAK,GAAG;AAElB,UAAI,KAAK,KAAK,SAAS,IAAK,MAAK,KAAK,OAAO,GAAG,KAAK,KAAK,SAAS,GAAG;AAAA,IAC1E,OAAO;AACH,WAAK,KAAK,GAAG,IAAI;AAAA,IACrB;AACA,SAAK,UAAU;AAAA,EACnB;AAAA,EAEA,MAAM,UAAU,SAAkB,QAAQ,IAAsB;AAC5D,SAAK,UAAU;AACf,QAAI,SAAS,CAAC,GAAG,KAAK,IAAI;AAC1B,QAAI,QAAS,UAAS,OAAO,OAAO,OAAK,EAAE,YAAY,OAAO;AAC9D,WAAO,OAAO,MAAM,CAAC,KAAK,EAAE,QAAQ;AAAA,EACxC;AAAA;AAAA,EAIA,MAAM,eAAe,OAAqC;AAEtD,SAAK,eAAe,KAAK,KAAK;AAE9B,QAAI;AACA,qBAAe,eAAe,KAAK,UAAU,KAAK,IAAI,MAAM,OAAO;AAAA,IACvE,QAAQ;AAAA,IAAqB;AAAA,EACjC;AAAA,EAEA,MAAM,cAAc,MAAmD;AACnE,QAAI,UAAU,CAAC,GAAG,KAAK,cAAc;AACrC,QAAI,KAAK,KAAM,WAAU,QAAQ,OAAO,OAAK,EAAE,SAAS,KAAK,IAAI;AACjE,QAAI,KAAK,MAAO,WAAU,QAAQ,MAAM,CAAC,KAAK,KAAK;AACnD,WAAO;AAAA,EACX;AAAA;AAAA,EAGA,oBAAqC;AACjC,WAAO,KAAK;AAAA,EAChB;AAAA;AAAA,EAIA,MAAM,sBAAsB,cAAgD;AAAA,EAG5E;AAAA,EAEA,MAAM,qBAAqB,KAAqD;AAC5E,WAAO;AAAA,EACX;AAAA;AAAA,EAIA,MAAM,mBAAyC;AAC3C,WAAO;AAAA,MACH,MAAM,SAAS;AAAA,MAAc;AAAA,MAC7B,MAAM,WAAW;AAAA,MAAc;AAAA,IACnC;AAAA,EACJ;AAAA;AAAA,EAIA,MAAM,qBAAqB,OAAsC;AAC7D,QAAI;AACA,qBAAe,uBAAuB,KAAK,UAAU,KAAK,IAAI,MAAM,OAAO;AAAA,IAC/E,QAAQ;AAAA,IAAqB;AAAA,EACjC;AAAA,EAEA,MAAM,qBAAqB,MAAqD;AAC5E,UAAM,QAAQ,KAAK,SAAS;AAC5B,QAAI;AACA,UAAI,CAAC,WAAW,qBAAqB,EAAG,QAAO,CAAC;AAChD,YAAM,MAAM,aAAa,uBAAuB,OAAO;AACvD,YAAM,QAAQ,IAAI,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AACnD,YAAM,SAAS,MACV,MAAM,CAAC,KAAK,EACZ,IAAI,CAAC,SAAS;AACX,YAAI;AAAE,iBAAO,KAAK,MAAM,IAAI;AAAA,QAAqB,QAAQ;AAAE,iBAAO;AAAA,QAAM;AAAA,MAC5E,CAAC,EACA,OAAO,CAAC,MAA2B,MAAM,IAAI;AAClD,aAAO;AAAA,IACX,QAAQ;AACJ,aAAO,CAAC;AAAA,IACZ;AAAA,EACJ;AACJ;","names":[]}
1
+ {"version":3,"sources":["../../src/storage/JsonStorage.ts"],"sourcesContent":["/**\n * TITAN — JSON File Storage Implementation\n * Implements StorageProvider using the same file paths, in-memory Maps,\n * and read/write patterns extracted from commandPost.ts and goals.ts.\n *\n * Drop-in replacement: commandPost.ts calls getStorage() and uses this interface\n * instead of its module-level Maps and bare fs calls.\n */\nimport { existsSync, readFileSync, writeFileSync, appendFileSync } from 'fs';\nimport { atomicWriteJsonFile } from '../utils/helpers.js';\nimport { join } from 'path';\nimport { TITAN_HOME, TELEMETRY_EVENTS_PATH } from '../utils/constants.js';\nimport { mkdirIfNotExists } from '../utils/helpers.js';\nimport logger from '../utils/logger.js';\nimport type {\n StorageProvider,\n IssueFilters,\n ActivityQueryOpts,\n BudgetReservation,\n Transaction,\n TelemetryEvent,\n} from './StorageProvider.js';\nimport type {\n TaskCheckout,\n BudgetPolicy,\n RegisteredAgent,\n ActivityEntry,\n CPIssue,\n CPComment,\n CPApproval,\n CPRun,\n} from '../agent/commandPost.js';\nimport type { Goal, Subtask } from '../agent/goals.js';\n\nconst COMPONENT = 'JsonStorage';\n\n// ─── Disk Paths (mirrors commandPost.ts / goals.ts) ───────────────────────\n\nconst GOALS_PATH = join(TITAN_HOME, 'goals.json');\nconst STATE_PATH = join(TITAN_HOME, 'command-post.json');\nconst ACTIVITY_PATH = join(TITAN_HOME, 'command-post-activity.jsonl');\n\n// ─── On-disk Shapes ───────────────────────────────────────────────────────\n\ninterface GoalsStore {\n goals: Goal[];\n lastUpdated: string;\n}\n\ninterface CommandPostState {\n checkouts: TaskCheckout[];\n budgetPolicies: BudgetPolicy[];\n agents: RegisteredAgent[];\n issues: CPIssue[];\n approvals: CPApproval[];\n runs: CPRun[];\n comments: CPComment[];\n issueCounter: number;\n lastSaved: string;\n}\n\n// ─── JsonStorage Class ────────────────────────────────────────────────────\n\nexport class JsonStorage implements StorageProvider {\n\n // ── In-memory caches ────────────────────────────────────────────────\n\n private goalsCache: Goal[] | null = null;\n\n private checkouts = new Map<string, TaskCheckout>();\n private budgetPolicies: BudgetPolicy[] = [];\n private agents = new Map<string, RegisteredAgent>();\n private issues = new Map<string, CPIssue>();\n private approvals = new Map<string, CPApproval>();\n private runs: CPRun[] = [];\n private comments: CPComment[] = [];\n private activityBuffer: ActivityEntry[] = [];\n private issueCounter = 0;\n\n private stateLoaded = false;\n private goalsLoaded = false;\n\n // ── Lifecycle ────────────────────────────────────────────────────────\n\n async init(): Promise<void> {\n mkdirIfNotExists(TITAN_HOME);\n this.loadGoals();\n this.loadState();\n logger.info(COMPONENT, 'JSON storage initialized');\n }\n\n async shutdown(): Promise<void> {\n this.saveGoals();\n this.saveState();\n logger.info(COMPONENT, 'JSON storage shut down');\n }\n\n // ── Internal: Goals persistence ───────────────────────────────────\n\n private loadGoals(): void {\n if (this.goalsLoaded) return;\n this.goalsLoaded = true;\n\n if (!existsSync(GOALS_PATH)) {\n this.goalsCache = [];\n return;\n }\n try {\n const raw = readFileSync(GOALS_PATH, 'utf-8');\n const store = JSON.parse(raw) as GoalsStore;\n this.goalsCache = store.goals || [];\n } catch (err) {\n logger.warn(COMPONENT, `Failed to load goals: ${(err as Error).message}`);\n this.goalsCache = [];\n }\n }\n\n private saveGoals(): void {\n const goals = this.goalsCache || [];\n try {\n mkdirIfNotExists(TITAN_HOME);\n const store: GoalsStore = {\n goals,\n lastUpdated: new Date().toISOString(),\n };\n atomicWriteJsonFile(GOALS_PATH, store);\n } catch (err) {\n logger.error(COMPONENT, `Failed to save goals: ${(err as Error).message}`);\n }\n }\n\n // ── Internal: Command Post persistence ───────────────────────────\n\n private loadState(): void {\n if (this.stateLoaded) return;\n this.stateLoaded = true;\n\n if (!existsSync(STATE_PATH)) return;\n try {\n const raw = readFileSync(STATE_PATH, 'utf-8');\n const state = JSON.parse(raw) as CommandPostState;\n\n for (const c of state.checkouts || []) {\n if (c.status === 'locked') this.checkouts.set(c.subtaskId, c);\n }\n this.budgetPolicies = state.budgetPolicies || [];\n for (const a of state.agents || []) {\n if (!a.role) a.role = 'general'; // backcompat\n this.agents.set(a.id, a);\n }\n for (const i of state.issues || []) this.issues.set(i.id, i);\n for (const ap of state.approvals || []) this.approvals.set(ap.id, ap);\n this.runs.push(...(state.runs || []).slice(-200)); // keep last 200\n this.comments.push(...(state.comments || []));\n this.issueCounter = state.issueCounter || (state.issues?.length || 0);\n } catch (err) {\n logger.warn(COMPONENT, `Failed to load state: ${(err as Error).message}`);\n }\n }\n\n private saveState(): void {\n try {\n mkdirIfNotExists(TITAN_HOME);\n const state: CommandPostState = {\n checkouts: Array.from(this.checkouts.values()),\n budgetPolicies: this.budgetPolicies,\n agents: Array.from(this.agents.values()),\n issues: Array.from(this.issues.values()),\n approvals: Array.from(this.approvals.values()),\n runs: this.runs.slice(-200),\n comments: this.comments,\n issueCounter: this.issueCounter,\n lastSaved: new Date().toISOString(),\n };\n atomicWriteJsonFile(STATE_PATH, state);\n } catch (err) {\n logger.error(COMPONENT, `Failed to save state: ${(err as Error).message}`);\n }\n }\n\n // ── Goals ────────────────────────────────────────────────────────────\n\n async getGoals(): Promise<Goal[]> {\n this.loadGoals();\n return [...(this.goalsCache || [])];\n }\n\n async getGoal(id: string): Promise<Goal | undefined> {\n this.loadGoals();\n return this.goalsCache?.find(g => g.id === id);\n }\n\n async saveGoal(goal: Goal): Promise<void> {\n this.loadGoals();\n const goals = this.goalsCache!;\n const idx = goals.findIndex(g => g.id === goal.id);\n if (idx === -1) {\n goals.push(goal);\n } else {\n goals[idx] = goal;\n }\n this.saveGoals();\n }\n\n async deleteGoal(id: string): Promise<boolean> {\n this.loadGoals();\n const goals = this.goalsCache!;\n const idx = goals.findIndex(g => g.id === id);\n if (idx === -1) return false;\n goals.splice(idx, 1);\n this.saveGoals();\n return true;\n }\n\n async saveSubtask(goalId: string, subtask: Subtask): Promise<void> {\n // Subtasks are stored inline on the parent Goal in JSON mode.\n const goal = await this.getGoal(goalId);\n if (!goal) return;\n const idx = goal.subtasks.findIndex(st => st.id === subtask.id);\n if (idx === -1) {\n goal.subtasks.push(subtask);\n } else {\n goal.subtasks[idx] = subtask;\n }\n await this.saveGoal(goal);\n }\n\n // ── Agents ───────────────────────────────────────────────────────────\n\n async getAgents(): Promise<RegisteredAgent[]> {\n this.loadState();\n return Array.from(this.agents.values());\n }\n\n async getAgent(id: string): Promise<RegisteredAgent | undefined> {\n this.loadState();\n return this.agents.get(id);\n }\n\n async saveAgent(agent: RegisteredAgent): Promise<void> {\n this.loadState();\n this.agents.set(agent.id, agent);\n this.saveState();\n }\n\n async deleteAgent(id: string): Promise<boolean> {\n this.loadState();\n const existed = this.agents.has(id);\n this.agents.delete(id);\n if (existed) this.saveState();\n return existed;\n }\n\n // ── Task Checkouts ────────────────────────────────────────────────────\n\n async getCheckouts(): Promise<TaskCheckout[]> {\n this.loadState();\n return Array.from(this.checkouts.values());\n }\n\n async getCheckout(subtaskId: string): Promise<TaskCheckout | undefined> {\n this.loadState();\n return this.checkouts.get(subtaskId);\n }\n\n async saveCheckout(checkout: TaskCheckout): Promise<void> {\n this.loadState();\n this.checkouts.set(checkout.subtaskId, checkout);\n this.saveState();\n }\n\n async deleteCheckout(subtaskId: string): Promise<void> {\n this.loadState();\n this.checkouts.delete(subtaskId);\n this.saveState();\n }\n\n // ── Budget Policies ───────────────────────────────────────────────────\n\n async getBudgetPolicies(): Promise<BudgetPolicy[]> {\n this.loadState();\n return [...this.budgetPolicies];\n }\n\n async getBudgetPolicy(id: string): Promise<BudgetPolicy | undefined> {\n this.loadState();\n return this.budgetPolicies.find(p => p.id === id);\n }\n\n async saveBudgetPolicy(policy: BudgetPolicy): Promise<void> {\n this.loadState();\n const idx = this.budgetPolicies.findIndex(p => p.id === policy.id);\n if (idx === -1) {\n this.budgetPolicies.push(policy);\n } else {\n this.budgetPolicies[idx] = policy;\n }\n this.saveState();\n }\n\n async deleteBudgetPolicy(id: string): Promise<boolean> {\n this.loadState();\n const idx = this.budgetPolicies.findIndex(p => p.id === id);\n if (idx === -1) return false;\n this.budgetPolicies.splice(idx, 1);\n this.saveState();\n return true;\n }\n\n // ── Issues ────────────────────────────────────────────────────────────\n\n async getIssues(): Promise<CPIssue[]> {\n this.loadState();\n return Array.from(this.issues.values());\n }\n\n async getIssue(id: string): Promise<CPIssue | undefined> {\n this.loadState();\n return this.issues.get(id);\n }\n\n async saveIssue(issue: CPIssue): Promise<void> {\n this.loadState();\n this.issues.set(issue.id, issue);\n this.saveState();\n }\n\n async deleteIssue(id: string): Promise<boolean> {\n this.loadState();\n const existed = this.issues.has(id);\n this.issues.delete(id);\n if (existed) this.saveState();\n return existed;\n }\n\n async queryIssues(filters: IssueFilters): Promise<CPIssue[]> {\n this.loadState();\n let result = Array.from(this.issues.values());\n if (filters.status) result = result.filter(i => i.status === filters.status);\n if (filters.assigneeAgentId) result = result.filter(i => i.assigneeAgentId === filters.assigneeAgentId);\n if (filters.goalId) result = result.filter(i => i.goalId === filters.goalId);\n return result.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());\n }\n\n // ── Issue Counter ─────────────────────────────────────────────────────\n\n async getIssueCounter(): Promise<number> {\n this.loadState();\n return this.issueCounter;\n }\n\n async incrementIssueCounter(): Promise<number> {\n this.loadState();\n this.issueCounter++;\n this.saveState();\n return this.issueCounter;\n }\n\n // ── Comments ──────────────────────────────────────────────────────────\n\n async getComments(issueId: string): Promise<CPComment[]> {\n this.loadState();\n return this.comments.filter(c => c.issueId === issueId);\n }\n\n async saveComment(comment: CPComment): Promise<void> {\n this.loadState();\n this.comments.push(comment);\n this.saveState();\n }\n\n // ── Approvals ─────────────────────────────────────────────────────────\n\n async getApprovals(): Promise<CPApproval[]> {\n this.loadState();\n return Array.from(this.approvals.values());\n }\n\n async getApproval(id: string): Promise<CPApproval | undefined> {\n this.loadState();\n return this.approvals.get(id);\n }\n\n async saveApproval(approval: CPApproval): Promise<void> {\n this.loadState();\n this.approvals.set(approval.id, approval);\n this.saveState();\n }\n\n // ── Runs ──────────────────────────────────────────────────────────────\n\n async getRuns(): Promise<CPRun[]> {\n this.loadState();\n return [...this.runs];\n }\n\n async getRun(id: string): Promise<CPRun | undefined> {\n this.loadState();\n return this.runs.find(r => r.id === id);\n }\n\n async saveRun(run: CPRun): Promise<void> {\n this.loadState();\n const idx = this.runs.findIndex(r => r.id === run.id);\n if (idx === -1) {\n this.runs.push(run);\n // Mirror the hard cap from commandPost.ts\n if (this.runs.length > 500) this.runs.splice(0, this.runs.length - 500);\n } else {\n this.runs[idx] = run;\n }\n this.saveState();\n }\n\n async queryRuns(agentId?: string, limit = 50): Promise<CPRun[]> {\n this.loadState();\n let result = [...this.runs];\n if (agentId) result = result.filter(r => r.agentId === agentId);\n return result.slice(-limit).reverse();\n }\n\n // ── Activity ──────────────────────────────────────────────────────────\n\n async appendActivity(entry: ActivityEntry): Promise<void> {\n // In-memory buffer (non-blocking; size managed by CommandPost)\n this.activityBuffer.push(entry);\n // JSONL append — non-critical, same as commandPost.ts original\n try {\n appendFileSync(ACTIVITY_PATH, JSON.stringify(entry) + '\\n', 'utf-8');\n } catch { /* non-critical */ }\n }\n\n async queryActivity(opts: ActivityQueryOpts): Promise<ActivityEntry[]> {\n let entries = [...this.activityBuffer];\n if (opts.type) entries = entries.filter(e => e.type === opts.type);\n if (opts.limit) entries = entries.slice(-opts.limit);\n return entries;\n }\n\n /** Expose internal buffer so CommandPost can manage its own size cap */\n getActivityBuffer(): ActivityEntry[] {\n return this.activityBuffer;\n }\n\n // ── Budget Reservations (no-op in JSON mode) ──────────────────────────\n\n async saveBudgetReservation(_reservation: BudgetReservation): Promise<void> {\n // JSON mode: reservations are not persisted separately.\n // Budget spend is tracked directly on BudgetPolicy.currentSpend.\n }\n\n async getBudgetReservation(_id: string): Promise<BudgetReservation | undefined> {\n return undefined;\n }\n\n // ── Transactions (no-op — event-loop guarantee is sufficient in JSON mode) ─\n\n async beginTransaction(): Promise<Transaction> {\n return {\n async commit() { /* no-op */ },\n async rollback() { /* no-op */ },\n };\n }\n\n // ── Telemetry ─────────────────────────────────────────────────────────\n\n async appendTelemetryEvent(entry: TelemetryEvent): Promise<void> {\n try {\n appendFileSync(TELEMETRY_EVENTS_PATH, JSON.stringify(entry) + '\\n', 'utf-8');\n } catch { /* non-critical */ }\n }\n\n async queryTelemetryEvents(opts: { limit?: number }): Promise<TelemetryEvent[]> {\n const limit = opts.limit ?? 100;\n try {\n if (!existsSync(TELEMETRY_EVENTS_PATH)) return [];\n const raw = readFileSync(TELEMETRY_EVENTS_PATH, 'utf-8');\n const lines = raw.trim().split('\\n').filter(Boolean);\n const events = lines\n .slice(-limit)\n .map((line) => {\n try { return JSON.parse(line) as TelemetryEvent; } catch { return null; }\n })\n .filter((e): e is TelemetryEvent => e !== null);\n return events;\n } catch {\n return [];\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { homedir } from "os";
3
3
  import { join } from "path";
4
- const TITAN_VERSION = "5.4.1";
4
+ const TITAN_VERSION = "5.5.5";
5
5
  const TITAN_CODENAME = "Spacewalk";
6
6
  const TITAN_NAME = "TITAN";
7
7
  const TITAN_FULL_NAME = "The Intelligent Task Automation Network";
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/constants.ts"],"sourcesContent":["/**\n * TITAN Constants\n */\nimport { homedir } from 'os';\nimport { join } from 'path';\n\nexport const TITAN_VERSION = '5.4.1';\nexport const TITAN_CODENAME = 'Spacewalk';\nexport const TITAN_NAME = 'TITAN';\nexport const TITAN_FULL_NAME = 'The Intelligent Task Automation Network';\nexport const TITAN_ASCII_LOGO = `\n╔══════════════════════════════════════════════════════╗\n║ ║\n║ ████████╗██╗████████╗ █████╗ ███╗ ██╗ ║\n║ ██║ ██║ ██║ ██╔══██╗████╗ ██║ ║\n║ ██║ ██║ ██║ ███████║██╔██╗ ██║ ║\n║ ██║ ██║ ██║ ██╔══██║██║╚██╗██║ ║\n║ ██║ ██║ ██║ ██║ ██║██║ ╚████║ ║\n║ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ║\n║ ║\n║ The Intelligent Task Automation Network ║\n║ v${TITAN_VERSION} • by Tony Elliott ║\n╚══════════════════════════════════════════════════════╝`;\n\n// Paths\n// Hunt Finding #03 (2026-04-14): honor TITAN_HOME env var if set.\n// Previously this was hardcoded to `~/.titan`, which meant:\n// - Docker containers couldn't override the config path\n// - Shared machines couldn't isolate per-user state\n// - Test fixtures couldn't run against an isolated home\n// - The systemd unit's `Environment=TITAN_HOME=...` was silently ignored\n// The env var is read once at module load (constants are resolved at import time).\n// If TITAN_HOME starts with `~/`, expand it to the user's home dir.\nfunction resolveTitanHome(): string {\n const envHome = process.env.TITAN_HOME;\n if (envHome && envHome.trim().length > 0) {\n const trimmed = envHome.trim();\n if (trimmed.startsWith('~/')) {\n return join(homedir(), trimmed.slice(2));\n }\n if (trimmed === '~') {\n return homedir();\n }\n return trimmed;\n }\n return join(homedir(), '.titan');\n}\nexport const TITAN_HOME = resolveTitanHome();\nexport const TITAN_CONFIG_PATH = join(TITAN_HOME, 'titan.json');\nexport const TITAN_DB_PATH = join(TITAN_HOME, 'titan.db');\nexport const TITAN_WORKSPACE = join(TITAN_HOME, 'workspace');\nexport const TITAN_SKILLS_DIR = join(TITAN_WORKSPACE, 'skills');\nexport const TITAN_LOGS_DIR = join(TITAN_HOME, 'logs');\nexport const TITAN_MEMORY_DIR = join(TITAN_HOME, 'memory');\n\n// Workspace prompt files (injected into agent context)\nexport const AGENTS_MD = join(TITAN_WORKSPACE, 'AGENTS.md');\nexport const SOUL_MD = join(TITAN_WORKSPACE, 'SOUL.md');\nexport const TOOLS_MD = join(TITAN_WORKSPACE, 'TOOLS.md');\nexport const TITAN_MD_FILENAME = 'TITAN.md';\nexport const AUTOPILOT_MD = join(TITAN_HOME, 'AUTOPILOT.md');\nexport const AUTOPILOT_RUNS_PATH = join(TITAN_HOME, 'autopilot-runs.jsonl');\nexport const TITAN_CREDENTIALS_DIR = join(TITAN_HOME, 'credentials');\n\n// Income & lead tracking\nexport const INCOME_LEDGER_PATH = join(TITAN_HOME, 'income-ledger.jsonl');\nexport const FREELANCE_LEADS_PATH = join(TITAN_HOME, 'freelance-leads.jsonl');\nexport const FREELANCE_PROFILE_PATH = join(TITAN_HOME, 'freelance-profile.json');\nexport const LEADS_PATH = join(TITAN_HOME, 'leads.jsonl');\nexport const TELEMETRY_EVENTS_PATH = join(TITAN_HOME, 'telemetry-events.jsonl');\nexport const SOMADRIVE_STATE_PATH = join(TITAN_HOME, 'soma-drive-state.json');\nexport const ACTIVITY_LOG_PATH = join(TITAN_HOME, 'activity-log.jsonl');\n\n// Gateway defaults\nexport const DEFAULT_GATEWAY_HOST = '0.0.0.0';\nexport const DEFAULT_GATEWAY_PORT = 48420;\nexport const DEFAULT_WEB_PORT = 48421;\n\n// Agent defaults\nexport const DEFAULT_MODEL = 'anthropic/claude-sonnet-4-20250514';\n/** v5.4.1: User-preference ceiling. Providers clamp per-model via\n * clampMaxTokens() so this can be high without causing 400s on\n * capped endpoints (e.g. Claude Sonnet 4 8K, Cohere 4K). */\nexport const DEFAULT_MAX_TOKENS = 200000;\nexport const DEFAULT_TEMPERATURE = 0.7;\nexport const MAX_CONTEXT_MESSAGES = 50;\nexport const SESSION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes\n\n// Security\nexport const DEFAULT_SANDBOX_MODE = 'host';\n/** Default allowed tools. Empty = allow ALL registered tools.\n * Use security.deniedTools to block specific tools instead. */\nexport const ALLOWED_TOOLS_DEFAULT: string[] = [];\nexport const DENIED_TOOLS_DEFAULT: string[] = [];\n"],"mappings":";AAGA,SAAS,eAAe;AACxB,SAAS,YAAY;AAEd,MAAM,gBAAgB;AACtB,MAAM,iBAAiB;AACvB,MAAM,aAAa;AACnB,MAAM,kBAAkB;AACxB,MAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAW1B,aAAa;AAAA;AAYnB,SAAS,mBAA2B;AAChC,QAAM,UAAU,QAAQ,IAAI;AAC5B,MAAI,WAAW,QAAQ,KAAK,EAAE,SAAS,GAAG;AACtC,UAAM,UAAU,QAAQ,KAAK;AAC7B,QAAI,QAAQ,WAAW,IAAI,GAAG;AAC1B,aAAO,KAAK,QAAQ,GAAG,QAAQ,MAAM,CAAC,CAAC;AAAA,IAC3C;AACA,QAAI,YAAY,KAAK;AACjB,aAAO,QAAQ;AAAA,IACnB;AACA,WAAO;AAAA,EACX;AACA,SAAO,KAAK,QAAQ,GAAG,QAAQ;AACnC;AACO,MAAM,aAAa,iBAAiB;AACpC,MAAM,oBAAoB,KAAK,YAAY,YAAY;AACvD,MAAM,gBAAgB,KAAK,YAAY,UAAU;AACjD,MAAM,kBAAkB,KAAK,YAAY,WAAW;AACpD,MAAM,mBAAmB,KAAK,iBAAiB,QAAQ;AACvD,MAAM,iBAAiB,KAAK,YAAY,MAAM;AAC9C,MAAM,mBAAmB,KAAK,YAAY,QAAQ;AAGlD,MAAM,YAAY,KAAK,iBAAiB,WAAW;AACnD,MAAM,UAAU,KAAK,iBAAiB,SAAS;AAC/C,MAAM,WAAW,KAAK,iBAAiB,UAAU;AACjD,MAAM,oBAAoB;AAC1B,MAAM,eAAe,KAAK,YAAY,cAAc;AACpD,MAAM,sBAAsB,KAAK,YAAY,sBAAsB;AACnE,MAAM,wBAAwB,KAAK,YAAY,aAAa;AAG5D,MAAM,qBAAqB,KAAK,YAAY,qBAAqB;AACjE,MAAM,uBAAuB,KAAK,YAAY,uBAAuB;AACrE,MAAM,yBAAyB,KAAK,YAAY,wBAAwB;AACxE,MAAM,aAAa,KAAK,YAAY,aAAa;AACjD,MAAM,wBAAwB,KAAK,YAAY,wBAAwB;AACvE,MAAM,uBAAuB,KAAK,YAAY,uBAAuB;AACrE,MAAM,oBAAoB,KAAK,YAAY,oBAAoB;AAG/D,MAAM,uBAAuB;AAC7B,MAAM,uBAAuB;AAC7B,MAAM,mBAAmB;AAGzB,MAAM,gBAAgB;AAItB,MAAM,qBAAqB;AAC3B,MAAM,sBAAsB;AAC5B,MAAM,uBAAuB;AAC7B,MAAM,qBAAqB,KAAK,KAAK;AAGrC,MAAM,uBAAuB;AAG7B,MAAM,wBAAkC,CAAC;AACzC,MAAM,uBAAiC,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../src/utils/constants.ts"],"sourcesContent":["/**\n * TITAN Constants\n */\nimport { homedir } from 'os';\nimport { join } from 'path';\n\nexport const TITAN_VERSION = '5.5.5';\nexport const TITAN_CODENAME = 'Spacewalk';\nexport const TITAN_NAME = 'TITAN';\nexport const TITAN_FULL_NAME = 'The Intelligent Task Automation Network';\nexport const TITAN_ASCII_LOGO = `\n╔══════════════════════════════════════════════════════╗\n║ ║\n║ ████████╗██╗████████╗ █████╗ ███╗ ██╗ ║\n║ ██║ ██║ ██║ ██╔══██╗████╗ ██║ ║\n║ ██║ ██║ ██║ ███████║██╔██╗ ██║ ║\n║ ██║ ██║ ██║ ██╔══██║██║╚██╗██║ ║\n║ ██║ ██║ ██║ ██║ ██║██║ ╚████║ ║\n║ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ║\n║ ║\n║ The Intelligent Task Automation Network ║\n║ v${TITAN_VERSION} • by Tony Elliott ║\n╚══════════════════════════════════════════════════════╝`;\n\n// Paths\n// Hunt Finding #03 (2026-04-14): honor TITAN_HOME env var if set.\n// Previously this was hardcoded to `~/.titan`, which meant:\n// - Docker containers couldn't override the config path\n// - Shared machines couldn't isolate per-user state\n// - Test fixtures couldn't run against an isolated home\n// - The systemd unit's `Environment=TITAN_HOME=...` was silently ignored\n// The env var is read once at module load (constants are resolved at import time).\n// If TITAN_HOME starts with `~/`, expand it to the user's home dir.\nfunction resolveTitanHome(): string {\n const envHome = process.env.TITAN_HOME;\n if (envHome && envHome.trim().length > 0) {\n const trimmed = envHome.trim();\n if (trimmed.startsWith('~/')) {\n return join(homedir(), trimmed.slice(2));\n }\n if (trimmed === '~') {\n return homedir();\n }\n return trimmed;\n }\n return join(homedir(), '.titan');\n}\nexport const TITAN_HOME = resolveTitanHome();\nexport const TITAN_CONFIG_PATH = join(TITAN_HOME, 'titan.json');\nexport const TITAN_DB_PATH = join(TITAN_HOME, 'titan.db');\nexport const TITAN_WORKSPACE = join(TITAN_HOME, 'workspace');\nexport const TITAN_SKILLS_DIR = join(TITAN_WORKSPACE, 'skills');\nexport const TITAN_LOGS_DIR = join(TITAN_HOME, 'logs');\nexport const TITAN_MEMORY_DIR = join(TITAN_HOME, 'memory');\n\n// Workspace prompt files (injected into agent context)\nexport const AGENTS_MD = join(TITAN_WORKSPACE, 'AGENTS.md');\nexport const SOUL_MD = join(TITAN_WORKSPACE, 'SOUL.md');\nexport const TOOLS_MD = join(TITAN_WORKSPACE, 'TOOLS.md');\nexport const TITAN_MD_FILENAME = 'TITAN.md';\nexport const AUTOPILOT_MD = join(TITAN_HOME, 'AUTOPILOT.md');\nexport const AUTOPILOT_RUNS_PATH = join(TITAN_HOME, 'autopilot-runs.jsonl');\nexport const TITAN_CREDENTIALS_DIR = join(TITAN_HOME, 'credentials');\n\n// Income & lead tracking\nexport const INCOME_LEDGER_PATH = join(TITAN_HOME, 'income-ledger.jsonl');\nexport const FREELANCE_LEADS_PATH = join(TITAN_HOME, 'freelance-leads.jsonl');\nexport const FREELANCE_PROFILE_PATH = join(TITAN_HOME, 'freelance-profile.json');\nexport const LEADS_PATH = join(TITAN_HOME, 'leads.jsonl');\nexport const TELEMETRY_EVENTS_PATH = join(TITAN_HOME, 'telemetry-events.jsonl');\nexport const SOMADRIVE_STATE_PATH = join(TITAN_HOME, 'soma-drive-state.json');\nexport const ACTIVITY_LOG_PATH = join(TITAN_HOME, 'activity-log.jsonl');\n\n// Gateway defaults\nexport const DEFAULT_GATEWAY_HOST = '0.0.0.0';\nexport const DEFAULT_GATEWAY_PORT = 48420;\nexport const DEFAULT_WEB_PORT = 48421;\n\n// Agent defaults\nexport const DEFAULT_MODEL = 'anthropic/claude-sonnet-4-20250514';\n/** v5.4.1: User-preference ceiling. Providers clamp per-model via\n * clampMaxTokens() so this can be high without causing 400s on\n * capped endpoints (e.g. Claude Sonnet 4 8K, Cohere 4K). */\nexport const DEFAULT_MAX_TOKENS = 200000;\nexport const DEFAULT_TEMPERATURE = 0.7;\nexport const MAX_CONTEXT_MESSAGES = 50;\nexport const SESSION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes\n\n// Security\nexport const DEFAULT_SANDBOX_MODE = 'host';\n/** Default allowed tools. Empty = allow ALL registered tools.\n * Use security.deniedTools to block specific tools instead. */\nexport const ALLOWED_TOOLS_DEFAULT: string[] = [];\nexport const DENIED_TOOLS_DEFAULT: string[] = [];\n"],"mappings":";AAGA,SAAS,eAAe;AACxB,SAAS,YAAY;AAEd,MAAM,gBAAgB;AACtB,MAAM,iBAAiB;AACvB,MAAM,aAAa;AACnB,MAAM,kBAAkB;AACxB,MAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAW1B,aAAa;AAAA;AAYnB,SAAS,mBAA2B;AAChC,QAAM,UAAU,QAAQ,IAAI;AAC5B,MAAI,WAAW,QAAQ,KAAK,EAAE,SAAS,GAAG;AACtC,UAAM,UAAU,QAAQ,KAAK;AAC7B,QAAI,QAAQ,WAAW,IAAI,GAAG;AAC1B,aAAO,KAAK,QAAQ,GAAG,QAAQ,MAAM,CAAC,CAAC;AAAA,IAC3C;AACA,QAAI,YAAY,KAAK;AACjB,aAAO,QAAQ;AAAA,IACnB;AACA,WAAO;AAAA,EACX;AACA,SAAO,KAAK,QAAQ,GAAG,QAAQ;AACnC;AACO,MAAM,aAAa,iBAAiB;AACpC,MAAM,oBAAoB,KAAK,YAAY,YAAY;AACvD,MAAM,gBAAgB,KAAK,YAAY,UAAU;AACjD,MAAM,kBAAkB,KAAK,YAAY,WAAW;AACpD,MAAM,mBAAmB,KAAK,iBAAiB,QAAQ;AACvD,MAAM,iBAAiB,KAAK,YAAY,MAAM;AAC9C,MAAM,mBAAmB,KAAK,YAAY,QAAQ;AAGlD,MAAM,YAAY,KAAK,iBAAiB,WAAW;AACnD,MAAM,UAAU,KAAK,iBAAiB,SAAS;AAC/C,MAAM,WAAW,KAAK,iBAAiB,UAAU;AACjD,MAAM,oBAAoB;AAC1B,MAAM,eAAe,KAAK,YAAY,cAAc;AACpD,MAAM,sBAAsB,KAAK,YAAY,sBAAsB;AACnE,MAAM,wBAAwB,KAAK,YAAY,aAAa;AAG5D,MAAM,qBAAqB,KAAK,YAAY,qBAAqB;AACjE,MAAM,uBAAuB,KAAK,YAAY,uBAAuB;AACrE,MAAM,yBAAyB,KAAK,YAAY,wBAAwB;AACxE,MAAM,aAAa,KAAK,YAAY,aAAa;AACjD,MAAM,wBAAwB,KAAK,YAAY,wBAAwB;AACvE,MAAM,uBAAuB,KAAK,YAAY,uBAAuB;AACrE,MAAM,oBAAoB,KAAK,YAAY,oBAAoB;AAG/D,MAAM,uBAAuB;AAC7B,MAAM,uBAAuB;AAC7B,MAAM,mBAAmB;AAGzB,MAAM,gBAAgB;AAItB,MAAM,qBAAqB;AAC3B,MAAM,sBAAsB;AAC5B,MAAM,uBAAuB;AAC7B,MAAM,qBAAqB,KAAK,KAAK;AAGrC,MAAM,uBAAuB;AAG7B,MAAM,wBAAkC,CAAC;AACzC,MAAM,uBAAiC,CAAC;","names":[]}
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync } from "fs";
3
3
  import { dirname } from "path";
4
- function ensureDir(dirPath) {
4
+ function mkdirIfNotExists(dirPath) {
5
5
  if (!existsSync(dirPath)) {
6
6
  mkdirSync(dirPath, { recursive: true });
7
7
  }
8
8
  }
9
+ const ensureDir = mkdirIfNotExists;
9
10
  function readJsonFile(filePath) {
10
11
  try {
11
12
  if (!existsSync(filePath)) return null;
@@ -107,6 +108,7 @@ export {
107
108
  fetchWithRetry,
108
109
  formatBytes,
109
110
  formatDuration,
111
+ mkdirIfNotExists,
110
112
  readJsonFile,
111
113
  shortId,
112
114
  sleep,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/helpers.ts"],"sourcesContent":["/**\n * TITAN Helper Utilities\n */\nimport { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync } from 'fs';\nimport { dirname, join } from 'path';\n\n/** Ensure a directory exists, creating it recursively if needed */\nexport function ensureDir(dirPath: string): void {\n if (!existsSync(dirPath)) {\n mkdirSync(dirPath, { recursive: true });\n }\n}\n\n/** Safely read a JSON file, returning null on failure */\nexport function readJsonFile<T = unknown>(filePath: string): T | null {\n try {\n if (!existsSync(filePath)) return null;\n const content = readFileSync(filePath, 'utf-8');\n return JSON.parse(content) as T;\n } catch {\n return null;\n }\n}\n\n/** Safely write a JSON file, creating parent dirs if needed */\nexport function writeJsonFile(filePath: string, data: unknown): void {\n ensureDir(dirname(filePath));\n writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');\n}\n\n/** Atomic file write — writes to temp file then renames to avoid corruption on crash */\nexport function atomicWriteFileSync(filePath: string, data: string | Buffer): void {\n ensureDir(dirname(filePath));\n const tmpPath = `${filePath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2, 8)}`;\n writeFileSync(tmpPath, data, 'utf-8');\n renameSync(tmpPath, filePath);\n}\n\n/** Atomic JSON file write — uses atomicWriteFileSync internally */\nexport function atomicWriteJsonFile(filePath: string, data: unknown): void {\n atomicWriteFileSync(filePath, JSON.stringify(data, null, 2));\n}\n\n/** Safe string truncation */\nexport function truncate(str: string, maxLength: number): string {\n if (str.length <= maxLength) return str;\n return str.slice(0, maxLength - 3) + '...';\n}\n\n/** Sleep for a given number of milliseconds */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** Generate a short ID */\nexport function shortId(): string {\n return Math.random().toString(36).slice(2, 10);\n}\n\n/** Format bytes into human-readable string */\nexport function formatBytes(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;\n}\n\n/** Format a duration in ms to human-readable */\nexport function formatDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;\n if (ms < 3600000) return `${Math.floor(ms / 60000)}m ${Math.floor((ms % 60000) / 1000)}s`;\n return `${Math.floor(ms / 3600000)}h ${Math.floor((ms % 3600000) / 60000)}m`;\n}\n\n/** Fetch with retry logic and exponential backoff */\nexport async function fetchWithRetry(\n url: string,\n options: RequestInit,\n config?: { maxRetries?: number; initialDelayMs?: number; retryableStatuses?: number[]; timeoutMs?: number }\n): Promise<Response> {\n const maxRetries = config?.maxRetries ?? 3;\n const initialDelay = config?.initialDelayMs ?? 1000;\n const retryable = new Set(config?.retryableStatuses ?? [429, 500, 502, 503]);\n const timeoutMs = config?.timeoutMs ?? 120_000; // 2 minute default timeout\n\n let lastError: Error | null = null;\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n // Apply timeout if caller hasn't already set an AbortSignal\n const fetchOptions = { ...options };\n if (!fetchOptions.signal) {\n fetchOptions.signal = AbortSignal.timeout(timeoutMs);\n }\n const response = await fetch(url, fetchOptions);\n if (!retryable.has(response.status) || attempt === maxRetries) {\n return response;\n }\n // Respect Retry-After header (cap at 30s)\n const retryAfter = response.headers.get('Retry-After');\n const delayMs = retryAfter\n ? Math.min(parseInt(retryAfter, 10) * 1000 || initialDelay, 30000)\n : initialDelay * Math.pow(2, attempt);\n\n // Import logger dynamically to avoid circular deps\n const { default: logger } = await import('../utils/logger.js');\n logger.warn('Retry', `${response.status} from ${url} — retrying in ${delayMs}ms (attempt ${attempt + 1}/${maxRetries})`);\n // Hunt Finding #29 (2026-04-14): consume the intermediate response\n // body before the retry delay so its socket returns to the pool.\n // Without this, every retry-eligible response leaked its socket.\n await response.body?.cancel().catch(() => {});\n await new Promise(r => setTimeout(r, delayMs));\n } catch (err) {\n lastError = err as Error;\n if (attempt === maxRetries) break;\n const delayMs = initialDelay * Math.pow(2, attempt);\n await new Promise(r => setTimeout(r, delayMs));\n }\n }\n throw lastError || new Error('Request failed after retries');\n}\n\n/** Deep merge two objects */\nexport function deepMerge<T extends Record<string, unknown>>(target: T, source: Partial<T>): T {\n const result = { ...target };\n for (const key of Object.keys(source) as Array<keyof T>) {\n const sourceVal = source[key];\n const targetVal = result[key];\n if (\n sourceVal &&\n typeof sourceVal === 'object' &&\n !Array.isArray(sourceVal) &&\n targetVal &&\n typeof targetVal === 'object' &&\n !Array.isArray(targetVal)\n ) {\n result[key] = deepMerge(\n targetVal as Record<string, unknown>,\n sourceVal as Record<string, unknown>,\n ) as T[keyof T];\n } else if (sourceVal !== undefined) {\n result[key] = sourceVal as T[keyof T];\n }\n }\n return result;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/utils/helpers.ts"],"sourcesContent":["/**\n * TITAN Helper Utilities\n */\nimport { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync } from 'fs';\nimport { dirname, join } from 'path';\n\n/** Ensure a directory exists, creating it recursively if needed */\nexport function mkdirIfNotExists(dirPath: string): void {\n if (!existsSync(dirPath)) {\n mkdirSync(dirPath, { recursive: true });\n }\n}\n\n// Backward-compatible alias — deprecated, use mkdirIfNotExists\nexport const ensureDir = mkdirIfNotExists;\n\n/** Safely read a JSON file, returning null on failure */\nexport function readJsonFile<T = unknown>(filePath: string): T | null {\n try {\n if (!existsSync(filePath)) return null;\n const content = readFileSync(filePath, 'utf-8');\n return JSON.parse(content) as T;\n } catch {\n return null;\n }\n}\n\n/** Safely write a JSON file, creating parent dirs if needed */\nexport function writeJsonFile(filePath: string, data: unknown): void {\n ensureDir(dirname(filePath));\n writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');\n}\n\n/** Atomic file write — writes to temp file then renames to avoid corruption on crash */\nexport function atomicWriteFileSync(filePath: string, data: string | Buffer): void {\n ensureDir(dirname(filePath));\n const tmpPath = `${filePath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2, 8)}`;\n writeFileSync(tmpPath, data, 'utf-8');\n renameSync(tmpPath, filePath);\n}\n\n/** Atomic JSON file write — uses atomicWriteFileSync internally */\nexport function atomicWriteJsonFile(filePath: string, data: unknown): void {\n atomicWriteFileSync(filePath, JSON.stringify(data, null, 2));\n}\n\n/** Safe string truncation */\nexport function truncate(str: string, maxLength: number): string {\n if (str.length <= maxLength) return str;\n return str.slice(0, maxLength - 3) + '...';\n}\n\n/** Sleep for a given number of milliseconds */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** Generate a short ID */\nexport function shortId(): string {\n return Math.random().toString(36).slice(2, 10);\n}\n\n/** Format bytes into human-readable string */\nexport function formatBytes(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;\n}\n\n/** Format a duration in ms to human-readable */\nexport function formatDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;\n if (ms < 3600000) return `${Math.floor(ms / 60000)}m ${Math.floor((ms % 60000) / 1000)}s`;\n return `${Math.floor(ms / 3600000)}h ${Math.floor((ms % 3600000) / 60000)}m`;\n}\n\n/** Fetch with retry logic and exponential backoff */\nexport async function fetchWithRetry(\n url: string,\n options: RequestInit,\n config?: { maxRetries?: number; initialDelayMs?: number; retryableStatuses?: number[]; timeoutMs?: number }\n): Promise<Response> {\n const maxRetries = config?.maxRetries ?? 3;\n const initialDelay = config?.initialDelayMs ?? 1000;\n const retryable = new Set(config?.retryableStatuses ?? [429, 500, 502, 503]);\n const timeoutMs = config?.timeoutMs ?? 120_000; // 2 minute default timeout\n\n let lastError: Error | null = null;\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n // Apply timeout if caller hasn't already set an AbortSignal\n const fetchOptions = { ...options };\n if (!fetchOptions.signal) {\n fetchOptions.signal = AbortSignal.timeout(timeoutMs);\n }\n const response = await fetch(url, fetchOptions);\n if (!retryable.has(response.status) || attempt === maxRetries) {\n return response;\n }\n // Respect Retry-After header (cap at 30s)\n const retryAfter = response.headers.get('Retry-After');\n const delayMs = retryAfter\n ? Math.min(parseInt(retryAfter, 10) * 1000 || initialDelay, 30000)\n : initialDelay * Math.pow(2, attempt);\n\n // Import logger dynamically to avoid circular deps\n const { default: logger } = await import('../utils/logger.js');\n logger.warn('Retry', `${response.status} from ${url} — retrying in ${delayMs}ms (attempt ${attempt + 1}/${maxRetries})`);\n // Hunt Finding #29 (2026-04-14): consume the intermediate response\n // body before the retry delay so its socket returns to the pool.\n // Without this, every retry-eligible response leaked its socket.\n await response.body?.cancel().catch(() => {});\n await new Promise(r => setTimeout(r, delayMs));\n } catch (err) {\n lastError = err as Error;\n if (attempt === maxRetries) break;\n const delayMs = initialDelay * Math.pow(2, attempt);\n await new Promise(r => setTimeout(r, delayMs));\n }\n }\n throw lastError || new Error('Request failed after retries');\n}\n\n/** Deep merge two objects */\nexport function deepMerge<T extends Record<string, unknown>>(target: T, source: Partial<T>): T {\n const result = { ...target };\n for (const key of Object.keys(source) as Array<keyof T>) {\n const sourceVal = source[key];\n const targetVal = result[key];\n if (\n sourceVal &&\n typeof sourceVal === 'object' &&\n !Array.isArray(sourceVal) &&\n targetVal &&\n typeof targetVal === 'object' &&\n !Array.isArray(targetVal)\n ) {\n result[key] = deepMerge(\n targetVal as Record<string, unknown>,\n sourceVal as Record<string, unknown>,\n ) as T[keyof T];\n } else if (sourceVal !== undefined) {\n result[key] = sourceVal as T[keyof T];\n }\n }\n return result;\n}\n"],"mappings":";AAGA,SAAS,YAAY,WAAW,cAAc,eAAe,kBAAkB;AAC/E,SAAS,eAAqB;AAGvB,SAAS,iBAAiB,SAAuB;AACpD,MAAI,CAAC,WAAW,OAAO,GAAG;AACtB,cAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AAAA,EAC1C;AACJ;AAGO,MAAM,YAAY;AAGlB,SAAS,aAA0B,UAA4B;AAClE,MAAI;AACA,QAAI,CAAC,WAAW,QAAQ,EAAG,QAAO;AAClC,UAAM,UAAU,aAAa,UAAU,OAAO;AAC9C,WAAO,KAAK,MAAM,OAAO;AAAA,EAC7B,QAAQ;AACJ,WAAO;AAAA,EACX;AACJ;AAGO,SAAS,cAAc,UAAkB,MAAqB;AACjE,YAAU,QAAQ,QAAQ,CAAC;AAC3B,gBAAc,UAAU,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG,OAAO;AAClE;AAGO,SAAS,oBAAoB,UAAkB,MAA6B;AAC/E,YAAU,QAAQ,QAAQ,CAAC;AAC3B,QAAM,UAAU,GAAG,QAAQ,QAAQ,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AACvF,gBAAc,SAAS,MAAM,OAAO;AACpC,aAAW,SAAS,QAAQ;AAChC;AAGO,SAAS,oBAAoB,UAAkB,MAAqB;AACvE,sBAAoB,UAAU,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAC/D;AAGO,SAAS,SAAS,KAAa,WAA2B;AAC7D,MAAI,IAAI,UAAU,UAAW,QAAO;AACpC,SAAO,IAAI,MAAM,GAAG,YAAY,CAAC,IAAI;AACzC;AAGO,SAAS,MAAM,IAA2B;AAC7C,SAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAC3D;AAGO,SAAS,UAAkB;AAC9B,SAAO,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE;AACjD;AAGO,SAAS,YAAY,OAAuB;AAC/C,MAAI,UAAU,EAAG,QAAO;AACxB,QAAM,IAAI;AACV,QAAM,QAAQ,CAAC,KAAK,MAAM,MAAM,IAAI;AACpC,QAAM,IAAI,KAAK,MAAM,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC;AAClD,SAAO,GAAG,YAAY,QAAQ,KAAK,IAAI,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC;AACzE;AAGO,SAAS,eAAe,IAAoB;AAC/C,MAAI,KAAK,IAAM,QAAO,GAAG,EAAE;AAC3B,MAAI,KAAK,IAAO,QAAO,IAAI,KAAK,KAAM,QAAQ,CAAC,CAAC;AAChD,MAAI,KAAK,KAAS,QAAO,GAAG,KAAK,MAAM,KAAK,GAAK,CAAC,KAAK,KAAK,MAAO,KAAK,MAAS,GAAI,CAAC;AACtF,SAAO,GAAG,KAAK,MAAM,KAAK,IAAO,CAAC,KAAK,KAAK,MAAO,KAAK,OAAW,GAAK,CAAC;AAC7E;AAGA,eAAsB,eAClB,KACA,SACA,QACiB;AACjB,QAAM,aAAa,QAAQ,cAAc;AACzC,QAAM,eAAe,QAAQ,kBAAkB;AAC/C,QAAM,YAAY,IAAI,IAAI,QAAQ,qBAAqB,CAAC,KAAK,KAAK,KAAK,GAAG,CAAC;AAC3E,QAAM,YAAY,QAAQ,aAAa;AAEvC,MAAI,YAA0B;AAC9B,WAAS,UAAU,GAAG,WAAW,YAAY,WAAW;AACpD,QAAI;AAEA,YAAM,eAAe,EAAE,GAAG,QAAQ;AAClC,UAAI,CAAC,aAAa,QAAQ;AACtB,qBAAa,SAAS,YAAY,QAAQ,SAAS;AAAA,MACvD;AACA,YAAM,WAAW,MAAM,MAAM,KAAK,YAAY;AAC9C,UAAI,CAAC,UAAU,IAAI,SAAS,MAAM,KAAK,YAAY,YAAY;AAC3D,eAAO;AAAA,MACX;AAEA,YAAM,aAAa,SAAS,QAAQ,IAAI,aAAa;AACrD,YAAM,UAAU,aACV,KAAK,IAAI,SAAS,YAAY,EAAE,IAAI,OAAQ,cAAc,GAAK,IAC/D,eAAe,KAAK,IAAI,GAAG,OAAO;AAGxC,YAAM,EAAE,SAAS,OAAO,IAAI,MAAM,OAAO,oBAAoB;AAC7D,aAAO,KAAK,SAAS,GAAG,SAAS,MAAM,SAAS,GAAG,uBAAkB,OAAO,eAAe,UAAU,CAAC,IAAI,UAAU,GAAG;AAIvH,YAAM,SAAS,MAAM,OAAO,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAC5C,YAAM,IAAI,QAAQ,OAAK,WAAW,GAAG,OAAO,CAAC;AAAA,IACjD,SAAS,KAAK;AACV,kBAAY;AACZ,UAAI,YAAY,WAAY;AAC5B,YAAM,UAAU,eAAe,KAAK,IAAI,GAAG,OAAO;AAClD,YAAM,IAAI,QAAQ,OAAK,WAAW,GAAG,OAAO,CAAC;AAAA,IACjD;AAAA,EACJ;AACA,QAAM,aAAa,IAAI,MAAM,8BAA8B;AAC/D;AAGO,SAAS,UAA6C,QAAW,QAAuB;AAC3F,QAAM,SAAS,EAAE,GAAG,OAAO;AAC3B,aAAW,OAAO,OAAO,KAAK,MAAM,GAAqB;AACrD,UAAM,YAAY,OAAO,GAAG;AAC5B,UAAM,YAAY,OAAO,GAAG;AAC5B,QACI,aACA,OAAO,cAAc,YACrB,CAAC,MAAM,QAAQ,SAAS,KACxB,aACA,OAAO,cAAc,YACrB,CAAC,MAAM,QAAQ,SAAS,GAC1B;AACE,aAAO,GAAG,IAAI;AAAA,QACV;AAAA,QACA;AAAA,MACJ;AAAA,IACJ,WAAW,cAAc,QAAW;AAChC,aAAO,GAAG,IAAI;AAAA,IAClB;AAAA,EACJ;AACA,SAAO;AACX;","names":[]}