titan-agent 5.4.2 → 5.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/agent/agent.js +9 -5
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/agentLoop.js +7 -3
- package/dist/agent/agentLoop.js.map +1 -1
- package/dist/agent/checkpoint.js +2 -2
- package/dist/agent/checkpoint.js.map +1 -1
- package/dist/agent/commandPost.js +3 -3
- package/dist/agent/commandPost.js.map +1 -1
- package/dist/agent/goalProposer.js +2 -2
- package/dist/agent/goalProposer.js.map +1 -1
- package/dist/agent/goals.js +3 -3
- package/dist/agent/goals.js.map +1 -1
- package/dist/agent/peerAdvise.js +1 -1
- package/dist/agent/peerAdvise.js.map +1 -1
- package/dist/agent/planner.js +4 -4
- package/dist/agent/planner.js.map +1 -1
- package/dist/agent/userProfile.js +2 -2
- package/dist/agent/userProfile.js.map +1 -1
- package/dist/cli/doctor.js +33 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/onboard.js +4 -4
- package/dist/cli/onboard.js.map +1 -1
- package/dist/config/config.js +3 -3
- package/dist/config/config.js.map +1 -1
- package/dist/config/schema.js +8 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/gateway/routes/adminRouter.js +500 -0
- package/dist/gateway/routes/adminRouter.js.map +1 -0
- package/dist/gateway/routes/agents.js +231 -0
- package/dist/gateway/routes/agents.js.map +1 -0
- package/dist/gateway/routes/agentsRouter.js +32 -0
- package/dist/gateway/routes/agentsRouter.js.map +1 -0
- package/dist/gateway/routes/checkpoints.js +41 -0
- package/dist/gateway/routes/checkpoints.js.map +1 -0
- package/dist/gateway/routes/commandPost.js +755 -0
- package/dist/gateway/routes/commandPost.js.map +1 -0
- package/dist/gateway/routes/companies.js +166 -0
- package/dist/gateway/routes/companies.js.map +1 -0
- package/dist/gateway/routes/files.js +295 -0
- package/dist/gateway/routes/files.js.map +1 -0
- package/dist/gateway/routes/hardwareRouter.js +151 -0
- package/dist/gateway/routes/hardwareRouter.js.map +1 -0
- package/dist/gateway/routes/mcpRouter.js +88 -0
- package/dist/gateway/routes/mcpRouter.js.map +1 -0
- package/dist/gateway/routes/mesh.js +464 -0
- package/dist/gateway/routes/mesh.js.map +1 -0
- package/dist/gateway/routes/metricsRouter.js +131 -0
- package/dist/gateway/routes/metricsRouter.js.map +1 -0
- package/dist/gateway/routes/organism.js +82 -0
- package/dist/gateway/routes/organism.js.map +1 -0
- package/dist/gateway/routes/paperclip.js +101 -0
- package/dist/gateway/routes/paperclip.js.map +1 -0
- package/dist/gateway/routes/sessions.js +227 -0
- package/dist/gateway/routes/sessions.js.map +1 -0
- package/dist/gateway/routes/skills.js +295 -0
- package/dist/gateway/routes/skills.js.map +1 -0
- package/dist/gateway/routes/socialRouter.js +145 -0
- package/dist/gateway/routes/socialRouter.js.map +1 -0
- package/dist/gateway/routes/systemRouter.js +220 -0
- package/dist/gateway/routes/systemRouter.js.map +1 -0
- package/dist/gateway/routes/teamsRecipes.js +297 -0
- package/dist/gateway/routes/teamsRecipes.js.map +1 -0
- package/dist/gateway/routes/tests.js +401 -0
- package/dist/gateway/routes/tests.js.map +1 -0
- package/dist/gateway/routes/traces.js +33 -0
- package/dist/gateway/routes/traces.js.map +1 -0
- package/dist/gateway/routes/voiceRouter.js +770 -0
- package/dist/gateway/routes/voiceRouter.js.map +1 -0
- package/dist/gateway/routes/watchRouter.js +131 -0
- package/dist/gateway/routes/watchRouter.js.map +1 -0
- package/dist/gateway/server.js +1179 -7379
- package/dist/gateway/server.js.map +1 -1
- package/dist/mcp/registry.js +2 -2
- package/dist/mcp/registry.js.map +1 -1
- package/dist/memory/episodic.js +2 -2
- package/dist/memory/episodic.js.map +1 -1
- package/dist/memory/learning.js +3 -3
- package/dist/memory/learning.js.map +1 -1
- package/dist/memory/memory.js +3 -3
- package/dist/memory/memory.js.map +1 -1
- package/dist/organism/drives.js +2 -2
- package/dist/organism/drives.js.map +1 -1
- package/dist/providers/errorTaxonomy.js +13 -0
- package/dist/providers/errorTaxonomy.js.map +1 -1
- package/dist/providers/ollama.js +3 -1
- package/dist/providers/ollama.js.map +1 -1
- package/dist/providers/openai_compat.js +4 -3
- package/dist/providers/openai_compat.js.map +1 -1
- package/dist/providers/router.js +13 -0
- package/dist/providers/router.js.map +1 -1
- package/dist/safety/fixOscillation.js +15 -0
- package/dist/safety/fixOscillation.js.map +1 -1
- package/dist/safety/killSwitch.js +2 -2
- package/dist/safety/killSwitch.js.map +1 -1
- package/dist/safety/selfRepair.js +7 -3
- package/dist/safety/selfRepair.js.map +1 -1
- package/dist/skills/builtin/agent_debate.js +2 -2
- package/dist/skills/builtin/agent_debate.js.map +1 -1
- package/dist/skills/builtin/apply_patch.js +3 -3
- package/dist/skills/builtin/apply_patch.js.map +1 -1
- package/dist/skills/builtin/shell.js +2 -2
- package/dist/skills/builtin/shell.js.map +1 -1
- package/dist/skills/builtin/voice_control.js +49 -0
- package/dist/skills/builtin/voice_control.js.map +1 -0
- package/dist/skills/builtin/widget_gallery.js +6 -1
- package/dist/skills/builtin/widget_gallery.js.map +1 -1
- package/dist/skills/registry.js +15 -4
- package/dist/skills/registry.js.map +1 -1
- package/dist/storage/JsonStorage.js +4 -4
- package/dist/storage/JsonStorage.js.map +1 -1
- package/dist/utils/constants.js +1 -1
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/helpers.js +3 -1
- package/dist/utils/helpers.js.map +1 -1
- package/dist/utils/lifecycle.js +86 -0
- package/dist/utils/lifecycle.js.map +1 -0
- package/dist/voice/bridge.js +136 -0
- package/dist/voice/bridge.js.map +1 -0
- package/docs/COO-MASTER-PLAN-2026-05-02.md +474 -0
- package/docs/HANDOFF/2026-04-29.md +141 -0
- package/docs/HANDOFF-2026-04-30.md +144 -0
- package/docs/HANDOFF-2026-05-03.md +114 -0
- package/docs/adr/2026-04-29-widget-pipeline-traceability.md +49 -0
- package/docs/agent-memory/README.md +45 -0
- package/docs/agent-memory/commands.md +100 -0
- package/docs/agent-memory/context-tree.md +101 -0
- package/docs/agent-memory/current-state.md +54 -0
- package/docs/agent-memory/decisions.md +78 -0
- package/docs/agent-memory/known-issues.md +76 -0
- package/docs/agent-memory/reflections.md +52 -0
- package/docs/agent-memory/skills-candidates.md +80 -0
- package/docs/superpowers/plans/2026-04-29-comprehensive-audit.md +256 -0
- package/docs/superpowers/plans/2026-04-29-comprehensive-test-plan.md +396 -0
- package/docs/superpowers/plans/2026-04-29-fix-all-prs.md +251 -0
- package/docs/superpowers/plans/2026-04-29-gitnexus-gap-remediation.md +969 -0
- package/package.json +5 -2
- package/ui/dist/assets/{AuditPanel-CM6Wg9hO.js → AuditPanel-VzSndmDN.js} +2 -2
- package/ui/dist/assets/{AutonomyPanel-CESx3ANg.js → AutonomyPanel-BiFouzAV.js} +2 -2
- package/ui/dist/assets/AutopilotPanel-fjOfM668.js +1 -0
- package/ui/dist/assets/{AutoresearchPanel-DR47NqT5.js → AutoresearchPanel-CVCxzAH3.js} +2 -2
- package/ui/dist/assets/BackupPanel-CHVTG--q.js +1 -0
- package/ui/dist/assets/{BrowserPanel-C15x9bLn.js → BrowserPanel-D5mvMKFU.js} +2 -2
- package/ui/dist/assets/CPActivity-B12mt35m.js +1 -0
- package/ui/dist/assets/CPAgentDetail-DsdShc-1.js +1 -0
- package/ui/dist/assets/CPAgents-j_7C-oQV.js +1 -0
- package/ui/dist/assets/CPApprovals-BShKSX9X.js +1 -0
- package/ui/dist/assets/CPCosts-CKPlhBDs.js +1 -0
- package/ui/dist/assets/CPDashboard-11c0nkxK.js +1 -0
- package/ui/dist/assets/CPFiles-BhLEOnXy.js +1 -0
- package/ui/dist/assets/CPGoals-Bi3t1b2P.js +1 -0
- package/ui/dist/assets/CPInbox-Bbr7khp6.js +11 -0
- package/ui/dist/assets/CPIssueDetail-DSdgNK8r.js +1 -0
- package/ui/dist/assets/CPIssues-DDEVKhX6.js +1 -0
- package/ui/dist/assets/CPLayout-DgPOfyGv.js +17 -0
- package/ui/dist/assets/CPOrg-Df73RrRJ.js +8 -0
- package/ui/dist/assets/CPRuns-ByioAz8w.js +1 -0
- package/ui/dist/assets/{CPSocial-nb-j7sOE.js → CPSocial-Dlnr_w1X.js} +2 -2
- package/ui/dist/assets/ChannelsPanel-DQjQCTK5.js +1 -0
- package/ui/dist/assets/CheckpointsPanel-C4vKjlAJ.js +1 -0
- package/ui/dist/assets/CommandPostHub-C9pp5Giq.js +24 -0
- package/ui/dist/assets/CronPanel-C6bzUfrD.js +1 -0
- package/ui/dist/assets/DaemonPanel-BA5Tb_UO.js +1 -0
- package/ui/dist/assets/{DataTable-B2Ma8hfi.js → DataTable-CH7IYJJh.js} +1 -1
- package/ui/dist/assets/{EmptyState-CcKyk5Yn.js → EmptyState-jU6yNDnF.js} +1 -1
- package/ui/dist/assets/{EvalHarnessPanel-BqtMc1ZM.js → EvalHarnessPanel-DnYqredY.js} +2 -2
- package/ui/dist/assets/EvalPanel-ChO7CD1r.js +1 -0
- package/ui/dist/assets/{FilesPanel-3QKvrWPo.js → FilesPanel-CaUkv2is.js} +2 -2
- package/ui/dist/assets/FleetPanel-DC_5uj0N.js +1 -0
- package/ui/dist/assets/{HomelabPanel-DhrjTX9m.js → HomelabPanel-CE5PGRpL.js} +2 -2
- package/ui/dist/assets/InfraView-C-uSlvb9.js +2 -0
- package/ui/dist/assets/InlineEditableField-BMQjiE6-.js +1 -0
- package/ui/dist/assets/Input-Bu_b3qmY.js +1 -0
- package/ui/dist/assets/IntegrationsPanel-DsYpAq43.js +1 -0
- package/ui/dist/assets/IntelligenceView-DUdIO1K7.js +2 -0
- package/ui/dist/assets/LearningPanel-UpQZC-mA.js +1 -0
- package/ui/dist/assets/LogsPanel-ClXJ4fcr.js +1 -0
- package/ui/dist/assets/McpPanel-JKgtIERQ.js +1 -0
- package/ui/dist/assets/{MemoryGraphPanel-Bzvjmzvk.js → MemoryGraphPanel-Bo2OrvA6.js} +2 -2
- package/ui/dist/assets/MemoryWikiPanel-BqJ1AmYm.js +11 -0
- package/ui/dist/assets/{MeshPanel-C3LJSlht.js → MeshPanel-BJVGYvwk.js} +2 -2
- package/ui/dist/assets/Modal-CAAooiZU.js +1 -0
- package/ui/dist/assets/NvidiaPanel-BtCg3G4w.js +1 -0
- package/ui/dist/assets/OrganismPanel-DgrTTzcF.js +1 -0
- package/ui/dist/assets/OverviewPanel-rVav1Hox.js +1 -0
- package/ui/dist/assets/{PageHeader-BimceqQo.js → PageHeader-CnZtP8ek.js} +1 -1
- package/ui/dist/assets/PaperclipPanel-C-FKdhiF.js +1 -0
- package/ui/dist/assets/{PersonasPanel-L1j78p6H.js → PersonasPanel-BmlxokfB.js} +1 -1
- package/ui/dist/assets/RecipesPanel-BNKKChis.js +1 -0
- package/ui/dist/assets/SecurityPanel-I7JRHiNy.js +1 -0
- package/ui/dist/assets/SelfImprovePanel-u9h0Lt3p.js +1 -0
- package/ui/dist/assets/{SelfProposalsPanel-lNmiDThB.js → SelfProposalsPanel-DKl9iBjM.js} +2 -2
- package/ui/dist/assets/SessionsPanel-BhRiWI_g.js +1 -0
- package/ui/dist/assets/{SessionsTab-JQbltWww.js → SessionsTab-Bk08wyeY.js} +1 -1
- package/ui/dist/assets/SettingsPanel-haLfmG2k.js +1 -0
- package/ui/dist/assets/SettingsView--gi3fxI8.js +2 -0
- package/ui/dist/assets/{SkeletonLoader-atQtpcF5.js → SkeletonLoader-B5v09EF_.js} +1 -1
- package/ui/dist/assets/{SkillsPanel-DlFs2ih7.js → SkillsPanel-BlAHFLcQ.js} +1 -1
- package/ui/dist/assets/SomaView-CExtS3zw.js +5 -0
- package/ui/dist/assets/{StatCard-DciE_Iqc.js → StatCard-BIsyMybM.js} +1 -1
- package/ui/dist/assets/{StatusBadge-BtfSPoW2.js → StatusBadge-D5nU7El8.js} +1 -1
- package/ui/dist/assets/Tabs-BBYZrBI8.js +1 -0
- package/ui/dist/assets/TeamsPanel-LPXJg823.js +1 -0
- package/ui/dist/assets/TelemetryPanel-EqpRBmOI.js +1 -0
- package/ui/dist/assets/TitanCanvas-BCbWnLMd.js +985 -0
- package/ui/dist/assets/ToolsView-CeP0Zz-N.js +2 -0
- package/ui/dist/assets/{Tooltip-70UK0E2I.js → Tooltip-BSO2XVpF.js} +1 -1
- package/ui/dist/assets/TraceViewer-BKI7o5B0.js +1 -0
- package/ui/dist/assets/TrainingPanel-c-RhjdE1.js +1 -0
- package/ui/dist/assets/VoiceOverlay-D-gc58b0.js +27 -0
- package/ui/dist/assets/VramPanel-C6xc7zgd.js +1 -0
- package/ui/dist/assets/{WatchView-C-sGFpVy.js → WatchView-dqBVCVH0.js} +1 -1
- package/ui/dist/assets/WorkTab-CBoLNrTM.js +1 -0
- package/ui/dist/assets/{WorkflowsPanel-CvgQU1xI.js → WorkflowsPanel-BAnSTOYe.js} +2 -2
- package/ui/dist/assets/approvalHeadline-DB9SgR-9.js +1 -0
- package/ui/dist/assets/{arrow-left-DwqHtJiU.js → arrow-left-5chqas7J.js} +1 -1
- package/ui/dist/assets/briefcase-D4vLzudp.js +6 -0
- package/ui/dist/assets/{chart-column-BtNO6sRy.js → chart-column-CdFlBpoP.js} +1 -1
- package/ui/dist/assets/check-Bpm1IONe.js +6 -0
- package/ui/dist/assets/chevron-down-D7OLjvuD.js +6 -0
- package/ui/dist/assets/chevron-right-aQEw2mUW.js +6 -0
- package/ui/dist/assets/chevron-up-C5g6pEj8.js +6 -0
- package/ui/dist/assets/{circle-check-big-DZRE_MbN.js → circle-check-big-fPhEdP88.js} +1 -1
- package/ui/dist/assets/clock-CTsgP_Sn.js +6 -0
- package/ui/dist/assets/{dollar-sign-aVG3a5eL.js → dollar-sign-CudFVYFc.js} +1 -1
- package/ui/dist/assets/{download-BxiWJU4G.js → download-DZRxDn67.js} +1 -1
- package/ui/dist/assets/external-link-BZ0y_Ahx.js +6 -0
- package/ui/dist/assets/{eye-off-CkgfFYhm.js → eye-off-BmJF0YYx.js} +1 -1
- package/ui/dist/assets/folder-DA43TRCm.js +11 -0
- package/ui/dist/assets/{funnel-PkLdxKyC.js → funnel-J3mULzrz.js} +1 -1
- package/ui/dist/assets/{git-branch-BM-Gw95X.js → git-branch-oHibJqDq.js} +1 -1
- package/ui/dist/assets/{index-D0RJ8701.css → index-BR0vfkIi.css} +1 -1
- package/ui/dist/assets/{index-CahJbWSR.js → index-DzwowwSI.js} +20 -20
- package/ui/dist/assets/{layers-BuGf4FIJ.js → layers-DsyEyu7z.js} +1 -1
- package/ui/dist/assets/{legacy-CR6o4t-y.js → legacy-8ITl64sV.js} +1 -1
- package/ui/dist/assets/{lightbulb-n8gc_XAL.js → lightbulb-C54Ske-p.js} +1 -1
- package/ui/dist/assets/list-todo-Cnd4rdoK.js +6 -0
- package/ui/dist/assets/loader-circle-1YOBsoQp.js +6 -0
- package/ui/dist/assets/network-DbGDAdrn.js +6 -0
- package/ui/dist/assets/{pause-DCV52koX.js → pause-CYhO_uQo.js} +1 -1
- package/ui/dist/assets/{play-CcJ9BnCh.js → play-DVY9c5Ck.js} +1 -1
- package/ui/dist/assets/{plug-CfWBXfCl.js → plug-BcXjlPUL.js} +1 -1
- package/ui/dist/assets/plus-Csu2v9GN.js +6 -0
- package/ui/dist/assets/{proxy-CzZDfLmm.js → proxy-DxS2_9D7.js} +1 -1
- package/ui/dist/assets/rotate-ccw-Co-_W04j.js +6 -0
- package/ui/dist/assets/save-Btx-kpoW.js +6 -0
- package/ui/dist/assets/search-0hXTwEZR.js +6 -0
- package/ui/dist/assets/send-TEpapzQR.js +6 -0
- package/ui/dist/assets/shield-check-DjBJXZUr.js +6 -0
- package/ui/dist/assets/{square-DJpUhlxi.js → square-OweUvjP-.js} +1 -1
- package/ui/dist/assets/{target-DWcmM_9m.js → target-BRW80Xer.js} +1 -1
- package/ui/dist/assets/terminal-BtiqJ628.js +16 -0
- package/ui/dist/assets/{toggle-right-YusFQ69L.js → toggle-right-CKtSrl28.js} +1 -1
- package/ui/dist/assets/{trash-2-CK7yQ55V.js → trash-2-DgWrHVax.js} +1 -1
- package/ui/dist/assets/{trending-up-DGjFyubC.js → trending-up-MpIrE4j6.js} +1 -1
- package/ui/dist/assets/{trophy-uQv_NgDB.js → trophy-CECuZNhX.js} +1 -1
- package/ui/dist/assets/users-dZgv4ePG.js +16 -0
- package/ui/dist/assets/wrench-CDz3xYve.js +11 -0
- package/ui/dist/index.html +2 -2
- package/ui/dist/assets/AutopilotPanel-DtEet1hJ.js +0 -1
- package/ui/dist/assets/BackupPanel-BGP8p3l3.js +0 -1
- package/ui/dist/assets/CPAgents-DYUtPzSq.js +0 -1
- package/ui/dist/assets/CPDashboard-Bf0-SyCh.js +0 -6
- package/ui/dist/assets/CPFiles-CxgxjQcO.js +0 -1
- package/ui/dist/assets/CPGoals-BsmCMTvT.js +0 -1
- package/ui/dist/assets/CPInbox-tMSbmQ9H.js +0 -11
- package/ui/dist/assets/ChannelsPanel-DP5C2OKd.js +0 -1
- package/ui/dist/assets/CheckpointsPanel-DlranVLZ.js +0 -1
- package/ui/dist/assets/CommandPostHub-BgxIa4Ev.js +0 -29
- package/ui/dist/assets/CronPanel-LoT5yKwJ.js +0 -1
- package/ui/dist/assets/DaemonPanel-DBGMqaE_.js +0 -1
- package/ui/dist/assets/EvalPanel-Bc33j0pN.js +0 -1
- package/ui/dist/assets/FleetPanel-CSsXuQYj.js +0 -1
- package/ui/dist/assets/InfraView-CR6HyrL6.js +0 -2
- package/ui/dist/assets/InlineEditableField-CnvF-yFR.js +0 -1
- package/ui/dist/assets/Input-GTHp2Rkr.js +0 -1
- package/ui/dist/assets/IntegrationsPanel-CymCRE3T.js +0 -1
- package/ui/dist/assets/IntelligenceView-C1IHxJRC.js +0 -2
- package/ui/dist/assets/LearningPanel-DOCES3lH.js +0 -1
- package/ui/dist/assets/LogsPanel-BLnAqEaZ.js +0 -1
- package/ui/dist/assets/McpPanel-ChUzmr3z.js +0 -1
- package/ui/dist/assets/MemoryWikiPanel-Dwk3Aqwd.js +0 -11
- package/ui/dist/assets/NvidiaPanel-CeZK_-CV.js +0 -1
- package/ui/dist/assets/OrganismPanel-BB6YOiQV.js +0 -1
- package/ui/dist/assets/OverviewPanel-BmtBhQnv.js +0 -1
- package/ui/dist/assets/PaperclipPanel-C-brgwA3.js +0 -1
- package/ui/dist/assets/RecipesPanel-34lCfynJ.js +0 -1
- package/ui/dist/assets/SecurityPanel-CBTPWLj6.js +0 -1
- package/ui/dist/assets/SelfImprovePanel-BrPbFHhG.js +0 -1
- package/ui/dist/assets/SessionsPanel-DAEYIn83.js +0 -1
- package/ui/dist/assets/SettingsPanel-CzRROAYQ.js +0 -1
- package/ui/dist/assets/SettingsView-CN7ii2uw.js +0 -2
- package/ui/dist/assets/SomaView-Ba642Oqb.js +0 -5
- package/ui/dist/assets/TeamsPanel-DKQ5z2Qe.js +0 -1
- package/ui/dist/assets/TelemetryPanel-B6KAc55Q.js +0 -1
- package/ui/dist/assets/TitanCanvas-C-s0A-lv.js +0 -1092
- package/ui/dist/assets/ToolsView-Dei0KMP0.js +0 -2
- package/ui/dist/assets/TraceViewer-BniolyBx.js +0 -1
- package/ui/dist/assets/TrainingPanel-Bz4CTPGW.js +0 -1
- package/ui/dist/assets/VoiceOverlay-CmNCrLcd.js +0 -37
- package/ui/dist/assets/VramPanel-Xh_OtRDR.js +0 -1
- package/ui/dist/assets/WorkTab-BjLNmgIK.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/agent/userProfile.ts"],"sourcesContent":["/**\n * TITAN — User Skill Profile Manager\n * Tracks tool usage, skill level, preferences, and correction history.\n * Profile persisted to ~/.titan/user-profile.json.\n */\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { TITAN_HOME } from '../utils/constants.js';\nimport { readJsonFile, writeJsonFile,
|
|
1
|
+
{"version":3,"sources":["../../src/agent/userProfile.ts"],"sourcesContent":["/**\n * TITAN — User Skill Profile Manager\n * Tracks tool usage, skill level, preferences, and correction history.\n * Profile persisted to ~/.titan/user-profile.json.\n */\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { TITAN_HOME } from '../utils/constants.js';\nimport { readJsonFile, writeJsonFile, mkdirIfNotExists } from '../utils/helpers.js';\nimport logger from '../utils/logger.js';\n\nconst COMPONENT = 'UserProfile';\nconst PROFILE_PATH = join(TITAN_HOME, 'user-profile.json');\n\nexport interface Correction {\n context: string;\n correction: string;\n timestamp: number;\n}\n\nexport interface UserProfile {\n /** Frequency map of tool name → usage count */\n toolUsage: Record<string, number>;\n /** Overall skill level derived from usage patterns */\n skillLevel: 'beginner' | 'intermediate' | 'advanced';\n /** User preferences (use case, display name, etc.) */\n preferences: Record<string, string>;\n /** History of user corrections for learning */\n corrections: Correction[];\n /** Whether first-run wizard has been completed */\n firstRunCompleted: boolean;\n /** ISO timestamp of profile creation */\n createdAt: string;\n /** ISO timestamp of last update */\n updatedAt: string;\n}\n\nfunction createDefaultProfile(): UserProfile {\n return {\n toolUsage: {},\n skillLevel: 'beginner',\n preferences: {},\n corrections: [],\n firstRunCompleted: false,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n}\n\nlet cachedProfile: UserProfile | null = null;\n\n/** Load user profile from disk, creating default if missing */\nexport function loadProfile(): UserProfile {\n if (cachedProfile) return cachedProfile;\n\n mkdirIfNotExists(TITAN_HOME);\n\n if (existsSync(PROFILE_PATH)) {\n const loaded = readJsonFile<UserProfile>(PROFILE_PATH);\n if (loaded) {\n cachedProfile = loaded;\n logger.debug(COMPONENT, 'Loaded user profile');\n return cachedProfile;\n }\n }\n\n cachedProfile = createDefaultProfile();\n saveProfile(cachedProfile);\n logger.info(COMPONENT, 'Created new user profile');\n return cachedProfile;\n}\n\n/** Save user profile to disk */\nexport function saveProfile(profile: UserProfile): void {\n profile.updatedAt = new Date().toISOString();\n writeJsonFile(PROFILE_PATH, profile);\n cachedProfile = profile;\n}\n\n/** Record a tool usage event */\nexport function recordToolUsage(toolName: string): void {\n const profile = loadProfile();\n profile.toolUsage[toolName] = (profile.toolUsage[toolName] || 0) + 1;\n profile.skillLevel = deriveSkillLevel(profile);\n saveProfile(profile);\n}\n\n/** Record a user correction for future reference */\nexport function recordCorrection(context: string, correction: string): void {\n const profile = loadProfile();\n profile.corrections.push({\n context,\n correction,\n timestamp: Date.now(),\n });\n // Keep last 100 corrections\n if (profile.corrections.length > 100) {\n profile.corrections = profile.corrections.slice(-100);\n }\n saveProfile(profile);\n}\n\n/** Derive skill level from total tool usage */\nexport function deriveSkillLevel(profile: UserProfile): UserProfile['skillLevel'] {\n const totalUsage = Object.values(profile.toolUsage).reduce((a, b) => a + b, 0);\n const uniqueTools = Object.keys(profile.toolUsage).length;\n\n if (totalUsage >= 200 && uniqueTools >= 15) return 'advanced';\n if (totalUsage >= 50 && uniqueTools >= 8) return 'intermediate';\n return 'beginner';\n}\n\n/** Get current skill level */\nexport function getSkillLevel(): UserProfile['skillLevel'] {\n return loadProfile().skillLevel;\n}\n\n/** Get top N most-used tools */\nexport function getTopTools(n: number = 5): Array<{ name: string; count: number }> {\n const profile = loadProfile();\n return Object.entries(profile.toolUsage)\n .sort(([, a], [, b]) => b - a)\n .slice(0, n)\n .map(([name, count]) => ({ name, count }));\n}\n\n/** Check if this is the first run */\nexport function isFirstRun(): boolean {\n return !loadProfile().firstRunCompleted;\n}\n\n/** Mark first-run wizard as completed */\nexport function completeFirstRun(): void {\n const profile = loadProfile();\n profile.firstRunCompleted = true;\n saveProfile(profile);\n}\n\n/** Clear cached profile (for testing) */\nexport function clearCache(): void {\n cachedProfile = null;\n}\n"],"mappings":";AAKA,SAAS,kBAAkB;AAC3B,SAAS,YAAY;AACrB,SAAS,kBAAkB;AAC3B,SAAS,cAAc,eAAe,wBAAwB;AAC9D,OAAO,YAAY;AAEnB,MAAM,YAAY;AAClB,MAAM,eAAe,KAAK,YAAY,mBAAmB;AAyBzD,SAAS,uBAAoC;AACzC,SAAO;AAAA,IACH,WAAW,CAAC;AAAA,IACZ,YAAY;AAAA,IACZ,aAAa,CAAC;AAAA,IACd,aAAa,CAAC;AAAA,IACd,mBAAmB;AAAA,IACnB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,EACtC;AACJ;AAEA,IAAI,gBAAoC;AAGjC,SAAS,cAA2B;AACvC,MAAI,cAAe,QAAO;AAE1B,mBAAiB,UAAU;AAE3B,MAAI,WAAW,YAAY,GAAG;AAC1B,UAAM,SAAS,aAA0B,YAAY;AACrD,QAAI,QAAQ;AACR,sBAAgB;AAChB,aAAO,MAAM,WAAW,qBAAqB;AAC7C,aAAO;AAAA,IACX;AAAA,EACJ;AAEA,kBAAgB,qBAAqB;AACrC,cAAY,aAAa;AACzB,SAAO,KAAK,WAAW,0BAA0B;AACjD,SAAO;AACX;AAGO,SAAS,YAAY,SAA4B;AACpD,UAAQ,aAAY,oBAAI,KAAK,GAAE,YAAY;AAC3C,gBAAc,cAAc,OAAO;AACnC,kBAAgB;AACpB;AAGO,SAAS,gBAAgB,UAAwB;AACpD,QAAM,UAAU,YAAY;AAC5B,UAAQ,UAAU,QAAQ,KAAK,QAAQ,UAAU,QAAQ,KAAK,KAAK;AACnE,UAAQ,aAAa,iBAAiB,OAAO;AAC7C,cAAY,OAAO;AACvB;AAGO,SAAS,iBAAiB,SAAiB,YAA0B;AACxE,QAAM,UAAU,YAAY;AAC5B,UAAQ,YAAY,KAAK;AAAA,IACrB;AAAA,IACA;AAAA,IACA,WAAW,KAAK,IAAI;AAAA,EACxB,CAAC;AAED,MAAI,QAAQ,YAAY,SAAS,KAAK;AAClC,YAAQ,cAAc,QAAQ,YAAY,MAAM,IAAI;AAAA,EACxD;AACA,cAAY,OAAO;AACvB;AAGO,SAAS,iBAAiB,SAAiD;AAC9E,QAAM,aAAa,OAAO,OAAO,QAAQ,SAAS,EAAE,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC;AAC7E,QAAM,cAAc,OAAO,KAAK,QAAQ,SAAS,EAAE;AAEnD,MAAI,cAAc,OAAO,eAAe,GAAI,QAAO;AACnD,MAAI,cAAc,MAAM,eAAe,EAAG,QAAO;AACjD,SAAO;AACX;AAGO,SAAS,gBAA2C;AACvD,SAAO,YAAY,EAAE;AACzB;AAGO,SAAS,YAAY,IAAY,GAA2C;AAC/E,QAAM,UAAU,YAAY;AAC5B,SAAO,OAAO,QAAQ,QAAQ,SAAS,EAClC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,EAC5B,MAAM,GAAG,CAAC,EACV,IAAI,CAAC,CAAC,MAAM,KAAK,OAAO,EAAE,MAAM,MAAM,EAAE;AACjD;AAGO,SAAS,aAAsB;AAClC,SAAO,CAAC,YAAY,EAAE;AAC1B;AAGO,SAAS,mBAAyB;AACrC,QAAM,UAAU,YAAY;AAC5B,UAAQ,oBAAoB;AAC5B,cAAY,OAAO;AACvB;AAGO,SAAS,aAAmB;AAC/B,kBAAgB;AACpB;","names":[]}
|
package/dist/cli/doctor.js
CHANGED
|
@@ -141,6 +141,39 @@ async function runDoctor(options) {
|
|
|
141
141
|
});
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
|
+
const modelStr = config.agent.model || "";
|
|
145
|
+
const knownProviderPrefixes = [
|
|
146
|
+
"ollama/",
|
|
147
|
+
"anthropic/",
|
|
148
|
+
"openai/",
|
|
149
|
+
"google/",
|
|
150
|
+
"groq/",
|
|
151
|
+
"mistral/",
|
|
152
|
+
"openrouter/",
|
|
153
|
+
"xai/",
|
|
154
|
+
"together/",
|
|
155
|
+
"deepseek/",
|
|
156
|
+
"fireworks/",
|
|
157
|
+
"cerebras/",
|
|
158
|
+
"cohere/",
|
|
159
|
+
"perplexity/",
|
|
160
|
+
"azure/",
|
|
161
|
+
"openai_compat/"
|
|
162
|
+
];
|
|
163
|
+
const hasProviderPrefix = knownProviderPrefixes.some((p) => modelStr.startsWith(p));
|
|
164
|
+
if (!hasProviderPrefix && modelStr) {
|
|
165
|
+
checks.push({
|
|
166
|
+
name: "Model resolution",
|
|
167
|
+
status: "warn",
|
|
168
|
+
message: `"${modelStr}" has no provider prefix (e.g. ollama/${modelStr}). TITAN will try to auto-detect the provider but may fail at runtime. Add a provider prefix to avoid ambiguity.`
|
|
169
|
+
});
|
|
170
|
+
} else if (hasProviderPrefix) {
|
|
171
|
+
checks.push({
|
|
172
|
+
name: "Model resolution",
|
|
173
|
+
status: "pass",
|
|
174
|
+
message: `${modelStr} (provider prefix detected)`
|
|
175
|
+
});
|
|
176
|
+
}
|
|
144
177
|
} catch (error) {
|
|
145
178
|
checks.push({
|
|
146
179
|
name: "Config validation",
|
package/dist/cli/doctor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/doctor.ts"],"sourcesContent":["/**\n * TITAN -- Doctor Diagnostic Tool\n * Checks system health, configuration, connectivity, and dependencies.\n * Supports --fix flag to auto-heal detected issues via selfHeal.ts.\n * Supports --json flag for machine-readable output.\n */\nimport chalk from 'chalk';\nimport { existsSync, readdirSync, statSync } from 'fs';\nimport { join } from 'path';\nimport { loadConfig, configExists } from '../config/config.js';\nimport { TITAN_HOME, TITAN_CONFIG_PATH, TITAN_DB_PATH, TITAN_WORKSPACE, TITAN_VERSION, TITAN_LOGS_DIR } from '../utils/constants.js';\nimport { healthCheckAll } from '../providers/router.js';\nimport { auditSecurity } from '../security/sandbox.js';\nimport { getStallStats } from '../agent/stallDetector.js';\nimport {\n fixMissingTitanHome,\n fixMissingConfig,\n fixInvalidConfig,\n fixMissingWorkspace,\n fixBrokenChannelConfig,\n fixPermissions,\n fixStaleLogFiles,\n fixOrphanedSessions,\n type HealResult,\n} from './selfHeal.js';\n\ninterface CheckResult {\n name: string;\n status: 'pass' | 'warn' | 'fail';\n message: string;\n /** Key used to map to an auto-fix function */\n fixKey?: string;\n}\n\n/** Fetch weekly npm download count for a package */\nasync function fetchNpmDownloads(packageName: string): Promise<number | null> {\n try {\n const response = await fetch(`https://api.npmjs.org/downloads/point/last-week/${packageName}`, {\n signal: AbortSignal.timeout(5000),\n });\n if (!response.ok) return null;\n const data = await response.json() as { downloads?: number };\n return data.downloads ?? null;\n } catch {\n return null;\n }\n}\n\nexport interface DoctorReport {\n version: string;\n timestamp: string;\n checks: CheckResult[];\n summary: { pass: number; warn: number; fail: number };\n npm?: { weeklyDownloads: number | null };\n fixes?: HealResult[];\n}\n\nexport async function runDoctor(options?: { fix?: boolean; json?: boolean; dryRun?: boolean }): Promise<DoctorReport> {\n const autoFix = options?.fix ?? false;\n const dryRun = options?.dryRun ?? false;\n const jsonOutput = options?.json ?? false;\n\n if (!jsonOutput) {\n console.log(chalk.cyan(`\\n🩺 TITAN Doctor v${TITAN_VERSION}\\n`));\n console.log(chalk.gray('Running diagnostics...\\n'));\n }\n\n const checks: CheckResult[] = [];\n const healResults: HealResult[] = [];\n\n // 1. Node.js version\n const nodeVersion = process.versions.node;\n const [major] = nodeVersion.split('.').map(Number);\n checks.push({\n name: 'Node.js version',\n status: major >= 20 ? 'pass' : major >= 18 ? 'warn' : 'fail',\n message: `v${nodeVersion} ${major >= 20 ? '(recommended)' : major >= 18 ? '(minimum, upgrade recommended)' : '(too old, need >= 20)'}`,\n });\n\n // 2. TITAN home directory\n checks.push({\n name: 'TITAN home directory',\n status: existsSync(TITAN_HOME) ? 'pass' : 'warn',\n message: existsSync(TITAN_HOME) ? TITAN_HOME : `Not found: ${TITAN_HOME} (run: titan onboard)`,\n fixKey: 'titanHome',\n });\n\n // 3. Configuration file\n checks.push({\n name: 'Configuration file',\n status: configExists() ? 'pass' : 'warn',\n message: configExists() ? TITAN_CONFIG_PATH : `Not found (run: titan onboard)`,\n fixKey: 'config',\n });\n\n // 4. Database (lazily created — not having one on a fresh install is normal)\n checks.push({\n name: 'Database',\n status: 'pass',\n message: existsSync(TITAN_DB_PATH) ? TITAN_DB_PATH : 'Will be created on first use (this is normal)',\n });\n\n // 5. Workspace\n checks.push({\n name: 'Workspace directory',\n status: existsSync(TITAN_WORKSPACE) ? 'pass' : 'warn',\n message: existsSync(TITAN_WORKSPACE) ? TITAN_WORKSPACE : `Not found (run: titan onboard)`,\n fixKey: 'workspace',\n });\n\n // 6. AI Provider connectivity\n if (configExists()) {\n if (!jsonOutput) console.log(chalk.gray(' Checking AI providers...'));\n try {\n const config = loadConfig();\n const providerHealth = await healthCheckAll();\n for (const [name, healthy] of Object.entries(providerHealth)) {\n let message = 'Reachable';\n if (!healthy) {\n // Provide actionable error messages for missing API keys\n const providerConfig = (config.providers as Record<string, Record<string, unknown>>)?.[name];\n const hasApiKey = !!(providerConfig?.apiKey);\n const envVarMap: Record<string, string> = {\n anthropic: 'ANTHROPIC_API_KEY', openai: 'OPENAI_API_KEY',\n google: 'GOOGLE_API_KEY', groq: 'GROQ_API_KEY',\n mistral: 'MISTRAL_API_KEY', openrouter: 'OPENROUTER_API_KEY',\n xai: 'XAI_API_KEY', together: 'TOGETHER_API_KEY',\n deepseek: 'DEEPSEEK_API_KEY', fireworks: 'FIREWORKS_API_KEY',\n cerebras: 'CEREBRAS_API_KEY', cohere: 'COHERE_API_KEY',\n perplexity: 'PERPLEXITY_API_KEY', azure: 'AZURE_OPENAI_API_KEY',\n };\n const envVar = envVarMap[name];\n const hasEnvVar = envVar ? !!process.env[envVar] : false;\n\n if (name === 'ollama') {\n const baseUrl = (providerConfig?.baseUrl as string) || 'http://localhost:11434';\n message = `Unreachable at ${baseUrl} — is Ollama running?`;\n } else if (!hasApiKey && !hasEnvVar) {\n message = envVar\n ? `No API key — set ${envVar} or add providers.${name}.apiKey to ~/.titan/titan.json`\n : `No API key — add providers.${name}.apiKey to ~/.titan/titan.json`;\n } else {\n message = 'API key set but provider unreachable — check key validity or network';\n }\n }\n checks.push({\n name: `Provider: ${name}`,\n status: healthy ? 'pass' : 'warn',\n message,\n });\n }\n } catch (error) {\n checks.push({\n name: 'AI Providers',\n status: 'warn',\n message: `Could not check: ${(error as Error).message}`,\n });\n }\n }\n\n // 7. Configuration validation\n if (configExists()) {\n try {\n const config = loadConfig();\n checks.push({\n name: 'Config validation',\n status: 'pass',\n message: `Model: ${config.agent.model}`,\n });\n\n // Check channel configuration\n for (const [channelName, channelConfig] of Object.entries(config.channels)) {\n if (channelConfig.enabled) {\n const hasToken = !!(channelConfig.token || channelConfig.apiKey);\n checks.push({\n name: `Channel: ${channelName}`,\n status: hasToken ? 'pass' : 'fail',\n message: hasToken ? 'Configured' : 'Enabled but no token set',\n fixKey: 'channels',\n });\n }\n }\n } catch (error) {\n checks.push({\n name: 'Config validation',\n status: 'fail',\n message: (error as Error).message,\n fixKey: 'invalidConfig',\n });\n }\n }\n\n // 8. Cloudflare Tunnel (when enabled)\n if (configExists()) {\n try {\n const cfg = loadConfig();\n if (cfg.tunnel?.enabled) {\n let tunnelAvailable = false;\n try {\n const { execSync } = await import('child_process');\n execSync('cloudflared --version', { stdio: 'ignore' });\n tunnelAvailable = true;\n } catch {\n // not installed\n }\n checks.push({\n name: 'Cloudflare Tunnel (cloudflared)',\n status: tunnelAvailable ? 'pass' : 'fail',\n message: tunnelAvailable ? 'cloudflared binary found' : 'cloudflared not installed (https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/)',\n });\n }\n } catch {\n // config load failed — handled elsewhere\n }\n }\n\n // 9. Security audit\n if (configExists()) {\n const securityIssues = auditSecurity();\n for (const issue of securityIssues) {\n checks.push({\n name: 'Security',\n status: issue.level === 'error' ? 'fail' : issue.level === 'warn' ? 'warn' : 'pass',\n message: issue.message,\n });\n }\n }\n\n // 9. Disk space\n try {\n const { execSync } = await import('child_process');\n const dfOutput = execSync('df -h / | tail -1', { encoding: 'utf-8' });\n const parts = dfOutput.trim().split(/\\s+/);\n const available = parts[3];\n const usePercent = parts.length >= 5 ? parseInt(parts[4], 10) : NaN;\n checks.push({\n name: 'Disk space',\n status: isNaN(usePercent) ? 'warn' : usePercent < 90 ? 'pass' : usePercent < 95 ? 'warn' : 'fail',\n message: isNaN(usePercent) ? 'Could not parse disk usage' : `${available} available (${parts[4]} used)`,\n });\n } catch {\n checks.push({ name: 'Disk space', status: 'warn', message: 'Could not check' });\n }\n\n // 10. Memory\n const memUsage = process.memoryUsage();\n const rssGB = (memUsage.rss / 1024 / 1024).toFixed(1);\n checks.push({\n name: 'Memory usage',\n status: 'pass',\n message: `${rssGB} MB RSS`,\n });\n\n // 11. Stall Detector Status\n const stallStatus = getStallStats();\n let stallStatusLevel: 'pass' | 'warn' | 'fail' = 'pass';\n let stallMessage = 'Healthy (0 active stalls)';\n\n // getStallStats returns an array of session stats\n const activeStalls = stallStatus.length;\n if (activeStalls > 0) {\n stallStatusLevel = activeStalls > 2 ? 'fail' : 'warn';\n stallMessage = `Detected ${activeStalls} stuck sessions.`;\n }\n checks.push({\n name: 'Agent Stall Status',\n status: stallStatusLevel,\n message: stallMessage,\n });\n\n // 12. Stale sessions check\n const sessionsDir = join(TITAN_HOME, 'sessions');\n if (existsSync(sessionsDir)) {\n try {\n const sessionFiles = readdirSync(sessionsDir);\n const oneDayAgo = Date.now() - 24 * 60 * 60 * 1000;\n let staleCount = 0;\n for (const file of sessionFiles) {\n const fullPath = join(sessionsDir, file);\n try {\n const stat = statSync(fullPath);\n if (stat.isFile() && stat.mtimeMs < oneDayAgo) {\n staleCount++;\n }\n } catch {\n // skip unreadable files\n }\n }\n checks.push({\n name: 'Stale sessions',\n status: staleCount > 0 ? 'warn' : 'pass',\n message: staleCount > 0 ? `${staleCount} session file(s) older than 24 hours` : 'No stale sessions',\n fixKey: 'staleSessions',\n });\n } catch {\n checks.push({ name: 'Stale sessions', status: 'warn', message: 'Could not read sessions directory' });\n }\n } else {\n checks.push({ name: 'Stale sessions', status: 'pass', message: 'No sessions directory' });\n }\n\n // 13. Log directory size check\n if (existsSync(TITAN_LOGS_DIR)) {\n try {\n const logFiles = readdirSync(TITAN_LOGS_DIR);\n let totalBytes = 0;\n for (const file of logFiles) {\n const fullPath = join(TITAN_LOGS_DIR, file);\n try {\n const stat = statSync(fullPath);\n if (stat.isFile()) {\n totalBytes += stat.size;\n }\n } catch {\n // skip unreadable files\n }\n }\n const totalMB = totalBytes / (1024 * 1024);\n checks.push({\n name: 'Log directory size',\n status: totalMB > 100 ? 'warn' : 'pass',\n message: totalMB > 100\n ? `${totalMB.toFixed(1)} MB (consider rotating logs)`\n : `${totalMB.toFixed(1)} MB`,\n fixKey: totalMB > 100 ? 'staleLogs' : undefined,\n });\n } catch {\n checks.push({ name: 'Log directory size', status: 'warn', message: 'Could not check log directory' });\n }\n } else {\n checks.push({ name: 'Log directory size', status: 'pass', message: 'No logs directory' });\n }\n\n // 14. Permissions check\n checks.push({\n name: 'TITAN home permissions',\n status: existsSync(TITAN_HOME) ? 'pass' : 'warn',\n message: existsSync(TITAN_HOME) ? 'Exists' : 'Cannot check (TITAN_HOME missing)',\n fixKey: 'permissions',\n });\n\n // 15. npm download count\n if (!jsonOutput) console.log(chalk.gray(' Checking npm downloads...'));\n const npmDownloads = await fetchNpmDownloads('titan-agent');\n if (npmDownloads !== null) {\n checks.push({\n name: 'npm weekly downloads',\n status: 'pass',\n message: `${npmDownloads.toLocaleString()} downloads/week (titan-agent)`,\n });\n } else {\n checks.push({\n name: 'npm weekly downloads',\n status: 'warn',\n message: 'Could not fetch npm download stats',\n });\n }\n\n // Auto-fix pass if --fix was specified\n if (autoFix) {\n if (dryRun) {\n if (!jsonOutput) console.log(chalk.cyan('\\n 🔧 Dry run — showing fixes that WOULD be applied:\\n'));\n } else {\n if (!jsonOutput) console.log(chalk.cyan('\\n 🔧 Running auto-fix...\\n'));\n }\n\n const issueChecks = checks.filter((c) => (c.status === 'warn' || c.status === 'fail') && c.fixKey);\n const fixKeysNeeded = new Set(issueChecks.map((c) => c.fixKey!));\n\n const fixMap: Record<string, () => HealResult> = {\n titanHome: fixMissingTitanHome,\n config: fixMissingConfig,\n invalidConfig: fixInvalidConfig,\n workspace: fixMissingWorkspace,\n channels: fixBrokenChannelConfig,\n permissions: fixPermissions,\n staleLogs: fixStaleLogFiles,\n staleSessions: fixOrphanedSessions,\n };\n\n const fixDescriptions: Record<string, string> = {\n titanHome: 'Create TITAN home directory',\n config: 'Create default configuration file',\n invalidConfig: 'Reset invalid configuration to defaults',\n workspace: 'Create workspace directory',\n channels: 'Disable misconfigured channels',\n permissions: 'Fix file permissions on TITAN home',\n staleLogs: 'Clean up stale log files',\n staleSessions: 'Remove orphaned session files',\n };\n\n if (dryRun) {\n for (const key of fixKeysNeeded) {\n if (fixMap[key]) {\n const description = fixDescriptions[key] ?? key;\n healResults.push({ action: key, success: true, message: `[dry-run] Would fix: ${description}` });\n if (!jsonOutput) {\n console.log(` ${chalk.yellow('⏭')} ${key}: ${chalk.gray(`Would fix: ${description}`)}`);\n }\n }\n }\n\n if (!jsonOutput) {\n console.log(chalk.cyan(`\\n 🔧 Dry run complete — ${fixKeysNeeded.size} fix(es) would be applied. Run without --dry-run to apply.`));\n }\n } else {\n for (const key of fixKeysNeeded) {\n const fixFn = fixMap[key];\n if (fixFn) {\n const result = fixFn();\n healResults.push(result);\n if (!jsonOutput) {\n const icon = result.success ? chalk.green('✅') : chalk.red('❌');\n console.log(` ${icon} ${result.action}: ${chalk.gray(result.message)}`);\n }\n }\n }\n\n if (!jsonOutput) {\n const fixedCount = healResults.filter((r) => r.success).length;\n const remainingCount = healResults.filter((r) => !r.success).length;\n console.log(chalk.cyan(`\\n 🔧 ${fixedCount} issues auto-fixed, ${remainingCount} remaining`));\n }\n }\n }\n\n const passCount = checks.filter((c) => c.status === 'pass').length;\n const warnCount = checks.filter((c) => c.status === 'warn').length;\n const failCount = checks.filter((c) => c.status === 'fail').length;\n\n // Build the report\n const report: DoctorReport = {\n version: TITAN_VERSION,\n timestamp: new Date().toISOString(),\n checks,\n summary: { pass: passCount, warn: warnCount, fail: failCount },\n npm: { weeklyDownloads: npmDownloads },\n };\n if (healResults.length > 0) {\n report.fixes = healResults;\n }\n\n // Output\n if (jsonOutput) {\n console.log(JSON.stringify(report, null, 2));\n } else {\n // Print results\n console.log('');\n const statusIcons = { pass: chalk.green('✅'), warn: chalk.yellow('⚠️ '), fail: chalk.red('❌') };\n for (const check of checks) {\n console.log(` ${statusIcons[check.status]} ${chalk.white(check.name)}: ${chalk.gray(check.message)}`);\n }\n\n console.log(`\\n ${chalk.green(`${passCount} passed`)} | ${chalk.yellow(`${warnCount} warnings`)} | ${chalk.red(`${failCount} failed`)}`);\n\n if (failCount > 0) {\n console.log(chalk.red('\\n ⚠️ Some checks failed. Run `titan doctor --fix` or `titan onboard` to fix common issues.\\n'));\n } else if (warnCount > 0) {\n console.log(chalk.yellow('\\n ℹ️ Some warnings found. Run `titan doctor --fix` to auto-fix or review the items above.\\n'));\n } else {\n console.log(chalk.green('\\n 🎉 All checks passed! TITAN is healthy.\\n'));\n }\n }\n\n return report;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/doctor.ts"],"sourcesContent":["/**\n * TITAN -- Doctor Diagnostic Tool\n * Checks system health, configuration, connectivity, and dependencies.\n * Supports --fix flag to auto-heal detected issues via selfHeal.ts.\n * Supports --json flag for machine-readable output.\n */\nimport chalk from 'chalk';\nimport { existsSync, readdirSync, statSync } from 'fs';\nimport { join } from 'path';\nimport { loadConfig, configExists } from '../config/config.js';\nimport { TITAN_HOME, TITAN_CONFIG_PATH, TITAN_DB_PATH, TITAN_WORKSPACE, TITAN_VERSION, TITAN_LOGS_DIR } from '../utils/constants.js';\nimport { healthCheckAll } from '../providers/router.js';\nimport { auditSecurity } from '../security/sandbox.js';\nimport { getStallStats } from '../agent/stallDetector.js';\nimport {\n fixMissingTitanHome,\n fixMissingConfig,\n fixInvalidConfig,\n fixMissingWorkspace,\n fixBrokenChannelConfig,\n fixPermissions,\n fixStaleLogFiles,\n fixOrphanedSessions,\n type HealResult,\n} from './selfHeal.js';\n\ninterface CheckResult {\n name: string;\n status: 'pass' | 'warn' | 'fail';\n message: string;\n /** Key used to map to an auto-fix function */\n fixKey?: string;\n}\n\n/** Fetch weekly npm download count for a package */\nasync function fetchNpmDownloads(packageName: string): Promise<number | null> {\n try {\n const response = await fetch(`https://api.npmjs.org/downloads/point/last-week/${packageName}`, {\n signal: AbortSignal.timeout(5000),\n });\n if (!response.ok) return null;\n const data = await response.json() as { downloads?: number };\n return data.downloads ?? null;\n } catch {\n return null;\n }\n}\n\nexport interface DoctorReport {\n version: string;\n timestamp: string;\n checks: CheckResult[];\n summary: { pass: number; warn: number; fail: number };\n npm?: { weeklyDownloads: number | null };\n fixes?: HealResult[];\n}\n\nexport async function runDoctor(options?: { fix?: boolean; json?: boolean; dryRun?: boolean }): Promise<DoctorReport> {\n const autoFix = options?.fix ?? false;\n const dryRun = options?.dryRun ?? false;\n const jsonOutput = options?.json ?? false;\n\n if (!jsonOutput) {\n console.log(chalk.cyan(`\\n🩺 TITAN Doctor v${TITAN_VERSION}\\n`));\n console.log(chalk.gray('Running diagnostics...\\n'));\n }\n\n const checks: CheckResult[] = [];\n const healResults: HealResult[] = [];\n\n // 1. Node.js version\n const nodeVersion = process.versions.node;\n const [major] = nodeVersion.split('.').map(Number);\n checks.push({\n name: 'Node.js version',\n status: major >= 20 ? 'pass' : major >= 18 ? 'warn' : 'fail',\n message: `v${nodeVersion} ${major >= 20 ? '(recommended)' : major >= 18 ? '(minimum, upgrade recommended)' : '(too old, need >= 20)'}`,\n });\n\n // 2. TITAN home directory\n checks.push({\n name: 'TITAN home directory',\n status: existsSync(TITAN_HOME) ? 'pass' : 'warn',\n message: existsSync(TITAN_HOME) ? TITAN_HOME : `Not found: ${TITAN_HOME} (run: titan onboard)`,\n fixKey: 'titanHome',\n });\n\n // 3. Configuration file\n checks.push({\n name: 'Configuration file',\n status: configExists() ? 'pass' : 'warn',\n message: configExists() ? TITAN_CONFIG_PATH : `Not found (run: titan onboard)`,\n fixKey: 'config',\n });\n\n // 4. Database (lazily created — not having one on a fresh install is normal)\n checks.push({\n name: 'Database',\n status: 'pass',\n message: existsSync(TITAN_DB_PATH) ? TITAN_DB_PATH : 'Will be created on first use (this is normal)',\n });\n\n // 5. Workspace\n checks.push({\n name: 'Workspace directory',\n status: existsSync(TITAN_WORKSPACE) ? 'pass' : 'warn',\n message: existsSync(TITAN_WORKSPACE) ? TITAN_WORKSPACE : `Not found (run: titan onboard)`,\n fixKey: 'workspace',\n });\n\n // 6. AI Provider connectivity\n if (configExists()) {\n if (!jsonOutput) console.log(chalk.gray(' Checking AI providers...'));\n try {\n const config = loadConfig();\n const providerHealth = await healthCheckAll();\n for (const [name, healthy] of Object.entries(providerHealth)) {\n let message = 'Reachable';\n if (!healthy) {\n // Provide actionable error messages for missing API keys\n const providerConfig = (config.providers as Record<string, Record<string, unknown>>)?.[name];\n const hasApiKey = !!(providerConfig?.apiKey);\n const envVarMap: Record<string, string> = {\n anthropic: 'ANTHROPIC_API_KEY', openai: 'OPENAI_API_KEY',\n google: 'GOOGLE_API_KEY', groq: 'GROQ_API_KEY',\n mistral: 'MISTRAL_API_KEY', openrouter: 'OPENROUTER_API_KEY',\n xai: 'XAI_API_KEY', together: 'TOGETHER_API_KEY',\n deepseek: 'DEEPSEEK_API_KEY', fireworks: 'FIREWORKS_API_KEY',\n cerebras: 'CEREBRAS_API_KEY', cohere: 'COHERE_API_KEY',\n perplexity: 'PERPLEXITY_API_KEY', azure: 'AZURE_OPENAI_API_KEY',\n };\n const envVar = envVarMap[name];\n const hasEnvVar = envVar ? !!process.env[envVar] : false;\n\n if (name === 'ollama') {\n const baseUrl = (providerConfig?.baseUrl as string) || 'http://localhost:11434';\n message = `Unreachable at ${baseUrl} — is Ollama running?`;\n } else if (!hasApiKey && !hasEnvVar) {\n message = envVar\n ? `No API key — set ${envVar} or add providers.${name}.apiKey to ~/.titan/titan.json`\n : `No API key — add providers.${name}.apiKey to ~/.titan/titan.json`;\n } else {\n message = 'API key set but provider unreachable — check key validity or network';\n }\n }\n checks.push({\n name: `Provider: ${name}`,\n status: healthy ? 'pass' : 'warn',\n message,\n });\n }\n } catch (error) {\n checks.push({\n name: 'AI Providers',\n status: 'warn',\n message: `Could not check: ${(error as Error).message}`,\n });\n }\n }\n\n // 7. Configuration validation\n if (configExists()) {\n try {\n const config = loadConfig();\n checks.push({\n name: 'Config validation',\n status: 'pass',\n message: `Model: ${config.agent.model}`,\n });\n\n // Check channel configuration\n for (const [channelName, channelConfig] of Object.entries(config.channels)) {\n if (channelConfig.enabled) {\n const hasToken = !!(channelConfig.token || channelConfig.apiKey);\n checks.push({\n name: `Channel: ${channelName}`,\n status: hasToken ? 'pass' : 'fail',\n message: hasToken ? 'Configured' : 'Enabled but no token set',\n fixKey: 'channels',\n });\n }\n }\n\n // Check model resolution — does the configured model string look routable?\n const modelStr: string = config.agent.model || '';\n const knownProviderPrefixes = [\n 'ollama/', 'anthropic/', 'openai/', 'google/', 'groq/', 'mistral/',\n 'openrouter/', 'xai/', 'together/', 'deepseek/', 'fireworks/',\n 'cerebras/', 'cohere/', 'perplexity/', 'azure/', 'openai_compat/',\n ];\n const hasProviderPrefix = knownProviderPrefixes.some(p => modelStr.startsWith(p));\n if (!hasProviderPrefix && modelStr) {\n checks.push({\n name: 'Model resolution',\n status: 'warn',\n message: `\"${modelStr}\" has no provider prefix (e.g. ollama/${modelStr}). ` +\n `TITAN will try to auto-detect the provider but may fail at runtime. ` +\n `Add a provider prefix to avoid ambiguity.`,\n });\n } else if (hasProviderPrefix) {\n checks.push({\n name: 'Model resolution',\n status: 'pass',\n message: `${modelStr} (provider prefix detected)`,\n });\n }\n } catch (error) {\n checks.push({\n name: 'Config validation',\n status: 'fail',\n message: (error as Error).message,\n fixKey: 'invalidConfig',\n });\n }\n }\n\n // 8. Cloudflare Tunnel (when enabled)\n if (configExists()) {\n try {\n const cfg = loadConfig();\n if (cfg.tunnel?.enabled) {\n let tunnelAvailable = false;\n try {\n const { execSync } = await import('child_process');\n execSync('cloudflared --version', { stdio: 'ignore' });\n tunnelAvailable = true;\n } catch {\n // not installed\n }\n checks.push({\n name: 'Cloudflare Tunnel (cloudflared)',\n status: tunnelAvailable ? 'pass' : 'fail',\n message: tunnelAvailable ? 'cloudflared binary found' : 'cloudflared not installed (https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/)',\n });\n }\n } catch {\n // config load failed — handled elsewhere\n }\n }\n\n // 9. Security audit\n if (configExists()) {\n const securityIssues = auditSecurity();\n for (const issue of securityIssues) {\n checks.push({\n name: 'Security',\n status: issue.level === 'error' ? 'fail' : issue.level === 'warn' ? 'warn' : 'pass',\n message: issue.message,\n });\n }\n }\n\n // 9. Disk space\n try {\n const { execSync } = await import('child_process');\n const dfOutput = execSync('df -h / | tail -1', { encoding: 'utf-8' });\n const parts = dfOutput.trim().split(/\\s+/);\n const available = parts[3];\n const usePercent = parts.length >= 5 ? parseInt(parts[4], 10) : NaN;\n checks.push({\n name: 'Disk space',\n status: isNaN(usePercent) ? 'warn' : usePercent < 90 ? 'pass' : usePercent < 95 ? 'warn' : 'fail',\n message: isNaN(usePercent) ? 'Could not parse disk usage' : `${available} available (${parts[4]} used)`,\n });\n } catch {\n checks.push({ name: 'Disk space', status: 'warn', message: 'Could not check' });\n }\n\n // 10. Memory\n const memUsage = process.memoryUsage();\n const rssGB = (memUsage.rss / 1024 / 1024).toFixed(1);\n checks.push({\n name: 'Memory usage',\n status: 'pass',\n message: `${rssGB} MB RSS`,\n });\n\n // 11. Stall Detector Status\n const stallStatus = getStallStats();\n let stallStatusLevel: 'pass' | 'warn' | 'fail' = 'pass';\n let stallMessage = 'Healthy (0 active stalls)';\n\n // getStallStats returns an array of session stats\n const activeStalls = stallStatus.length;\n if (activeStalls > 0) {\n stallStatusLevel = activeStalls > 2 ? 'fail' : 'warn';\n stallMessage = `Detected ${activeStalls} stuck sessions.`;\n }\n checks.push({\n name: 'Agent Stall Status',\n status: stallStatusLevel,\n message: stallMessage,\n });\n\n // 12. Stale sessions check\n const sessionsDir = join(TITAN_HOME, 'sessions');\n if (existsSync(sessionsDir)) {\n try {\n const sessionFiles = readdirSync(sessionsDir);\n const oneDayAgo = Date.now() - 24 * 60 * 60 * 1000;\n let staleCount = 0;\n for (const file of sessionFiles) {\n const fullPath = join(sessionsDir, file);\n try {\n const stat = statSync(fullPath);\n if (stat.isFile() && stat.mtimeMs < oneDayAgo) {\n staleCount++;\n }\n } catch {\n // skip unreadable files\n }\n }\n checks.push({\n name: 'Stale sessions',\n status: staleCount > 0 ? 'warn' : 'pass',\n message: staleCount > 0 ? `${staleCount} session file(s) older than 24 hours` : 'No stale sessions',\n fixKey: 'staleSessions',\n });\n } catch {\n checks.push({ name: 'Stale sessions', status: 'warn', message: 'Could not read sessions directory' });\n }\n } else {\n checks.push({ name: 'Stale sessions', status: 'pass', message: 'No sessions directory' });\n }\n\n // 13. Log directory size check\n if (existsSync(TITAN_LOGS_DIR)) {\n try {\n const logFiles = readdirSync(TITAN_LOGS_DIR);\n let totalBytes = 0;\n for (const file of logFiles) {\n const fullPath = join(TITAN_LOGS_DIR, file);\n try {\n const stat = statSync(fullPath);\n if (stat.isFile()) {\n totalBytes += stat.size;\n }\n } catch {\n // skip unreadable files\n }\n }\n const totalMB = totalBytes / (1024 * 1024);\n checks.push({\n name: 'Log directory size',\n status: totalMB > 100 ? 'warn' : 'pass',\n message: totalMB > 100\n ? `${totalMB.toFixed(1)} MB (consider rotating logs)`\n : `${totalMB.toFixed(1)} MB`,\n fixKey: totalMB > 100 ? 'staleLogs' : undefined,\n });\n } catch {\n checks.push({ name: 'Log directory size', status: 'warn', message: 'Could not check log directory' });\n }\n } else {\n checks.push({ name: 'Log directory size', status: 'pass', message: 'No logs directory' });\n }\n\n // 14. Permissions check\n checks.push({\n name: 'TITAN home permissions',\n status: existsSync(TITAN_HOME) ? 'pass' : 'warn',\n message: existsSync(TITAN_HOME) ? 'Exists' : 'Cannot check (TITAN_HOME missing)',\n fixKey: 'permissions',\n });\n\n // 15. npm download count\n if (!jsonOutput) console.log(chalk.gray(' Checking npm downloads...'));\n const npmDownloads = await fetchNpmDownloads('titan-agent');\n if (npmDownloads !== null) {\n checks.push({\n name: 'npm weekly downloads',\n status: 'pass',\n message: `${npmDownloads.toLocaleString()} downloads/week (titan-agent)`,\n });\n } else {\n checks.push({\n name: 'npm weekly downloads',\n status: 'warn',\n message: 'Could not fetch npm download stats',\n });\n }\n\n // Auto-fix pass if --fix was specified\n if (autoFix) {\n if (dryRun) {\n if (!jsonOutput) console.log(chalk.cyan('\\n 🔧 Dry run — showing fixes that WOULD be applied:\\n'));\n } else {\n if (!jsonOutput) console.log(chalk.cyan('\\n 🔧 Running auto-fix...\\n'));\n }\n\n const issueChecks = checks.filter((c) => (c.status === 'warn' || c.status === 'fail') && c.fixKey);\n const fixKeysNeeded = new Set(issueChecks.map((c) => c.fixKey!));\n\n const fixMap: Record<string, () => HealResult> = {\n titanHome: fixMissingTitanHome,\n config: fixMissingConfig,\n invalidConfig: fixInvalidConfig,\n workspace: fixMissingWorkspace,\n channels: fixBrokenChannelConfig,\n permissions: fixPermissions,\n staleLogs: fixStaleLogFiles,\n staleSessions: fixOrphanedSessions,\n };\n\n const fixDescriptions: Record<string, string> = {\n titanHome: 'Create TITAN home directory',\n config: 'Create default configuration file',\n invalidConfig: 'Reset invalid configuration to defaults',\n workspace: 'Create workspace directory',\n channels: 'Disable misconfigured channels',\n permissions: 'Fix file permissions on TITAN home',\n staleLogs: 'Clean up stale log files',\n staleSessions: 'Remove orphaned session files',\n };\n\n if (dryRun) {\n for (const key of fixKeysNeeded) {\n if (fixMap[key]) {\n const description = fixDescriptions[key] ?? key;\n healResults.push({ action: key, success: true, message: `[dry-run] Would fix: ${description}` });\n if (!jsonOutput) {\n console.log(` ${chalk.yellow('⏭')} ${key}: ${chalk.gray(`Would fix: ${description}`)}`);\n }\n }\n }\n\n if (!jsonOutput) {\n console.log(chalk.cyan(`\\n 🔧 Dry run complete — ${fixKeysNeeded.size} fix(es) would be applied. Run without --dry-run to apply.`));\n }\n } else {\n for (const key of fixKeysNeeded) {\n const fixFn = fixMap[key];\n if (fixFn) {\n const result = fixFn();\n healResults.push(result);\n if (!jsonOutput) {\n const icon = result.success ? chalk.green('✅') : chalk.red('❌');\n console.log(` ${icon} ${result.action}: ${chalk.gray(result.message)}`);\n }\n }\n }\n\n if (!jsonOutput) {\n const fixedCount = healResults.filter((r) => r.success).length;\n const remainingCount = healResults.filter((r) => !r.success).length;\n console.log(chalk.cyan(`\\n 🔧 ${fixedCount} issues auto-fixed, ${remainingCount} remaining`));\n }\n }\n }\n\n const passCount = checks.filter((c) => c.status === 'pass').length;\n const warnCount = checks.filter((c) => c.status === 'warn').length;\n const failCount = checks.filter((c) => c.status === 'fail').length;\n\n // Build the report\n const report: DoctorReport = {\n version: TITAN_VERSION,\n timestamp: new Date().toISOString(),\n checks,\n summary: { pass: passCount, warn: warnCount, fail: failCount },\n npm: { weeklyDownloads: npmDownloads },\n };\n if (healResults.length > 0) {\n report.fixes = healResults;\n }\n\n // Output\n if (jsonOutput) {\n console.log(JSON.stringify(report, null, 2));\n } else {\n // Print results\n console.log('');\n const statusIcons = { pass: chalk.green('✅'), warn: chalk.yellow('⚠️ '), fail: chalk.red('❌') };\n for (const check of checks) {\n console.log(` ${statusIcons[check.status]} ${chalk.white(check.name)}: ${chalk.gray(check.message)}`);\n }\n\n console.log(`\\n ${chalk.green(`${passCount} passed`)} | ${chalk.yellow(`${warnCount} warnings`)} | ${chalk.red(`${failCount} failed`)}`);\n\n if (failCount > 0) {\n console.log(chalk.red('\\n ⚠️ Some checks failed. Run `titan doctor --fix` or `titan onboard` to fix common issues.\\n'));\n } else if (warnCount > 0) {\n console.log(chalk.yellow('\\n ℹ️ Some warnings found. Run `titan doctor --fix` to auto-fix or review the items above.\\n'));\n } else {\n console.log(chalk.green('\\n 🎉 All checks passed! TITAN is healthy.\\n'));\n }\n }\n\n return report;\n}\n"],"mappings":"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","names":[]}
|
package/dist/cli/onboard.js
CHANGED
|
@@ -4,7 +4,7 @@ import chalk from "chalk";
|
|
|
4
4
|
import { exec } from "child_process";
|
|
5
5
|
import { saveConfig, getDefaultConfig } from "../config/config.js";
|
|
6
6
|
import { TITAN_HOME, TITAN_WORKSPACE, TITAN_SKILLS_DIR, TITAN_CONFIG_PATH } from "../utils/constants.js";
|
|
7
|
-
import {
|
|
7
|
+
import { mkdirIfNotExists } from "../utils/helpers.js";
|
|
8
8
|
import { initMemory } from "../memory/memory.js";
|
|
9
9
|
import { loadProfile, saveProfile } from "../memory/relationship.js";
|
|
10
10
|
async function fetchOllamaModels(baseUrl) {
|
|
@@ -466,9 +466,9 @@ async function runOnboard(_installDaemon) {
|
|
|
466
466
|
});
|
|
467
467
|
config.logging.level = logLevel;
|
|
468
468
|
console.log(chalk.yellow("\n\u2500\u2500\u2500 Setting up workspace \u2500\u2500\u2500\n"));
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
469
|
+
mkdirIfNotExists(TITAN_HOME);
|
|
470
|
+
mkdirIfNotExists(TITAN_WORKSPACE);
|
|
471
|
+
mkdirIfNotExists(TITAN_SKILLS_DIR);
|
|
472
472
|
initMemory();
|
|
473
473
|
saveConfig(config);
|
|
474
474
|
if (profileName || profileLevel) {
|
package/dist/cli/onboard.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/onboard.ts"],"sourcesContent":["/**\n * TITAN — Onboarding Wizard\n * Interactive setup for first-time users. Covers all key settings.\n */\nimport { select, input, confirm, password, checkbox } from '@inquirer/prompts';\nimport chalk from 'chalk';\nimport { exec } from 'child_process';\nimport { saveConfig, getDefaultConfig } from '../config/config.js';\nimport { TITAN_HOME, TITAN_WORKSPACE, TITAN_SKILLS_DIR, TITAN_CONFIG_PATH } from '../utils/constants.js';\nimport { ensureDir } from '../utils/helpers.js';\nimport { initMemory } from '../memory/memory.js';\nimport { loadProfile, saveProfile } from '../memory/relationship.js';\n\n\n// ─── Ollama helpers ───────────────────────────────────────────────\nasync function fetchOllamaModels(baseUrl: string): Promise<string[]> {\n try {\n const res = await fetch(`${baseUrl}/api/tags`, { signal: AbortSignal.timeout(3000) });\n if (!res.ok) return [];\n const json = await res.json() as { models?: { name: string }[] };\n return (json.models || []).map((m) => m.name).filter(Boolean);\n } catch {\n return [];\n }\n}\n\n// ─── API key validation ──────────────────────────────────────────\n// Tests a provider key against its real models endpoint.\n// Returns { ok: true } on success or { ok: false, error: string } on failure.\n// Used by the onboarding wizard to catch typo'd / expired / fake keys\n// BEFORE the user finishes setup and hits a generic 500 in the gateway.\nasync function validateProviderKey(\n provider: string,\n apiKey: string,\n): Promise<{ ok: boolean; error?: string }> {\n if (!apiKey || apiKey.trim().length === 0) {\n return { ok: false, error: 'Key is empty' };\n }\n const trimmed = apiKey.trim();\n try {\n const ctl = AbortSignal.timeout(8000);\n if (provider === 'anthropic') {\n const res = await fetch('https://api.anthropic.com/v1/models', {\n method: 'GET',\n headers: { 'x-api-key': trimmed, 'anthropic-version': '2023-06-01' },\n signal: ctl,\n });\n if (res.status === 401 || res.status === 403) return { ok: false, error: 'Authentication failed (401/403)' };\n if (!res.ok) return { ok: false, error: `HTTP ${res.status} ${res.statusText}` };\n return { ok: true };\n }\n if (provider === 'openai') {\n const res = await fetch('https://api.openai.com/v1/models', {\n method: 'GET',\n headers: { Authorization: `Bearer ${trimmed}` },\n signal: ctl,\n });\n if (res.status === 401 || res.status === 403) return { ok: false, error: 'Authentication failed (401/403)' };\n if (!res.ok) return { ok: false, error: `HTTP ${res.status} ${res.statusText}` };\n return { ok: true };\n }\n if (provider === 'google') {\n const res = await fetch(\n `https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(trimmed)}`,\n { method: 'GET', signal: ctl },\n );\n if (res.status === 401 || res.status === 403 || res.status === 400) {\n return { ok: false, error: `Authentication failed (${res.status})` };\n }\n if (!res.ok) return { ok: false, error: `HTTP ${res.status} ${res.statusText}` };\n return { ok: true };\n }\n // Unknown provider — skip validation, accept the key\n return { ok: true };\n } catch (err) {\n const msg = (err as Error).message;\n if (msg.includes('aborted')) return { ok: false, error: 'Request timed out (network or wrong endpoint)' };\n return { ok: false, error: msg };\n }\n}\n\n// Captures and validates an API key with retry. User can also skip.\n// Returns the validated key, or empty string if user chose to skip.\nasync function captureAndValidateKey(provider: string): Promise<string> {\n for (;;) { // retry loop until user provides a valid key, skips, or forces\n const apiKey = await password({\n message: `Paste your ${provider} API key here (input is hidden):`,\n mask: '*',\n });\n if (!apiKey || apiKey.trim().length === 0) {\n const skip = await confirm({\n message: 'No key entered. Skip validation and continue anyway?',\n default: false,\n });\n if (skip) return '';\n continue;\n }\n process.stdout.write(chalk.gray(` → Testing key against ${provider}... `));\n const result = await validateProviderKey(provider, apiKey);\n if (result.ok) {\n console.log(chalk.green('✅ valid'));\n return apiKey.trim();\n }\n console.log(chalk.red(`❌ ${result.error}`));\n const choice = await select({\n message: 'What would you like to do?',\n choices: [\n { name: '🔁 Re-enter the key', value: 'retry' },\n { name: '⏭️ Skip key validation and use it anyway (advanced)', value: 'force' },\n { name: '❌ Skip this provider', value: 'skip' },\n ],\n });\n if (choice === 'retry') continue;\n if (choice === 'force') return apiKey.trim();\n if (choice === 'skip') return '';\n }\n}\n\nimport { TITAN_VERSION } from '../utils/constants.js';\n\n// ─── Channel token validation ────────────────────────────────────\n// Quick check if a channel bot token is valid by calling the platform's identity endpoint.\nasync function validateChannelToken(channel: string, token: string): Promise<boolean> {\n try {\n const ctl = AbortSignal.timeout(8000);\n if (channel === 'discord') {\n const res = await fetch('https://discord.com/api/v10/users/@me', {\n headers: { Authorization: `Bot ${token}` }, signal: ctl,\n });\n return res.ok;\n }\n if (channel === 'telegram') {\n const res = await fetch(`https://api.telegram.org/bot${token}/getMe`, { signal: ctl });\n return res.ok;\n }\n if (channel === 'slack') {\n const res = await fetch('https://slack.com/api/auth.test', {\n method: 'POST',\n headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/x-www-form-urlencoded' },\n signal: ctl,\n });\n if (!res.ok) return false;\n const data = await res.json() as { ok?: boolean };\n return data.ok === true;\n }\n return true; // unknown channel — skip validation\n } catch {\n return false;\n }\n}\n\nfunction printLogo(): void {\n const c = chalk;\n const border = c.cyan;\n const row1 = c.yellowBright;\n const row2 = c.yellow;\n const row3 = c.greenBright;\n const row4 = c.cyanBright;\n const row5 = c.blueBright;\n const tagline = c.white;\n const credit = c.magentaBright;\n const ver = c.gray;\n\n console.log('');\n console.log(border(' ╔══════════════════════════════════════════════════════════╗'));\n console.log(border(' ║ ║'));\n console.log(border(' ║ ') + row1('████████╗██╗████████╗ █████╗ ███╗ ██╗') + border(' ║'));\n console.log(border(' ║ ') + row2(' ██║ ██║ ██║ ██╔══██╗ ████╗ ██║') + border(' ║'));\n console.log(border(' ║ ') + row3(' ██║ ██║ ██║ ███████║ ██╔██╗ ██║') + border(' ║'));\n console.log(border(' ║ ') + row4(' ██║ ██║ ██║ ██╔══██║ ██║╚██╗██║') + border(' ║'));\n console.log(border(' ║ ') + row5(' ██║ ██║ ██║ ██║ ██║ ██║ ╚████║') + border(' ║'));\n console.log(border(' ║ ') + c.blue(' ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═══╝') + border(' ║'));\n console.log(border(' ║ ║'));\n console.log(border(' ║ ') + tagline('The Intelligent Task Automation Network') + border(' ║'));\n console.log(border(' ║ ') + ver(`v${TITAN_VERSION}`) + c.gray(' • ') + credit('by Tony Elliott') + border(' ║'));\n console.log(border(' ╚══════════════════════════════════════════════════════════╝'));\n console.log('');\n}\n\n// ─── Main wizard ──────────────────────────────────────────────────\nexport async function runOnboard(_installDaemon?: boolean): Promise<boolean> {\n printLogo();\n console.log(chalk.gray(' Welcome! This wizard will configure your personal AI assistant.'));\n console.log(chalk.gray(' Press Ctrl+C at any time to cancel.\\n'));\n\n\n const config = getDefaultConfig();\n\n // ─── Step 0: System Check + Profile ──────────────────────────\n console.log(chalk.yellow('─── Step 0: System Check ───\\n'));\n\n // Node.js version\n console.log(chalk.green(` ✅ Node.js ${process.version}`));\n\n // Check Ollama\n const ollamaModelsCheck = await fetchOllamaModels('http://localhost:11434');\n if (ollamaModelsCheck.length > 0) {\n console.log(chalk.green(` ✅ Ollama detected (${ollamaModelsCheck.length} model(s): ${ollamaModelsCheck.slice(0, 3).join(', ')}${ollamaModelsCheck.length > 3 ? ', ...' : ''})`));\n } else {\n console.log(chalk.yellow(' ⚠️ Ollama not detected (local free AI unavailable — install from ollama.ai)'));\n }\n\n // Check Docker\n await new Promise<void>((resolve) => {\n exec('docker info --format \"{{.ServerVersion}}\"', { timeout: 3000 }, (err, stdout) => {\n if (!err && stdout.trim()) {\n console.log(chalk.green(` ✅ Docker available (v${stdout.trim()} — docker sandbox mode enabled)`));\n } else {\n console.log(chalk.yellow(' ⚠️ Docker not found (docker sandbox mode won\\'t be available)'));\n }\n resolve();\n });\n });\n\n console.log('');\n console.log(chalk.yellow('─── Step 0: Personalization ───\\n'));\n console.log(chalk.gray(' This helps TITAN respond in your style — like a JARVIS that knows you.\\n'));\n\n const profileName = await input({\n message: 'Your first name (optional, for personalization):',\n default: '',\n });\n\n const profileLevel = await select({\n message: 'Your technical level:',\n choices: [\n { name: 'Beginner — explain everything in plain English', value: 'beginner' },\n { name: 'Intermediate — I know the basics', value: 'intermediate' },\n { name: 'Expert — no hand-holding', value: 'expert' },\n ],\n });\n\n // ─── Step 1: Primary AI Provider ─────────────────────────────\n console.log(chalk.yellow('\\n─── Step 1 of 7: AI Provider ───\\n'));\n\n const provider = await select({\n message: 'Which AI provider would you like to use as your primary?',\n choices: [\n { name: '🟣 Anthropic (Claude) — Best reasoning, recommended', value: 'anthropic' },\n { name: '🟢 OpenAI (GPT-4o) — Great all-rounder', value: 'openai' },\n { name: '🔵 Google (Gemini) — Fast & multimodal', value: 'google' },\n { name: '🟠 Ollama (Local) — Free, private, runs on your machine', value: 'ollama' },\n ],\n });\n\n // ─── Step 2: Model Selection ──────────────────────────────────\n console.log(chalk.yellow('\\n─── Step 2 of 7: Model ───\\n'));\n\n if (provider === 'ollama') {\n const ollamaUrl = await input({\n message: 'Ollama base URL:',\n default: 'http://localhost:11434',\n });\n config.providers.ollama.baseUrl = ollamaUrl;\n\n console.log(chalk.gray(`\\n 🔍 Detecting models at ${ollamaUrl}...`));\n const installedModels = await fetchOllamaModels(ollamaUrl);\n\n if (installedModels.length > 0) {\n console.log(chalk.green(` ✅ Found ${installedModels.length} installed model(s)\\n`));\n const chosen = await select({\n message: 'Select a model to use:',\n choices: installedModels.map((m) => ({ name: m, value: `ollama/${m}` })),\n });\n config.agent.model = chosen;\n } else {\n console.log(chalk.yellow(' ⚠️ No models detected (Ollama may not be running, or no models pulled yet).'));\n console.log(chalk.gray(' Run: ollama pull qwen3.5:4b to install a model'));\n console.log(chalk.gray(' See: docs/MODELS.md for GPU-tiered model recommendations\\n'));\n const modelName = await input({\n message: 'Enter the Ollama model name to use:',\n default: 'qwen3.5:4b',\n });\n config.agent.model = `ollama/${modelName}`;\n }\n } else {\n // Cloud provider — guide user to get their API key\n const keyGuides: Record<string, { url: string; hint: string; name: string }> = {\n anthropic: {\n url: 'https://console.anthropic.com/settings/keys',\n hint: 'Looks like: sk-ant-api03-...',\n name: 'Anthropic Console',\n },\n openai: {\n url: 'https://platform.openai.com/api-keys',\n hint: 'Looks like: sk-proj-... or sk-...',\n name: 'OpenAI Platform',\n },\n google: {\n url: 'https://aistudio.google.com/app/apikey',\n hint: 'Looks like: AIza...',\n name: 'Google AI Studio',\n },\n };\n\n const guide = keyGuides[provider];\n if (guide) {\n console.log(chalk.cyan(`\\n 📋 To get your ${chalk.white(provider)} API key:`));\n console.log(chalk.white(` → Go to: ${chalk.underline(guide.url)}`));\n console.log(chalk.gray(` → ${guide.hint}`));\n console.log(chalk.green(`\\n 🔒 Security guarantee:`));\n console.log(chalk.gray(` Your key is stored ONLY on YOUR computer at:`));\n console.log(chalk.gray(` ~/.titan/config.json`));\n console.log(chalk.gray(` It goes directly to ${provider.charAt(0).toUpperCase() + provider.slice(1)}'s servers.`));\n console.log(chalk.gray(` TITAN never sees it. No one else ever sees it.\\n`));\n }\n\n const apiKey = await captureAndValidateKey(provider);\n\n const modelChoices: Record<string, { name: string; value: string }[]> = {\n anthropic: [\n { name: 'claude-sonnet-4-20250514 (Latest, recommended)', value: 'anthropic/claude-sonnet-4-20250514' },\n { name: 'claude-opus-4-0 (Most capable, slower)', value: 'anthropic/claude-opus-4-0' },\n { name: 'claude-3-5-haiku-20241022 (Fastest, cheapest)', value: 'anthropic/claude-3-5-haiku-20241022' },\n ],\n openai: [\n { name: 'gpt-4o (Recommended)', value: 'openai/gpt-4o' },\n { name: 'gpt-4o-mini (Fast & cheap)', value: 'openai/gpt-4o-mini' },\n { name: 'o3 (Best reasoning)', value: 'openai/o3' },\n { name: 'o4-mini (Fast reasoning)', value: 'openai/o4-mini' },\n ],\n google: [\n { name: 'gemini-2.5-flash (Recommended)', value: 'google/gemini-2.5-flash' },\n { name: 'gemini-2.5-pro (Most capable)', value: 'google/gemini-2.5-pro' },\n { name: 'gemini-2.0-flash (Fast)', value: 'google/gemini-2.0-flash' },\n ],\n };\n\n const models = modelChoices[provider] || [];\n const selectedModel = await select({\n message: 'Which model would you like to use?',\n choices: [...models, { name: '✏️ Enter manually', value: '__manual__' }],\n });\n\n if (selectedModel === '__manual__') {\n config.agent.model = await input({ message: 'Enter model identifier:' });\n } else {\n config.agent.model = selectedModel;\n }\n\n if (provider === 'anthropic') {\n config.providers.anthropic.apiKey = apiKey;\n } else if (provider === 'openai') {\n config.providers.openai.apiKey = apiKey;\n } else if (provider === 'google') {\n config.providers.google.apiKey = apiKey;\n }\n\n // Offer to add additional providers as fallback\n const addFallback = await confirm({\n message: 'Add a second provider as fallback (for failover if the primary is unavailable)?',\n default: false,\n });\n\n if (addFallback) {\n const fallbackProviders = ['anthropic', 'openai', 'google', 'ollama'].filter((p) => p !== provider);\n const fallback = await select({\n message: 'Select fallback provider:',\n choices: fallbackProviders.map((p) => ({ name: p.charAt(0).toUpperCase() + p.slice(1), value: p })),\n });\n if (fallback === 'ollama') {\n const ollamaUrl = await input({ message: 'Ollama base URL:', default: 'http://localhost:11434' });\n config.providers.ollama.baseUrl = ollamaUrl;\n const ollamaModels = await fetchOllamaModels(ollamaUrl);\n if (ollamaModels.length === 0) {\n console.log(chalk.yellow(` ⚠️ Ollama at ${ollamaUrl} is unreachable or has no models — fallback may not work.`));\n } else {\n console.log(chalk.green(` ✅ Ollama fallback ready (${ollamaModels.length} models available)`));\n }\n } else {\n const fallbackKey = await captureAndValidateKey(fallback);\n if (fallback === 'anthropic') config.providers.anthropic.apiKey = fallbackKey;\n else if (fallback === 'openai') config.providers.openai.apiKey = fallbackKey;\n else if (fallback === 'google') config.providers.google.apiKey = fallbackKey;\n }\n }\n }\n\n // ─── Step 3: Autonomy Mode ────────────────────────────────────\n console.log(chalk.yellow('\\n─── Step 3 of 7: Autonomy ───\\n'));\n console.log(chalk.gray(' Controls how independently TITAN acts.\\n'));\n\n const autonomyMode = await select({\n message: 'How much autonomy should TITAN have?',\n choices: [\n {\n name: '🟡 Supervised (Recommended) — safe ops run freely, dangerous ops ask first',\n value: 'supervised',\n },\n {\n name: '🟢 Autonomous — full auto, acts without asking. Best for power users.',\n value: 'autonomous',\n },\n {\n name: '🔴 Locked — every single action requires your approval.',\n value: 'locked',\n },\n ],\n });\n config.autonomy.mode = autonomyMode as 'supervised' | 'autonomous' | 'locked';\n\n // ─── Step 4: Security / Sandbox ──────────────────────────────\n console.log(chalk.yellow('\\n─── Step 4 of 7: Security ───\\n'));\n\n const sandboxMode = await select({\n message: 'Sandbox mode for shell commands:',\n choices: [\n { name: '🖥️ Host (Full access — single user machines)', value: 'host' },\n { name: '🐳 Docker (Isolated containers — recommended for shared machines)', value: 'docker' },\n { name: '🚫 None (No restrictions — not recommended)', value: 'none' },\n ],\n });\n config.security.sandboxMode = sandboxMode as 'host' | 'docker' | 'none';\n\n const enableShield = await confirm({\n message: 'Enable Prompt Injection Shield? (blocks attempts to hijack TITAN via chat messages)',\n default: true,\n });\n config.security.shield.enabled = enableShield;\n if (enableShield) {\n const shieldMode = await select({\n message: 'Shield strictness:',\n choices: [\n { name: 'Strict (recommended) — blocks suspicious payloads aggressively', value: 'strict' },\n { name: 'Standard — blocks only obvious injection attempts', value: 'standard' },\n ],\n });\n config.security.shield.mode = shieldMode as 'strict' | 'standard';\n }\n\n // ─── Step 5: Channels ─────────────────────────────────────────\n console.log(chalk.yellow('\\n─── Step 5 of 7: Messaging Channels ───\\n'));\n console.log(chalk.gray(' Connect TITAN to Discord, Telegram, Slack, etc. (all optional)\\n'));\n\n const channelChoices = await checkbox({\n message: 'Which channels would you like to configure? (space to select, enter to continue)',\n choices: [\n { name: '🎮 Discord', value: 'discord' },\n { name: '✈️ Telegram', value: 'telegram' },\n { name: '💼 Slack', value: 'slack' },\n { name: '💬 Google Chat (webhook)', value: 'googlechat' },\n { name: '📱 WhatsApp (requires phone pairing after setup)', value: 'whatsapp' },\n { name: '⏭️ Skip — configure later in Mission Control Settings', value: 'skip' },\n ],\n });\n\n if (!channelChoices.includes('skip')) {\n for (const channel of channelChoices) {\n if (channel === 'whatsapp') {\n config.channels.whatsapp.enabled = true;\n console.log(chalk.gray(' ℹ️ Run titan pairing after setup to link your phone'));\n } else if (channel === 'googlechat') {\n const webhook = await input({ message: ' Google Chat incoming webhook URL:' });\n config.channels.googlechat.enabled = true;\n config.channels.googlechat.token = webhook;\n } else {\n const token = await password({ message: ` ${channel} bot token:`, mask: '*' });\n if (token && token.trim().length > 0) {\n // Validate token with a quick API call\n process.stdout.write(chalk.gray(` → Testing ${channel} token... `));\n const valid = await validateChannelToken(channel, token.trim());\n if (valid) {\n console.log(chalk.green('✅ valid'));\n } else {\n console.log(chalk.yellow('⚠️ could not verify (token saved anyway — check it in Mission Control if the channel fails)'));\n }\n }\n if (channel === 'discord') {\n config.channels.discord.enabled = true;\n config.channels.discord.token = token;\n } else if (channel === 'telegram') {\n config.channels.telegram.enabled = true;\n config.channels.telegram.token = token;\n } else if (channel === 'slack') {\n config.channels.slack.enabled = true;\n config.channels.slack.token = token;\n }\n }\n }\n }\n\n // ─── Step 6: Gateway ─────────────────────────────────────────\n console.log(chalk.yellow('\\n─── Step 6 of 7: Gateway ───\\n'));\n console.log(chalk.gray(' Mission Control is served at http://127.0.0.1:<port>\\n'));\n\n const useDefaultPort = await confirm({\n message: 'Use default gateway port (48420)?',\n default: true,\n });\n if (!useDefaultPort) {\n const port = await input({ message: 'Enter gateway port:', default: '48420' });\n config.gateway.port = parseInt(port, 10);\n }\n\n const enableGatewayAuth = await confirm({\n message: 'Enable gateway authentication? (recommended if accessible from other devices)',\n default: false,\n });\n if (enableGatewayAuth) {\n const authMode = await select({\n message: 'Authentication mode:',\n choices: [\n { name: 'Token (API key in request header)', value: 'token' },\n { name: 'Password (browser prompt)', value: 'password' },\n ],\n });\n config.gateway.auth.mode = authMode as 'token' | 'password';\n if (authMode === 'token') {\n config.gateway.auth.token = await password({ message: 'Set a gateway token:', mask: '*' });\n } else {\n config.gateway.auth.password = await password({ message: 'Set a gateway password:', mask: '*' });\n }\n }\n\n // ─── Step 6.5: Daemon Installation ───────────────────────────\n console.log(chalk.yellow('\\n─── Auto-Start: System Service ───\\n'));\n console.log(chalk.gray(' Install TITAN as a system service so it auto-starts on login.\\n'));\n\n let daemonInstalled = false;\n const installDaemon = await confirm({\n message: 'Install TITAN as a system service? (auto-starts on login)',\n default: true,\n });\n if (installDaemon) {\n await installDaemonService();\n daemonInstalled = true;\n }\n\n // ─── Step 7: Logging ─────────────────────────────────────────\n console.log(chalk.yellow('\\n─── Step 7 of 7: Logging ───\\n'));\n\n const logLevel = await select({\n message: 'Log level:',\n choices: [\n { name: 'info (recommended)', value: 'info' },\n { name: 'debug (verbose — for troubleshooting)', value: 'debug' },\n { name: 'warn (quiet — warnings and errors only)', value: 'warn' },\n { name: 'silent (no logs)', value: 'silent' },\n ],\n });\n config.logging.level = logLevel as 'info' | 'debug' | 'warn' | 'silent';\n\n // ─── Finalise ─────────────────────────────────────────────────\n console.log(chalk.yellow('\\n─── Setting up workspace ───\\n'));\n ensureDir(TITAN_HOME);\n ensureDir(TITAN_WORKSPACE);\n ensureDir(TITAN_SKILLS_DIR);\n initMemory();\n saveConfig(config);\n\n // Save user profile\n if (profileName || profileLevel) {\n const profile = loadProfile();\n if (profileName) profile.name = profileName;\n if (profileLevel) profile.technicalLevel = profileLevel as typeof profile.technicalLevel;\n saveProfile(profile);\n }\n\n const modeEmoji = autonomyMode === 'autonomous' ? '🟢' : autonomyMode === 'locked' ? '🔴' : '🟡';\n const providerName = config.agent.model.split('/')[0];\n const modelName = config.agent.model.split('/').slice(1).join('/');\n const enabledChannels = ['discord','telegram','slack','googlechat','whatsapp']\n .filter(ch => config.channels[ch as keyof typeof config.channels]?.enabled);\n\n console.log(chalk.green('\\n╔══════════════════════════════════════════════════╗'));\n console.log(chalk.green('║ ✅ TITAN is ready! ║'));\n console.log(chalk.green('╚══════════════════════════════════════════════════╝\\n'));\n console.log(chalk.white(' Your configuration:'));\n if (profileName) console.log(chalk.gray(` Name: ${profileName} (${profileLevel})`));\n console.log(chalk.gray(` Provider: ${providerName} / ${modelName}`));\n console.log(chalk.gray(` Autonomy: ${modeEmoji} ${autonomyMode}`));\n console.log(chalk.gray(` Sandbox: ${config.security.sandboxMode}`));\n console.log(chalk.gray(` Logs: ${config.logging.level}`));\n if (enabledChannels.length > 0) {\n console.log(chalk.gray(` Channels: ${enabledChannels.map(ch => '✅ ' + ch).join(', ')}`));\n }\n console.log(chalk.gray(` Service: ${daemonInstalled ? '✅ Installed (auto-starts on login)' : '❌ Manual only (run titan gateway)'}`));\n console.log(chalk.gray(` Config: ${TITAN_CONFIG_PATH}`));\n console.log(chalk.white('\\n Next steps:'));\n console.log(chalk.cyan(' titan gateway ') + chalk.gray(`→ Open Mission Control at http://127.0.0.1:${config.gateway.port}`));\n console.log(chalk.cyan(' titan agent -m \"Hello\" ') + chalk.gray('→ Send a direct message'));\n console.log(chalk.cyan(' titan doctor ') + chalk.gray('→ Diagnose configuration & connectivity'));\n console.log();\n\n const launch = await confirm({\n message: `Start Mission Control (web GUI) now at http://127.0.0.1:${config.gateway.port}?`,\n default: true,\n });\n\n return launch;\n}\n\nasync function installDaemonService(): Promise<void> {\n const platform = process.platform;\n\n if (platform === 'linux') {\n console.log(chalk.gray('Creating systemd user service...'));\n const serviceContent = `[Unit]\nDescription=TITAN Gateway\nAfter=network.target\n\n[Service]\nType=simple\nExecStart=${process.execPath} ${process.argv[1]} gateway\nRestart=on-failure\nRestartSec=10\n\n[Install]\nWantedBy=default.target\n`;\n const { writeFileSync, mkdirSync, existsSync } = await import('fs');\n const { join } = await import('path');\n const { homedir } = await import('os');\n const serviceDir = join(homedir(), '.config', 'systemd', 'user');\n if (!existsSync(serviceDir)) mkdirSync(serviceDir, { recursive: true });\n writeFileSync(join(serviceDir, 'titan.service'), serviceContent);\n console.log(chalk.green(' Service file installed. Enable with:'));\n console.log(chalk.gray(' $ systemctl --user enable titan'));\n console.log(chalk.gray(' $ systemctl --user start titan'));\n } else if (platform === 'darwin') {\n console.log(chalk.yellow(' macOS: create a LaunchAgent plist manually to run as a daemon.'));\n } else {\n console.log(chalk.yellow(' Daemon installation not supported on this platform yet.'));\n }\n}\n"],"mappings":"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","names":["modelName"]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/onboard.ts"],"sourcesContent":["/**\n * TITAN — Onboarding Wizard\n * Interactive setup for first-time users. Covers all key settings.\n */\nimport { select, input, confirm, password, checkbox } from '@inquirer/prompts';\nimport chalk from 'chalk';\nimport { exec } from 'child_process';\nimport { saveConfig, getDefaultConfig } from '../config/config.js';\nimport { TITAN_HOME, TITAN_WORKSPACE, TITAN_SKILLS_DIR, TITAN_CONFIG_PATH } from '../utils/constants.js';\nimport { mkdirIfNotExists } from '../utils/helpers.js';\nimport { initMemory } from '../memory/memory.js';\nimport { loadProfile, saveProfile } from '../memory/relationship.js';\n\n\n// ─── Ollama helpers ───────────────────────────────────────────────\nasync function fetchOllamaModels(baseUrl: string): Promise<string[]> {\n try {\n const res = await fetch(`${baseUrl}/api/tags`, { signal: AbortSignal.timeout(3000) });\n if (!res.ok) return [];\n const json = await res.json() as { models?: { name: string }[] };\n return (json.models || []).map((m) => m.name).filter(Boolean);\n } catch {\n return [];\n }\n}\n\n// ─── API key validation ──────────────────────────────────────────\n// Tests a provider key against its real models endpoint.\n// Returns { ok: true } on success or { ok: false, error: string } on failure.\n// Used by the onboarding wizard to catch typo'd / expired / fake keys\n// BEFORE the user finishes setup and hits a generic 500 in the gateway.\nasync function validateProviderKey(\n provider: string,\n apiKey: string,\n): Promise<{ ok: boolean; error?: string }> {\n if (!apiKey || apiKey.trim().length === 0) {\n return { ok: false, error: 'Key is empty' };\n }\n const trimmed = apiKey.trim();\n try {\n const ctl = AbortSignal.timeout(8000);\n if (provider === 'anthropic') {\n const res = await fetch('https://api.anthropic.com/v1/models', {\n method: 'GET',\n headers: { 'x-api-key': trimmed, 'anthropic-version': '2023-06-01' },\n signal: ctl,\n });\n if (res.status === 401 || res.status === 403) return { ok: false, error: 'Authentication failed (401/403)' };\n if (!res.ok) return { ok: false, error: `HTTP ${res.status} ${res.statusText}` };\n return { ok: true };\n }\n if (provider === 'openai') {\n const res = await fetch('https://api.openai.com/v1/models', {\n method: 'GET',\n headers: { Authorization: `Bearer ${trimmed}` },\n signal: ctl,\n });\n if (res.status === 401 || res.status === 403) return { ok: false, error: 'Authentication failed (401/403)' };\n if (!res.ok) return { ok: false, error: `HTTP ${res.status} ${res.statusText}` };\n return { ok: true };\n }\n if (provider === 'google') {\n const res = await fetch(\n `https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(trimmed)}`,\n { method: 'GET', signal: ctl },\n );\n if (res.status === 401 || res.status === 403 || res.status === 400) {\n return { ok: false, error: `Authentication failed (${res.status})` };\n }\n if (!res.ok) return { ok: false, error: `HTTP ${res.status} ${res.statusText}` };\n return { ok: true };\n }\n // Unknown provider — skip validation, accept the key\n return { ok: true };\n } catch (err) {\n const msg = (err as Error).message;\n if (msg.includes('aborted')) return { ok: false, error: 'Request timed out (network or wrong endpoint)' };\n return { ok: false, error: msg };\n }\n}\n\n// Captures and validates an API key with retry. User can also skip.\n// Returns the validated key, or empty string if user chose to skip.\nasync function captureAndValidateKey(provider: string): Promise<string> {\n for (;;) { // retry loop until user provides a valid key, skips, or forces\n const apiKey = await password({\n message: `Paste your ${provider} API key here (input is hidden):`,\n mask: '*',\n });\n if (!apiKey || apiKey.trim().length === 0) {\n const skip = await confirm({\n message: 'No key entered. Skip validation and continue anyway?',\n default: false,\n });\n if (skip) return '';\n continue;\n }\n process.stdout.write(chalk.gray(` → Testing key against ${provider}... `));\n const result = await validateProviderKey(provider, apiKey);\n if (result.ok) {\n console.log(chalk.green('✅ valid'));\n return apiKey.trim();\n }\n console.log(chalk.red(`❌ ${result.error}`));\n const choice = await select({\n message: 'What would you like to do?',\n choices: [\n { name: '🔁 Re-enter the key', value: 'retry' },\n { name: '⏭️ Skip key validation and use it anyway (advanced)', value: 'force' },\n { name: '❌ Skip this provider', value: 'skip' },\n ],\n });\n if (choice === 'retry') continue;\n if (choice === 'force') return apiKey.trim();\n if (choice === 'skip') return '';\n }\n}\n\nimport { TITAN_VERSION } from '../utils/constants.js';\n\n// ─── Channel token validation ────────────────────────────────────\n// Quick check if a channel bot token is valid by calling the platform's identity endpoint.\nasync function validateChannelToken(channel: string, token: string): Promise<boolean> {\n try {\n const ctl = AbortSignal.timeout(8000);\n if (channel === 'discord') {\n const res = await fetch('https://discord.com/api/v10/users/@me', {\n headers: { Authorization: `Bot ${token}` }, signal: ctl,\n });\n return res.ok;\n }\n if (channel === 'telegram') {\n const res = await fetch(`https://api.telegram.org/bot${token}/getMe`, { signal: ctl });\n return res.ok;\n }\n if (channel === 'slack') {\n const res = await fetch('https://slack.com/api/auth.test', {\n method: 'POST',\n headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/x-www-form-urlencoded' },\n signal: ctl,\n });\n if (!res.ok) return false;\n const data = await res.json() as { ok?: boolean };\n return data.ok === true;\n }\n return true; // unknown channel — skip validation\n } catch {\n return false;\n }\n}\n\nfunction printLogo(): void {\n const c = chalk;\n const border = c.cyan;\n const row1 = c.yellowBright;\n const row2 = c.yellow;\n const row3 = c.greenBright;\n const row4 = c.cyanBright;\n const row5 = c.blueBright;\n const tagline = c.white;\n const credit = c.magentaBright;\n const ver = c.gray;\n\n console.log('');\n console.log(border(' ╔══════════════════════════════════════════════════════════╗'));\n console.log(border(' ║ ║'));\n console.log(border(' ║ ') + row1('████████╗██╗████████╗ █████╗ ███╗ ██╗') + border(' ║'));\n console.log(border(' ║ ') + row2(' ██║ ██║ ██║ ██╔══██╗ ████╗ ██║') + border(' ║'));\n console.log(border(' ║ ') + row3(' ██║ ██║ ██║ ███████║ ██╔██╗ ██║') + border(' ║'));\n console.log(border(' ║ ') + row4(' ██║ ██║ ██║ ██╔══██║ ██║╚██╗██║') + border(' ║'));\n console.log(border(' ║ ') + row5(' ██║ ██║ ██║ ██║ ██║ ██║ ╚████║') + border(' ║'));\n console.log(border(' ║ ') + c.blue(' ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═══╝') + border(' ║'));\n console.log(border(' ║ ║'));\n console.log(border(' ║ ') + tagline('The Intelligent Task Automation Network') + border(' ║'));\n console.log(border(' ║ ') + ver(`v${TITAN_VERSION}`) + c.gray(' • ') + credit('by Tony Elliott') + border(' ║'));\n console.log(border(' ╚══════════════════════════════════════════════════════════╝'));\n console.log('');\n}\n\n// ─── Main wizard ──────────────────────────────────────────────────\nexport async function runOnboard(_installDaemon?: boolean): Promise<boolean> {\n printLogo();\n console.log(chalk.gray(' Welcome! This wizard will configure your personal AI assistant.'));\n console.log(chalk.gray(' Press Ctrl+C at any time to cancel.\\n'));\n\n\n const config = getDefaultConfig();\n\n // ─── Step 0: System Check + Profile ──────────────────────────\n console.log(chalk.yellow('─── Step 0: System Check ───\\n'));\n\n // Node.js version\n console.log(chalk.green(` ✅ Node.js ${process.version}`));\n\n // Check Ollama\n const ollamaModelsCheck = await fetchOllamaModels('http://localhost:11434');\n if (ollamaModelsCheck.length > 0) {\n console.log(chalk.green(` ✅ Ollama detected (${ollamaModelsCheck.length} model(s): ${ollamaModelsCheck.slice(0, 3).join(', ')}${ollamaModelsCheck.length > 3 ? ', ...' : ''})`));\n } else {\n console.log(chalk.yellow(' ⚠️ Ollama not detected (local free AI unavailable — install from ollama.ai)'));\n }\n\n // Check Docker\n await new Promise<void>((resolve) => {\n exec('docker info --format \"{{.ServerVersion}}\"', { timeout: 3000 }, (err, stdout) => {\n if (!err && stdout.trim()) {\n console.log(chalk.green(` ✅ Docker available (v${stdout.trim()} — docker sandbox mode enabled)`));\n } else {\n console.log(chalk.yellow(' ⚠️ Docker not found (docker sandbox mode won\\'t be available)'));\n }\n resolve();\n });\n });\n\n console.log('');\n console.log(chalk.yellow('─── Step 0: Personalization ───\\n'));\n console.log(chalk.gray(' This helps TITAN respond in your style — like a JARVIS that knows you.\\n'));\n\n const profileName = await input({\n message: 'Your first name (optional, for personalization):',\n default: '',\n });\n\n const profileLevel = await select({\n message: 'Your technical level:',\n choices: [\n { name: 'Beginner — explain everything in plain English', value: 'beginner' },\n { name: 'Intermediate — I know the basics', value: 'intermediate' },\n { name: 'Expert — no hand-holding', value: 'expert' },\n ],\n });\n\n // ─── Step 1: Primary AI Provider ─────────────────────────────\n console.log(chalk.yellow('\\n─── Step 1 of 7: AI Provider ───\\n'));\n\n const provider = await select({\n message: 'Which AI provider would you like to use as your primary?',\n choices: [\n { name: '🟣 Anthropic (Claude) — Best reasoning, recommended', value: 'anthropic' },\n { name: '🟢 OpenAI (GPT-4o) — Great all-rounder', value: 'openai' },\n { name: '🔵 Google (Gemini) — Fast & multimodal', value: 'google' },\n { name: '🟠 Ollama (Local) — Free, private, runs on your machine', value: 'ollama' },\n ],\n });\n\n // ─── Step 2: Model Selection ──────────────────────────────────\n console.log(chalk.yellow('\\n─── Step 2 of 7: Model ───\\n'));\n\n if (provider === 'ollama') {\n const ollamaUrl = await input({\n message: 'Ollama base URL:',\n default: 'http://localhost:11434',\n });\n config.providers.ollama.baseUrl = ollamaUrl;\n\n console.log(chalk.gray(`\\n 🔍 Detecting models at ${ollamaUrl}...`));\n const installedModels = await fetchOllamaModels(ollamaUrl);\n\n if (installedModels.length > 0) {\n console.log(chalk.green(` ✅ Found ${installedModels.length} installed model(s)\\n`));\n const chosen = await select({\n message: 'Select a model to use:',\n choices: installedModels.map((m) => ({ name: m, value: `ollama/${m}` })),\n });\n config.agent.model = chosen;\n } else {\n console.log(chalk.yellow(' ⚠️ No models detected (Ollama may not be running, or no models pulled yet).'));\n console.log(chalk.gray(' Run: ollama pull qwen3.5:4b to install a model'));\n console.log(chalk.gray(' See: docs/MODELS.md for GPU-tiered model recommendations\\n'));\n const modelName = await input({\n message: 'Enter the Ollama model name to use:',\n default: 'qwen3.5:4b',\n });\n config.agent.model = `ollama/${modelName}`;\n }\n } else {\n // Cloud provider — guide user to get their API key\n const keyGuides: Record<string, { url: string; hint: string; name: string }> = {\n anthropic: {\n url: 'https://console.anthropic.com/settings/keys',\n hint: 'Looks like: sk-ant-api03-...',\n name: 'Anthropic Console',\n },\n openai: {\n url: 'https://platform.openai.com/api-keys',\n hint: 'Looks like: sk-proj-... or sk-...',\n name: 'OpenAI Platform',\n },\n google: {\n url: 'https://aistudio.google.com/app/apikey',\n hint: 'Looks like: AIza...',\n name: 'Google AI Studio',\n },\n };\n\n const guide = keyGuides[provider];\n if (guide) {\n console.log(chalk.cyan(`\\n 📋 To get your ${chalk.white(provider)} API key:`));\n console.log(chalk.white(` → Go to: ${chalk.underline(guide.url)}`));\n console.log(chalk.gray(` → ${guide.hint}`));\n console.log(chalk.green(`\\n 🔒 Security guarantee:`));\n console.log(chalk.gray(` Your key is stored ONLY on YOUR computer at:`));\n console.log(chalk.gray(` ~/.titan/config.json`));\n console.log(chalk.gray(` It goes directly to ${provider.charAt(0).toUpperCase() + provider.slice(1)}'s servers.`));\n console.log(chalk.gray(` TITAN never sees it. No one else ever sees it.\\n`));\n }\n\n const apiKey = await captureAndValidateKey(provider);\n\n const modelChoices: Record<string, { name: string; value: string }[]> = {\n anthropic: [\n { name: 'claude-sonnet-4-20250514 (Latest, recommended)', value: 'anthropic/claude-sonnet-4-20250514' },\n { name: 'claude-opus-4-0 (Most capable, slower)', value: 'anthropic/claude-opus-4-0' },\n { name: 'claude-3-5-haiku-20241022 (Fastest, cheapest)', value: 'anthropic/claude-3-5-haiku-20241022' },\n ],\n openai: [\n { name: 'gpt-4o (Recommended)', value: 'openai/gpt-4o' },\n { name: 'gpt-4o-mini (Fast & cheap)', value: 'openai/gpt-4o-mini' },\n { name: 'o3 (Best reasoning)', value: 'openai/o3' },\n { name: 'o4-mini (Fast reasoning)', value: 'openai/o4-mini' },\n ],\n google: [\n { name: 'gemini-2.5-flash (Recommended)', value: 'google/gemini-2.5-flash' },\n { name: 'gemini-2.5-pro (Most capable)', value: 'google/gemini-2.5-pro' },\n { name: 'gemini-2.0-flash (Fast)', value: 'google/gemini-2.0-flash' },\n ],\n };\n\n const models = modelChoices[provider] || [];\n const selectedModel = await select({\n message: 'Which model would you like to use?',\n choices: [...models, { name: '✏️ Enter manually', value: '__manual__' }],\n });\n\n if (selectedModel === '__manual__') {\n config.agent.model = await input({ message: 'Enter model identifier:' });\n } else {\n config.agent.model = selectedModel;\n }\n\n if (provider === 'anthropic') {\n config.providers.anthropic.apiKey = apiKey;\n } else if (provider === 'openai') {\n config.providers.openai.apiKey = apiKey;\n } else if (provider === 'google') {\n config.providers.google.apiKey = apiKey;\n }\n\n // Offer to add additional providers as fallback\n const addFallback = await confirm({\n message: 'Add a second provider as fallback (for failover if the primary is unavailable)?',\n default: false,\n });\n\n if (addFallback) {\n const fallbackProviders = ['anthropic', 'openai', 'google', 'ollama'].filter((p) => p !== provider);\n const fallback = await select({\n message: 'Select fallback provider:',\n choices: fallbackProviders.map((p) => ({ name: p.charAt(0).toUpperCase() + p.slice(1), value: p })),\n });\n if (fallback === 'ollama') {\n const ollamaUrl = await input({ message: 'Ollama base URL:', default: 'http://localhost:11434' });\n config.providers.ollama.baseUrl = ollamaUrl;\n const ollamaModels = await fetchOllamaModels(ollamaUrl);\n if (ollamaModels.length === 0) {\n console.log(chalk.yellow(` ⚠️ Ollama at ${ollamaUrl} is unreachable or has no models — fallback may not work.`));\n } else {\n console.log(chalk.green(` ✅ Ollama fallback ready (${ollamaModels.length} models available)`));\n }\n } else {\n const fallbackKey = await captureAndValidateKey(fallback);\n if (fallback === 'anthropic') config.providers.anthropic.apiKey = fallbackKey;\n else if (fallback === 'openai') config.providers.openai.apiKey = fallbackKey;\n else if (fallback === 'google') config.providers.google.apiKey = fallbackKey;\n }\n }\n }\n\n // ─── Step 3: Autonomy Mode ────────────────────────────────────\n console.log(chalk.yellow('\\n─── Step 3 of 7: Autonomy ───\\n'));\n console.log(chalk.gray(' Controls how independently TITAN acts.\\n'));\n\n const autonomyMode = await select({\n message: 'How much autonomy should TITAN have?',\n choices: [\n {\n name: '🟡 Supervised (Recommended) — safe ops run freely, dangerous ops ask first',\n value: 'supervised',\n },\n {\n name: '🟢 Autonomous — full auto, acts without asking. Best for power users.',\n value: 'autonomous',\n },\n {\n name: '🔴 Locked — every single action requires your approval.',\n value: 'locked',\n },\n ],\n });\n config.autonomy.mode = autonomyMode as 'supervised' | 'autonomous' | 'locked';\n\n // ─── Step 4: Security / Sandbox ──────────────────────────────\n console.log(chalk.yellow('\\n─── Step 4 of 7: Security ───\\n'));\n\n const sandboxMode = await select({\n message: 'Sandbox mode for shell commands:',\n choices: [\n { name: '🖥️ Host (Full access — single user machines)', value: 'host' },\n { name: '🐳 Docker (Isolated containers — recommended for shared machines)', value: 'docker' },\n { name: '🚫 None (No restrictions — not recommended)', value: 'none' },\n ],\n });\n config.security.sandboxMode = sandboxMode as 'host' | 'docker' | 'none';\n\n const enableShield = await confirm({\n message: 'Enable Prompt Injection Shield? (blocks attempts to hijack TITAN via chat messages)',\n default: true,\n });\n config.security.shield.enabled = enableShield;\n if (enableShield) {\n const shieldMode = await select({\n message: 'Shield strictness:',\n choices: [\n { name: 'Strict (recommended) — blocks suspicious payloads aggressively', value: 'strict' },\n { name: 'Standard — blocks only obvious injection attempts', value: 'standard' },\n ],\n });\n config.security.shield.mode = shieldMode as 'strict' | 'standard';\n }\n\n // ─── Step 5: Channels ─────────────────────────────────────────\n console.log(chalk.yellow('\\n─── Step 5 of 7: Messaging Channels ───\\n'));\n console.log(chalk.gray(' Connect TITAN to Discord, Telegram, Slack, etc. (all optional)\\n'));\n\n const channelChoices = await checkbox({\n message: 'Which channels would you like to configure? (space to select, enter to continue)',\n choices: [\n { name: '🎮 Discord', value: 'discord' },\n { name: '✈️ Telegram', value: 'telegram' },\n { name: '💼 Slack', value: 'slack' },\n { name: '💬 Google Chat (webhook)', value: 'googlechat' },\n { name: '📱 WhatsApp (requires phone pairing after setup)', value: 'whatsapp' },\n { name: '⏭️ Skip — configure later in Mission Control Settings', value: 'skip' },\n ],\n });\n\n if (!channelChoices.includes('skip')) {\n for (const channel of channelChoices) {\n if (channel === 'whatsapp') {\n config.channels.whatsapp.enabled = true;\n console.log(chalk.gray(' ℹ️ Run titan pairing after setup to link your phone'));\n } else if (channel === 'googlechat') {\n const webhook = await input({ message: ' Google Chat incoming webhook URL:' });\n config.channels.googlechat.enabled = true;\n config.channels.googlechat.token = webhook;\n } else {\n const token = await password({ message: ` ${channel} bot token:`, mask: '*' });\n if (token && token.trim().length > 0) {\n // Validate token with a quick API call\n process.stdout.write(chalk.gray(` → Testing ${channel} token... `));\n const valid = await validateChannelToken(channel, token.trim());\n if (valid) {\n console.log(chalk.green('✅ valid'));\n } else {\n console.log(chalk.yellow('⚠️ could not verify (token saved anyway — check it in Mission Control if the channel fails)'));\n }\n }\n if (channel === 'discord') {\n config.channels.discord.enabled = true;\n config.channels.discord.token = token;\n } else if (channel === 'telegram') {\n config.channels.telegram.enabled = true;\n config.channels.telegram.token = token;\n } else if (channel === 'slack') {\n config.channels.slack.enabled = true;\n config.channels.slack.token = token;\n }\n }\n }\n }\n\n // ─── Step 6: Gateway ─────────────────────────────────────────\n console.log(chalk.yellow('\\n─── Step 6 of 7: Gateway ───\\n'));\n console.log(chalk.gray(' Mission Control is served at http://127.0.0.1:<port>\\n'));\n\n const useDefaultPort = await confirm({\n message: 'Use default gateway port (48420)?',\n default: true,\n });\n if (!useDefaultPort) {\n const port = await input({ message: 'Enter gateway port:', default: '48420' });\n config.gateway.port = parseInt(port, 10);\n }\n\n const enableGatewayAuth = await confirm({\n message: 'Enable gateway authentication? (recommended if accessible from other devices)',\n default: false,\n });\n if (enableGatewayAuth) {\n const authMode = await select({\n message: 'Authentication mode:',\n choices: [\n { name: 'Token (API key in request header)', value: 'token' },\n { name: 'Password (browser prompt)', value: 'password' },\n ],\n });\n config.gateway.auth.mode = authMode as 'token' | 'password';\n if (authMode === 'token') {\n config.gateway.auth.token = await password({ message: 'Set a gateway token:', mask: '*' });\n } else {\n config.gateway.auth.password = await password({ message: 'Set a gateway password:', mask: '*' });\n }\n }\n\n // ─── Step 6.5: Daemon Installation ───────────────────────────\n console.log(chalk.yellow('\\n─── Auto-Start: System Service ───\\n'));\n console.log(chalk.gray(' Install TITAN as a system service so it auto-starts on login.\\n'));\n\n let daemonInstalled = false;\n const installDaemon = await confirm({\n message: 'Install TITAN as a system service? (auto-starts on login)',\n default: true,\n });\n if (installDaemon) {\n await installDaemonService();\n daemonInstalled = true;\n }\n\n // ─── Step 7: Logging ─────────────────────────────────────────\n console.log(chalk.yellow('\\n─── Step 7 of 7: Logging ───\\n'));\n\n const logLevel = await select({\n message: 'Log level:',\n choices: [\n { name: 'info (recommended)', value: 'info' },\n { name: 'debug (verbose — for troubleshooting)', value: 'debug' },\n { name: 'warn (quiet — warnings and errors only)', value: 'warn' },\n { name: 'silent (no logs)', value: 'silent' },\n ],\n });\n config.logging.level = logLevel as 'info' | 'debug' | 'warn' | 'silent';\n\n // ─── Finalise ─────────────────────────────────────────────────\n console.log(chalk.yellow('\\n─── Setting up workspace ───\\n'));\n mkdirIfNotExists(TITAN_HOME);\n mkdirIfNotExists(TITAN_WORKSPACE);\n mkdirIfNotExists(TITAN_SKILLS_DIR);\n initMemory();\n saveConfig(config);\n\n // Save user profile\n if (profileName || profileLevel) {\n const profile = loadProfile();\n if (profileName) profile.name = profileName;\n if (profileLevel) profile.technicalLevel = profileLevel as typeof profile.technicalLevel;\n saveProfile(profile);\n }\n\n const modeEmoji = autonomyMode === 'autonomous' ? '🟢' : autonomyMode === 'locked' ? '🔴' : '🟡';\n const providerName = config.agent.model.split('/')[0];\n const modelName = config.agent.model.split('/').slice(1).join('/');\n const enabledChannels = ['discord','telegram','slack','googlechat','whatsapp']\n .filter(ch => config.channels[ch as keyof typeof config.channels]?.enabled);\n\n console.log(chalk.green('\\n╔══════════════════════════════════════════════════╗'));\n console.log(chalk.green('║ ✅ TITAN is ready! ║'));\n console.log(chalk.green('╚══════════════════════════════════════════════════╝\\n'));\n console.log(chalk.white(' Your configuration:'));\n if (profileName) console.log(chalk.gray(` Name: ${profileName} (${profileLevel})`));\n console.log(chalk.gray(` Provider: ${providerName} / ${modelName}`));\n console.log(chalk.gray(` Autonomy: ${modeEmoji} ${autonomyMode}`));\n console.log(chalk.gray(` Sandbox: ${config.security.sandboxMode}`));\n console.log(chalk.gray(` Logs: ${config.logging.level}`));\n if (enabledChannels.length > 0) {\n console.log(chalk.gray(` Channels: ${enabledChannels.map(ch => '✅ ' + ch).join(', ')}`));\n }\n console.log(chalk.gray(` Service: ${daemonInstalled ? '✅ Installed (auto-starts on login)' : '❌ Manual only (run titan gateway)'}`));\n console.log(chalk.gray(` Config: ${TITAN_CONFIG_PATH}`));\n console.log(chalk.white('\\n Next steps:'));\n console.log(chalk.cyan(' titan gateway ') + chalk.gray(`→ Open Mission Control at http://127.0.0.1:${config.gateway.port}`));\n console.log(chalk.cyan(' titan agent -m \"Hello\" ') + chalk.gray('→ Send a direct message'));\n console.log(chalk.cyan(' titan doctor ') + chalk.gray('→ Diagnose configuration & connectivity'));\n console.log();\n\n const launch = await confirm({\n message: `Start Mission Control (web GUI) now at http://127.0.0.1:${config.gateway.port}?`,\n default: true,\n });\n\n return launch;\n}\n\nasync function installDaemonService(): Promise<void> {\n const platform = process.platform;\n\n if (platform === 'linux') {\n console.log(chalk.gray('Creating systemd user service...'));\n const serviceContent = `[Unit]\nDescription=TITAN Gateway\nAfter=network.target\n\n[Service]\nType=simple\nExecStart=${process.execPath} ${process.argv[1]} gateway\nRestart=on-failure\nRestartSec=10\n\n[Install]\nWantedBy=default.target\n`;\n const { writeFileSync, mkdirSync, existsSync } = await import('fs');\n const { join } = await import('path');\n const { homedir } = await import('os');\n const serviceDir = join(homedir(), '.config', 'systemd', 'user');\n if (!existsSync(serviceDir)) mkdirSync(serviceDir, { recursive: true });\n writeFileSync(join(serviceDir, 'titan.service'), serviceContent);\n console.log(chalk.green(' Service file installed. Enable with:'));\n console.log(chalk.gray(' $ systemctl --user enable titan'));\n console.log(chalk.gray(' $ systemctl --user start titan'));\n } else if (platform === 'darwin') {\n console.log(chalk.yellow(' macOS: create a LaunchAgent plist manually to run as a daemon.'));\n } else {\n console.log(chalk.yellow(' Daemon installation not supported on this platform yet.'));\n }\n}\n"],"mappings":"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","names":["modelName"]}
|
package/dist/config/config.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { existsSync } from "fs";
|
|
3
3
|
import { TITAN_CONFIG_PATH, TITAN_HOME } from "../utils/constants.js";
|
|
4
|
-
import { readJsonFile, writeJsonFile,
|
|
4
|
+
import { readJsonFile, writeJsonFile, mkdirIfNotExists, deepMerge } from "../utils/helpers.js";
|
|
5
5
|
import { TitanConfigSchema } from "./schema.js";
|
|
6
6
|
import logger from "../utils/logger.js";
|
|
7
7
|
const COMPONENT = "Config";
|
|
@@ -11,7 +11,7 @@ function getDefaultConfig() {
|
|
|
11
11
|
}
|
|
12
12
|
function loadConfig() {
|
|
13
13
|
if (cachedConfig) return cachedConfig;
|
|
14
|
-
|
|
14
|
+
mkdirIfNotExists(TITAN_HOME);
|
|
15
15
|
let rawConfig = {};
|
|
16
16
|
if (existsSync(TITAN_CONFIG_PATH)) {
|
|
17
17
|
const loaded = readJsonFile(TITAN_CONFIG_PATH);
|
|
@@ -68,7 +68,7 @@ function loadConfig() {
|
|
|
68
68
|
return cachedConfig;
|
|
69
69
|
}
|
|
70
70
|
function saveConfig(config) {
|
|
71
|
-
|
|
71
|
+
mkdirIfNotExists(TITAN_HOME);
|
|
72
72
|
writeJsonFile(TITAN_CONFIG_PATH, config);
|
|
73
73
|
cachedConfig = config;
|
|
74
74
|
logger.info(COMPONENT, `Config saved to ${TITAN_CONFIG_PATH}`);
|