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
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from "child_process";
|
|
3
|
+
import { execSync } from "child_process";
|
|
4
|
+
import { registerSkill } from "../registry.js";
|
|
5
|
+
import logger from "../../utils/logger.js";
|
|
6
|
+
const COMPONENT = "DelegateAgent";
|
|
7
|
+
const EXTERNAL_AGENTS = {
|
|
8
|
+
codex: { bin: "codex", label: "OpenAI Codex CLI", buildArgs: (t) => ["exec", "--full-auto", t] },
|
|
9
|
+
aider: { bin: "aider", label: "aider", buildArgs: (t) => ["--message", t, "--yes-always"] },
|
|
10
|
+
goose: { bin: "goose", label: "Goose", buildArgs: (t) => ["run", "-t", t] },
|
|
11
|
+
gemini: { bin: "gemini", label: "Gemini CLI", buildArgs: (t) => ["-p", t] },
|
|
12
|
+
opencode: { bin: "opencode", label: "OpenCode", buildArgs: (t) => ["run", t] }
|
|
13
|
+
};
|
|
14
|
+
const FORBIDDEN = /* @__PURE__ */ new Set(["claude", "claude-code", "claude_code"]);
|
|
15
|
+
function detectAvailableAgents(isAvailable) {
|
|
16
|
+
return Object.entries(EXTERNAL_AGENTS).filter(([name, spec]) => !FORBIDDEN.has(name) && isAvailable(spec.bin)).map(([name]) => name);
|
|
17
|
+
}
|
|
18
|
+
function buildAgentCommand(agent, task) {
|
|
19
|
+
if (FORBIDDEN.has(agent)) throw new Error("Delegation to Claude Code is not permitted (standing rule).");
|
|
20
|
+
const spec = EXTERNAL_AGENTS[agent];
|
|
21
|
+
if (!spec) throw new Error(`Unknown agent "${agent}". Known: ${Object.keys(EXTERNAL_AGENTS).join(", ")}`);
|
|
22
|
+
if (!task || !task.trim()) throw new Error("A task is required.");
|
|
23
|
+
return { cmd: spec.bin, args: spec.buildArgs(task) };
|
|
24
|
+
}
|
|
25
|
+
function binExists(bin) {
|
|
26
|
+
try {
|
|
27
|
+
execSync(`command -v ${bin}`, { stdio: "ignore" });
|
|
28
|
+
return true;
|
|
29
|
+
} catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function runAgent(cmd, args, cwd, timeoutMs) {
|
|
34
|
+
return new Promise((resolve) => {
|
|
35
|
+
let out = "";
|
|
36
|
+
const child = spawn(cmd, args, { cwd, env: process.env });
|
|
37
|
+
const cap = (d) => {
|
|
38
|
+
out += d.toString();
|
|
39
|
+
if (out.length > 2e4) out = out.slice(-2e4);
|
|
40
|
+
};
|
|
41
|
+
child.stdout.on("data", cap);
|
|
42
|
+
child.stderr.on("data", cap);
|
|
43
|
+
const timer = setTimeout(() => {
|
|
44
|
+
child.kill("SIGKILL");
|
|
45
|
+
resolve({ ok: false, output: out + `
|
|
46
|
+
[delegation timed out after ${timeoutMs}ms]` });
|
|
47
|
+
}, timeoutMs);
|
|
48
|
+
child.on("error", (e) => {
|
|
49
|
+
clearTimeout(timer);
|
|
50
|
+
resolve({ ok: false, output: `Failed to launch ${cmd}: ${e.message}` });
|
|
51
|
+
});
|
|
52
|
+
child.on("close", (code) => {
|
|
53
|
+
clearTimeout(timer);
|
|
54
|
+
resolve({ ok: code === 0, output: out || `(no output, exit ${code})` });
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function registerDelegateAgentSkill() {
|
|
59
|
+
registerSkill(
|
|
60
|
+
{ name: "delegate_agent", description: "Delegate a coding task to an external coding agent (Codex/aider/Goose/\u2026)", version: "1.0.0", source: "bundled", enabled: true },
|
|
61
|
+
{
|
|
62
|
+
name: "delegate_agent",
|
|
63
|
+
description: 'Delegate a coding task to an EXTERNAL coding agent installed on this machine (Codex CLI, aider, Goose, Gemini CLI, OpenCode). Detects what is available, runs it non-interactively against your task, and returns its output.\n\nUSE THIS WHEN: you want a specialist coding agent to handle a self-contained implementation task. Args: task (required), agent (optional \u2014 auto-picks the first available), cwd (optional), timeoutSeconds (optional, default 300). Returns the agent output or an honest "not installed" message. (Claude Code is intentionally not supported.)',
|
|
64
|
+
parameters: {
|
|
65
|
+
type: "object",
|
|
66
|
+
properties: {
|
|
67
|
+
task: { type: "string", description: "The coding task to delegate (a clear, self-contained instruction)." },
|
|
68
|
+
agent: { type: "string", enum: Object.keys(EXTERNAL_AGENTS), description: "Which agent (optional \u2014 defaults to the first available)." },
|
|
69
|
+
cwd: { type: "string", description: "Working directory (defaults to the current directory)." },
|
|
70
|
+
timeoutSeconds: { type: "number", description: "Max seconds before killing the agent (default 300)." }
|
|
71
|
+
},
|
|
72
|
+
required: ["task"]
|
|
73
|
+
},
|
|
74
|
+
execute: async (args) => {
|
|
75
|
+
const task = String(args.task || "");
|
|
76
|
+
if (!task.trim()) return 'delegate_agent requires a "task".';
|
|
77
|
+
const available = detectAvailableAgents(binExists);
|
|
78
|
+
if (available.length === 0) {
|
|
79
|
+
return `No external coding agent is installed. Tried: ${Object.values(EXTERNAL_AGENTS).map((a) => a.bin).join(", ")}. Install one (e.g. \`npm i -g @openai/codex\` or \`pipx install aider-chat\`) to use delegation. (Claude Code is intentionally not supported.)`;
|
|
80
|
+
}
|
|
81
|
+
const agent = args.agent || available[0];
|
|
82
|
+
if (!available.includes(agent)) {
|
|
83
|
+
return `Agent "${agent}" is not installed. Available: ${available.join(", ")}.`;
|
|
84
|
+
}
|
|
85
|
+
let cmd, cmdArgs;
|
|
86
|
+
try {
|
|
87
|
+
({ cmd, args: cmdArgs } = buildAgentCommand(agent, task));
|
|
88
|
+
} catch (e) {
|
|
89
|
+
return e.message;
|
|
90
|
+
}
|
|
91
|
+
const cwd = args.cwd || process.cwd();
|
|
92
|
+
const timeoutMs = Math.max(5e3, Number(args.timeoutSeconds || 300) * 1e3);
|
|
93
|
+
logger.info(COMPONENT, `Delegating to ${agent} (${EXTERNAL_AGENTS[agent].label}) in ${cwd}`);
|
|
94
|
+
const { ok, output } = await runAgent(cmd, cmdArgs, cwd, timeoutMs);
|
|
95
|
+
return `[${EXTERNAL_AGENTS[agent].label} ${ok ? "completed" : "failed/timed-out"}]
|
|
96
|
+
${output}`;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
export {
|
|
102
|
+
EXTERNAL_AGENTS,
|
|
103
|
+
buildAgentCommand,
|
|
104
|
+
detectAvailableAgents,
|
|
105
|
+
registerDelegateAgentSkill
|
|
106
|
+
};
|
|
107
|
+
//# sourceMappingURL=delegate_agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/skills/builtin/delegate_agent.ts"],"sourcesContent":["/**\n * TITAN — External coding-agent delegation (v7.0)\n *\n * Orchestrate OTHER coding agents (Codex CLI, aider, Goose, Gemini CLI, …) as\n * sub-agents: detect what's installed, spawn one with a task, capture its output.\n * Honestly disables when none is installed.\n *\n * STANDING RULE: TITAN must NEVER invoke Claude Code / the `claude` CLI at\n * runtime. `claude` is deliberately absent from the registry and rejected.\n *\n * detectAvailableAgents() + buildAgentCommand() are pure (dependency-injected)\n * for tests; the skill wires them to real `which` + `spawn`.\n */\nimport { spawn } from 'child_process';\nimport { execSync } from 'child_process';\nimport { registerSkill } from '../registry.js';\nimport logger from '../../utils/logger.js';\n\nconst COMPONENT = 'DelegateAgent';\n\ninterface AgentSpec {\n bin: string;\n label: string;\n /** Build the argv to run the agent non-interactively against a task. */\n buildArgs: (task: string) => string[];\n}\n\n/** Supported external coding agents. Claude Code is intentionally excluded. */\nexport const EXTERNAL_AGENTS: Record<string, AgentSpec> = {\n codex: { bin: 'codex', label: 'OpenAI Codex CLI', buildArgs: (t) => ['exec', '--full-auto', t] },\n aider: { bin: 'aider', label: 'aider', buildArgs: (t) => ['--message', t, '--yes-always'] },\n goose: { bin: 'goose', label: 'Goose', buildArgs: (t) => ['run', '-t', t] },\n gemini: { bin: 'gemini', label: 'Gemini CLI', buildArgs: (t) => ['-p', t] },\n opencode: { bin: 'opencode', label: 'OpenCode', buildArgs: (t) => ['run', t] },\n};\n\n/** Names that must NEVER be delegated to (standing rule). */\nconst FORBIDDEN = new Set(['claude', 'claude-code', 'claude_code']);\n\n/**\n * Which agents are available, given an `isAvailable(bin) => boolean` probe.\n * Pure — inject the probe for tests.\n */\nexport function detectAvailableAgents(isAvailable: (bin: string) => boolean): string[] {\n return Object.entries(EXTERNAL_AGENTS)\n .filter(([name, spec]) => !FORBIDDEN.has(name) && isAvailable(spec.bin))\n .map(([name]) => name);\n}\n\n/** Build the spawn command for an agent + task. Throws on unknown/forbidden. */\nexport function buildAgentCommand(agent: string, task: string): { cmd: string; args: string[] } {\n if (FORBIDDEN.has(agent)) throw new Error('Delegation to Claude Code is not permitted (standing rule).');\n const spec = EXTERNAL_AGENTS[agent];\n if (!spec) throw new Error(`Unknown agent \"${agent}\". Known: ${Object.keys(EXTERNAL_AGENTS).join(', ')}`);\n if (!task || !task.trim()) throw new Error('A task is required.');\n return { cmd: spec.bin, args: spec.buildArgs(task) };\n}\n\n/** Real PATH probe via `command -v`. */\nfunction binExists(bin: string): boolean {\n try { execSync(`command -v ${bin}`, { stdio: 'ignore' }); return true; } catch { return false; }\n}\n\n/** Run an external agent, capturing combined output (bounded). */\nfunction runAgent(cmd: string, args: string[], cwd: string, timeoutMs: number): Promise<{ ok: boolean; output: string }> {\n return new Promise((resolve) => {\n let out = '';\n const child = spawn(cmd, args, { cwd, env: process.env });\n const cap = (d: Buffer) => { out += d.toString(); if (out.length > 20000) out = out.slice(-20000); };\n child.stdout.on('data', cap);\n child.stderr.on('data', cap);\n const timer = setTimeout(() => { child.kill('SIGKILL'); resolve({ ok: false, output: out + `\\n[delegation timed out after ${timeoutMs}ms]` }); }, timeoutMs);\n child.on('error', (e) => { clearTimeout(timer); resolve({ ok: false, output: `Failed to launch ${cmd}: ${e.message}` }); });\n child.on('close', (code) => { clearTimeout(timer); resolve({ ok: code === 0, output: out || `(no output, exit ${code})` }); });\n });\n}\n\nexport function registerDelegateAgentSkill(): void {\n registerSkill(\n { name: 'delegate_agent', description: 'Delegate a coding task to an external coding agent (Codex/aider/Goose/…)', version: '1.0.0', source: 'bundled', enabled: true },\n {\n name: 'delegate_agent',\n description:\n 'Delegate a coding task to an EXTERNAL coding agent installed on this machine (Codex CLI, aider, Goose, Gemini CLI, OpenCode). Detects what is available, runs it non-interactively against your task, and returns its output.\\n\\n' +\n 'USE THIS WHEN: you want a specialist coding agent to handle a self-contained implementation task. Args: task (required), agent (optional — auto-picks the first available), cwd (optional), timeoutSeconds (optional, default 300). Returns the agent output or an honest \"not installed\" message. (Claude Code is intentionally not supported.)',\n parameters: {\n type: 'object',\n properties: {\n task: { type: 'string', description: 'The coding task to delegate (a clear, self-contained instruction).' },\n agent: { type: 'string', enum: Object.keys(EXTERNAL_AGENTS), description: 'Which agent (optional — defaults to the first available).' },\n cwd: { type: 'string', description: 'Working directory (defaults to the current directory).' },\n timeoutSeconds: { type: 'number', description: 'Max seconds before killing the agent (default 300).' },\n },\n required: ['task'],\n },\n execute: async (args: Record<string, unknown>): Promise<string> => {\n const task = String(args.task || '');\n if (!task.trim()) return 'delegate_agent requires a \"task\".';\n const available = detectAvailableAgents(binExists);\n if (available.length === 0) {\n return `No external coding agent is installed. Tried: ${Object.values(EXTERNAL_AGENTS).map((a) => a.bin).join(', ')}. Install one (e.g. \\`npm i -g @openai/codex\\` or \\`pipx install aider-chat\\`) to use delegation. (Claude Code is intentionally not supported.)`;\n }\n const agent = (args.agent as string) || available[0];\n if (!available.includes(agent)) {\n return `Agent \"${agent}\" is not installed. Available: ${available.join(', ')}.`;\n }\n let cmd: string, cmdArgs: string[];\n try { ({ cmd, args: cmdArgs } = buildAgentCommand(agent, task)); }\n catch (e) { return (e as Error).message; }\n const cwd = (args.cwd as string) || process.cwd();\n const timeoutMs = Math.max(5_000, Number(args.timeoutSeconds || 300) * 1000);\n logger.info(COMPONENT, `Delegating to ${agent} (${EXTERNAL_AGENTS[agent].label}) in ${cwd}`);\n const { ok, output } = await runAgent(cmd, cmdArgs, cwd, timeoutMs);\n return `[${EXTERNAL_AGENTS[agent].label} ${ok ? 'completed' : 'failed/timed-out'}]\\n${output}`;\n },\n },\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { registerSkill } from "../registry.js";
|
|
3
|
+
import { summarizeMemoryTaxonomy, renderMemoryTaxonomy } from "../../memory/taxonomy.js";
|
|
4
|
+
import { loadConfig } from "../../config/config.js";
|
|
5
|
+
import logger from "../../utils/logger.js";
|
|
6
|
+
const COMPONENT = "MemoryMap";
|
|
7
|
+
function registerMemoryMapSkill() {
|
|
8
|
+
registerSkill(
|
|
9
|
+
{ name: "memory_map", description: "Describe TITAN's named memory taxonomy and which types are active", version: "1.0.0", source: "bundled", enabled: true },
|
|
10
|
+
{
|
|
11
|
+
name: "memory_map",
|
|
12
|
+
description: `Describe TITAN's MEMORY TAXONOMY \u2014 the nine named memory types (working, episodic, semantic, procedural, emotional/drive, prospective, relational, narrative, shared), what each captures, the real subsystem backing it, and whether it's active right now.
|
|
13
|
+
|
|
14
|
+
USE THIS WHEN: "what do you remember?", "what kinds of memory do you have?", "what's your memory architecture?", or to explain how TITAN persists context across turns and sessions.`,
|
|
15
|
+
parameters: { type: "object", properties: {}, required: [] },
|
|
16
|
+
execute: async () => {
|
|
17
|
+
try {
|
|
18
|
+
const config = loadConfig();
|
|
19
|
+
let hindsightConnected = false;
|
|
20
|
+
try {
|
|
21
|
+
const { memory } = await import("../../memory/facade.js");
|
|
22
|
+
hindsightConnected = Boolean(await memory.episodic.isCrossSessionConnected());
|
|
23
|
+
} catch {
|
|
24
|
+
}
|
|
25
|
+
const summary = summarizeMemoryTaxonomy(config, { hindsightConnected });
|
|
26
|
+
logger.info(COMPONENT, `Memory taxonomy: ${summary.active}/${summary.total} types active`);
|
|
27
|
+
return renderMemoryTaxonomy(summary);
|
|
28
|
+
} catch (e) {
|
|
29
|
+
return `Failed to summarize memory taxonomy: ${e.message}`;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
export {
|
|
36
|
+
registerMemoryMapSkill
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=memory_map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/skills/builtin/memory_map.ts"],"sourcesContent":["/**\n * TITAN — Memory taxonomy skill (v7.0)\n *\n * Surfaces TITAN's named memory taxonomy (see src/memory/taxonomy.ts) with live\n * availability. Answers \"what do you remember, and how?\" with the honest map of\n * the nine real memory subsystems — including the emotional/drive type that no\n * competitor has. Backs the v7.0 Memory panel and counters the field's\n * \"N memory types\" marketing with a real, drive-backed taxonomy.\n */\nimport { registerSkill } from '../registry.js';\nimport { summarizeMemoryTaxonomy, renderMemoryTaxonomy } from '../../memory/taxonomy.js';\nimport { loadConfig } from '../../config/config.js';\nimport logger from '../../utils/logger.js';\n\nconst COMPONENT = 'MemoryMap';\n\nexport function registerMemoryMapSkill(): void {\n registerSkill(\n { name: 'memory_map', description: \"Describe TITAN's named memory taxonomy and which types are active\", version: '1.0.0', source: 'bundled', enabled: true },\n {\n name: 'memory_map',\n description:\n \"Describe TITAN's MEMORY TAXONOMY — the nine named memory types (working, episodic, semantic, procedural, emotional/drive, prospective, relational, narrative, shared), what each captures, the real subsystem backing it, and whether it's active right now.\\n\\n\" +\n 'USE THIS WHEN: \"what do you remember?\", \"what kinds of memory do you have?\", \"what\\'s your memory architecture?\", or to explain how TITAN persists context across turns and sessions.',\n parameters: { type: 'object', properties: {}, required: [] },\n execute: async (): Promise<string> => {\n try {\n const config = loadConfig() as unknown as Record<string, unknown>;\n let hindsightConnected = false;\n try {\n const { memory } = await import('../../memory/facade.js');\n hindsightConnected = Boolean(await memory.episodic.isCrossSessionConnected());\n } catch { /* Hindsight optional */ }\n const summary = summarizeMemoryTaxonomy(config, { hindsightConnected });\n logger.info(COMPONENT, `Memory taxonomy: ${summary.active}/${summary.total} types active`);\n return renderMemoryTaxonomy(summary);\n } catch (e) {\n return `Failed to summarize memory taxonomy: ${(e as Error).message}`;\n }\n },\n },\n );\n}\n"],"mappings":";AASA,SAAS,qBAAqB;AAC9B,SAAS,yBAAyB,4BAA4B;AAC9D,SAAS,kBAAkB;AAC3B,OAAO,YAAY;AAEnB,MAAM,YAAY;AAEX,SAAS,yBAA+B;AAC3C;AAAA,IACI,EAAE,MAAM,cAAc,aAAa,qEAAqE,SAAS,SAAS,QAAQ,WAAW,SAAS,KAAK;AAAA,IAC3J;AAAA,MACI,MAAM;AAAA,MACN,aACI;AAAA;AAAA;AAAA,MAEJ,YAAY,EAAE,MAAM,UAAU,YAAY,CAAC,GAAG,UAAU,CAAC,EAAE;AAAA,MAC3D,SAAS,YAA6B;AAClC,YAAI;AACA,gBAAM,SAAS,WAAW;AAC1B,cAAI,qBAAqB;AACzB,cAAI;AACA,kBAAM,EAAE,OAAO,IAAI,MAAM,OAAO,wBAAwB;AACxD,iCAAqB,QAAQ,MAAM,OAAO,SAAS,wBAAwB,CAAC;AAAA,UAChF,QAAQ;AAAA,UAA2B;AACnC,gBAAM,UAAU,wBAAwB,QAAQ,EAAE,mBAAmB,CAAC;AACtE,iBAAO,KAAK,WAAW,oBAAoB,QAAQ,MAAM,IAAI,QAAQ,KAAK,eAAe;AACzF,iBAAO,qBAAqB,OAAO;AAAA,QACvC,SAAS,GAAG;AACR,iBAAO,wCAAyC,EAAY,OAAO;AAAA,QACvE;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AACJ;","names":[]}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { registerSkill } from "../registry.js";
|
|
3
|
+
import { addReminder, listReminders, cancelReminder } from "../../agent/reminders.js";
|
|
4
|
+
function registerReminderSkill() {
|
|
5
|
+
registerSkill(
|
|
6
|
+
{
|
|
7
|
+
name: "reminder",
|
|
8
|
+
description: "Set, list, and cancel reminders that TITAN delivers to the user at a specific time.",
|
|
9
|
+
version: "1.0.0",
|
|
10
|
+
source: "bundled",
|
|
11
|
+
enabled: true
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
name: "reminder",
|
|
15
|
+
description: [
|
|
16
|
+
"Set, list, or cancel personal reminders. TITAN delivers the reminder to the user at the right time (the mascot announces it on the desk).",
|
|
17
|
+
"",
|
|
18
|
+
`USE THIS when the user says: "remind me to X at/on Y", "don't let me forget X", "ping me Friday about X". This is the ONLY correct way to set a reminder \u2014 never claim a reminder is set without calling this.`,
|
|
19
|
+
'NOT for recurring jobs ("every morning", "daily at 9") \u2192 use the `cron` tool for those.',
|
|
20
|
+
"",
|
|
21
|
+
"ACTIONS:",
|
|
22
|
+
' \u2022 set \u2014 message (what to say) + a time. For RELATIVE asks ("in 20 minutes", "in 2 hours") pass inMinutes (a number) \u2014 do NOT compute ISO yourself. For ABSOLUTE times ("Friday 5pm") pass when as ISO 8601 WITH the local timezone offset from your date/time context (e.g. "2026-06-12T17:00:00-07:00").',
|
|
23
|
+
" \u2022 list \u2014 pending reminders.",
|
|
24
|
+
' \u2022 cancel \u2014 id (from list), or "all" to clear pending.',
|
|
25
|
+
"",
|
|
26
|
+
"Returns the saved reminder with its exact local fire time \u2014 confirm THAT time back to the user."
|
|
27
|
+
].join("\n"),
|
|
28
|
+
parameters: {
|
|
29
|
+
type: "object",
|
|
30
|
+
properties: {
|
|
31
|
+
action: { type: "string", enum: ["set", "list", "cancel"], description: "What to do." },
|
|
32
|
+
message: { type: "string", description: "set: what to remind the user about." },
|
|
33
|
+
when: { type: "string", description: "set (absolute): ISO 8601 datetime with timezone offset." },
|
|
34
|
+
inMinutes: { type: "number", description: 'set (relative): fire this many minutes from now. Preferred for "in N minutes/hours" asks.' },
|
|
35
|
+
id: { type: "string", description: 'cancel: reminder id, or "all".' }
|
|
36
|
+
},
|
|
37
|
+
required: ["action"]
|
|
38
|
+
},
|
|
39
|
+
execute: async (args) => {
|
|
40
|
+
const action = String(args.action ?? "");
|
|
41
|
+
if (action === "set") {
|
|
42
|
+
const inMinutes = Number(args.inMinutes);
|
|
43
|
+
const whenIso = Number.isFinite(inMinutes) && inMinutes > 0 ? new Date(Date.now() + inMinutes * 6e4).toISOString() : String(args.when ?? "");
|
|
44
|
+
const result = addReminder(String(args.message ?? ""), whenIso);
|
|
45
|
+
if ("error" in result) return `Error: ${result.error}`;
|
|
46
|
+
const local = new Date(result.dueAt).toLocaleString();
|
|
47
|
+
return `Reminder set (id: ${result.id}): "${result.message}" \u2014 I'll tell you on ${local}.`;
|
|
48
|
+
}
|
|
49
|
+
if (action === "list") {
|
|
50
|
+
const pending = listReminders();
|
|
51
|
+
if (pending.length === 0) return "No pending reminders.";
|
|
52
|
+
return pending.map((r) => `${r.id} \u2014 "${r.message}" at ${new Date(r.dueAt).toLocaleString()}`).join("\n");
|
|
53
|
+
}
|
|
54
|
+
if (action === "cancel") {
|
|
55
|
+
const id = String(args.id ?? "");
|
|
56
|
+
if (!id) return 'Error: provide id (or "all").';
|
|
57
|
+
return cancelReminder(id) ? `Cancelled ${id}.` : `No pending reminder matched "${id}".`;
|
|
58
|
+
}
|
|
59
|
+
return "Error: action must be set, list, or cancel.";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
export {
|
|
65
|
+
registerReminderSkill
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=reminders.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/skills/builtin/reminders.ts"],"sourcesContent":["/**\n * Reminder skill — the tool models were hallucinating (v7.0).\n *\n * \"Remind me Friday at 5pm to buy charcoal\" now has a real, verifiable path:\n * action=set persists a reminder; a 60s daemon watcher fires it through the\n * heartbeat channel so the mascot says it (and any heartbeat consumer shows\n * it). The system prompt always carries the current local date+time, so the\n * model converts natural language (\"Friday 5pm\") to ISO itself.\n */\nimport { registerSkill } from '../registry.js';\nimport { addReminder, listReminders, cancelReminder } from '../../agent/reminders.js';\n\nexport function registerReminderSkill(): void {\n registerSkill(\n {\n name: 'reminder',\n description: 'Set, list, and cancel reminders that TITAN delivers to the user at a specific time.',\n version: '1.0.0',\n source: 'bundled',\n enabled: true,\n },\n {\n name: 'reminder',\n description: [\n 'Set, list, or cancel personal reminders. TITAN delivers the reminder to the user at the right time (the mascot announces it on the desk).',\n '',\n 'USE THIS when the user says: \"remind me to X at/on Y\", \"don\\'t let me forget X\", \"ping me Friday about X\". This is the ONLY correct way to set a reminder — never claim a reminder is set without calling this.',\n 'NOT for recurring jobs (\"every morning\", \"daily at 9\") → use the `cron` tool for those.',\n '',\n 'ACTIONS:',\n ' • set — message (what to say) + a time. For RELATIVE asks (\"in 20 minutes\", \"in 2 hours\") pass inMinutes (a number) — do NOT compute ISO yourself. For ABSOLUTE times (\"Friday 5pm\") pass when as ISO 8601 WITH the local timezone offset from your date/time context (e.g. \"2026-06-12T17:00:00-07:00\").',\n ' • list — pending reminders.',\n ' • cancel — id (from list), or \"all\" to clear pending.',\n '',\n 'Returns the saved reminder with its exact local fire time — confirm THAT time back to the user.',\n ].join('\\n'),\n parameters: {\n type: 'object',\n properties: {\n action: { type: 'string', enum: ['set', 'list', 'cancel'], description: 'What to do.' },\n message: { type: 'string', description: 'set: what to remind the user about.' },\n when: { type: 'string', description: 'set (absolute): ISO 8601 datetime with timezone offset.' },\n inMinutes: { type: 'number', description: 'set (relative): fire this many minutes from now. Preferred for \"in N minutes/hours\" asks.' },\n id: { type: 'string', description: 'cancel: reminder id, or \"all\".' },\n },\n required: ['action'],\n },\n execute: async (args: Record<string, unknown>): Promise<string> => {\n const action = String(args.action ?? '');\n if (action === 'set') {\n const inMinutes = Number(args.inMinutes);\n const whenIso = Number.isFinite(inMinutes) && inMinutes > 0\n ? new Date(Date.now() + inMinutes * 60_000).toISOString()\n : String(args.when ?? '');\n const result = addReminder(String(args.message ?? ''), whenIso);\n if ('error' in result) return `Error: ${result.error}`;\n const local = new Date(result.dueAt).toLocaleString();\n return `Reminder set (id: ${result.id}): \"${result.message}\" — I'll tell you on ${local}.`;\n }\n if (action === 'list') {\n const pending = listReminders();\n if (pending.length === 0) return 'No pending reminders.';\n return pending.map(r => `${r.id} — \"${r.message}\" at ${new Date(r.dueAt).toLocaleString()}`).join('\\n');\n }\n if (action === 'cancel') {\n const id = String(args.id ?? '');\n if (!id) return 'Error: provide id (or \"all\").';\n return cancelReminder(id) ? `Cancelled ${id}.` : `No pending reminder matched \"${id}\".`;\n }\n return 'Error: action must be set, list, or cancel.';\n },\n },\n );\n}\n"],"mappings":";AASA,SAAS,qBAAqB;AAC9B,SAAS,aAAa,eAAe,sBAAsB;AAEpD,SAAS,wBAA8B;AAC1C;AAAA,IACI;AAAA,MACI,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,SAAS;AAAA,IACb;AAAA,IACA;AAAA,MACI,MAAM;AAAA,MACN,aAAa;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACJ,EAAE,KAAK,IAAI;AAAA,MACX,YAAY;AAAA,QACR,MAAM;AAAA,QACN,YAAY;AAAA,UACR,QAAQ,EAAE,MAAM,UAAU,MAAM,CAAC,OAAO,QAAQ,QAAQ,GAAG,aAAa,cAAc;AAAA,UACtF,SAAS,EAAE,MAAM,UAAU,aAAa,sCAAsC;AAAA,UAC9E,MAAM,EAAE,MAAM,UAAU,aAAa,0DAA0D;AAAA,UAC/F,WAAW,EAAE,MAAM,UAAU,aAAa,4FAA4F;AAAA,UACtI,IAAI,EAAE,MAAM,UAAU,aAAa,iCAAiC;AAAA,QACxE;AAAA,QACA,UAAU,CAAC,QAAQ;AAAA,MACvB;AAAA,MACA,SAAS,OAAO,SAAmD;AAC/D,cAAM,SAAS,OAAO,KAAK,UAAU,EAAE;AACvC,YAAI,WAAW,OAAO;AAClB,gBAAM,YAAY,OAAO,KAAK,SAAS;AACvC,gBAAM,UAAU,OAAO,SAAS,SAAS,KAAK,YAAY,IACpD,IAAI,KAAK,KAAK,IAAI,IAAI,YAAY,GAAM,EAAE,YAAY,IACtD,OAAO,KAAK,QAAQ,EAAE;AAC5B,gBAAM,SAAS,YAAY,OAAO,KAAK,WAAW,EAAE,GAAG,OAAO;AAC9D,cAAI,WAAW,OAAQ,QAAO,UAAU,OAAO,KAAK;AACpD,gBAAM,QAAQ,IAAI,KAAK,OAAO,KAAK,EAAE,eAAe;AACpD,iBAAO,qBAAqB,OAAO,EAAE,OAAO,OAAO,OAAO,6BAAwB,KAAK;AAAA,QAC3F;AACA,YAAI,WAAW,QAAQ;AACnB,gBAAM,UAAU,cAAc;AAC9B,cAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,iBAAO,QAAQ,IAAI,OAAK,GAAG,EAAE,EAAE,YAAO,EAAE,OAAO,QAAQ,IAAI,KAAK,EAAE,KAAK,EAAE,eAAe,CAAC,EAAE,EAAE,KAAK,IAAI;AAAA,QAC1G;AACA,YAAI,WAAW,UAAU;AACrB,gBAAM,KAAK,OAAO,KAAK,MAAM,EAAE;AAC/B,cAAI,CAAC,GAAI,QAAO;AAChB,iBAAO,eAAe,EAAE,IAAI,aAAa,EAAE,MAAM,gCAAgC,EAAE;AAAA,QACvF;AACA,eAAO;AAAA,MACX;AAAA,IACJ;AAAA,EACJ;AACJ;","names":[]}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { registerSkill } from "../registry.js";
|
|
3
|
+
import {
|
|
4
|
+
readGoalSpec,
|
|
5
|
+
writeGoalSpec,
|
|
6
|
+
setAcceptance,
|
|
7
|
+
renderSpecMd,
|
|
8
|
+
specReadiness
|
|
9
|
+
} from "../../agent/goalSpec.js";
|
|
10
|
+
import { listSessionGoals } from "../../agent/autonomyContext.js";
|
|
11
|
+
import logger from "../../utils/logger.js";
|
|
12
|
+
const COMPONENT = "SpecSkill";
|
|
13
|
+
function resolveGoalId(explicit) {
|
|
14
|
+
if (explicit && explicit.trim()) return { goalId: explicit.trim() };
|
|
15
|
+
const active = listSessionGoals();
|
|
16
|
+
if (active.length === 1) return { goalId: active[0].goalId };
|
|
17
|
+
if (active.length === 0) {
|
|
18
|
+
return { error: 'No active goal to attach a spec to. Pass an explicit "goalId" (the id of the goal/task this spec describes).' };
|
|
19
|
+
}
|
|
20
|
+
const ids = active.map((g) => `${g.goalId} (${g.goalTitle})`).join(", ");
|
|
21
|
+
return { error: `Multiple goals are active \u2014 pass an explicit "goalId". Active: ${ids}` };
|
|
22
|
+
}
|
|
23
|
+
function asStringArray(v) {
|
|
24
|
+
if (Array.isArray(v)) return v.map((x) => String(x)).filter((s) => s.trim().length > 0);
|
|
25
|
+
if (typeof v === "string" && v.trim()) {
|
|
26
|
+
try {
|
|
27
|
+
const p = JSON.parse(v);
|
|
28
|
+
if (Array.isArray(p)) return p.map((x) => String(x));
|
|
29
|
+
} catch {
|
|
30
|
+
}
|
|
31
|
+
return v.split("\n").map((s) => s.replace(/^[-*]\s*/, "").trim()).filter(Boolean);
|
|
32
|
+
}
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
function registerSpecSkill() {
|
|
36
|
+
registerSkill(
|
|
37
|
+
{ name: "spec", description: "Author and check a goal's definition-of-done (spec + acceptance criteria)", version: "1.0.0", source: "bundled", enabled: true },
|
|
38
|
+
{
|
|
39
|
+
name: "spec",
|
|
40
|
+
description: `Spec-driven workflow: write and check a goal's DEFINITION OF DONE (problem, requirements, testable acceptance criteria). The spec is persisted and re-shown to you every turn so you work against it.
|
|
41
|
+
|
|
42
|
+
actions:
|
|
43
|
+
\u2022 define \u2014 create/replace the spec. Args: problem, requirements[], acceptance[] (each a testable statement), constraints[], nonGoals[], title?. Acceptance items auto-get ids ac1, ac2, \u2026
|
|
44
|
+
\u2022 get \u2014 show the current spec (markdown).
|
|
45
|
+
\u2022 check \u2014 mark one acceptance criterion. Args: criterionId (e.g. "ac1"), status ("met"|"unmet"|"unknown"), evidence? (a test name / observation).
|
|
46
|
+
\u2022 status \u2014 readiness rollup (met/total, %). A goal is only DONE when every criterion is 'met'.
|
|
47
|
+
|
|
48
|
+
USE THIS WHEN starting non-trivial work ("define done first"), and before declaring a task complete (check every criterion with evidence). goalId is optional \u2014 auto-resolves to the active goal.`,
|
|
49
|
+
parameters: {
|
|
50
|
+
type: "object",
|
|
51
|
+
properties: {
|
|
52
|
+
action: { type: "string", enum: ["define", "get", "check", "status"], description: "What to do." },
|
|
53
|
+
goalId: { type: "string", description: "Goal/task id this spec belongs to. Optional \u2014 auto-resolves to the active goal." },
|
|
54
|
+
title: { type: "string", description: "(define) Short title for the spec." },
|
|
55
|
+
problem: { type: "string", description: "(define) One-paragraph problem / desired outcome." },
|
|
56
|
+
requirements: { type: "array", items: { type: "string" }, description: "(define) What the solution must do." },
|
|
57
|
+
acceptance: { type: "array", items: { type: "string" }, description: '(define) Testable "done" statements. Auto-ided ac1..acN.' },
|
|
58
|
+
constraints: { type: "array", items: { type: "string" }, description: "(define) Hard limits (perf/security/scope)." },
|
|
59
|
+
nonGoals: { type: "array", items: { type: "string" }, description: "(define) Explicitly out of scope." },
|
|
60
|
+
criterionId: { type: "string", description: '(check) Which acceptance criterion, e.g. "ac1".' },
|
|
61
|
+
status: { type: "string", enum: ["met", "unmet", "unknown"], description: "(check) New status for the criterion." },
|
|
62
|
+
evidence: { type: "string", description: "(check) How you know \u2014 a test name, log line, observation." }
|
|
63
|
+
},
|
|
64
|
+
required: ["action"]
|
|
65
|
+
},
|
|
66
|
+
execute: async (args) => {
|
|
67
|
+
const action = String(args.action || "").toLowerCase();
|
|
68
|
+
const { goalId, error } = resolveGoalId(args.goalId);
|
|
69
|
+
if (error) return error;
|
|
70
|
+
const gid = goalId;
|
|
71
|
+
try {
|
|
72
|
+
switch (action) {
|
|
73
|
+
case "define": {
|
|
74
|
+
const acceptanceTexts = asStringArray(args.acceptance);
|
|
75
|
+
const spec = {
|
|
76
|
+
goalId: gid,
|
|
77
|
+
title: String(args.title || readGoalSpec(gid)?.title || gid),
|
|
78
|
+
problem: String(args.problem || ""),
|
|
79
|
+
requirements: asStringArray(args.requirements),
|
|
80
|
+
acceptance: acceptanceTexts.map((text, i) => ({ id: `ac${i + 1}`, text, status: "unmet" })),
|
|
81
|
+
constraints: asStringArray(args.constraints),
|
|
82
|
+
nonGoals: asStringArray(args.nonGoals),
|
|
83
|
+
createdAt: readGoalSpec(gid)?.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
|
|
84
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
85
|
+
};
|
|
86
|
+
writeGoalSpec(spec);
|
|
87
|
+
const r = specReadiness(spec);
|
|
88
|
+
return `Spec defined for goal ${gid}: ${spec.acceptance.length} acceptance criteria (${r.met}/${r.total} met). Re-shown each turn \u2014 check criteria with action=check as you satisfy them.
|
|
89
|
+
|
|
90
|
+
${renderSpecMd(spec)}`;
|
|
91
|
+
}
|
|
92
|
+
case "get": {
|
|
93
|
+
const spec = readGoalSpec(gid);
|
|
94
|
+
if (!spec) return `No spec exists for goal ${gid} yet. Create one with action=define.`;
|
|
95
|
+
return renderSpecMd(spec);
|
|
96
|
+
}
|
|
97
|
+
case "check": {
|
|
98
|
+
const critId = String(args.criterionId || "").trim();
|
|
99
|
+
const status = String(args.status || "").toLowerCase();
|
|
100
|
+
if (!critId) return 'check requires "criterionId" (e.g. "ac1").';
|
|
101
|
+
if (!["met", "unmet", "unknown"].includes(status)) return 'check requires "status" of met | unmet | unknown.';
|
|
102
|
+
const spec = readGoalSpec(gid);
|
|
103
|
+
if (!spec) return `No spec exists for goal ${gid}. Create one with action=define first.`;
|
|
104
|
+
const updated = setAcceptance(gid, critId, status, args.evidence);
|
|
105
|
+
if (!updated) {
|
|
106
|
+
const ids = spec.acceptance.map((a) => a.id).join(", ") || "(none)";
|
|
107
|
+
return `No criterion "${critId}" in goal ${gid}'s spec. Known criteria: ${ids}.`;
|
|
108
|
+
}
|
|
109
|
+
const r = specReadiness(updated);
|
|
110
|
+
return `Marked ${critId} = ${status}${args.evidence ? ` (evidence: ${args.evidence})` : ""}. Acceptance now ${r.met}/${r.total} met (${r.pct}%).${r.ready ? " \u2705 All criteria met \u2014 spec is satisfied." : ""}`;
|
|
111
|
+
}
|
|
112
|
+
case "status": {
|
|
113
|
+
const spec = readGoalSpec(gid);
|
|
114
|
+
if (!spec) return `No spec exists for goal ${gid} yet. Create one with action=define.`;
|
|
115
|
+
const r = specReadiness(spec);
|
|
116
|
+
const lines = [`Spec readiness for goal ${gid}: ${r.met}/${r.total} met (${r.pct}%)${r.ready ? " \u2014 \u2705 READY" : ""}`];
|
|
117
|
+
for (const a of spec.acceptance) {
|
|
118
|
+
const mark = a.status === "met" ? "\u2705" : a.status === "unknown" ? "\u2753" : "\u2B1C";
|
|
119
|
+
lines.push(` ${mark} ${a.id}: ${a.text}${a.evidence ? ` \u2014 ${a.evidence}` : ""}`);
|
|
120
|
+
}
|
|
121
|
+
if (!r.ready && r.total > 0) lines.push(`
|
|
122
|
+
NOT done \u2014 ${r.unmet + r.unknown} criteri${r.unmet + r.unknown === 1 ? "on" : "a"} still open.`);
|
|
123
|
+
return lines.join("\n");
|
|
124
|
+
}
|
|
125
|
+
default:
|
|
126
|
+
return `Unknown spec action "${action}". Use define | get | check | status.`;
|
|
127
|
+
}
|
|
128
|
+
} catch (e) {
|
|
129
|
+
logger.warn(COMPONENT, `spec ${action} failed: ${e.message}`);
|
|
130
|
+
return `spec ${action} failed: ${e.message}`;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
export {
|
|
137
|
+
registerSpecSkill
|
|
138
|
+
};
|
|
139
|
+
//# sourceMappingURL=spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/skills/builtin/spec.ts"],"sourcesContent":["/**\n * TITAN — Spec-driven workflow skill (v7.0)\n *\n * Exposes the `spec` tool so the agent (or a human via the API) can author and\n * check a goal's **definition of done**: problem statement, requirements, and\n * testable acceptance criteria. The spec is persisted as `spec.md` next to the\n * goal's `plan.md` and re-injected into the prompt every turn (see\n * `src/agent/goalSpec.ts` + `agent.ts` recency-position wiring).\n *\n * The 2026 spec-engineering loop this enables:\n * 1. `spec` action=define — write the problem + acceptance criteria up front.\n * 2. … agent does the work, reciting the spec each turn …\n * 3. `spec` action=check — mark each criterion met/unmet WITH evidence.\n * 4. `spec` action=status — only \"done\" when 100% of criteria are `met`.\n *\n * Complements `goalPlanFile` (the step ladder) — spec is \"are we there?\",\n * plan is \"what's next?\".\n */\nimport { registerSkill } from '../registry.js';\nimport {\n readGoalSpec, writeGoalSpec, setAcceptance, renderSpecMd, specReadiness,\n type GoalSpec, type AcceptanceStatus,\n} from '../../agent/goalSpec.js';\nimport { listSessionGoals } from '../../agent/autonomyContext.js';\nimport logger from '../../utils/logger.js';\n\nconst COMPONENT = 'SpecSkill';\n\n/**\n * Resolve which goal the spec action targets. Explicit `goalId` wins; otherwise\n * auto-resolve when exactly one goal session is active. Returns `{ error }` with\n * guidance when ambiguous so the agent gets a clear next step instead of a throw.\n */\nfunction resolveGoalId(explicit?: string): { goalId?: string; error?: string } {\n if (explicit && explicit.trim()) return { goalId: explicit.trim() };\n const active = listSessionGoals();\n if (active.length === 1) return { goalId: active[0].goalId };\n if (active.length === 0) {\n return { error: 'No active goal to attach a spec to. Pass an explicit \"goalId\" (the id of the goal/task this spec describes).' };\n }\n const ids = active.map((g) => `${g.goalId} (${g.goalTitle})`).join(', ');\n return { error: `Multiple goals are active — pass an explicit \"goalId\". Active: ${ids}` };\n}\n\n/** Coerce a loose array-of-strings arg (the LLM may send a JSON string). */\nfunction asStringArray(v: unknown): string[] {\n if (Array.isArray(v)) return v.map((x) => String(x)).filter((s) => s.trim().length > 0);\n if (typeof v === 'string' && v.trim()) {\n try { const p = JSON.parse(v); if (Array.isArray(p)) return p.map((x) => String(x)); } catch { /* not json */ }\n return v.split('\\n').map((s) => s.replace(/^[-*]\\s*/, '').trim()).filter(Boolean);\n }\n return [];\n}\n\nexport function registerSpecSkill(): void {\n registerSkill(\n { name: 'spec', description: \"Author and check a goal's definition-of-done (spec + acceptance criteria)\", version: '1.0.0', source: 'bundled', enabled: true },\n {\n name: 'spec',\n description:\n \"Spec-driven workflow: write and check a goal's DEFINITION OF DONE (problem, requirements, testable acceptance criteria). The spec is persisted and re-shown to you every turn so you work against it.\\n\\n\" +\n 'actions:\\n' +\n '• define — create/replace the spec. Args: problem, requirements[], acceptance[] (each a testable statement), constraints[], nonGoals[], title?. Acceptance items auto-get ids ac1, ac2, …\\n' +\n '• get — show the current spec (markdown).\\n' +\n '• check — mark one acceptance criterion. Args: criterionId (e.g. \"ac1\"), status (\"met\"|\"unmet\"|\"unknown\"), evidence? (a test name / observation).\\n' +\n \"• status — readiness rollup (met/total, %). A goal is only DONE when every criterion is 'met'.\\n\\n\" +\n 'USE THIS WHEN starting non-trivial work (\"define done first\"), and before declaring a task complete (check every criterion with evidence). goalId is optional — auto-resolves to the active goal.',\n parameters: {\n type: 'object',\n properties: {\n action: { type: 'string', enum: ['define', 'get', 'check', 'status'], description: 'What to do.' },\n goalId: { type: 'string', description: 'Goal/task id this spec belongs to. Optional — auto-resolves to the active goal.' },\n title: { type: 'string', description: '(define) Short title for the spec.' },\n problem: { type: 'string', description: '(define) One-paragraph problem / desired outcome.' },\n requirements: { type: 'array', items: { type: 'string' }, description: '(define) What the solution must do.' },\n acceptance: { type: 'array', items: { type: 'string' }, description: '(define) Testable \"done\" statements. Auto-ided ac1..acN.' },\n constraints: { type: 'array', items: { type: 'string' }, description: '(define) Hard limits (perf/security/scope).' },\n nonGoals: { type: 'array', items: { type: 'string' }, description: '(define) Explicitly out of scope.' },\n criterionId: { type: 'string', description: '(check) Which acceptance criterion, e.g. \"ac1\".' },\n status: { type: 'string', enum: ['met', 'unmet', 'unknown'], description: '(check) New status for the criterion.' },\n evidence: { type: 'string', description: '(check) How you know — a test name, log line, observation.' },\n },\n required: ['action'],\n },\n execute: async (args: Record<string, unknown>): Promise<string> => {\n const action = String(args.action || '').toLowerCase();\n const { goalId, error } = resolveGoalId(args.goalId as string | undefined);\n if (error) return error;\n const gid = goalId!;\n\n try {\n switch (action) {\n case 'define': {\n const acceptanceTexts = asStringArray(args.acceptance);\n const spec: GoalSpec = {\n goalId: gid,\n title: String(args.title || readGoalSpec(gid)?.title || gid),\n problem: String(args.problem || ''),\n requirements: asStringArray(args.requirements),\n acceptance: acceptanceTexts.map((text, i) => ({ id: `ac${i + 1}`, text, status: 'unmet' as AcceptanceStatus })),\n constraints: asStringArray(args.constraints),\n nonGoals: asStringArray(args.nonGoals),\n createdAt: readGoalSpec(gid)?.createdAt || new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n writeGoalSpec(spec);\n const r = specReadiness(spec);\n return `Spec defined for goal ${gid}: ${spec.acceptance.length} acceptance criteria (${r.met}/${r.total} met). Re-shown each turn — check criteria with action=check as you satisfy them.\\n\\n${renderSpecMd(spec)}`;\n }\n case 'get': {\n const spec = readGoalSpec(gid);\n if (!spec) return `No spec exists for goal ${gid} yet. Create one with action=define.`;\n return renderSpecMd(spec);\n }\n case 'check': {\n const critId = String(args.criterionId || '').trim();\n const status = String(args.status || '').toLowerCase() as AcceptanceStatus;\n if (!critId) return 'check requires \"criterionId\" (e.g. \"ac1\").';\n if (!['met', 'unmet', 'unknown'].includes(status)) return 'check requires \"status\" of met | unmet | unknown.';\n const spec = readGoalSpec(gid);\n if (!spec) return `No spec exists for goal ${gid}. Create one with action=define first.`;\n const updated = setAcceptance(gid, critId, status, args.evidence as string | undefined);\n if (!updated) {\n const ids = spec.acceptance.map((a) => a.id).join(', ') || '(none)';\n return `No criterion \"${critId}\" in goal ${gid}'s spec. Known criteria: ${ids}.`;\n }\n const r = specReadiness(updated);\n return `Marked ${critId} = ${status}${args.evidence ? ` (evidence: ${args.evidence})` : ''}. Acceptance now ${r.met}/${r.total} met (${r.pct}%).${r.ready ? ' ✅ All criteria met — spec is satisfied.' : ''}`;\n }\n case 'status': {\n const spec = readGoalSpec(gid);\n if (!spec) return `No spec exists for goal ${gid} yet. Create one with action=define.`;\n const r = specReadiness(spec);\n const lines = [`Spec readiness for goal ${gid}: ${r.met}/${r.total} met (${r.pct}%)${r.ready ? ' — ✅ READY' : ''}`];\n for (const a of spec.acceptance) {\n const mark = a.status === 'met' ? '✅' : a.status === 'unknown' ? '❓' : '⬜';\n lines.push(` ${mark} ${a.id}: ${a.text}${a.evidence ? ` — ${a.evidence}` : ''}`);\n }\n if (!r.ready && r.total > 0) lines.push(`\\nNOT done — ${r.unmet + r.unknown} criteri${r.unmet + r.unknown === 1 ? 'on' : 'a'} still open.`);\n return lines.join('\\n');\n }\n default:\n return `Unknown spec action \"${action}\". Use define | get | check | status.`;\n }\n } catch (e) {\n logger.warn(COMPONENT, `spec ${action} failed: ${(e as Error).message}`);\n return `spec ${action} failed: ${(e as Error).message}`;\n }\n },\n },\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -257,20 +257,22 @@ ALWAYS show the top match's name + category to the user before calling gallery_g
|
|
|
257
257
|
},
|
|
258
258
|
{
|
|
259
259
|
name: "gallery_get",
|
|
260
|
-
description: `Fetch a single widget template from the gallery by id, with REPLACE_WITH_X placeholders substituted.
|
|
260
|
+
description: `Fetch a single widget template from the gallery by id, with REPLACE_WITH_X placeholders substituted. Use it to INSPECT a template; to actually place the widget, call create_widget \u2014 NOT a _____react fence.
|
|
261
261
|
|
|
262
|
-
USE WHEN: you just got a template id from gallery_search and
|
|
262
|
+
USE WHEN: you just got a template id from gallery_search and need to inspect/verify its source. ALWAYS call gallery_search first to get the id \u2014 never guess a template name.
|
|
263
|
+
|
|
264
|
+
AFTER THIS: call create_widget({ template: "<id>", fill: {...} }) to place it on the user's canvas. create_widget reports whether the canvas actually received it \u2014 a pasted _____react fence cannot confirm delivery and creates duplicates. Never claim a widget is "on the canvas" unless create_widget confirmed delivery.
|
|
263
265
|
|
|
264
266
|
DO NOT USE FOR:
|
|
265
267
|
- Browsing what's available \u2192 use gallery_search (returns ranked matches with descriptions).
|
|
266
268
|
- Listing every template \u2192 use gallery_list (full catalogue).
|
|
267
|
-
- Generating a brand-new widget that's not in the catalogue \u2192
|
|
269
|
+
- Generating a brand-new widget that's not in the catalogue \u2192 call create_widget with raw source.
|
|
268
270
|
|
|
269
271
|
Parameters:
|
|
270
272
|
- id (string, required) \u2014 exact template id from gallery_search results.
|
|
271
273
|
- fill (object, optional) \u2014 placeholder substitutions. Keys are the placeholder name WITHOUT the REPLACE_WITH_ prefix (so { "SYMBOL": "AAPL" } substitutes REPLACE_WITH_SYMBOL). Values are escaped automatically for backslash, single quote, and backtick.
|
|
272
274
|
|
|
273
|
-
Returns: { source: string, size: { width, height }, category, displayName }.
|
|
275
|
+
Returns: { source: string, size: { width, height }, category, displayName, next }. Follow the \`next\` instruction.
|
|
274
276
|
|
|
275
277
|
Errors:
|
|
276
278
|
- "Template not found: <id>" \u2014 the id is wrong (typo or stale). Re-run gallery_search to get a fresh id.
|
|
@@ -303,7 +305,12 @@ Errors:
|
|
|
303
305
|
category: t.category,
|
|
304
306
|
defaultSize: t.defaultSize,
|
|
305
307
|
source: sourceWithMeta,
|
|
306
|
-
placeholders: t.placeholders ?? []
|
|
308
|
+
placeholders: t.placeholders ?? [],
|
|
309
|
+
// v7.0 honesty fix: models were pasting the source into a
|
|
310
|
+
// _____react fence and claiming "it's on your canvas" with
|
|
311
|
+
// no delivery confirmation. The result itself now routes
|
|
312
|
+
// them to the verifiable path.
|
|
313
|
+
next: `Call create_widget({ template: "${t.id}"${fill ? `, fill: ${JSON.stringify(fill)}` : ""} }) NOW to place it \u2014 do NOT paste a _____react fence (it cannot confirm delivery and duplicates). Only claim the widget is on the canvas if create_widget confirms delivery.`
|
|
307
314
|
});
|
|
308
315
|
}
|
|
309
316
|
}
|