titan-agent 6.5.2 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +180 -53
- package/assets/agent-skills/NOTICE-ECC.md +39 -0
- package/assets/agent-skills/agent-introspection-debugging/SKILL.md +153 -0
- package/assets/agent-skills/continuous-agent-loop/SKILL.md +45 -0
- package/assets/agent-skills/continuous-learning/SKILL.md +131 -0
- package/assets/agent-skills/continuous-learning/config.json +18 -0
- package/assets/agent-skills/continuous-learning/evaluate-session.sh +69 -0
- package/assets/agent-skills/production-audit/SKILL.md +206 -0
- package/assets/agent-skills/recursive-decision-ledger/SKILL.md +79 -0
- package/assets/agent-skills/scientific-thinking-literature-review/SKILL.md +192 -0
- package/assets/agent-skills/scientific-thinking-scholar-evaluation/SKILL.md +160 -0
- package/assets/agent-skills/verification-loop/SKILL.md +126 -0
- package/dist/agent/agent.js +67 -26
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/agentLoop.js +6 -2
- package/dist/agent/agentLoop.js.map +1 -1
- package/dist/agent/autoModeClassifier.js +26 -2
- package/dist/agent/autoModeClassifier.js.map +1 -1
- package/dist/agent/goalDriver.js +2 -0
- package/dist/agent/goalDriver.js.map +1 -1
- package/dist/agent/goalSpec.js +229 -0
- package/dist/agent/goalSpec.js.map +1 -0
- package/dist/agent/heartbeat.js +130 -0
- package/dist/agent/heartbeat.js.map +1 -0
- package/dist/agent/missionDecompose.js +38 -0
- package/dist/agent/missionDecompose.js.map +1 -0
- package/dist/agent/muscleMemory.js +291 -0
- package/dist/agent/muscleMemory.js.map +1 -0
- package/dist/agent/observationWriter.js +56 -0
- package/dist/agent/observationWriter.js.map +1 -0
- package/dist/agent/promptSectionCaps.js +6 -0
- package/dist/agent/promptSectionCaps.js.map +1 -1
- package/dist/agent/reminders.js +101 -0
- package/dist/agent/reminders.js.map +1 -0
- package/dist/agent/systemWidgets.js +41 -0
- package/dist/agent/systemWidgets.js.map +1 -0
- package/dist/agent/toolRunner.js +24 -0
- package/dist/agent/toolRunner.js.map +1 -1
- package/dist/agent/toolSearch.js +3 -0
- package/dist/agent/toolSearch.js.map +1 -1
- package/dist/channels/messenger.js +39 -0
- package/dist/channels/messenger.js.map +1 -1
- package/dist/config/config.js +7 -0
- package/dist/config/config.js.map +1 -1
- package/dist/config/schema.js +18 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/eval/harness.js +13 -3
- package/dist/eval/harness.js.map +1 -1
- package/dist/gateway/onboarding.js +91 -0
- package/dist/gateway/onboarding.js.map +1 -0
- package/dist/gateway/routes/skills.js +2 -1
- package/dist/gateway/routes/skills.js.map +1 -1
- package/dist/gateway/routes/studioRouter.js +88 -0
- package/dist/gateway/routes/studioRouter.js.map +1 -0
- package/dist/gateway/routes/watchRouter.js +4 -4
- package/dist/gateway/routes/watchRouter.js.map +1 -1
- package/dist/gateway/server.js +251 -43
- package/dist/gateway/server.js.map +1 -1
- package/dist/memory/taxonomy.js +117 -0
- package/dist/memory/taxonomy.js.map +1 -0
- package/dist/providers/modelCapabilities.js +13 -0
- package/dist/providers/modelCapabilities.js.map +1 -1
- package/dist/providers/ollama.js +8 -2
- package/dist/providers/ollama.js.map +1 -1
- package/dist/providers/openai.js +1 -1
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/openai_compat.js +38 -2
- package/dist/providers/openai_compat.js.map +1 -1
- package/dist/providers/router.js +14 -0
- package/dist/providers/router.js.map +1 -1
- package/dist/recipes/runner.js +8 -1
- package/dist/recipes/runner.js.map +1 -1
- package/dist/recipes/store.js +2 -1
- package/dist/recipes/store.js.map +1 -1
- package/dist/skills/builtin/codebase_explore.js +214 -0
- package/dist/skills/builtin/codebase_explore.js.map +1 -0
- package/dist/skills/builtin/config_audit.js +160 -0
- package/dist/skills/builtin/config_audit.js.map +1 -0
- package/dist/skills/builtin/delegate_agent.js +107 -0
- package/dist/skills/builtin/delegate_agent.js.map +1 -0
- package/dist/skills/builtin/memory_map.js +38 -0
- package/dist/skills/builtin/memory_map.js.map +1 -0
- package/dist/skills/builtin/reminders.js +67 -0
- package/dist/skills/builtin/reminders.js.map +1 -0
- package/dist/skills/builtin/spec.js +139 -0
- package/dist/skills/builtin/spec.js.map +1 -0
- package/dist/skills/builtin/widget_gallery.js +12 -5
- package/dist/skills/builtin/widget_gallery.js.map +1 -1
- package/dist/skills/frontmatterLoader.js +7 -1
- package/dist/skills/frontmatterLoader.js.map +1 -1
- package/dist/skills/registry.js +12 -0
- package/dist/skills/registry.js.map +1 -1
- package/dist/substrate/traceBus.js.map +1 -1
- package/dist/telemetry/traceStore.js +127 -0
- package/dist/telemetry/traceStore.js.map +1 -0
- package/dist/utils/constants.js +1 -1
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/contrast.js +69 -0
- package/dist/utils/contrast.js.map +1 -0
- package/dist/watch/sessionContext.js +14 -0
- package/dist/watch/sessionContext.js.map +1 -0
- package/dist/watch/sessionTrace.js +51 -0
- package/dist/watch/sessionTrace.js.map +1 -0
- package/dist/watch/studioBuffer.js +53 -0
- package/dist/watch/studioBuffer.js.map +1 -0
- package/package.json +4 -3
- package/ui/dist/assets/AboutYouMemory-CZKEOd_O.js +11 -0
- package/ui/dist/assets/AuditPanel-Bu71N5Er.js +1 -0
- package/ui/dist/assets/{AutonomyPanel-CmaXJV8d.js → AutonomyPanel-DB-39dX4.js} +2 -2
- package/ui/dist/assets/{AutopilotPanel-CbohPtXW.js → AutopilotPanel-Cj8oKxWv.js} +1 -1
- package/ui/dist/assets/{AutoresearchPanel-DCwiQ2v2.js → AutoresearchPanel-3s8pjm6Z.js} +2 -2
- package/ui/dist/assets/BackupPanel-EUQJMJE7.js +1 -0
- package/ui/dist/assets/{BrowserPanel-D6UaSxap.js → BrowserPanel-Beo4F5Ar.js} +2 -2
- package/ui/dist/assets/Button-MdXmb4_n.js +1 -0
- package/ui/dist/assets/CPActivity-B1Se9VVc.js +1 -0
- package/ui/dist/assets/CPAgentDetail-BYji6tT8.js +1 -0
- package/ui/dist/assets/CPAgents-BSUKucTe.js +1 -0
- package/ui/dist/assets/CPApprovals-B4v0em6e.js +1 -0
- package/ui/dist/assets/CPCosts-9ikh61Kv.js +1 -0
- package/ui/dist/assets/CPDashboard-sOok2T5v.js +1 -0
- package/ui/dist/assets/{CPFiles-BO73EZwJ.js → CPFiles-DB2nY5JE.js} +1 -1
- package/ui/dist/assets/CPGoals-8Z1yOY8e.js +1 -0
- package/ui/dist/assets/CPInbox-Cq6-UY8F.js +11 -0
- package/ui/dist/assets/CPIssueDetail-NAGfmJg8.js +1 -0
- package/ui/dist/assets/CPIssues-BzX6Rckx.js +1 -0
- package/ui/dist/assets/CPLayout-BcRM6QSg.js +2 -0
- package/ui/dist/assets/CPOrg-B7DQ4UQP.js +1 -0
- package/ui/dist/assets/CPRuns-D-cpPw_M.js +1 -0
- package/ui/dist/assets/{CPSocial-Qw5rKy_4.js → CPSocial-DshtmcK0.js} +3 -3
- package/ui/dist/assets/CPVoice-DfXRnQVU.js +1 -0
- package/ui/dist/assets/{ChannelsPanel-DS21E-Iz.js → ChannelsPanel-BnaTOeyf.js} +1 -1
- package/ui/dist/assets/CheckpointsPanel-C62naE4U.js +1 -0
- package/ui/dist/assets/CommandPostHub-B_L1CAss.js +24 -0
- package/ui/dist/assets/ConfirmDialog-VErHWAbo.js +1 -0
- package/ui/dist/assets/CronPanel-BwMrrZ5d.js +1 -0
- package/ui/dist/assets/{DataTable-PnhPeDBG.js → DataTable-BCqSUuN7.js} +1 -1
- package/ui/dist/assets/{DreamPanel-DIrtlk2K.js → DreamPanel-BNAcCLBB.js} +2 -2
- package/ui/dist/assets/EmptyState-D9kQf1PX.js +1 -0
- package/ui/dist/assets/{EvalHarnessPanel-uYb_ZEQG.js → EvalHarnessPanel-BaMLdBNm.js} +2 -2
- package/ui/dist/assets/EvalPanel-CW-SSjtg.js +1 -0
- package/ui/dist/assets/{FileViewer-CVO3TRs3.js → FileViewer-BL00nsd7.js} +1 -1
- package/ui/dist/assets/FilesPanel-CeC6YUSd.js +16 -0
- package/ui/dist/assets/FleetPanel-EyWF7l3W.js +1 -0
- package/ui/dist/assets/{HomelabPanel-BZvN4LPM.js → HomelabPanel-BRfKRYe7.js} +2 -2
- package/ui/dist/assets/InfraView-Jmqhg_Yc.js +2 -0
- package/ui/dist/assets/{InlineEditableField-mBzpbcLB.js → InlineEditableField-DgMrLDj1.js} +1 -1
- package/ui/dist/assets/Input-CBTwa_Iw.js +1 -0
- package/ui/dist/assets/IntegrationsPanel-DQL-7Ec6.js +1 -0
- package/ui/dist/assets/IntelligenceView-DxD78qfP.js +2 -0
- package/ui/dist/assets/LearningPanel-C_JzSbJU.js +1 -0
- package/ui/dist/assets/LiveStudio-Db5yeaWo.js +7 -0
- package/ui/dist/assets/{LogsPanel-DbP3Mwnr.js → LogsPanel-CpinKwaZ.js} +1 -1
- package/ui/dist/assets/McpPanel-D-MqN_f-.js +1 -0
- package/ui/dist/assets/MemoryGraphPanel-BnD5jRqf.js +1 -0
- package/ui/dist/assets/MemoryTaxonomyPanel-BBI202dd.js +6 -0
- package/ui/dist/assets/MemoryWikiPanel-Dn3XZHL0.js +6 -0
- package/ui/dist/assets/{MeshPanel-Bf-4brXL.js → MeshPanel-C-mRJpr0.js} +1 -1
- package/ui/dist/assets/{MissionCanvas-CJyhnauG.js → MissionCanvas-CbZW83Ch.js} +1 -1
- package/ui/dist/assets/{MissionChat-C2Nto3zM.js → MissionChat-Bs75jPAD.js} +1 -1
- package/ui/dist/assets/{MissionLibrary-RXyBHsLL.js → MissionLibrary-BxQ6SxPe.js} +1 -1
- package/ui/dist/assets/MissionStart-CBuBPasl.js +1 -0
- package/ui/dist/assets/Modal-ybPGvlQs.js +9 -0
- package/ui/dist/assets/{NvidiaPanel-4DlcQlyl.js → NvidiaPanel-DdG13OX4.js} +1 -1
- package/ui/dist/assets/OrganismPanel-xZWUJKyr.js +1 -0
- package/ui/dist/assets/OverviewPanel-B45ZYhJV.js +1 -0
- package/ui/dist/assets/{PageHeader-bnc85wQN.js → PageHeader-DdrbS1aq.js} +1 -1
- package/ui/dist/assets/PersonaProfilesPanel-CKER-EU5.js +8 -0
- package/ui/dist/assets/{PersonasPanel-dR8VppcD.js → PersonasPanel-CMMQ3nh3.js} +1 -1
- package/ui/dist/assets/{PhoneDeskPanel-CdVOY7H9.js → PhoneDeskPanel-Bw_Y-cVE.js} +2 -2
- package/ui/dist/assets/RecipesPanel-DzMcxpJJ.js +1 -0
- package/ui/dist/assets/SecurityPanel-BCq3Fzbr.js +1 -0
- package/ui/dist/assets/SelfImprovePanel-YE3hT8jK.js +1 -0
- package/ui/dist/assets/SelfProposalsPanel-DXuqBM6p.js +1 -0
- package/ui/dist/assets/SessionsPanel-DORz5goR.js +1 -0
- package/ui/dist/assets/SessionsTab-qYHDOuC8.js +1 -0
- package/ui/dist/assets/SettingsPanel-BbwPu1i7.js +1 -0
- package/ui/dist/assets/SettingsView-zgqkDDBJ.js +2 -0
- package/ui/dist/assets/{SkeletonLoader-Cax7YTqW.js → SkeletonLoader-r6OGXaU9.js} +1 -1
- package/ui/dist/assets/SkillsPanel-BjEOBMRo.js +11 -0
- package/ui/dist/assets/{SomaView-eG3wI4S1.js → SomaView-DLzApZVW.js} +2 -2
- package/ui/dist/assets/{StatCard-Djr487DV.js → StatCard-DLq8aBps.js} +1 -1
- package/ui/dist/assets/{StatusBadge-JpCoA33_.js → StatusBadge-BqlvIbdj.js} +1 -1
- package/ui/dist/assets/{Tabs-DJHu-roP.js → Tabs-DdUThlp1.js} +1 -1
- package/ui/dist/assets/TeamsPanel-uIIKoU7I.js +1 -0
- package/ui/dist/assets/{TelemetryPanel-D4PXsd-X.js → TelemetryPanel-dVr3yQQr.js} +1 -1
- package/ui/dist/assets/TitanCanvas-xHAJqwG2.js +945 -0
- package/ui/dist/assets/ToolsView-CG1mZdiy.js +2 -0
- package/ui/dist/assets/{Tooltip-B1LhTXJ8.js → Tooltip-C2tXJcrN.js} +1 -1
- package/ui/dist/assets/TraceViewer-BIMD_Osr.js +1 -0
- package/ui/dist/assets/TracesPanel-nMUiyMj5.js +1 -0
- package/ui/dist/assets/TrainingPanel-CT5R4HWm.js +1 -0
- package/ui/dist/assets/{VoiceOverlay-B_ss7Zg_.js → VoiceOverlay-Br4QnCtw.js} +3 -3
- package/ui/dist/assets/VramPanel-CdnJYytg.js +1 -0
- package/ui/dist/assets/WatchView-TNU6Ns1Q.js +13 -0
- package/ui/dist/assets/WorkTab-wTlX_UKP.js +1 -0
- package/ui/dist/assets/WorkflowBuilderPanel-CDpVt5ux.js +6 -0
- package/ui/dist/assets/WorkflowsPanel-zsFqsLdn.js +11 -0
- package/ui/dist/assets/{archive-gZFnGd5A.js → archive-Bh689DNg.js} +1 -1
- package/ui/dist/assets/{arrow-left-qA0Qer2h.js → arrow-left-WkVYLm80.js} +1 -1
- package/ui/dist/assets/{book-open-DIxdPqmD.js → book-open-ohEXgUsS.js} +1 -1
- package/ui/dist/assets/{bot-CvIF1uHi.js → bot-DvEcyQcD.js} +1 -1
- package/ui/dist/assets/{chart-column-BQiM-Td4.js → chart-column-w3goFd5f.js} +1 -1
- package/ui/dist/assets/{check-DgyDEFtq.js → check-CuRYh4Zh.js} +1 -1
- package/ui/dist/assets/{chevron-right-CQ1NTOtd.js → chevron-right-DbLSHmff.js} +1 -1
- package/ui/dist/assets/{circle-check-big-CAFcaPPH.js → circle-check-big-Bkba568b.js} +1 -1
- package/ui/dist/assets/{circle-stop-C-8xGv0n.js → circle-stop-Bx2ohEg8.js} +1 -1
- package/ui/dist/assets/{clipboard-list-9DdqBj1F.js → clipboard-list-Dj9tORnu.js} +1 -1
- package/ui/dist/assets/{clock-CF9BCIpL.js → clock-JyQAYy6X.js} +1 -1
- package/ui/dist/assets/{dollar-sign-LDRZBae6.js → dollar-sign-XxwPAA2a.js} +1 -1
- package/ui/dist/assets/{download-BBNXvBO0.js → download-D1izVEOL.js} +1 -1
- package/ui/dist/assets/{external-link-D_ji4Bec.js → external-link-DZ_rZsIt.js} +1 -1
- package/ui/dist/assets/{file-text-DrdTDEYp.js → file-text-Cfawu8Bs.js} +1 -1
- package/ui/dist/assets/{flask-conical-BGn5PgFX.js → flask-conical-Ql8QxhgY.js} +1 -1
- package/ui/dist/assets/{folder-BeZZUGnK.js → folder-DAdIw-Pb.js} +1 -1
- package/ui/dist/assets/{funnel-CAJgGO5M.js → funnel-FycfZcXo.js} +1 -1
- package/ui/dist/assets/{git-branch-BcXabeOs.js → git-branch-C2qrhGGu.js} +1 -1
- package/ui/dist/assets/index-Cml2x9pA.js +507 -0
- package/ui/dist/assets/index-yWybhcfI.css +1 -0
- package/ui/dist/assets/{layers-DxYDmPA_.js → layers-yzjtGlHB.js} +1 -1
- package/ui/dist/assets/{legacy-dHWI7k8P.js → legacy-D21WSMF1.js} +1 -1
- package/ui/dist/assets/{lightbulb-B0Du4SM4.js → lightbulb-BZJNK69S.js} +1 -1
- package/ui/dist/assets/{link-CUpaumqr.js → link-CnFkBkaY.js} +1 -1
- package/ui/dist/assets/{list-todo-CDDhmPQB.js → list-todo-BlgfQHup.js} +1 -1
- package/ui/dist/assets/{message-square-D5VWlv-Q.js → message-square-CRsG9u6_.js} +1 -1
- package/ui/dist/assets/{mic-Ddcc6Ann.js → mic-B32RHc7Y.js} +1 -1
- package/ui/dist/assets/{missions-2zox16Tc.js → missions-1iw8Z2_0.js} +1 -1
- package/ui/dist/assets/{network-DaJ7ugwX.js → network-C9RXQGrV.js} +1 -1
- package/ui/dist/assets/{pause-BukaK6rs.js → pause-BT1Bc2q3.js} +1 -1
- package/ui/dist/assets/{pencil-D_YwQBeg.js → pencil-BK5IU6o0.js} +1 -1
- package/ui/dist/assets/{play-BjdwtYMk.js → play-Cl1nC_gc.js} +1 -1
- package/ui/dist/assets/{plug-yISDdeW2.js → plug-DvcpOalj.js} +1 -1
- package/ui/dist/assets/{plus-BSjTdepW.js → plus-Dpo1qfrl.js} +1 -1
- package/ui/dist/assets/{radio-B7kX_yWE.js → radio-C5c9IyqX.js} +1 -1
- package/ui/dist/assets/{refresh-cw-CwDpzXUn.js → refresh-cw-C-iZkzuS.js} +1 -1
- package/ui/dist/assets/{rotate-ccw-7SQDTI0_.js → rotate-ccw-qzrB3SNw.js} +1 -1
- package/ui/dist/assets/{save-CjTPAQM0.js → save-DwR9wQVu.js} +1 -1
- package/ui/dist/assets/{search-BP7VlNxX.js → search-D10l0m3-.js} +1 -1
- package/ui/dist/assets/{send-C2XDuRPf.js → send-DtXGsaFW.js} +1 -1
- package/ui/dist/assets/{server-BE8W-AT4.js → server-BzisF3LL.js} +1 -1
- package/ui/dist/assets/settings-Dbwd1_-c.js +6 -0
- package/ui/dist/assets/{shield-check-s7la2J2K.js → shield-check-CXlDJyAW.js} +1 -1
- package/ui/dist/assets/square-BBC-JKzY.js +11 -0
- package/ui/dist/assets/{terminal-B8IK4WsO.js → terminal-DaBIlWEM.js} +1 -1
- package/ui/dist/assets/{test-tube-Xfn9DJeg.js → test-tube-CDATRD5t.js} +1 -1
- package/ui/dist/assets/{toggle-right-CHpzOIlj.js → toggle-right-DTmrC5RD.js} +1 -1
- package/ui/dist/assets/{trash-2-B1C85ePK.js → trash-2-CTeyjxD_.js} +1 -1
- package/ui/dist/assets/{trending-up-DDGHQZY1.js → trending-up-CXPRjRV4.js} +1 -1
- package/ui/dist/assets/{trophy-D0LhJSPA.js → trophy-DbVdXRtU.js} +1 -1
- package/ui/dist/assets/{volume-2-DMaE91b5.js → volume-2-DYDBmm3M.js} +1 -1
- package/ui/dist/assets/{wifi-off-DR9h8HGA.js → wifi-off-BBuIGbiP.js} +1 -1
- package/ui/dist/assets/zoom-out-D47_pRAO.js +16 -0
- package/ui/dist/index.html +2 -2
- package/ui/dist/sw.js +1 -1
- package/ui/dist/assets/AuditPanel-BaftX5MP.js +0 -1
- package/ui/dist/assets/BackupPanel-DAy9G7Wt.js +0 -1
- package/ui/dist/assets/CPActivity-BYDsUoMn.js +0 -1
- package/ui/dist/assets/CPAgentDetail-Bb9-GAJY.js +0 -1
- package/ui/dist/assets/CPAgents-BTZuGnki.js +0 -1
- package/ui/dist/assets/CPApprovals-BME2ARkO.js +0 -1
- package/ui/dist/assets/CPCosts-mOXwWq0i.js +0 -1
- package/ui/dist/assets/CPDashboard-CTlKGXXQ.js +0 -1
- package/ui/dist/assets/CPGoals-BNWhNP14.js +0 -1
- package/ui/dist/assets/CPInbox-ybe4r8LW.js +0 -16
- package/ui/dist/assets/CPIssueDetail-DaMMGbjw.js +0 -1
- package/ui/dist/assets/CPIssues-BgpQOISw.js +0 -1
- package/ui/dist/assets/CPLayout-bgErauTx.js +0 -2
- package/ui/dist/assets/CPOrg-C8l5SIWJ.js +0 -8
- package/ui/dist/assets/CPRuns-DB8S7loF.js +0 -1
- package/ui/dist/assets/CPVoice-DfwHPewA.js +0 -1
- package/ui/dist/assets/CheckpointsPanel-9-l_8GdG.js +0 -1
- package/ui/dist/assets/CommandPostHub-z55Yrhj1.js +0 -24
- package/ui/dist/assets/CronPanel-kEZK3gpx.js +0 -1
- package/ui/dist/assets/EmptyState-CfvU7SdB.js +0 -1
- package/ui/dist/assets/EvalPanel-CDG-njyj.js +0 -1
- package/ui/dist/assets/FilesPanel-CaLPog2e.js +0 -16
- package/ui/dist/assets/FleetPanel-BtlaV6pH.js +0 -1
- package/ui/dist/assets/InfraView-C0zEuFrR.js +0 -2
- package/ui/dist/assets/Input-CbrMbLgn.js +0 -1
- package/ui/dist/assets/IntegrationsPanel-B4TyR6jC.js +0 -1
- package/ui/dist/assets/IntelligenceView-DZ4HxYZ3.js +0 -2
- package/ui/dist/assets/LearningPanel-B4RIm_iQ.js +0 -1
- package/ui/dist/assets/McpPanel-BmNUFozc.js +0 -1
- package/ui/dist/assets/MemoryGraphPanel-JPurHV0L.js +0 -16
- package/ui/dist/assets/MemoryWikiPanel-DdvCAZHa.js +0 -6
- package/ui/dist/assets/MissionStart-wUkcEP0T.js +0 -1
- package/ui/dist/assets/Modal-BmS7C6FN.js +0 -1
- package/ui/dist/assets/OrganismPanel-C2LYDPrn.js +0 -1
- package/ui/dist/assets/OverviewPanel-DK8uuq4D.js +0 -1
- package/ui/dist/assets/PersonaProfilesPanel-DGtokXUu.js +0 -8
- package/ui/dist/assets/RecipesPanel-D3Zs2wxr.js +0 -1
- package/ui/dist/assets/SecurityPanel-BMERf796.js +0 -1
- package/ui/dist/assets/SelfImprovePanel-BxqWHXCU.js +0 -1
- package/ui/dist/assets/SelfProposalsPanel-CuC94vdx.js +0 -2
- package/ui/dist/assets/SessionsPanel-CQ8qvzp7.js +0 -1
- package/ui/dist/assets/SessionsTab-B3eHV3jf.js +0 -1
- package/ui/dist/assets/SettingsPanel-Cumls7N2.js +0 -1
- package/ui/dist/assets/SettingsView-BtA67pol.js +0 -2
- package/ui/dist/assets/SkillsPanel-CA415CT8.js +0 -11
- package/ui/dist/assets/TeamsPanel-C_Vu6vnY.js +0 -1
- package/ui/dist/assets/TitanCanvas-TuYZSZO7.js +0 -1117
- package/ui/dist/assets/ToolsView-BvTN6vFn.js +0 -2
- package/ui/dist/assets/TraceViewer-Bh8Jo3Dr.js +0 -1
- package/ui/dist/assets/TrainingPanel-Dmbd1rJ-.js +0 -1
- package/ui/dist/assets/VramPanel-CPICbZ2s.js +0 -1
- package/ui/dist/assets/WatchView-BCgLVfiV.js +0 -13
- package/ui/dist/assets/WorkTab-iptofXO9.js +0 -1
- package/ui/dist/assets/WorkflowsPanel-3RYkFHyf.js +0 -11
- package/ui/dist/assets/chevron-up-UyfdjRp6.js +0 -6
- package/ui/dist/assets/index-CUgepw5Q.js +0 -337
- package/ui/dist/assets/index-Dm6zcSTS.css +0 -1
- package/ui/dist/assets/proxy-CWET5FFX.js +0 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/recipes/store.ts"],"sourcesContent":["/**\n * TITAN — Recipe Store\n * Saves and loads personal recipes from ~/.titan/recipes/\n */\nimport { existsSync, readdirSync, readFileSync, writeFileSync, unlinkSync, mkdirSync } from 'fs';\nimport { join } from 'path';\nimport { TITAN_HOME } from '../utils/constants.js';\nimport type { Recipe, RecipeStep } from './types.js';\n\nconst RECIPES_DIR = join(TITAN_HOME, 'recipes');\n\nfunction ensureRecipesDir(): void {\n if (!existsSync(RECIPES_DIR)) mkdirSync(RECIPES_DIR, { recursive: true });\n}\n\n/** Load all saved recipes */\nexport function listRecipes(): Recipe[] {\n ensureRecipesDir();\n return readdirSync(RECIPES_DIR)\n .filter((f) => f.endsWith('.json'))\n .map((f) => {\n try {\n return JSON.parse(readFileSync(join(RECIPES_DIR, f), 'utf-8')) as Recipe;\n } catch {\n return null;\n }\n })\n .filter((r): r is Recipe => r !== null);\n}\n\n/** Get a recipe by ID or slash command */\nexport function getRecipe(idOrSlash: string): Recipe | null {\n const recipes = listRecipes();\n return recipes.find(\n (r) => r.id === idOrSlash || r.slashCommand === idOrSlash\n ) || null;\n}\n\n/** Save or update a recipe */\nexport function saveRecipe(recipe: Recipe): void {\n ensureRecipesDir();\n writeFileSync(join(RECIPES_DIR, `${recipe.id}.json`), JSON.stringify(recipe, null, 2), 'utf-8');\n}\n\n/** Delete a recipe by ID */\nexport function deleteRecipe(id: string): void {\n const path = join(RECIPES_DIR, `${id}.json`);\n if (existsSync(path)) unlinkSync(path);\n}\n\n/** Get a recipe by slash command (e.g. \"code-review\") */\nexport function findBySlashCommand(command: string): Recipe | null {\n return listRecipes().find((r) => r.slashCommand === command) || null;\n}\n\n/** Return built-in starter recipes */\nexport function getBuiltinRecipes(): Recipe[] {\n const now = new Date().toISOString();\n return [\n {\n id: 'code-review',\n name: 'Code Review',\n description: 'Review a file or snippet for bugs, issues, and improvements',\n slashCommand: 'code-review',\n parameters: {\n file: { description: 'Path to the file to review', required: false },\n },\n steps: [\n { prompt: 'Please do a thorough code review of {{file}}. Look for bugs, security issues, performance problems, and suggest improvements. Be direct and specific.' },\n ],\n author: 'Tony Elliott',\n tags: ['coding', 'review'],\n createdAt: now,\n },\n {\n id: 'daily-standup',\n name: 'Daily Standup',\n description: 'Summarise what you did yesterday and plan for today',\n slashCommand: 'standup',\n steps: [\n { prompt: 'Help me prepare my daily standup. Ask me what I worked on yesterday, what I\\'m working on today, and whether I have any blockers. Then format it as a clean standup message I can copy.' },\n ],\n author: 'Tony Elliott',\n tags: ['productivity', 'work'],\n createdAt: now,\n },\n {\n id: 'explain-code',\n name: 'Explain Code',\n description: 'Explain what a piece of code does in plain English',\n slashCommand: 'explain',\n parameters: {\n file: { description: 'File or code snippet to explain', required: false },\n },\n steps: [\n { prompt: 'Please explain {{file}} in plain English. Break down what it does, how it works, and any important patterns or concepts. Assume I\\'m a smart person but may not know this codebase.' },\n ],\n author: 'Tony Elliott',\n tags: ['coding', 'learning'],\n createdAt: now,\n },\n {\n id: 'brainstorm',\n name: 'Brainstorm',\n description: 'Brainstorm ideas on any topic',\n slashCommand: 'brainstorm',\n parameters: {\n topic: { description: 'Topic to brainstorm about', required: true },\n },\n steps: [\n { prompt: 'Let\\'s brainstorm ideas about {{topic}}. Give me at least 10 creative, diverse ideas. Think outside the box and include some unconventional options. Then help me evaluate the best ones.' },\n ],\n author: 'Tony Elliott',\n tags: ['creativity', 'productivity'],\n createdAt: now,\n },\n {\n id: 'debug',\n name: 'Debug Issue',\n description: 'Help debug an error or unexpected behavior',\n slashCommand: 'debug',\n parameters: {\n error: { description: 'The error message or description of the problem', required: false },\n },\n steps: [\n { prompt: 'Help me debug this issue: {{error}}. Walk me through potential root causes, how to diagnose each one, and then provide a fix.' },\n ],\n author: 'Tony Elliott',\n tags: ['coding', 'debugging'],\n createdAt: now,\n },\n {\n id: 'morning-briefing',\n name: 'Morning Briefing',\n description: 'Get a personalised daily briefing — active projects, goals, monitors, and suggested tasks',\n slashCommand: 'briefing',\n steps: [\n {\n prompt: 'Give me my morning briefing. Summarise: (1) my active projects and any recent progress, (2) my current goals and which are highest priority, (3) any active monitors that are watching for events, (4) suggested tasks I could work on today based on what I\\'ve been doing, and (5) one motivational thought to start the day. Be concise and actionable.',\n },\n ],\n author: 'Tony Elliott',\n tags: ['productivity', 'daily', 'briefing'],\n createdAt: now,\n },\n // ── Research Pipeline Recipes (DeerFlow-inspired) ──────────\n {\n id: 'research',\n name: 'Deep Research',\n description: 'Research any topic with parallel agents and get a structured report',\n slashCommand: 'research',\n parameters: {\n topic: { description: 'The topic or question to research', required: true },\n },\n steps: [\n { prompt: 'Use the deep_research_pipeline tool to research: {{topic}}. Use standard depth with full report output.', tool: 'deep_research_pipeline' },\n ],\n author: 'Tony Elliott',\n tags: ['research', 'ai'],\n createdAt: now,\n },\n {\n id: 'market-analysis',\n name: 'Market Analysis',\n description: 'Analyze a market with competitive landscape and trends',\n slashCommand: 'market-analysis',\n parameters: {\n market: { description: 'The market or industry to analyze', required: true },\n },\n steps: [\n { prompt: 'Use the deep_research_pipeline tool to research: \"Comprehensive market analysis of {{market}}: market size, growth trends, key players, competitive landscape, opportunities, and challenges in 2026\". Use 4 sub-questions for thorough coverage.', tool: 'deep_research_pipeline' },\n ],\n author: 'Tony Elliott',\n tags: ['research', 'business'],\n createdAt: now,\n },\n {\n id: 'competitor-intel',\n name: 'Competitor Intelligence',\n description: 'Research a competitor with detailed analysis',\n slashCommand: 'competitor-intel',\n parameters: {\n company: { description: 'The company to research', required: true },\n },\n steps: [\n { prompt: 'Use the deep_research_pipeline tool to research: \"Competitive intelligence report on {{company}}: products, pricing, market position, strengths, weaknesses, recent news, and strategic direction\". Use 4 sub-questions.', tool: 'deep_research_pipeline' },\n ],\n author: 'Tony Elliott',\n tags: ['research', 'business'],\n createdAt: now,\n },\n {\n id: 'tech-report',\n name: 'Tech Deep Dive',\n description: 'Technical deep-dive report on a technology',\n slashCommand: 'tech-report',\n parameters: {\n technology: { description: 'The technology to research', required: true },\n },\n steps: [\n { prompt: 'Use the deep_research_pipeline tool to research: \"Technical deep-dive on {{technology}}: architecture, capabilities, ecosystem, adoption, pros/cons, comparisons, and future outlook\". Use deep depth.', tool: 'deep_research_pipeline' },\n ],\n author: 'Tony Elliott',\n tags: ['research', 'technology'],\n createdAt: now,\n },\n // ── Experiment Recipes (Autoresearch-inspired) ──────────────\n {\n id: 'experiment',\n name: 'Experiment Loop',\n description: 'Start an autonomous experiment loop to optimize something',\n slashCommand: 'experiment',\n parameters: {\n goal: { description: 'What to optimize', required: true },\n },\n steps: [\n { prompt: 'Help me set up an experiment loop. My goal is: {{goal}}. Ask me what file to modify, what command to run for evaluation, and what metric to measure. Then use the experiment_loop tool to start.', tool: 'experiment_loop' },\n ],\n author: 'Tony Elliott',\n tags: ['experimentation', 'optimization'],\n createdAt: now,\n },\n {\n id: 'optimize',\n name: 'Optimize',\n description: 'Iteratively optimize a file or configuration',\n slashCommand: 'optimize',\n parameters: {\n description: { description: 'What to optimize and how', required: true },\n },\n steps: [\n { prompt: 'I want to optimize: {{description}}. Identify the target file, determine an appropriate eval command and metric, then use the experiment_loop tool to run iterative optimization experiments.' },\n ],\n author: 'Tony Elliott',\n tags: ['experimentation', 'optimization'],\n createdAt: now,\n },\n {\n id: 'ab-test',\n name: 'A/B Test',\n description: 'A/B test different approaches with measured results',\n slashCommand: 'ab-test',\n parameters: {\n variants: { description: 'Description of the variants to test', required: true },\n },\n steps: [\n { prompt: 'I want to A/B test: {{variants}}. Help me set up a controlled experiment using the experiment_loop tool. Define clear metrics and run each variant systematically.' },\n ],\n author: 'Tony Elliott',\n tags: ['experimentation', 'testing'],\n createdAt: now,\n },\n // ── Web Automation Recipes ──────────────────────────────\n {\n id: 'fill-form',\n name: 'Fill Web Form',\n description: 'Fill a web form with your data — reads fields, fills, verifies, handles CAPTCHA',\n slashCommand: 'fill-form',\n parameters: {\n url: { description: 'URL of the form to fill', required: true },\n data: { description: 'JSON mapping field labels to values', required: true },\n },\n steps: [\n {\n prompt: 'Use the smart_form_fill tool to fill the form at {{url}} with data: {{data}}. Set submit=true. If CAPTCHA is detected, tell me to complete it manually.',\n tool: 'smart_form_fill',\n },\n ],\n author: 'Tony Elliott',\n tags: ['web', 'forms', 'automation'],\n createdAt: now,\n },\n ];\n}\n\n/** Seed builtin recipes if user has none */\nexport function seedBuiltinRecipes(): void {\n ensureRecipesDir();\n const existing = listRecipes();\n if (existing.length === 0) {\n for (const r of getBuiltinRecipes()) {\n saveRecipe(r);\n }\n }\n}\n\n/** Export a recipe to YAML format */\nexport function exportRecipeYaml(recipe: Recipe): string {\n const lines: string[] = [];\n lines.push(`# TITAN Workflow: ${recipe.name}`);\n lines.push(`id: ${recipe.id}`);\n lines.push(`name: \"${recipe.name}\"`);\n lines.push(`description: \"${recipe.description}\"`);\n if (recipe.slashCommand) lines.push(`slashCommand: ${recipe.slashCommand}`);\n if (recipe.author) lines.push(`author: \"${recipe.author}\"`);\n if (recipe.tags?.length) lines.push(`tags: [${recipe.tags.join(', ')}]`);\n\n if (recipe.parameters && Object.keys(recipe.parameters).length > 0) {\n lines.push('parameters:');\n for (const [key, param] of Object.entries(recipe.parameters)) {\n lines.push(` ${key}:`);\n lines.push(` description: \"${param.description}\"`);\n lines.push(` required: ${param.required}`);\n if (param.default) lines.push(` default: \"${param.default}\"`);\n }\n }\n\n lines.push('steps:');\n for (const step of recipe.steps) {\n lines.push(` - prompt: \"${step.prompt.replace(/\"/g, '\\\\\"')}\"`);\n if (step.tool) lines.push(` tool: ${step.tool}`);\n if (step.awaitConfirm) lines.push(` awaitConfirm: true`);\n }\n\n return lines.join('\\n') + '\\n';\n}\n\n/** Import a recipe from simple YAML-like format */\nexport function importRecipeYaml(yaml: string): Recipe {\n const lines = yaml.split('\\n').filter(l => !l.startsWith('#') && l.trim());\n const recipe: Partial<Recipe> = { steps: [], createdAt: new Date().toISOString() };\n\n let inSteps = false;\n let inParams = false;\n let currentStep: Partial<RecipeStep> = {};\n let currentParamKey = '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed.startsWith('steps:')) { inSteps = true; inParams = false; continue; }\n if (trimmed.startsWith('parameters:')) { inParams = true; inSteps = false; recipe.parameters = {}; continue; }\n\n if (!inSteps && !inParams) {\n const [key, ...rest] = trimmed.split(':');\n const val = rest.join(':').trim().replace(/^[\"']|[\"']$/g, '');\n if (key === 'id') recipe.id = val;\n else if (key === 'name') recipe.name = val;\n else if (key === 'description') recipe.description = val;\n else if (key === 'slashCommand') recipe.slashCommand = val;\n else if (key === 'author') recipe.author = val;\n else if (key === 'tags') recipe.tags = val.replace(/[[\\]]/g, '').split(',').map(t => t.trim());\n } else if (inParams) {\n if (line.match(/^\\s{2}\\w+:$/)) {\n currentParamKey = trimmed.replace(':', '');\n if (recipe.parameters) recipe.parameters[currentParamKey] = { description: '', required: false };\n } else if (currentParamKey && recipe.parameters) {\n const [k, ...v] = trimmed.split(':');\n const val = v.join(':').trim().replace(/^[\"']|[\"']$/g, '');\n if (k.trim() === 'description') recipe.parameters[currentParamKey].description = val;\n else if (k.trim() === 'required') recipe.parameters[currentParamKey].required = val === 'true';\n else if (k.trim() === 'default') recipe.parameters[currentParamKey].default = val;\n }\n } else if (inSteps) {\n if (trimmed.startsWith('- prompt:')) {\n if (currentStep.prompt) recipe.steps!.push(currentStep as RecipeStep);\n currentStep = { prompt: trimmed.replace(/^- prompt:\\s*[\"']?/, '').replace(/[\"']$/, '') };\n } else if (trimmed.startsWith('tool:')) {\n currentStep.tool = trimmed.replace('tool:', '').trim();\n } else if (trimmed.startsWith('awaitConfirm:')) {\n currentStep.awaitConfirm = trimmed.includes('true');\n }\n }\n }\n if (currentStep.prompt) recipe.steps!.push(currentStep as RecipeStep);\n\n if (!recipe.id || !recipe.name || !recipe.steps?.length) {\n throw new Error('Invalid YAML: id, name, and at least one step are required');\n }\n\n return recipe as Recipe;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/recipes/store.ts"],"sourcesContent":["/**\n * TITAN — Recipe Store\n * Saves and loads personal recipes from ~/.titan/recipes/\n */\nimport { existsSync, readdirSync, readFileSync, writeFileSync, unlinkSync, mkdirSync } from 'fs';\nimport { join } from 'path';\nimport { TITAN_HOME } from '../utils/constants.js';\nimport type { Recipe, RecipeStep } from './types.js';\n\nconst RECIPES_DIR = join(TITAN_HOME, 'recipes');\n\nfunction ensureRecipesDir(): void {\n if (!existsSync(RECIPES_DIR)) mkdirSync(RECIPES_DIR, { recursive: true });\n}\n\n/** Load all saved recipes */\nexport function listRecipes(): Recipe[] {\n ensureRecipesDir();\n return readdirSync(RECIPES_DIR)\n .filter((f) => f.endsWith('.json'))\n .map((f) => {\n try {\n return JSON.parse(readFileSync(join(RECIPES_DIR, f), 'utf-8')) as Recipe;\n } catch {\n return null;\n }\n })\n .filter((r): r is Recipe => r !== null);\n}\n\n/** Get a recipe by ID or slash command */\nexport function getRecipe(idOrSlash: string): Recipe | null {\n const recipes = listRecipes();\n return recipes.find(\n (r) => r.id === idOrSlash || r.slashCommand === idOrSlash\n ) || null;\n}\n\n/** Save or update a recipe */\nexport function saveRecipe(recipe: Recipe): void {\n ensureRecipesDir();\n writeFileSync(join(RECIPES_DIR, `${recipe.id}.json`), JSON.stringify(recipe, null, 2), 'utf-8');\n}\n\n/** Delete a recipe by ID */\nexport function deleteRecipe(id: string): void {\n const path = join(RECIPES_DIR, `${id}.json`);\n if (existsSync(path)) unlinkSync(path);\n}\n\n/** Get a recipe by slash command (e.g. \"code-review\") */\nexport function findBySlashCommand(command: string): Recipe | null {\n // Normalize: compare slash-less on both sides so a stored '/foo' (any\n // future source) still resolves against parseSlashCommand's bare 'foo'.\n const bare = command.replace(/^\\/+/, '');\n return listRecipes().find((r) => (r.slashCommand || '').replace(/^\\/+/, '') === bare) || null;\n}\n\n/** Return built-in starter recipes */\nexport function getBuiltinRecipes(): Recipe[] {\n const now = new Date().toISOString();\n return [\n {\n id: 'code-review',\n name: 'Code Review',\n description: 'Review a file or snippet for bugs, issues, and improvements',\n slashCommand: 'code-review',\n parameters: {\n file: { description: 'Path to the file to review', required: false },\n },\n steps: [\n { prompt: 'Please do a thorough code review of {{file}}. Look for bugs, security issues, performance problems, and suggest improvements. Be direct and specific.' },\n ],\n author: 'Tony Elliott',\n tags: ['coding', 'review'],\n createdAt: now,\n },\n {\n id: 'daily-standup',\n name: 'Daily Standup',\n description: 'Summarise what you did yesterday and plan for today',\n slashCommand: 'standup',\n steps: [\n { prompt: 'Help me prepare my daily standup. Ask me what I worked on yesterday, what I\\'m working on today, and whether I have any blockers. Then format it as a clean standup message I can copy.' },\n ],\n author: 'Tony Elliott',\n tags: ['productivity', 'work'],\n createdAt: now,\n },\n {\n id: 'explain-code',\n name: 'Explain Code',\n description: 'Explain what a piece of code does in plain English',\n slashCommand: 'explain',\n parameters: {\n file: { description: 'File or code snippet to explain', required: false },\n },\n steps: [\n { prompt: 'Please explain {{file}} in plain English. Break down what it does, how it works, and any important patterns or concepts. Assume I\\'m a smart person but may not know this codebase.' },\n ],\n author: 'Tony Elliott',\n tags: ['coding', 'learning'],\n createdAt: now,\n },\n {\n id: 'brainstorm',\n name: 'Brainstorm',\n description: 'Brainstorm ideas on any topic',\n slashCommand: 'brainstorm',\n parameters: {\n topic: { description: 'Topic to brainstorm about', required: true },\n },\n steps: [\n { prompt: 'Let\\'s brainstorm ideas about {{topic}}. Give me at least 10 creative, diverse ideas. Think outside the box and include some unconventional options. Then help me evaluate the best ones.' },\n ],\n author: 'Tony Elliott',\n tags: ['creativity', 'productivity'],\n createdAt: now,\n },\n {\n id: 'debug',\n name: 'Debug Issue',\n description: 'Help debug an error or unexpected behavior',\n slashCommand: 'debug',\n parameters: {\n error: { description: 'The error message or description of the problem', required: false },\n },\n steps: [\n { prompt: 'Help me debug this issue: {{error}}. Walk me through potential root causes, how to diagnose each one, and then provide a fix.' },\n ],\n author: 'Tony Elliott',\n tags: ['coding', 'debugging'],\n createdAt: now,\n },\n {\n id: 'morning-briefing',\n name: 'Morning Briefing',\n description: 'Get a personalised daily briefing — active projects, goals, monitors, and suggested tasks',\n slashCommand: 'briefing',\n steps: [\n {\n prompt: 'Give me my morning briefing. Summarise: (1) my active projects and any recent progress, (2) my current goals and which are highest priority, (3) any active monitors that are watching for events, (4) suggested tasks I could work on today based on what I\\'ve been doing, and (5) one motivational thought to start the day. Be concise and actionable.',\n },\n ],\n author: 'Tony Elliott',\n tags: ['productivity', 'daily', 'briefing'],\n createdAt: now,\n },\n // ── Research Pipeline Recipes (DeerFlow-inspired) ──────────\n {\n id: 'research',\n name: 'Deep Research',\n description: 'Research any topic with parallel agents and get a structured report',\n slashCommand: 'research',\n parameters: {\n topic: { description: 'The topic or question to research', required: true },\n },\n steps: [\n { prompt: 'Use the deep_research_pipeline tool to research: {{topic}}. Use standard depth with full report output.', tool: 'deep_research_pipeline' },\n ],\n author: 'Tony Elliott',\n tags: ['research', 'ai'],\n createdAt: now,\n },\n {\n id: 'market-analysis',\n name: 'Market Analysis',\n description: 'Analyze a market with competitive landscape and trends',\n slashCommand: 'market-analysis',\n parameters: {\n market: { description: 'The market or industry to analyze', required: true },\n },\n steps: [\n { prompt: 'Use the deep_research_pipeline tool to research: \"Comprehensive market analysis of {{market}}: market size, growth trends, key players, competitive landscape, opportunities, and challenges in 2026\". Use 4 sub-questions for thorough coverage.', tool: 'deep_research_pipeline' },\n ],\n author: 'Tony Elliott',\n tags: ['research', 'business'],\n createdAt: now,\n },\n {\n id: 'competitor-intel',\n name: 'Competitor Intelligence',\n description: 'Research a competitor with detailed analysis',\n slashCommand: 'competitor-intel',\n parameters: {\n company: { description: 'The company to research', required: true },\n },\n steps: [\n { prompt: 'Use the deep_research_pipeline tool to research: \"Competitive intelligence report on {{company}}: products, pricing, market position, strengths, weaknesses, recent news, and strategic direction\". Use 4 sub-questions.', tool: 'deep_research_pipeline' },\n ],\n author: 'Tony Elliott',\n tags: ['research', 'business'],\n createdAt: now,\n },\n {\n id: 'tech-report',\n name: 'Tech Deep Dive',\n description: 'Technical deep-dive report on a technology',\n slashCommand: 'tech-report',\n parameters: {\n technology: { description: 'The technology to research', required: true },\n },\n steps: [\n { prompt: 'Use the deep_research_pipeline tool to research: \"Technical deep-dive on {{technology}}: architecture, capabilities, ecosystem, adoption, pros/cons, comparisons, and future outlook\". Use deep depth.', tool: 'deep_research_pipeline' },\n ],\n author: 'Tony Elliott',\n tags: ['research', 'technology'],\n createdAt: now,\n },\n // ── Experiment Recipes (Autoresearch-inspired) ──────────────\n {\n id: 'experiment',\n name: 'Experiment Loop',\n description: 'Start an autonomous experiment loop to optimize something',\n slashCommand: 'experiment',\n parameters: {\n goal: { description: 'What to optimize', required: true },\n },\n steps: [\n { prompt: 'Help me set up an experiment loop. My goal is: {{goal}}. Ask me what file to modify, what command to run for evaluation, and what metric to measure. Then use the experiment_loop tool to start.', tool: 'experiment_loop' },\n ],\n author: 'Tony Elliott',\n tags: ['experimentation', 'optimization'],\n createdAt: now,\n },\n {\n id: 'optimize',\n name: 'Optimize',\n description: 'Iteratively optimize a file or configuration',\n slashCommand: 'optimize',\n parameters: {\n description: { description: 'What to optimize and how', required: true },\n },\n steps: [\n { prompt: 'I want to optimize: {{description}}. Identify the target file, determine an appropriate eval command and metric, then use the experiment_loop tool to run iterative optimization experiments.' },\n ],\n author: 'Tony Elliott',\n tags: ['experimentation', 'optimization'],\n createdAt: now,\n },\n {\n id: 'ab-test',\n name: 'A/B Test',\n description: 'A/B test different approaches with measured results',\n slashCommand: 'ab-test',\n parameters: {\n variants: { description: 'Description of the variants to test', required: true },\n },\n steps: [\n { prompt: 'I want to A/B test: {{variants}}. Help me set up a controlled experiment using the experiment_loop tool. Define clear metrics and run each variant systematically.' },\n ],\n author: 'Tony Elliott',\n tags: ['experimentation', 'testing'],\n createdAt: now,\n },\n // ── Web Automation Recipes ──────────────────────────────\n {\n id: 'fill-form',\n name: 'Fill Web Form',\n description: 'Fill a web form with your data — reads fields, fills, verifies, handles CAPTCHA',\n slashCommand: 'fill-form',\n parameters: {\n url: { description: 'URL of the form to fill', required: true },\n data: { description: 'JSON mapping field labels to values', required: true },\n },\n steps: [\n {\n prompt: 'Use the smart_form_fill tool to fill the form at {{url}} with data: {{data}}. Set submit=true. If CAPTCHA is detected, tell me to complete it manually.',\n tool: 'smart_form_fill',\n },\n ],\n author: 'Tony Elliott',\n tags: ['web', 'forms', 'automation'],\n createdAt: now,\n },\n ];\n}\n\n/** Seed builtin recipes if user has none */\nexport function seedBuiltinRecipes(): void {\n ensureRecipesDir();\n const existing = listRecipes();\n if (existing.length === 0) {\n for (const r of getBuiltinRecipes()) {\n saveRecipe(r);\n }\n }\n}\n\n/** Export a recipe to YAML format */\nexport function exportRecipeYaml(recipe: Recipe): string {\n const lines: string[] = [];\n lines.push(`# TITAN Workflow: ${recipe.name}`);\n lines.push(`id: ${recipe.id}`);\n lines.push(`name: \"${recipe.name}\"`);\n lines.push(`description: \"${recipe.description}\"`);\n if (recipe.slashCommand) lines.push(`slashCommand: ${recipe.slashCommand}`);\n if (recipe.author) lines.push(`author: \"${recipe.author}\"`);\n if (recipe.tags?.length) lines.push(`tags: [${recipe.tags.join(', ')}]`);\n\n if (recipe.parameters && Object.keys(recipe.parameters).length > 0) {\n lines.push('parameters:');\n for (const [key, param] of Object.entries(recipe.parameters)) {\n lines.push(` ${key}:`);\n lines.push(` description: \"${param.description}\"`);\n lines.push(` required: ${param.required}`);\n if (param.default) lines.push(` default: \"${param.default}\"`);\n }\n }\n\n lines.push('steps:');\n for (const step of recipe.steps) {\n lines.push(` - prompt: \"${step.prompt.replace(/\"/g, '\\\\\"')}\"`);\n if (step.tool) lines.push(` tool: ${step.tool}`);\n if (step.awaitConfirm) lines.push(` awaitConfirm: true`);\n }\n\n return lines.join('\\n') + '\\n';\n}\n\n/** Import a recipe from simple YAML-like format */\nexport function importRecipeYaml(yaml: string): Recipe {\n const lines = yaml.split('\\n').filter(l => !l.startsWith('#') && l.trim());\n const recipe: Partial<Recipe> = { steps: [], createdAt: new Date().toISOString() };\n\n let inSteps = false;\n let inParams = false;\n let currentStep: Partial<RecipeStep> = {};\n let currentParamKey = '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed.startsWith('steps:')) { inSteps = true; inParams = false; continue; }\n if (trimmed.startsWith('parameters:')) { inParams = true; inSteps = false; recipe.parameters = {}; continue; }\n\n if (!inSteps && !inParams) {\n const [key, ...rest] = trimmed.split(':');\n const val = rest.join(':').trim().replace(/^[\"']|[\"']$/g, '');\n if (key === 'id') recipe.id = val;\n else if (key === 'name') recipe.name = val;\n else if (key === 'description') recipe.description = val;\n else if (key === 'slashCommand') recipe.slashCommand = val;\n else if (key === 'author') recipe.author = val;\n else if (key === 'tags') recipe.tags = val.replace(/[[\\]]/g, '').split(',').map(t => t.trim());\n } else if (inParams) {\n if (line.match(/^\\s{2}\\w+:$/)) {\n currentParamKey = trimmed.replace(':', '');\n if (recipe.parameters) recipe.parameters[currentParamKey] = { description: '', required: false };\n } else if (currentParamKey && recipe.parameters) {\n const [k, ...v] = trimmed.split(':');\n const val = v.join(':').trim().replace(/^[\"']|[\"']$/g, '');\n if (k.trim() === 'description') recipe.parameters[currentParamKey].description = val;\n else if (k.trim() === 'required') recipe.parameters[currentParamKey].required = val === 'true';\n else if (k.trim() === 'default') recipe.parameters[currentParamKey].default = val;\n }\n } else if (inSteps) {\n if (trimmed.startsWith('- prompt:')) {\n if (currentStep.prompt) recipe.steps!.push(currentStep as RecipeStep);\n currentStep = { prompt: trimmed.replace(/^- prompt:\\s*[\"']?/, '').replace(/[\"']$/, '') };\n } else if (trimmed.startsWith('tool:')) {\n currentStep.tool = trimmed.replace('tool:', '').trim();\n } else if (trimmed.startsWith('awaitConfirm:')) {\n currentStep.awaitConfirm = trimmed.includes('true');\n }\n }\n }\n if (currentStep.prompt) recipe.steps!.push(currentStep as RecipeStep);\n\n if (!recipe.id || !recipe.name || !recipe.steps?.length) {\n throw new Error('Invalid YAML: id, name, and at least one step are required');\n }\n\n return recipe as Recipe;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readdirSync, statSync, readFileSync, existsSync } from "fs";
|
|
3
|
+
import { join, relative, extname, basename } from "path";
|
|
4
|
+
import { registerSkill } from "../registry.js";
|
|
5
|
+
import logger from "../../utils/logger.js";
|
|
6
|
+
const COMPONENT = "CodebaseExplore";
|
|
7
|
+
const IGNORED_DIRS = /* @__PURE__ */ new Set([
|
|
8
|
+
"node_modules",
|
|
9
|
+
".git",
|
|
10
|
+
"dist",
|
|
11
|
+
"build",
|
|
12
|
+
".next",
|
|
13
|
+
"out",
|
|
14
|
+
"coverage",
|
|
15
|
+
"vendor",
|
|
16
|
+
"__pycache__",
|
|
17
|
+
".venv",
|
|
18
|
+
"venv",
|
|
19
|
+
".cache",
|
|
20
|
+
"target",
|
|
21
|
+
".turbo",
|
|
22
|
+
".idea",
|
|
23
|
+
".vscode",
|
|
24
|
+
"tmp",
|
|
25
|
+
".pytest_cache",
|
|
26
|
+
"ui/dist",
|
|
27
|
+
".gitnexus"
|
|
28
|
+
]);
|
|
29
|
+
const LANG_BY_EXT = {
|
|
30
|
+
".ts": "TypeScript",
|
|
31
|
+
".tsx": "TypeScript/React",
|
|
32
|
+
".js": "JavaScript",
|
|
33
|
+
".jsx": "JavaScript/React",
|
|
34
|
+
".mjs": "JavaScript",
|
|
35
|
+
".cjs": "JavaScript",
|
|
36
|
+
".py": "Python",
|
|
37
|
+
".go": "Go",
|
|
38
|
+
".rs": "Rust",
|
|
39
|
+
".java": "Java",
|
|
40
|
+
".rb": "Ruby",
|
|
41
|
+
".php": "PHP",
|
|
42
|
+
".c": "C",
|
|
43
|
+
".h": "C",
|
|
44
|
+
".cpp": "C++",
|
|
45
|
+
".cc": "C++",
|
|
46
|
+
".cs": "C#",
|
|
47
|
+
".swift": "Swift",
|
|
48
|
+
".kt": "Kotlin",
|
|
49
|
+
".scala": "Scala",
|
|
50
|
+
".sh": "Shell",
|
|
51
|
+
".bash": "Shell",
|
|
52
|
+
".sql": "SQL",
|
|
53
|
+
".css": "CSS",
|
|
54
|
+
".scss": "SCSS",
|
|
55
|
+
".html": "HTML",
|
|
56
|
+
".vue": "Vue",
|
|
57
|
+
".svelte": "Svelte",
|
|
58
|
+
".md": "Markdown",
|
|
59
|
+
".json": "JSON",
|
|
60
|
+
".yaml": "YAML",
|
|
61
|
+
".yml": "YAML",
|
|
62
|
+
".toml": "TOML"
|
|
63
|
+
};
|
|
64
|
+
const KEY_FILES = [
|
|
65
|
+
{ match: /^package\.json$/, kind: "Node manifest" },
|
|
66
|
+
{ match: /^pyproject\.toml$|^setup\.py$|^requirements\.txt$/, kind: "Python manifest" },
|
|
67
|
+
{ match: /^go\.mod$/, kind: "Go module" },
|
|
68
|
+
{ match: /^Cargo\.toml$/, kind: "Rust crate" },
|
|
69
|
+
{ match: /^pom\.xml$|^build\.gradle$/, kind: "JVM build" },
|
|
70
|
+
{ match: /^Gemfile$/, kind: "Ruby bundle" },
|
|
71
|
+
{ match: /^composer\.json$/, kind: "PHP composer" },
|
|
72
|
+
{ match: /^Dockerfile$|^docker-compose\.ya?ml$/, kind: "container" },
|
|
73
|
+
{ match: /^readme(\.md)?$/i, kind: "README" },
|
|
74
|
+
{ match: /^tsconfig\.json$/, kind: "TS config" },
|
|
75
|
+
{ match: /^\.env(\.example)?$/, kind: "env template" }
|
|
76
|
+
];
|
|
77
|
+
function exploreCodebase(root, opts = {}) {
|
|
78
|
+
const maxDepth = opts.maxDepth ?? 6;
|
|
79
|
+
const maxFiles = opts.maxFiles ?? 4e3;
|
|
80
|
+
const languages = {};
|
|
81
|
+
const keyFiles = [];
|
|
82
|
+
const dirFileCounts = /* @__PURE__ */ new Map();
|
|
83
|
+
let fileCount = 0;
|
|
84
|
+
let dirCount = 0;
|
|
85
|
+
let truncated = false;
|
|
86
|
+
function walk(dir, depth) {
|
|
87
|
+
if (depth > maxDepth || truncated) return;
|
|
88
|
+
let entries;
|
|
89
|
+
try {
|
|
90
|
+
entries = readdirSync(dir);
|
|
91
|
+
} catch {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
for (const name of entries) {
|
|
95
|
+
if (name.startsWith(".") && name !== ".env" && name !== ".env.example") {
|
|
96
|
+
if (IGNORED_DIRS.has(name)) continue;
|
|
97
|
+
}
|
|
98
|
+
const full = join(dir, name);
|
|
99
|
+
let st;
|
|
100
|
+
try {
|
|
101
|
+
st = statSync(full);
|
|
102
|
+
} catch {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (st.isDirectory()) {
|
|
106
|
+
if (IGNORED_DIRS.has(name)) continue;
|
|
107
|
+
dirCount++;
|
|
108
|
+
walk(full, depth + 1);
|
|
109
|
+
} else if (st.isFile()) {
|
|
110
|
+
if (fileCount >= maxFiles) {
|
|
111
|
+
truncated = true;
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
fileCount++;
|
|
115
|
+
const rel = relative(root, full);
|
|
116
|
+
const ext = extname(name).toLowerCase();
|
|
117
|
+
const lang = LANG_BY_EXT[ext];
|
|
118
|
+
if (lang) languages[lang] = (languages[lang] || 0) + 1;
|
|
119
|
+
const topDir = rel.includes("/") ? rel.split("/")[0] : ".";
|
|
120
|
+
dirFileCounts.set(topDir, (dirFileCounts.get(topDir) || 0) + 1);
|
|
121
|
+
for (const kf of KEY_FILES) {
|
|
122
|
+
if (kf.match.test(name)) {
|
|
123
|
+
keyFiles.push({ path: rel, kind: kf.kind });
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
walk(root, 0);
|
|
131
|
+
const entrypoints = resolveEntrypoints(root);
|
|
132
|
+
const topDirs = [...dirFileCounts.entries()].filter(([d]) => d !== ".").sort((a, b) => b[1] - a[1]).slice(0, 8).map(([dir, files]) => ({ dir, files }));
|
|
133
|
+
const sortedLangs = {};
|
|
134
|
+
for (const [k, v] of Object.entries(languages).sort((a, b) => b[1] - a[1])) sortedLangs[k] = v;
|
|
135
|
+
return { root, fileCount, dirCount, languages: sortedLangs, entrypoints, keyFiles, topDirs, truncated };
|
|
136
|
+
}
|
|
137
|
+
function resolveEntrypoints(root) {
|
|
138
|
+
const found = [];
|
|
139
|
+
const pkgPath = join(root, "package.json");
|
|
140
|
+
if (existsSync(pkgPath)) {
|
|
141
|
+
try {
|
|
142
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
143
|
+
if (typeof pkg.main === "string") found.push(pkg.main);
|
|
144
|
+
if (pkg.bin && typeof pkg.bin === "object") {
|
|
145
|
+
for (const v of Object.values(pkg.bin)) if (typeof v === "string") found.push(v);
|
|
146
|
+
else if (typeof pkg.bin === "string") found.push(pkg.bin);
|
|
147
|
+
}
|
|
148
|
+
const startScript = pkg.scripts?.start;
|
|
149
|
+
if (startScript) {
|
|
150
|
+
const m = startScript.match(/\b([\w./-]+\.(?:js|mjs|cjs|ts))\b/);
|
|
151
|
+
if (m) found.push(m[1]);
|
|
152
|
+
}
|
|
153
|
+
} catch {
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
for (const cand of ["src/index.ts", "src/index.js", "src/main.ts", "index.ts", "index.js", "main.py", "app.py", "__main__.py", "cmd/main.go", "main.go", "src/main.rs"]) {
|
|
157
|
+
if (existsSync(join(root, cand))) found.push(cand);
|
|
158
|
+
}
|
|
159
|
+
return [...new Set(found.map((f) => f.replace(/^\.\//, "")))].slice(0, 8);
|
|
160
|
+
}
|
|
161
|
+
function formatCodebaseMap(m) {
|
|
162
|
+
const lines = [];
|
|
163
|
+
lines.push(`# Codebase map \u2014 ${basename(m.root) || m.root}`);
|
|
164
|
+
lines.push(`${m.fileCount} files across ${m.dirCount} dirs${m.truncated ? " (truncated at cap)" : ""}`);
|
|
165
|
+
const langs = Object.entries(m.languages).slice(0, 6).map(([l, n]) => `${l} (${n})`).join(", ");
|
|
166
|
+
if (langs) lines.push(`
|
|
167
|
+
**Languages:** ${langs}`);
|
|
168
|
+
if (m.entrypoints.length) lines.push(`
|
|
169
|
+
**Entrypoints:** ${m.entrypoints.join(", ")}`);
|
|
170
|
+
if (m.topDirs.length) lines.push(`
|
|
171
|
+
**Top source dirs:**
|
|
172
|
+
${m.topDirs.map((d) => `- \`${d.dir}/\` \u2014 ${d.files} files`).join("\n")}`);
|
|
173
|
+
if (m.keyFiles.length) {
|
|
174
|
+
const shown = m.keyFiles.slice(0, 12);
|
|
175
|
+
lines.push(`
|
|
176
|
+
**Key files:**
|
|
177
|
+
${shown.map((k) => `- \`${k.path}\` \u2014 ${k.kind}`).join("\n")}`);
|
|
178
|
+
}
|
|
179
|
+
return lines.join("\n");
|
|
180
|
+
}
|
|
181
|
+
function registerCodebaseExploreSkill() {
|
|
182
|
+
registerSkill(
|
|
183
|
+
{ name: "codebase_explore", description: "Map a codebase: languages, entrypoints, key files, structure", version: "1.0.0", source: "bundled", enabled: true },
|
|
184
|
+
{
|
|
185
|
+
name: "codebase_explore",
|
|
186
|
+
description: 'Explore + map a codebase to understand it before working on it. Walks the repo (skipping node_modules/.git/dist/\u2026), classifies languages, finds entrypoints + manifests + key files, and ranks the largest source dirs. Returns a structured map.\n\nUSE THIS WHEN: starting work in an unfamiliar repo, "understand this project", "where is the entrypoint", before a refactor/feature. Pass a path (defaults to the current directory).',
|
|
187
|
+
parameters: {
|
|
188
|
+
type: "object",
|
|
189
|
+
properties: {
|
|
190
|
+
path: { type: "string", description: "Directory to explore. Defaults to the current working directory." },
|
|
191
|
+
maxDepth: { type: "number", description: "Max directory depth (default 6)." }
|
|
192
|
+
},
|
|
193
|
+
required: []
|
|
194
|
+
},
|
|
195
|
+
execute: async (args) => {
|
|
196
|
+
const path = args.path || process.cwd();
|
|
197
|
+
if (!existsSync(path)) return `Path not found: ${path}`;
|
|
198
|
+
try {
|
|
199
|
+
const map = exploreCodebase(path, { maxDepth: args.maxDepth });
|
|
200
|
+
logger.info(COMPONENT, `Explored ${path}: ${map.fileCount} files, ${Object.keys(map.languages).length} languages`);
|
|
201
|
+
return formatCodebaseMap(map);
|
|
202
|
+
} catch (e) {
|
|
203
|
+
return `Codebase exploration failed: ${e.message}`;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
export {
|
|
210
|
+
exploreCodebase,
|
|
211
|
+
formatCodebaseMap,
|
|
212
|
+
registerCodebaseExploreSkill
|
|
213
|
+
};
|
|
214
|
+
//# sourceMappingURL=codebase_explore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/skills/builtin/codebase_explore.ts"],"sourcesContent":["/**\n * TITAN — Codebase Exploration Skill (v7.0, beats the operator-shell repo map)\n *\n * Active, iterative repo understanding: walk the tree, classify languages,\n * locate entrypoints + key files, and produce a structured map the agent can\n * reason over BEFORE touching code — instead of relying on a stale static index.\n *\n * `exploreCodebase()` is a pure-ish function (reads fs, no globals) exported for\n * tests. The `codebase_explore` tool wraps it for the agent.\n */\nimport { readdirSync, statSync, readFileSync, existsSync } from 'fs';\nimport { join, relative, extname, basename } from 'path';\nimport { registerSkill } from '../registry.js';\nimport logger from '../../utils/logger.js';\n\nconst COMPONENT = 'CodebaseExplore';\n\n/** Directories that are never source — skipped during the walk. */\nconst IGNORED_DIRS = new Set([\n 'node_modules', '.git', 'dist', 'build', '.next', 'out', 'coverage',\n 'vendor', '__pycache__', '.venv', 'venv', '.cache', 'target', '.turbo',\n '.idea', '.vscode', 'tmp', '.pytest_cache', 'ui/dist', '.gitnexus',\n]);\n\n/** Extension → language label. */\nconst LANG_BY_EXT: Record<string, string> = {\n '.ts': 'TypeScript', '.tsx': 'TypeScript/React', '.js': 'JavaScript', '.jsx': 'JavaScript/React',\n '.mjs': 'JavaScript', '.cjs': 'JavaScript', '.py': 'Python', '.go': 'Go', '.rs': 'Rust',\n '.java': 'Java', '.rb': 'Ruby', '.php': 'PHP', '.c': 'C', '.h': 'C', '.cpp': 'C++', '.cc': 'C++',\n '.cs': 'C#', '.swift': 'Swift', '.kt': 'Kotlin', '.scala': 'Scala', '.sh': 'Shell', '.bash': 'Shell',\n '.sql': 'SQL', '.css': 'CSS', '.scss': 'SCSS', '.html': 'HTML', '.vue': 'Vue', '.svelte': 'Svelte',\n '.md': 'Markdown', '.json': 'JSON', '.yaml': 'YAML', '.yml': 'YAML', '.toml': 'TOML',\n};\n\n/** Files that signal a project's shape. */\nconst KEY_FILES: Array<{ match: RegExp; kind: string }> = [\n { match: /^package\\.json$/, kind: 'Node manifest' },\n { match: /^pyproject\\.toml$|^setup\\.py$|^requirements\\.txt$/, kind: 'Python manifest' },\n { match: /^go\\.mod$/, kind: 'Go module' },\n { match: /^Cargo\\.toml$/, kind: 'Rust crate' },\n { match: /^pom\\.xml$|^build\\.gradle$/, kind: 'JVM build' },\n { match: /^Gemfile$/, kind: 'Ruby bundle' },\n { match: /^composer\\.json$/, kind: 'PHP composer' },\n { match: /^Dockerfile$|^docker-compose\\.ya?ml$/, kind: 'container' },\n { match: /^readme(\\.md)?$/i, kind: 'README' },\n { match: /^tsconfig\\.json$/, kind: 'TS config' },\n { match: /^\\.env(\\.example)?$/, kind: 'env template' },\n];\n\nexport interface CodebaseMap {\n root: string;\n fileCount: number;\n dirCount: number;\n /** Language label → file count, descending. */\n languages: Record<string, number>;\n /** Likely program entrypoints (relative paths). */\n entrypoints: string[];\n /** Project-shape files (manifests, README, configs). */\n keyFiles: Array<{ path: string; kind: string }>;\n /** Largest source directories by file count. */\n topDirs: Array<{ dir: string; files: number }>;\n /** Whether the walk hit the file cap. */\n truncated: boolean;\n}\n\ninterface ExploreOpts {\n maxDepth?: number; // default 6\n maxFiles?: number; // default 4000 — keeps a huge monorepo bounded\n}\n\n/** Walk + analyze a codebase rooted at `root`. Pure aside from fs reads. */\nexport function exploreCodebase(root: string, opts: ExploreOpts = {}): CodebaseMap {\n const maxDepth = opts.maxDepth ?? 6;\n const maxFiles = opts.maxFiles ?? 4000;\n const languages: Record<string, number> = {};\n const keyFiles: CodebaseMap['keyFiles'] = [];\n const dirFileCounts = new Map<string, number>();\n let fileCount = 0;\n let dirCount = 0;\n let truncated = false;\n\n function walk(dir: string, depth: number): void {\n if (depth > maxDepth || truncated) return;\n let entries: string[];\n try { entries = readdirSync(dir); } catch { return; }\n for (const name of entries) {\n if (name.startsWith('.') && name !== '.env' && name !== '.env.example') {\n if (IGNORED_DIRS.has(name)) continue;\n }\n const full = join(dir, name);\n let st;\n try { st = statSync(full); } catch { continue; }\n if (st.isDirectory()) {\n if (IGNORED_DIRS.has(name)) continue;\n dirCount++;\n walk(full, depth + 1);\n } else if (st.isFile()) {\n if (fileCount >= maxFiles) { truncated = true; return; }\n fileCount++;\n const rel = relative(root, full);\n const ext = extname(name).toLowerCase();\n const lang = LANG_BY_EXT[ext];\n if (lang) languages[lang] = (languages[lang] || 0) + 1;\n // track per-top-dir file counts\n const topDir = rel.includes('/') ? rel.split('/')[0] : '.';\n dirFileCounts.set(topDir, (dirFileCounts.get(topDir) || 0) + 1);\n // key files\n for (const kf of KEY_FILES) {\n if (kf.match.test(name)) { keyFiles.push({ path: rel, kind: kf.kind }); break; }\n }\n }\n }\n }\n walk(root, 0);\n\n // Resolve entrypoints from manifests + conventional files.\n const entrypoints = resolveEntrypoints(root);\n\n const topDirs = [...dirFileCounts.entries()]\n .filter(([d]) => d !== '.')\n .sort((a, b) => b[1] - a[1])\n .slice(0, 8)\n .map(([dir, files]) => ({ dir, files }));\n\n // Sort languages descending.\n const sortedLangs: Record<string, number> = {};\n for (const [k, v] of Object.entries(languages).sort((a, b) => b[1] - a[1])) sortedLangs[k] = v;\n\n return { root, fileCount, dirCount, languages: sortedLangs, entrypoints, keyFiles, topDirs, truncated };\n}\n\n/** Find likely entrypoints from manifests + conventional file names. */\nfunction resolveEntrypoints(root: string): string[] {\n const found: string[] = [];\n const pkgPath = join(root, 'package.json');\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n if (typeof pkg.main === 'string') found.push(pkg.main);\n if (pkg.bin && typeof pkg.bin === 'object') for (const v of Object.values(pkg.bin)) if (typeof v === 'string') found.push(v);\n else if (typeof pkg.bin === 'string') found.push(pkg.bin);\n const startScript = pkg.scripts?.start as string | undefined;\n if (startScript) {\n const m = startScript.match(/\\b([\\w./-]+\\.(?:js|mjs|cjs|ts))\\b/);\n if (m) found.push(m[1]);\n }\n } catch { /* malformed manifest — fall through to conventions */ }\n }\n for (const cand of ['src/index.ts', 'src/index.js', 'src/main.ts', 'index.ts', 'index.js', 'main.py', 'app.py', '__main__.py', 'cmd/main.go', 'main.go', 'src/main.rs']) {\n if (existsSync(join(root, cand))) found.push(cand);\n }\n // de-dup, keep order, cap\n return [...new Set(found.map((f) => f.replace(/^\\.\\//, '')))].slice(0, 8);\n}\n\n/** Render the map as a readable report for the agent. */\nexport function formatCodebaseMap(m: CodebaseMap): string {\n const lines: string[] = [];\n lines.push(`# Codebase map — ${basename(m.root) || m.root}`);\n lines.push(`${m.fileCount} files across ${m.dirCount} dirs${m.truncated ? ' (truncated at cap)' : ''}`);\n const langs = Object.entries(m.languages).slice(0, 6).map(([l, n]) => `${l} (${n})`).join(', ');\n if (langs) lines.push(`\\n**Languages:** ${langs}`);\n if (m.entrypoints.length) lines.push(`\\n**Entrypoints:** ${m.entrypoints.join(', ')}`);\n if (m.topDirs.length) lines.push(`\\n**Top source dirs:**\\n${m.topDirs.map((d) => `- \\`${d.dir}/\\` — ${d.files} files`).join('\\n')}`);\n if (m.keyFiles.length) {\n const shown = m.keyFiles.slice(0, 12);\n lines.push(`\\n**Key files:**\\n${shown.map((k) => `- \\`${k.path}\\` — ${k.kind}`).join('\\n')}`);\n }\n return lines.join('\\n');\n}\n\nexport function registerCodebaseExploreSkill(): void {\n registerSkill(\n { name: 'codebase_explore', description: 'Map a codebase: languages, entrypoints, key files, structure', version: '1.0.0', source: 'bundled', enabled: true },\n {\n name: 'codebase_explore',\n description:\n 'Explore + map a codebase to understand it before working on it. Walks the repo (skipping node_modules/.git/dist/…), classifies languages, finds entrypoints + manifests + key files, and ranks the largest source dirs. Returns a structured map.\\n\\nUSE THIS WHEN: starting work in an unfamiliar repo, \"understand this project\", \"where is the entrypoint\", before a refactor/feature. Pass a path (defaults to the current directory).',\n parameters: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Directory to explore. Defaults to the current working directory.' },\n maxDepth: { type: 'number', description: 'Max directory depth (default 6).' },\n },\n required: [],\n },\n execute: async (args: Record<string, unknown>): Promise<string> => {\n const path = (args.path as string) || process.cwd();\n if (!existsSync(path)) return `Path not found: ${path}`;\n try {\n const map = exploreCodebase(path, { maxDepth: args.maxDepth as number | undefined });\n logger.info(COMPONENT, `Explored ${path}: ${map.fileCount} files, ${Object.keys(map.languages).length} languages`);\n return formatCodebaseMap(map);\n } catch (e) {\n return `Codebase exploration failed: ${(e as Error).message}`;\n }\n },\n },\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { registerSkill } from "../registry.js";
|
|
3
|
+
import { loadConfig } from "../../config/config.js";
|
|
4
|
+
import logger from "../../utils/logger.js";
|
|
5
|
+
const COMPONENT = "ConfigAudit";
|
|
6
|
+
const SECRET_PATTERNS = [
|
|
7
|
+
{ name: "Anthropic API key", re: /\bsk-ant-[A-Za-z0-9_-]{20,}/ },
|
|
8
|
+
{ name: "OpenAI-style API key", re: /\bsk-[A-Za-z0-9]{32,}\b/ },
|
|
9
|
+
{ name: "AWS access key", re: /\bAKIA[0-9A-Z]{16}\b/ },
|
|
10
|
+
{ name: "Google API key", re: /\bAIza[0-9A-Za-z_-]{35}\b/ },
|
|
11
|
+
{ name: "private key block", re: /-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/ }
|
|
12
|
+
];
|
|
13
|
+
const DANGEROUS_TOOLS = ["shell", "exec", "code_exec", "execute_code", "computer_use", "apply_patch"];
|
|
14
|
+
function collectStrings(obj, path = "", out = []) {
|
|
15
|
+
if (typeof obj === "string") {
|
|
16
|
+
out.push({ path, value: obj });
|
|
17
|
+
} else if (Array.isArray(obj)) {
|
|
18
|
+
obj.forEach((v, i) => collectStrings(v, `${path}[${i}]`, out));
|
|
19
|
+
} else if (obj && typeof obj === "object") {
|
|
20
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
21
|
+
collectStrings(v, path ? `${path}.${k}` : k, out);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return out;
|
|
25
|
+
}
|
|
26
|
+
function auditConfig(config) {
|
|
27
|
+
const findings = [];
|
|
28
|
+
const get = (path) => path.split(".").reduce((o, k) => o && typeof o === "object" ? o[k] : void 0, config);
|
|
29
|
+
const authMode = get("gateway.auth.mode");
|
|
30
|
+
const authToken = get("gateway.auth.token");
|
|
31
|
+
const scan = get("security.preExecScan");
|
|
32
|
+
const allowed = get("agent.allowedTools");
|
|
33
|
+
const meshEnabled = get("mesh.enabled");
|
|
34
|
+
if (!authMode || authMode === "none") {
|
|
35
|
+
findings.push({
|
|
36
|
+
id: "auth-none",
|
|
37
|
+
severity: "critical",
|
|
38
|
+
title: "Gateway authentication is disabled",
|
|
39
|
+
detail: 'gateway.auth.mode is "none" \u2014 anyone who can reach the gateway port has full control of the agent, its tools, and its provider keys.',
|
|
40
|
+
remediation: 'Set gateway.auth.mode to "token" or "password" and configure a strong secret.'
|
|
41
|
+
});
|
|
42
|
+
} else if (authMode === "token" && !authToken) {
|
|
43
|
+
findings.push({
|
|
44
|
+
id: "auth-token-empty",
|
|
45
|
+
severity: "high",
|
|
46
|
+
title: "Token auth selected but no token is set",
|
|
47
|
+
detail: 'gateway.auth.mode is "token" but gateway.auth.token is empty \u2014 TITAN treats this as auth-disabled, so the gateway is effectively open.',
|
|
48
|
+
remediation: "Set gateway.auth.token to a strong secret, or switch to password mode."
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
if (scan === "off") {
|
|
52
|
+
findings.push({
|
|
53
|
+
id: "prescan-off",
|
|
54
|
+
severity: "high",
|
|
55
|
+
title: "Pre-execution command scanner is off",
|
|
56
|
+
detail: 'security.preExecScan is "off" \u2014 shell/exec commands run with no safety screening.',
|
|
57
|
+
remediation: 'Set security.preExecScan to "block" (recommended) or at least "warn".'
|
|
58
|
+
});
|
|
59
|
+
} else if (scan === "warn") {
|
|
60
|
+
findings.push({
|
|
61
|
+
id: "prescan-warn",
|
|
62
|
+
severity: "medium",
|
|
63
|
+
title: "Command scanner is warn-only (fail-open)",
|
|
64
|
+
detail: 'security.preExecScan is "warn" \u2014 dangerous commands are logged but NOT blocked. The scanner flags risk but still lets the command run.',
|
|
65
|
+
remediation: 'Set security.preExecScan to "block" to actually stop flagged commands.'
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
if (Array.isArray(allowed)) {
|
|
69
|
+
const dangerous = DANGEROUS_TOOLS.filter((t) => allowed.includes(t));
|
|
70
|
+
if (dangerous.length > 0) {
|
|
71
|
+
findings.push({
|
|
72
|
+
id: "dangerous-tools",
|
|
73
|
+
severity: "medium",
|
|
74
|
+
title: `Destructive tools enabled: ${dangerous.join(", ")}`,
|
|
75
|
+
detail: `agent.allowedTools includes destructive tools (${dangerous.join(", ")}). These should be gated by approval and screened by the command scanner.`,
|
|
76
|
+
remediation: 'Confirm approval gates are active and security.preExecScan is "block", or remove unused destructive tools from allowedTools.'
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
for (const { path, value } of collectStrings(config)) {
|
|
81
|
+
for (const { name, re } of SECRET_PATTERNS) {
|
|
82
|
+
if (re.test(value)) {
|
|
83
|
+
findings.push({
|
|
84
|
+
id: `secret-${path}`,
|
|
85
|
+
severity: "high",
|
|
86
|
+
title: `Possible ${name} hardcoded in config`,
|
|
87
|
+
detail: `A value at config path "${path}" matches a ${name} pattern. Secrets in the config file leak easily (backups, git, shares); TITAN reads provider keys from environment variables.`,
|
|
88
|
+
remediation: `Move this secret to an environment variable and remove it from the config file.`
|
|
89
|
+
});
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (meshEnabled === true) {
|
|
95
|
+
const meshSecret = get("mesh.hmacSecret") || get("mesh.secret") || get("mesh.psk");
|
|
96
|
+
if (!meshSecret) {
|
|
97
|
+
findings.push({
|
|
98
|
+
id: "mesh-no-auth",
|
|
99
|
+
severity: "medium",
|
|
100
|
+
title: "Mesh networking is enabled without a shared secret",
|
|
101
|
+
detail: "mesh.enabled is true but no HMAC/shared secret is configured \u2014 peers may be able to connect without authentication.",
|
|
102
|
+
remediation: "Configure a mesh shared secret / HMAC key, or disable mesh if it is unused."
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return findings;
|
|
107
|
+
}
|
|
108
|
+
const SEV_ORDER = ["critical", "high", "medium", "low", "info"];
|
|
109
|
+
const SEV_ICON = {
|
|
110
|
+
critical: "\u{1F534}",
|
|
111
|
+
high: "\u{1F7E0}",
|
|
112
|
+
medium: "\u{1F7E1}",
|
|
113
|
+
low: "\u26AA",
|
|
114
|
+
info: "\u2139\uFE0F"
|
|
115
|
+
};
|
|
116
|
+
function formatAuditReport(findings) {
|
|
117
|
+
if (findings.length === 0) {
|
|
118
|
+
return "\u2705 Config self-audit: no misconfigurations found. Gateway auth, command scanning, tool permissions, secrets, and mesh all look sound.";
|
|
119
|
+
}
|
|
120
|
+
const groups = SEV_ORDER.map((sev) => ({ sev, items: findings.filter((f) => f.severity === sev) })).filter((g) => g.items.length > 0);
|
|
121
|
+
const counts = groups.map((g) => `${g.items.length} ${g.sev}`).join(", ");
|
|
122
|
+
const lines = [`\u{1F6E1}\uFE0F Config self-audit \u2014 ${findings.length} finding(s): ${counts}`, ""];
|
|
123
|
+
for (const { sev, items } of groups) {
|
|
124
|
+
for (const f of items) {
|
|
125
|
+
lines.push(`${SEV_ICON[sev]} [${sev.toUpperCase()}] ${f.title}`);
|
|
126
|
+
lines.push(` ${f.detail}`);
|
|
127
|
+
lines.push(` \u2192 Fix: ${f.remediation}`);
|
|
128
|
+
lines.push("");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return lines.join("\n").trim();
|
|
132
|
+
}
|
|
133
|
+
function registerConfigAuditSkill() {
|
|
134
|
+
registerSkill(
|
|
135
|
+
{ name: "config_audit", description: "Audit TITAN's own configuration for security misconfigurations", version: "1.0.0", source: "bundled", enabled: true },
|
|
136
|
+
{
|
|
137
|
+
name: "config_audit",
|
|
138
|
+
description: `Run a security self-audit of TITAN's OWN configuration (not external code). Checks gateway authentication, the pre-execution command scanner, destructive-tool permissions, provider secrets misplaced in config, and mesh authentication. Returns a severity-ranked report with remediation.
|
|
139
|
+
|
|
140
|
+
USE THIS WHEN: "is my setup secure?", "audit my config", "check my configuration for security issues", before exposing the gateway to a network.`,
|
|
141
|
+
parameters: { type: "object", properties: {}, required: [] },
|
|
142
|
+
execute: async () => {
|
|
143
|
+
try {
|
|
144
|
+
const config = loadConfig();
|
|
145
|
+
const findings = auditConfig(config);
|
|
146
|
+
logger.info(COMPONENT, `Config self-audit: ${findings.length} finding(s)`);
|
|
147
|
+
return formatAuditReport(findings);
|
|
148
|
+
} catch (e) {
|
|
149
|
+
return `Config audit failed to load config: ${e.message}`;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
export {
|
|
156
|
+
auditConfig,
|
|
157
|
+
formatAuditReport,
|
|
158
|
+
registerConfigAuditSkill
|
|
159
|
+
};
|
|
160
|
+
//# sourceMappingURL=config_audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/skills/builtin/config_audit.ts"],"sourcesContent":["/**\n * TITAN — Configuration Self-Audit Skill (v7.0)\n *\n * AgentShield-style self-audit: scans TITAN's OWN configuration for the security\n * misconfigurations the v6.5 hardening pass surfaced (open gateway, fail-open\n * command scanner, destructive tools without enforcement, provider secrets\n * sitting in config instead of env vars, unauthenticated mesh).\n *\n * Complements `security_scan` (which scans external *codebases*). This audits\n * the agent's own setup. `auditConfig()` is a pure function exported for tests.\n */\nimport { registerSkill } from '../registry.js';\nimport { loadConfig } from '../../config/config.js';\nimport logger from '../../utils/logger.js';\n\nconst COMPONENT = 'ConfigAudit';\n\nexport type Severity = 'critical' | 'high' | 'medium' | 'low' | 'info';\n\nexport interface AuditFinding {\n id: string;\n severity: Severity;\n title: string;\n detail: string;\n remediation: string;\n}\n\n/**\n * Credential shapes that should live in ENV VARS, not in the config file.\n * Deliberately EXCLUDES channel tokens (xoxb-/xapp-), which legitimately live\n * in `channels.*` config — only cloud/provider keys + private keys are flagged.\n */\nconst SECRET_PATTERNS: { name: string; re: RegExp }[] = [\n { name: 'Anthropic API key', re: /\\bsk-ant-[A-Za-z0-9_-]{20,}/ },\n { name: 'OpenAI-style API key', re: /\\bsk-[A-Za-z0-9]{32,}\\b/ },\n { name: 'AWS access key', re: /\\bAKIA[0-9A-Z]{16}\\b/ },\n { name: 'Google API key', re: /\\bAIza[0-9A-Za-z_-]{35}\\b/ },\n { name: 'private key block', re: /-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/ },\n];\n\nconst DANGEROUS_TOOLS = ['shell', 'exec', 'code_exec', 'execute_code', 'computer_use', 'apply_patch'];\n\n/** Recursively collect (path, string-value) pairs from a config object. */\nfunction collectStrings(\n obj: unknown,\n path = '',\n out: { path: string; value: string }[] = [],\n): { path: string; value: string }[] {\n if (typeof obj === 'string') {\n out.push({ path, value: obj });\n } else if (Array.isArray(obj)) {\n obj.forEach((v, i) => collectStrings(v, `${path}[${i}]`, out));\n } else if (obj && typeof obj === 'object') {\n for (const [k, v] of Object.entries(obj as Record<string, unknown>)) {\n collectStrings(v, path ? `${path}.${k}` : k, out);\n }\n }\n return out;\n}\n\n/**\n * Pure config audit — returns findings ranked elsewhere. Exported for tests.\n */\nexport function auditConfig(config: Record<string, unknown>): AuditFinding[] {\n const findings: AuditFinding[] = [];\n const get = (path: string): unknown =>\n path.split('.').reduce<unknown>((o, k) => (o && typeof o === 'object' ? (o as Record<string, unknown>)[k] : undefined), config);\n\n const authMode = get('gateway.auth.mode');\n const authToken = get('gateway.auth.token');\n const scan = get('security.preExecScan');\n const allowed = get('agent.allowedTools');\n const meshEnabled = get('mesh.enabled');\n\n // 1. Gateway authentication\n if (!authMode || authMode === 'none') {\n findings.push({\n id: 'auth-none', severity: 'critical',\n title: 'Gateway authentication is disabled',\n detail: 'gateway.auth.mode is \"none\" — anyone who can reach the gateway port has full control of the agent, its tools, and its provider keys.',\n remediation: 'Set gateway.auth.mode to \"token\" or \"password\" and configure a strong secret.',\n });\n } else if (authMode === 'token' && !authToken) {\n findings.push({\n id: 'auth-token-empty', severity: 'high',\n title: 'Token auth selected but no token is set',\n detail: 'gateway.auth.mode is \"token\" but gateway.auth.token is empty — TITAN treats this as auth-disabled, so the gateway is effectively open.',\n remediation: 'Set gateway.auth.token to a strong secret, or switch to password mode.',\n });\n }\n\n // 2. Pre-execution command scanner\n if (scan === 'off') {\n findings.push({\n id: 'prescan-off', severity: 'high',\n title: 'Pre-execution command scanner is off',\n detail: 'security.preExecScan is \"off\" — shell/exec commands run with no safety screening.',\n remediation: 'Set security.preExecScan to \"block\" (recommended) or at least \"warn\".',\n });\n } else if (scan === 'warn') {\n findings.push({\n id: 'prescan-warn', severity: 'medium',\n title: 'Command scanner is warn-only (fail-open)',\n detail: 'security.preExecScan is \"warn\" — dangerous commands are logged but NOT blocked. The scanner flags risk but still lets the command run.',\n remediation: 'Set security.preExecScan to \"block\" to actually stop flagged commands.',\n });\n }\n\n // 3. Destructive tools enabled\n if (Array.isArray(allowed)) {\n const dangerous = DANGEROUS_TOOLS.filter((t) => (allowed as unknown[]).includes(t));\n if (dangerous.length > 0) {\n findings.push({\n id: 'dangerous-tools', severity: 'medium',\n title: `Destructive tools enabled: ${dangerous.join(', ')}`,\n detail: `agent.allowedTools includes destructive tools (${dangerous.join(', ')}). These should be gated by approval and screened by the command scanner.`,\n remediation: 'Confirm approval gates are active and security.preExecScan is \"block\", or remove unused destructive tools from allowedTools.',\n });\n }\n }\n\n // 4. Provider/cloud secrets sitting in config (should be env vars)\n for (const { path, value } of collectStrings(config)) {\n for (const { name, re } of SECRET_PATTERNS) {\n if (re.test(value)) {\n findings.push({\n id: `secret-${path}`, severity: 'high',\n title: `Possible ${name} hardcoded in config`,\n detail: `A value at config path \"${path}\" matches a ${name} pattern. Secrets in the config file leak easily (backups, git, shares); TITAN reads provider keys from environment variables.`,\n remediation: `Move this secret to an environment variable and remove it from the config file.`,\n });\n break;\n }\n }\n }\n\n // 5. Mesh exposed without a shared secret\n if (meshEnabled === true) {\n const meshSecret = get('mesh.hmacSecret') || get('mesh.secret') || get('mesh.psk');\n if (!meshSecret) {\n findings.push({\n id: 'mesh-no-auth', severity: 'medium',\n title: 'Mesh networking is enabled without a shared secret',\n detail: 'mesh.enabled is true but no HMAC/shared secret is configured — peers may be able to connect without authentication.',\n remediation: 'Configure a mesh shared secret / HMAC key, or disable mesh if it is unused.',\n });\n }\n }\n\n return findings;\n}\n\nconst SEV_ORDER: Severity[] = ['critical', 'high', 'medium', 'low', 'info'];\nconst SEV_ICON: Record<Severity, string> = {\n critical: '🔴', high: '🟠', medium: '🟡', low: '⚪', info: 'ℹ️',\n};\n\n/** Render findings as a readable, severity-grouped report. Exported for tests. */\nexport function formatAuditReport(findings: AuditFinding[]): string {\n if (findings.length === 0) {\n return '✅ Config self-audit: no misconfigurations found. Gateway auth, command scanning, tool permissions, secrets, and mesh all look sound.';\n }\n const groups = SEV_ORDER\n .map((sev) => ({ sev, items: findings.filter((f) => f.severity === sev) }))\n .filter((g) => g.items.length > 0);\n const counts = groups.map((g) => `${g.items.length} ${g.sev}`).join(', ');\n const lines = [`🛡️ Config self-audit — ${findings.length} finding(s): ${counts}`, ''];\n for (const { sev, items } of groups) {\n for (const f of items) {\n lines.push(`${SEV_ICON[sev]} [${sev.toUpperCase()}] ${f.title}`);\n lines.push(` ${f.detail}`);\n lines.push(` → Fix: ${f.remediation}`);\n lines.push('');\n }\n }\n return lines.join('\\n').trim();\n}\n\nexport function registerConfigAuditSkill(): void {\n registerSkill(\n { name: 'config_audit', description: \"Audit TITAN's own configuration for security misconfigurations\", version: '1.0.0', source: 'bundled', enabled: true },\n {\n name: 'config_audit',\n description: 'Run a security self-audit of TITAN\\'s OWN configuration (not external code). Checks gateway authentication, the pre-execution command scanner, destructive-tool permissions, provider secrets misplaced in config, and mesh authentication. Returns a severity-ranked report with remediation.\\n\\nUSE THIS WHEN: \"is my setup secure?\", \"audit my config\", \"check my configuration for security issues\", before exposing the gateway to a network.',\n parameters: { type: 'object', properties: {}, required: [] },\n execute: async () => {\n try {\n const config = loadConfig() as unknown as Record<string, unknown>;\n const findings = auditConfig(config);\n logger.info(COMPONENT, `Config self-audit: ${findings.length} finding(s)`);\n return formatAuditReport(findings);\n } catch (e) {\n return `Config audit failed to load config: ${(e as Error).message}`;\n }\n },\n },\n );\n}\n"],"mappings":"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","names":[]}
|