@gokulvenkatareddy/cortex 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (299) hide show
  1. package/README.md +1295 -0
  2. package/apps/octogent/.github/workflows/ci.yml +40 -0
  3. package/apps/octogent/.shims/claude +4 -0
  4. package/apps/octogent/AGENTS.md +71 -0
  5. package/apps/octogent/CONTRIBUTING.md +72 -0
  6. package/apps/octogent/LICENSE +21 -0
  7. package/apps/octogent/README.md +184 -0
  8. package/apps/octogent/apps/api/AGENTS.md +32 -0
  9. package/apps/octogent/apps/api/package.json +19 -0
  10. package/apps/octogent/apps/api/src/agentStateDetection.ts +181 -0
  11. package/apps/octogent/apps/api/src/claudeSessionScanner.ts +235 -0
  12. package/apps/octogent/apps/api/src/claudeSkills.ts +182 -0
  13. package/apps/octogent/apps/api/src/claudeUsage.ts +922 -0
  14. package/apps/octogent/apps/api/src/cli.ts +595 -0
  15. package/apps/octogent/apps/api/src/codeIntelStore.ts +46 -0
  16. package/apps/octogent/apps/api/src/codexUsage.ts +278 -0
  17. package/apps/octogent/apps/api/src/createApiServer/codeIntelRoutes.ts +60 -0
  18. package/apps/octogent/apps/api/src/createApiServer/conversationRoutes.ts +128 -0
  19. package/apps/octogent/apps/api/src/createApiServer/deckRoutes.ts +873 -0
  20. package/apps/octogent/apps/api/src/createApiServer/gitParsers.ts +140 -0
  21. package/apps/octogent/apps/api/src/createApiServer/gitRoutes.ts +214 -0
  22. package/apps/octogent/apps/api/src/createApiServer/miscRoutes.ts +316 -0
  23. package/apps/octogent/apps/api/src/createApiServer/monitorParsers.ts +137 -0
  24. package/apps/octogent/apps/api/src/createApiServer/monitorRoutes.ts +95 -0
  25. package/apps/octogent/apps/api/src/createApiServer/requestHandler.ts +311 -0
  26. package/apps/octogent/apps/api/src/createApiServer/requestParsers.ts +25 -0
  27. package/apps/octogent/apps/api/src/createApiServer/routeHelpers.ts +97 -0
  28. package/apps/octogent/apps/api/src/createApiServer/security.ts +70 -0
  29. package/apps/octogent/apps/api/src/createApiServer/terminalParsers.ts +167 -0
  30. package/apps/octogent/apps/api/src/createApiServer/terminalRoutes.ts +315 -0
  31. package/apps/octogent/apps/api/src/createApiServer/types.ts +24 -0
  32. package/apps/octogent/apps/api/src/createApiServer/uiStateParsers.ts +255 -0
  33. package/apps/octogent/apps/api/src/createApiServer/upgradeHandler.ts +38 -0
  34. package/apps/octogent/apps/api/src/createApiServer/usageRoutes.ts +84 -0
  35. package/apps/octogent/apps/api/src/createApiServer.ts +176 -0
  36. package/apps/octogent/apps/api/src/deck/readDeckTentacles.ts +595 -0
  37. package/apps/octogent/apps/api/src/githubRepoSummary.ts +397 -0
  38. package/apps/octogent/apps/api/src/logging.ts +9 -0
  39. package/apps/octogent/apps/api/src/monitor/defaults.ts +3 -0
  40. package/apps/octogent/apps/api/src/monitor/index.ts +8 -0
  41. package/apps/octogent/apps/api/src/monitor/repository.ts +303 -0
  42. package/apps/octogent/apps/api/src/monitor/service.ts +349 -0
  43. package/apps/octogent/apps/api/src/monitor/types.ts +120 -0
  44. package/apps/octogent/apps/api/src/monitor/xProvider.ts +587 -0
  45. package/apps/octogent/apps/api/src/projectPersistence.ts +377 -0
  46. package/apps/octogent/apps/api/src/prompts/index.ts +10 -0
  47. package/apps/octogent/apps/api/src/prompts/promptResolver.ts +145 -0
  48. package/apps/octogent/apps/api/src/runtimeMetadata.ts +69 -0
  49. package/apps/octogent/apps/api/src/server.ts +80 -0
  50. package/apps/octogent/apps/api/src/setupState.ts +80 -0
  51. package/apps/octogent/apps/api/src/setupStatus.ts +174 -0
  52. package/apps/octogent/apps/api/src/startupPrerequisites.ts +146 -0
  53. package/apps/octogent/apps/api/src/terminalRuntime/channelMessaging.ts +87 -0
  54. package/apps/octogent/apps/api/src/terminalRuntime/claudeTranscript.ts +279 -0
  55. package/apps/octogent/apps/api/src/terminalRuntime/constants.ts +15 -0
  56. package/apps/octogent/apps/api/src/terminalRuntime/conversations.ts +492 -0
  57. package/apps/octogent/apps/api/src/terminalRuntime/gitOperations.ts +341 -0
  58. package/apps/octogent/apps/api/src/terminalRuntime/hookProcessor.ts +405 -0
  59. package/apps/octogent/apps/api/src/terminalRuntime/protocol.ts +46 -0
  60. package/apps/octogent/apps/api/src/terminalRuntime/ptyEnvironment.ts +50 -0
  61. package/apps/octogent/apps/api/src/terminalRuntime/registry.ts +423 -0
  62. package/apps/octogent/apps/api/src/terminalRuntime/sessionRuntime.ts +671 -0
  63. package/apps/octogent/apps/api/src/terminalRuntime/systemClients.ts +432 -0
  64. package/apps/octogent/apps/api/src/terminalRuntime/types.ts +157 -0
  65. package/apps/octogent/apps/api/src/terminalRuntime/worktreeManager.ts +135 -0
  66. package/apps/octogent/apps/api/src/terminalRuntime.ts +567 -0
  67. package/apps/octogent/apps/api/src/usageUtils.ts +16 -0
  68. package/apps/octogent/apps/api/src/ws-shim.d.ts +28 -0
  69. package/apps/octogent/apps/api/tests/agentStateDetection.test.ts +67 -0
  70. package/apps/octogent/apps/api/tests/claudeUsage.test.ts +583 -0
  71. package/apps/octogent/apps/api/tests/codexUsage.test.ts +107 -0
  72. package/apps/octogent/apps/api/tests/createApiServer.test.ts +3207 -0
  73. package/apps/octogent/apps/api/tests/githubRepoSummary.test.ts +100 -0
  74. package/apps/octogent/apps/api/tests/logging.test.ts +33 -0
  75. package/apps/octogent/apps/api/tests/monitorApi.test.ts +467 -0
  76. package/apps/octogent/apps/api/tests/monitorCore.test.ts +104 -0
  77. package/apps/octogent/apps/api/tests/promptResolver.test.ts +109 -0
  78. package/apps/octogent/apps/api/tests/protocol.test.ts +14 -0
  79. package/apps/octogent/apps/api/tests/sessionRuntime.test.ts +608 -0
  80. package/apps/octogent/apps/api/tests/startupPrerequisites.test.ts +70 -0
  81. package/apps/octogent/apps/api/tests/upgradeHandler.test.ts +40 -0
  82. package/apps/octogent/apps/api/tests/xMonitorProvider.test.ts +109 -0
  83. package/apps/octogent/apps/api/tsconfig.json +7 -0
  84. package/apps/octogent/apps/api/vitest.config.ts +7 -0
  85. package/apps/octogent/apps/web/AGENTS.md +38 -0
  86. package/apps/octogent/apps/web/index.html +13 -0
  87. package/apps/octogent/apps/web/package.json +32 -0
  88. package/apps/octogent/apps/web/public/octopus-favicon.svg +26 -0
  89. package/apps/octogent/apps/web/src/App.tsx +646 -0
  90. package/apps/octogent/apps/web/src/app/canvas/types.ts +34 -0
  91. package/apps/octogent/apps/web/src/app/codeIntelAggregation.ts +278 -0
  92. package/apps/octogent/apps/web/src/app/constants.ts +28 -0
  93. package/apps/octogent/apps/web/src/app/conversationNormalizers.ts +135 -0
  94. package/apps/octogent/apps/web/src/app/formatTimestamp.ts +18 -0
  95. package/apps/octogent/apps/web/src/app/githubMetrics.ts +76 -0
  96. package/apps/octogent/apps/web/src/app/githubNormalizers.ts +91 -0
  97. package/apps/octogent/apps/web/src/app/hooks/useAgentRuntimeStates.ts +18 -0
  98. package/apps/octogent/apps/web/src/app/hooks/useBackendLivenessPolling.ts +53 -0
  99. package/apps/octogent/apps/web/src/app/hooks/useCanvasGraphData.ts +449 -0
  100. package/apps/octogent/apps/web/src/app/hooks/useCanvasTransform.ts +260 -0
  101. package/apps/octogent/apps/web/src/app/hooks/useClaudeUsagePolling.ts +40 -0
  102. package/apps/octogent/apps/web/src/app/hooks/useClickOutside.ts +30 -0
  103. package/apps/octogent/apps/web/src/app/hooks/useCodeIntelRuntime.ts +83 -0
  104. package/apps/octogent/apps/web/src/app/hooks/useCodexUsagePolling.ts +35 -0
  105. package/apps/octogent/apps/web/src/app/hooks/useConsoleKeyboardShortcuts.ts +31 -0
  106. package/apps/octogent/apps/web/src/app/hooks/useConversationsRuntime.ts +377 -0
  107. package/apps/octogent/apps/web/src/app/hooks/useForceSimulation.ts +319 -0
  108. package/apps/octogent/apps/web/src/app/hooks/useGitHubPrimaryViewModel.ts +143 -0
  109. package/apps/octogent/apps/web/src/app/hooks/useGithubSummaryPolling.ts +28 -0
  110. package/apps/octogent/apps/web/src/app/hooks/useInitialColumnsHydration.ts +64 -0
  111. package/apps/octogent/apps/web/src/app/hooks/useMonitorRuntime.ts +220 -0
  112. package/apps/octogent/apps/web/src/app/hooks/usePersistedUiState.ts +536 -0
  113. package/apps/octogent/apps/web/src/app/hooks/usePollingData.ts +79 -0
  114. package/apps/octogent/apps/web/src/app/hooks/usePromptLibrary.ts +185 -0
  115. package/apps/octogent/apps/web/src/app/hooks/useTentacleGitLifecycle.ts +530 -0
  116. package/apps/octogent/apps/web/src/app/hooks/useTerminalCompletionNotification.ts +94 -0
  117. package/apps/octogent/apps/web/src/app/hooks/useTerminalMutations.ts +266 -0
  118. package/apps/octogent/apps/web/src/app/hooks/useTerminalStateReconciliation.ts +23 -0
  119. package/apps/octogent/apps/web/src/app/hooks/useUsageHeatmapPolling.ts +43 -0
  120. package/apps/octogent/apps/web/src/app/hooks/useWorkspaceSetup.ts +80 -0
  121. package/apps/octogent/apps/web/src/app/hotkeys.ts +31 -0
  122. package/apps/octogent/apps/web/src/app/monitorNormalizers.ts +145 -0
  123. package/apps/octogent/apps/web/src/app/notificationSounds.ts +164 -0
  124. package/apps/octogent/apps/web/src/app/terminalRuntimeStateStore.ts +261 -0
  125. package/apps/octogent/apps/web/src/app/terminalState.ts +21 -0
  126. package/apps/octogent/apps/web/src/app/types.ts +42 -0
  127. package/apps/octogent/apps/web/src/app/uiStateNormalizers.ts +113 -0
  128. package/apps/octogent/apps/web/src/app/usageNormalizers.ts +58 -0
  129. package/apps/octogent/apps/web/src/components/ActiveAgentsSidebar.tsx +60 -0
  130. package/apps/octogent/apps/web/src/components/ActivityPrimaryView.tsx +21 -0
  131. package/apps/octogent/apps/web/src/components/AgentStateBadge.tsx +47 -0
  132. package/apps/octogent/apps/web/src/components/CanvasPrimaryView.tsx +1532 -0
  133. package/apps/octogent/apps/web/src/components/ClearAllConversationsDialog.tsx +33 -0
  134. package/apps/octogent/apps/web/src/components/CodeIntelArcDiagram.tsx +245 -0
  135. package/apps/octogent/apps/web/src/components/CodeIntelPrimaryView.tsx +104 -0
  136. package/apps/octogent/apps/web/src/components/CodeIntelTreemap.tsx +138 -0
  137. package/apps/octogent/apps/web/src/components/ConsolePrimaryNav.tsx +31 -0
  138. package/apps/octogent/apps/web/src/components/ConversationsPrimaryView.tsx +243 -0
  139. package/apps/octogent/apps/web/src/components/DeckPrimaryView.tsx +613 -0
  140. package/apps/octogent/apps/web/src/components/DeleteTentacleDialog.tsx +91 -0
  141. package/apps/octogent/apps/web/src/components/EmptyOctopus.tsx +715 -0
  142. package/apps/octogent/apps/web/src/components/GitHubPrimaryView.tsx +494 -0
  143. package/apps/octogent/apps/web/src/components/MonitorPrimaryView.tsx +475 -0
  144. package/apps/octogent/apps/web/src/components/PrimaryViewRouter.tsx +99 -0
  145. package/apps/octogent/apps/web/src/components/PromptsPrimaryView.tsx +243 -0
  146. package/apps/octogent/apps/web/src/components/RuntimeStatusStrip.tsx +273 -0
  147. package/apps/octogent/apps/web/src/components/SettingsPrimaryView.tsx +92 -0
  148. package/apps/octogent/apps/web/src/components/SidebarActionPanel.tsx +124 -0
  149. package/apps/octogent/apps/web/src/components/SidebarConversationsList.tsx +279 -0
  150. package/apps/octogent/apps/web/src/components/SidebarPromptsList.tsx +116 -0
  151. package/apps/octogent/apps/web/src/components/TelemetryTape.tsx +106 -0
  152. package/apps/octogent/apps/web/src/components/TentacleGitActionsDialog.tsx +341 -0
  153. package/apps/octogent/apps/web/src/components/Terminal.tsx +524 -0
  154. package/apps/octogent/apps/web/src/components/TerminalPromptPicker.tsx +140 -0
  155. package/apps/octogent/apps/web/src/components/UsageHeatmap.tsx +702 -0
  156. package/apps/octogent/apps/web/src/components/canvas/CanvasTentaclePanel.tsx +485 -0
  157. package/apps/octogent/apps/web/src/components/canvas/CanvasTerminalColumn.tsx +89 -0
  158. package/apps/octogent/apps/web/src/components/canvas/DeleteAllTerminalsDialog.tsx +221 -0
  159. package/apps/octogent/apps/web/src/components/canvas/OctopusNode.tsx +307 -0
  160. package/apps/octogent/apps/web/src/components/canvas/SessionNode.tsx +185 -0
  161. package/apps/octogent/apps/web/src/components/deck/ActionCards.tsx +118 -0
  162. package/apps/octogent/apps/web/src/components/deck/AddTentacleForm.tsx +269 -0
  163. package/apps/octogent/apps/web/src/components/deck/DeckBottomActions.tsx +56 -0
  164. package/apps/octogent/apps/web/src/components/deck/TentaclePod.tsx +334 -0
  165. package/apps/octogent/apps/web/src/components/deck/WorkspaceSetupCard.tsx +105 -0
  166. package/apps/octogent/apps/web/src/components/deck/octopusVisuals.ts +72 -0
  167. package/apps/octogent/apps/web/src/components/terminalReplay.ts +62 -0
  168. package/apps/octogent/apps/web/src/components/terminalWheel.ts +54 -0
  169. package/apps/octogent/apps/web/src/components/ui/ActionButton.tsx +34 -0
  170. package/apps/octogent/apps/web/src/components/ui/ConfirmationDialog.tsx +86 -0
  171. package/apps/octogent/apps/web/src/components/ui/MarkdownContent.tsx +43 -0
  172. package/apps/octogent/apps/web/src/components/ui/SettingsToggle.tsx +34 -0
  173. package/apps/octogent/apps/web/src/components/ui/StatusBadge.tsx +24 -0
  174. package/apps/octogent/apps/web/src/main.tsx +17 -0
  175. package/apps/octogent/apps/web/src/runtime/HttpTerminalSnapshotReader.ts +87 -0
  176. package/apps/octogent/apps/web/src/runtime/runtimeEndpoints.ts +412 -0
  177. package/apps/octogent/apps/web/src/styles/chrome-and-buttons.css +272 -0
  178. package/apps/octogent/apps/web/src/styles/console-canvas-activity.css +358 -0
  179. package/apps/octogent/apps/web/src/styles/console-canvas-canvas.css +1843 -0
  180. package/apps/octogent/apps/web/src/styles/console-canvas-code-intel.css +227 -0
  181. package/apps/octogent/apps/web/src/styles/console-canvas-conversations.css +705 -0
  182. package/apps/octogent/apps/web/src/styles/console-canvas-deck.css +1524 -0
  183. package/apps/octogent/apps/web/src/styles/console-canvas-github.css +541 -0
  184. package/apps/octogent/apps/web/src/styles/console-canvas-monitor.css +595 -0
  185. package/apps/octogent/apps/web/src/styles/console-canvas-pixpack.css +81 -0
  186. package/apps/octogent/apps/web/src/styles/console-canvas-prompts.css +474 -0
  187. package/apps/octogent/apps/web/src/styles/console-canvas-settings.css +207 -0
  188. package/apps/octogent/apps/web/src/styles/console-chrome-status-nav.css +441 -0
  189. package/apps/octogent/apps/web/src/styles/console-overrides-telemetry.css +320 -0
  190. package/apps/octogent/apps/web/src/styles/console-theme-tokens.css +25 -0
  191. package/apps/octogent/apps/web/src/styles/cortex-theme.css +412 -0
  192. package/apps/octogent/apps/web/src/styles/foundation.css +100 -0
  193. package/apps/octogent/apps/web/src/styles/sidebar-and-scrollbars.css +447 -0
  194. package/apps/octogent/apps/web/src/styles/terminal-and-status.css +356 -0
  195. package/apps/octogent/apps/web/src/styles.css +25 -0
  196. package/apps/octogent/apps/web/src/types/ws.d.ts +23 -0
  197. package/apps/octogent/apps/web/tests/CanvasPrimaryView.test.tsx +347 -0
  198. package/apps/octogent/apps/web/tests/HttpTerminalSnapshotReader.test.tsx +54 -0
  199. package/apps/octogent/apps/web/tests/RuntimeStatusStrip.test.tsx +70 -0
  200. package/apps/octogent/apps/web/tests/Terminal.test.tsx +87 -0
  201. package/apps/octogent/apps/web/tests/add-tentacle-form.test.tsx +48 -0
  202. package/apps/octogent/apps/web/tests/app-github-runtime.test.tsx +162 -0
  203. package/apps/octogent/apps/web/tests/app-monitor-runtime.test.tsx +657 -0
  204. package/apps/octogent/apps/web/tests/app-shell-navigation.test.tsx +109 -0
  205. package/apps/octogent/apps/web/tests/app-swarm-refresh.test.tsx +268 -0
  206. package/apps/octogent/apps/web/tests/app-ui-state-persistence.test.tsx +116 -0
  207. package/apps/octogent/apps/web/tests/app-workspace-setup.test.tsx +217 -0
  208. package/apps/octogent/apps/web/tests/canvas-tentacle-panel.test.tsx +195 -0
  209. package/apps/octogent/apps/web/tests/delete-all-terminals-dialog.test.tsx +76 -0
  210. package/apps/octogent/apps/web/tests/githubMetrics.test.tsx +52 -0
  211. package/apps/octogent/apps/web/tests/hotkeys.test.tsx +44 -0
  212. package/apps/octogent/apps/web/tests/runtimeEndpoints.test.tsx +240 -0
  213. package/apps/octogent/apps/web/tests/setup.ts +39 -0
  214. package/apps/octogent/apps/web/tests/tentacle-pod.test.tsx +62 -0
  215. package/apps/octogent/apps/web/tests/terminalReplay.test.ts +71 -0
  216. package/apps/octogent/apps/web/tests/terminalState.test.tsx +49 -0
  217. package/apps/octogent/apps/web/tests/terminalWheel.test.tsx +51 -0
  218. package/apps/octogent/apps/web/tests/test-utils/appTestHarness.ts +48 -0
  219. package/apps/octogent/apps/web/tests/uiPrimitives.test.tsx +31 -0
  220. package/apps/octogent/apps/web/tests/useAgentRuntimeStates.test.tsx +47 -0
  221. package/apps/octogent/apps/web/tsconfig.json +8 -0
  222. package/apps/octogent/apps/web/vite.api.bundle.config.mts +32 -0
  223. package/apps/octogent/apps/web/vite.config.ts +22 -0
  224. package/apps/octogent/bin/octogent +3 -0
  225. package/apps/octogent/biome.json +21 -0
  226. package/apps/octogent/docs/concepts/mental-model.md +79 -0
  227. package/apps/octogent/docs/concepts/runtime-and-api.md +60 -0
  228. package/apps/octogent/docs/concepts/tentacles.md +85 -0
  229. package/apps/octogent/docs/getting-started/installation.md +54 -0
  230. package/apps/octogent/docs/getting-started/quickstart.md +79 -0
  231. package/apps/octogent/docs/guides/inter-agent-messaging.md +43 -0
  232. package/apps/octogent/docs/guides/orchestrating-child-agents.md +49 -0
  233. package/apps/octogent/docs/guides/working-with-todos.md +56 -0
  234. package/apps/octogent/docs/index.md +40 -0
  235. package/apps/octogent/docs/reference/api.md +103 -0
  236. package/apps/octogent/docs/reference/cli.md +71 -0
  237. package/apps/octogent/docs/reference/experimental-features.md +28 -0
  238. package/apps/octogent/docs/reference/filesystem-layout.md +62 -0
  239. package/apps/octogent/docs/reference/troubleshooting.md +49 -0
  240. package/apps/octogent/package.json +35 -0
  241. package/apps/octogent/packages/core/AGENTS.md +31 -0
  242. package/apps/octogent/packages/core/package.json +12 -0
  243. package/apps/octogent/packages/core/src/adapters/InMemoryTerminalSnapshotReader.ts +10 -0
  244. package/apps/octogent/packages/core/src/application/buildTerminalList.ts +13 -0
  245. package/apps/octogent/packages/core/src/domain/agentRuntime.ts +18 -0
  246. package/apps/octogent/packages/core/src/domain/channel.ts +8 -0
  247. package/apps/octogent/packages/core/src/domain/completionSound.ts +14 -0
  248. package/apps/octogent/packages/core/src/domain/conversation.ts +48 -0
  249. package/apps/octogent/packages/core/src/domain/deck.ts +33 -0
  250. package/apps/octogent/packages/core/src/domain/git.ts +32 -0
  251. package/apps/octogent/packages/core/src/domain/monitor.ts +62 -0
  252. package/apps/octogent/packages/core/src/domain/setup.ts +27 -0
  253. package/apps/octogent/packages/core/src/domain/terminal.ts +17 -0
  254. package/apps/octogent/packages/core/src/domain/uiState.ts +22 -0
  255. package/apps/octogent/packages/core/src/domain/usage.ts +60 -0
  256. package/apps/octogent/packages/core/src/index.ts +15 -0
  257. package/apps/octogent/packages/core/src/ports/TerminalSnapshotReader.ts +5 -0
  258. package/apps/octogent/packages/core/src/util/typeCoercion.ts +20 -0
  259. package/apps/octogent/packages/core/tests/buildTerminalList.test.ts +75 -0
  260. package/apps/octogent/packages/core/tsconfig.json +7 -0
  261. package/apps/octogent/packages/core/tsconfig.tsbuildinfo +1 -0
  262. package/apps/octogent/packages/core/vitest.config.ts +7 -0
  263. package/apps/octogent/pnpm-lock.yaml +3212 -0
  264. package/apps/octogent/pnpm-workspace.yaml +3 -0
  265. package/apps/octogent/prompts/meta-prompt-generator.md +223 -0
  266. package/apps/octogent/prompts/octoboss-clean-contexts.md +30 -0
  267. package/apps/octogent/prompts/octoboss-reorganize-tentacles.md +29 -0
  268. package/apps/octogent/prompts/octoboss-reorganize-todos.md +27 -0
  269. package/apps/octogent/prompts/sandbox-init.md +3 -0
  270. package/apps/octogent/prompts/swarm-parent.md +83 -0
  271. package/apps/octogent/prompts/swarm-worker.md +50 -0
  272. package/apps/octogent/prompts/tentacle-context-init.md +1 -0
  273. package/apps/octogent/prompts/tentacle-planner.md +110 -0
  274. package/apps/octogent/prompts/tentacle-reorganize-todos.md +20 -0
  275. package/apps/octogent/prompts/tentacle-update-tentacle.md +18 -0
  276. package/apps/octogent/scripts/build-package.mjs +23 -0
  277. package/apps/octogent/scripts/dev.mjs +158 -0
  278. package/apps/octogent/scripts/smoke-public-install.mjs +271 -0
  279. package/apps/octogent/static/images/octogent-header.png +0 -0
  280. package/apps/octogent/static/images/preview_1.jpg +0 -0
  281. package/apps/octogent/static/images/preview_2.jpg +0 -0
  282. package/apps/octogent/static/images/preview_3.jpg +0 -0
  283. package/apps/octogent/static/images/preview_4.jpg +0 -0
  284. package/apps/octogent/static/images/preview_5.jpg +0 -0
  285. package/apps/octogent/static/images/preview_6.jpg +0 -0
  286. package/apps/octogent/tsconfig.base.json +16 -0
  287. package/bin/AGI +3 -0
  288. package/bin/AGI-install-app +71 -0
  289. package/bin/AGI-ui +16 -0
  290. package/bin/AGI-voice +15 -0
  291. package/bin/AGI-web +16 -0
  292. package/bin/cortex +109 -0
  293. package/bin/cortex-octogent +99 -0
  294. package/bin/import-specifier.mjs +13 -0
  295. package/bin/import-specifier.test.mjs +13 -0
  296. package/bin/octo +150 -0
  297. package/dist/cli.mjs +555650 -0
  298. package/package.json +157 -0
  299. package/scripts/setup-wizard.ts +390 -0
@@ -0,0 +1,524 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+
3
+ import { FileText, X } from "lucide-react";
4
+ import { buildTerminalSocketUrl } from "../runtime/runtimeEndpoints";
5
+ import { type AgentRuntimeState, AgentStateBadge, isAgentRuntimeState } from "./AgentStateBadge";
6
+ import { TerminalPromptPicker } from "./TerminalPromptPicker";
7
+ import { replayTerminalHistory } from "./terminalReplay";
8
+ import { wheelDeltaToScrollLines } from "./terminalWheel";
9
+
10
+ import "xterm/css/xterm.css";
11
+
12
+ type TerminalProps = {
13
+ terminalId: string;
14
+ terminalLabel?: string;
15
+ layoutVersion?: string | number;
16
+ isSelected?: boolean;
17
+ initialPrompt?: string;
18
+ hidePromptPicker?: boolean;
19
+ onSelectTerminal?: (terminalId: string) => void;
20
+ onAgentRuntimeStateChange?: (state: AgentRuntimeState) => void;
21
+ onTerminalRenamed?: ((terminalId: string, tentacleName: string) => void) | undefined;
22
+ onTerminalActivity?: ((terminalId: string) => void) | undefined;
23
+ };
24
+
25
+ type TerminalStateMessage = {
26
+ type: "state";
27
+ state: AgentRuntimeState;
28
+ };
29
+
30
+ type TerminalOutputMessage = {
31
+ type: "output";
32
+ data: string;
33
+ };
34
+
35
+ type TerminalHistoryMessage = {
36
+ type: "history";
37
+ data: string;
38
+ };
39
+
40
+ type TerminalRenameMessage = {
41
+ type: "rename";
42
+ tentacleName: string;
43
+ };
44
+
45
+ type TerminalActivityMessage = {
46
+ type: "activity";
47
+ };
48
+
49
+ type TerminalServerMessage =
50
+ | TerminalStateMessage
51
+ | TerminalOutputMessage
52
+ | TerminalHistoryMessage
53
+ | TerminalRenameMessage
54
+ | TerminalActivityMessage;
55
+
56
+ const PromptInjectIcon = () => (
57
+ <svg
58
+ aria-hidden="true"
59
+ className="terminal-inject-icon"
60
+ viewBox="0 0 16 16"
61
+ width="14"
62
+ height="14"
63
+ >
64
+ <path d="M2 3h12v1H2V3Zm0 3h8v1H2V6Zm0 3h6v1H2V9Zm9 0l3 2.5L11 14v-5Z" fill="currentColor" />
65
+ </svg>
66
+ );
67
+
68
+ export const Terminal = ({
69
+ terminalId,
70
+ terminalLabel,
71
+ layoutVersion,
72
+ isSelected,
73
+ initialPrompt,
74
+ hidePromptPicker,
75
+ onSelectTerminal,
76
+ onAgentRuntimeStateChange,
77
+ onTerminalRenamed,
78
+ onTerminalActivity,
79
+ }: TerminalProps) => {
80
+ const socketRef = useRef<WebSocket | null>(null);
81
+ const containerRef = useRef<HTMLDivElement | null>(null);
82
+ const [connectionState, setConnectionState] = useState("connecting");
83
+ const [agentState, setAgentRuntimeState] = useState<AgentRuntimeState>("idle");
84
+ const [isPromptBannerDismissed, setIsPromptBannerDismissed] = useState(false);
85
+ const [isPromptPickerOpen, setIsPromptPickerOpen] = useState(false);
86
+ const promptPickerBtnRef = useRef<HTMLButtonElement | null>(null);
87
+ const terminalRef = useRef<{
88
+ write: (value: string, callback?: () => void) => void;
89
+ scrollLines: (lineCount: number) => void;
90
+ clear: () => void;
91
+ reset: () => void;
92
+ clearSelection?: () => void;
93
+ refresh?: (start: number, end: number) => void;
94
+ cols: number;
95
+ rows: number;
96
+ } | null>(null);
97
+ const fitAddonRef = useRef<{ fit: () => void } | null>(null);
98
+ const requestResizeSyncRef = useRef<() => void>(() => {});
99
+ const onTerminalActivityRef = useRef(onTerminalActivity);
100
+ const onTerminalRenamedRef = useRef(onTerminalRenamed);
101
+ const rawTitle = terminalLabel && terminalLabel.length > 0 ? terminalLabel : terminalId;
102
+ const terminalTitle = rawTitle.length > 24 ? `${rawTitle.slice(0, 24)}...` : rawTitle;
103
+
104
+ onTerminalActivityRef.current = onTerminalActivity;
105
+ onTerminalRenamedRef.current = onTerminalRenamed;
106
+
107
+ useEffect(() => {
108
+ onAgentRuntimeStateChange?.(agentState);
109
+ }, [agentState, onAgentRuntimeStateChange]);
110
+
111
+ const handlePromptPickerSelect = useCallback((content: string) => {
112
+ const ws = socketRef.current;
113
+ if (ws && ws.readyState === 1) {
114
+ ws.send(JSON.stringify({ type: "input", data: content }));
115
+ }
116
+ }, []);
117
+
118
+ useEffect(() => {
119
+ let isCancelled = false;
120
+ let reconnectTimer: number | null = null;
121
+ let socket: WebSocket | null = null;
122
+ let requestResizeSync = () => {};
123
+ requestResizeSyncRef.current = () => {};
124
+ let cleanupTerminal = () => {};
125
+ let activeTerminal: {
126
+ write: (value: string, callback?: () => void) => void;
127
+ scrollLines: (lineCount: number) => void;
128
+ clear: () => void;
129
+ reset: () => void;
130
+ clearSelection?: () => void;
131
+ refresh?: (start: number, end: number) => void;
132
+ rows: number;
133
+ } | null = null;
134
+ let pendingHistoryData: string | null = null;
135
+ const pendingOutputChunks: string[] = [];
136
+
137
+ const connect = () => {
138
+ const nextSocket = new WebSocket(buildTerminalSocketUrl(terminalId));
139
+ socket = nextSocket;
140
+ setConnectionState("connecting");
141
+
142
+ nextSocket.addEventListener("open", () => {
143
+ if (isCancelled || socket !== nextSocket) {
144
+ return;
145
+ }
146
+ socketRef.current = nextSocket;
147
+ setConnectionState("connected");
148
+ requestResizeSync();
149
+ });
150
+
151
+ nextSocket.addEventListener("close", () => {
152
+ if (isCancelled || socket !== nextSocket) {
153
+ return;
154
+ }
155
+ socketRef.current = null;
156
+ setConnectionState("closed");
157
+ reconnectTimer = window.setTimeout(() => {
158
+ connect();
159
+ }, 900);
160
+ });
161
+
162
+ nextSocket.addEventListener("error", () => {
163
+ if (isCancelled || socket !== nextSocket) {
164
+ return;
165
+ }
166
+ setConnectionState("error");
167
+ });
168
+
169
+ nextSocket.addEventListener("message", (event) => {
170
+ if (isCancelled || socket !== nextSocket) {
171
+ return;
172
+ }
173
+
174
+ if (typeof event.data !== "string") {
175
+ return;
176
+ }
177
+
178
+ try {
179
+ const payload = JSON.parse(event.data) as TerminalServerMessage;
180
+ if (payload.type === "history" && typeof payload.data === "string") {
181
+ if (activeTerminal) {
182
+ const viewport =
183
+ containerRef.current?.querySelector<HTMLElement>(".xterm-viewport") ?? null;
184
+ replayTerminalHistory(activeTerminal, payload.data, viewport);
185
+ return;
186
+ }
187
+
188
+ pendingHistoryData = payload.data;
189
+ pendingOutputChunks.length = 0;
190
+ return;
191
+ }
192
+
193
+ if (payload.type === "output" && typeof payload.data === "string") {
194
+ if (activeTerminal) {
195
+ activeTerminal.write(payload.data);
196
+ return;
197
+ }
198
+
199
+ pendingOutputChunks.push(payload.data);
200
+ return;
201
+ }
202
+
203
+ if (payload.type === "state" && isAgentRuntimeState(payload.state)) {
204
+ setAgentRuntimeState(payload.state);
205
+ return;
206
+ }
207
+
208
+ if (payload.type === "rename" && typeof payload.tentacleName === "string") {
209
+ onTerminalRenamedRef.current?.(terminalId, payload.tentacleName);
210
+ return;
211
+ }
212
+
213
+ if (payload.type === "activity") {
214
+ onTerminalActivityRef.current?.(terminalId);
215
+ return;
216
+ }
217
+ } catch {
218
+ if (activeTerminal) {
219
+ activeTerminal.write(event.data);
220
+ return;
221
+ }
222
+
223
+ pendingOutputChunks.push(event.data);
224
+ }
225
+ });
226
+ };
227
+
228
+ connect();
229
+
230
+ if (import.meta.env.MODE === "test") {
231
+ return () => {
232
+ isCancelled = true;
233
+ if (reconnectTimer !== null) {
234
+ window.clearTimeout(reconnectTimer);
235
+ }
236
+ socket?.close();
237
+ };
238
+ }
239
+
240
+ void (async () => {
241
+ if (!containerRef.current) {
242
+ return;
243
+ }
244
+
245
+ try {
246
+ const [{ Terminal }, { FitAddon }] = await Promise.all([
247
+ import("xterm"),
248
+ import("@xterm/addon-fit"),
249
+ ]);
250
+
251
+ if (isCancelled || !containerRef.current) {
252
+ return;
253
+ }
254
+
255
+ const rootFontSize = Number.parseFloat(
256
+ window.getComputedStyle(document.documentElement).fontSize,
257
+ );
258
+ const terminalFontSize = Number.isFinite(rootFontSize)
259
+ ? Math.max(13, Math.round(rootFontSize * 0.82))
260
+ : 13;
261
+ const terminalBackground =
262
+ window
263
+ .getComputedStyle(document.documentElement)
264
+ .getPropertyValue("--terminal-bg")
265
+ .trim() || "#101722";
266
+
267
+ const terminal = new Terminal({
268
+ cursorBlink: true,
269
+ cursorInactiveStyle: "bar",
270
+ cursorStyle: "bar",
271
+ cursorWidth: 2,
272
+ fontFamily: '"JetBrains Mono", "IBM Plex Mono", monospace',
273
+ fontSize: terminalFontSize,
274
+ theme: {
275
+ background: terminalBackground,
276
+ foreground: "#f0f0f0",
277
+ cursor: "#faa32c",
278
+ cursorAccent: terminalBackground,
279
+ },
280
+ });
281
+ const fitAddon = new FitAddon();
282
+ terminal.loadAddon(fitAddon);
283
+ terminal.open(containerRef.current);
284
+ fitAddon.fit();
285
+ terminal.focus();
286
+
287
+ try {
288
+ const { Unicode11Addon } = await import("xterm-addon-unicode11");
289
+ const unicode11Addon = new Unicode11Addon();
290
+ terminal.loadAddon(unicode11Addon);
291
+ terminal.unicode.activeVersion = "11";
292
+ } catch {
293
+ // Non-critical: terminal works without unicode11, just with less accurate character widths
294
+ }
295
+ activeTerminal = terminal;
296
+
297
+ if (pendingHistoryData !== null) {
298
+ replayTerminalHistory(terminal, pendingHistoryData, null);
299
+ pendingHistoryData = null;
300
+ }
301
+ if (pendingOutputChunks.length > 0) {
302
+ for (const chunk of pendingOutputChunks) {
303
+ terminal.write(chunk);
304
+ }
305
+ pendingOutputChunks.length = 0;
306
+ }
307
+
308
+ const wheelListenerTarget = containerRef.current;
309
+ const viewportWheelTarget =
310
+ wheelListenerTarget.querySelector<HTMLElement>(".xterm-viewport") ?? wheelListenerTarget;
311
+ const onPointerDown = () => {
312
+ terminal.focus();
313
+ };
314
+ const onWheel = (event: WheelEvent) => {
315
+ const lines = wheelDeltaToScrollLines(event.deltaY, event.deltaMode);
316
+ if (lines === 0) {
317
+ return;
318
+ }
319
+
320
+ event.preventDefault();
321
+ event.stopPropagation();
322
+ terminal.scrollLines(lines);
323
+ };
324
+ wheelListenerTarget.addEventListener("pointerdown", onPointerDown, {
325
+ capture: true,
326
+ });
327
+ viewportWheelTarget.addEventListener("wheel", onWheel, {
328
+ passive: false,
329
+ });
330
+
331
+ let resizeDebounceTimer: number | null = null;
332
+ let lastSentCols = -1;
333
+ let lastSentRows = -1;
334
+
335
+ const sendResize = () => {
336
+ if (!socket || socket.readyState !== 1) {
337
+ return;
338
+ }
339
+
340
+ if (terminal.cols === lastSentCols && terminal.rows === lastSentRows) {
341
+ return;
342
+ }
343
+
344
+ socket.send(
345
+ JSON.stringify({
346
+ type: "resize",
347
+ cols: terminal.cols,
348
+ rows: terminal.rows,
349
+ }),
350
+ );
351
+ lastSentCols = terminal.cols;
352
+ lastSentRows = terminal.rows;
353
+ };
354
+
355
+ const scheduleResizeSync = () => {
356
+ if (resizeDebounceTimer !== null) {
357
+ window.clearTimeout(resizeDebounceTimer);
358
+ }
359
+ resizeDebounceTimer = window.setTimeout(() => {
360
+ resizeDebounceTimer = null;
361
+ sendResize();
362
+ }, 60);
363
+ };
364
+ requestResizeSync = scheduleResizeSync;
365
+ requestResizeSyncRef.current = scheduleResizeSync;
366
+
367
+ const onDataDisposable = terminal.onData((data) => {
368
+ if (!socket || socket.readyState !== 1) {
369
+ return;
370
+ }
371
+
372
+ socket.send(
373
+ JSON.stringify({
374
+ type: "input",
375
+ data,
376
+ }),
377
+ );
378
+ });
379
+
380
+ let observer: ResizeObserver | null = null;
381
+ if ("ResizeObserver" in window) {
382
+ observer = new ResizeObserver(() => {
383
+ fitAddon.fit();
384
+ scheduleResizeSync();
385
+ });
386
+ observer.observe(containerRef.current);
387
+ }
388
+
389
+ scheduleResizeSync();
390
+ terminalRef.current = terminal;
391
+ fitAddonRef.current = fitAddon;
392
+ cleanupTerminal = () => {
393
+ wheelListenerTarget.removeEventListener("pointerdown", onPointerDown, true);
394
+ viewportWheelTarget.removeEventListener("wheel", onWheel);
395
+ if (resizeDebounceTimer !== null) {
396
+ window.clearTimeout(resizeDebounceTimer);
397
+ }
398
+ observer?.disconnect();
399
+ onDataDisposable.dispose();
400
+ terminal.dispose();
401
+ terminalRef.current = null;
402
+ fitAddonRef.current = null;
403
+ requestResizeSyncRef.current = () => {};
404
+ };
405
+ } catch {
406
+ setConnectionState("fallback");
407
+ }
408
+ })();
409
+
410
+ return () => {
411
+ isCancelled = true;
412
+ if (reconnectTimer !== null) {
413
+ window.clearTimeout(reconnectTimer);
414
+ }
415
+ requestResizeSync = () => {};
416
+ requestResizeSyncRef.current = () => {};
417
+ cleanupTerminal();
418
+ socket?.close();
419
+ };
420
+ }, [terminalId]);
421
+
422
+ useEffect(() => {
423
+ if (layoutVersion === undefined) {
424
+ return;
425
+ }
426
+
427
+ const activeTerminal = terminalRef.current;
428
+ const fitAddon = fitAddonRef.current;
429
+ if (!activeTerminal || !fitAddon) {
430
+ return;
431
+ }
432
+
433
+ const frame = window.requestAnimationFrame(() => {
434
+ fitAddon.fit();
435
+ requestResizeSyncRef.current();
436
+ });
437
+
438
+ return () => {
439
+ window.cancelAnimationFrame(frame);
440
+ };
441
+ }, [layoutVersion]);
442
+
443
+ return (
444
+ <div
445
+ className={`terminal-pane${isSelected ? " terminal-pane--selected" : ""}`}
446
+ data-selected={isSelected ? "true" : "false"}
447
+ onFocusCapture={() => {
448
+ onSelectTerminal?.(terminalId);
449
+ }}
450
+ onPointerDownCapture={() => {
451
+ onSelectTerminal?.(terminalId);
452
+ }}
453
+ >
454
+ <div className="terminal-header" data-connection-state={connectionState}>
455
+ <span className="terminal-title">{terminalTitle}</span>
456
+ {initialPrompt && !isPromptBannerDismissed && (
457
+ <div className="terminal-prompt-banner">
458
+ <button
459
+ type="button"
460
+ className="terminal-prompt-banner-inject"
461
+ onClick={() => {
462
+ const ws = socketRef.current;
463
+ if (ws && ws.readyState === 1) {
464
+ ws.send(JSON.stringify({ type: "input", data: initialPrompt }));
465
+ }
466
+ setIsPromptBannerDismissed(true);
467
+ }}
468
+ title={initialPrompt}
469
+ >
470
+ <PromptInjectIcon />
471
+ <span className="terminal-prompt-banner-text">
472
+ {initialPrompt.length > 60 ? `${initialPrompt.slice(0, 60)}...` : initialPrompt}
473
+ </span>
474
+ </button>
475
+ <button
476
+ type="button"
477
+ className="terminal-prompt-banner-close"
478
+ aria-label="Dismiss prompt"
479
+ onClick={() => {
480
+ setIsPromptBannerDismissed(true);
481
+ }}
482
+ >
483
+ <X size={14} />
484
+ </button>
485
+ </div>
486
+ )}
487
+ <div className="terminal-header-actions">
488
+ {!hidePromptPicker && (
489
+ <div className="terminal-prompt-picker-anchor">
490
+ <button
491
+ ref={promptPickerBtnRef}
492
+ type="button"
493
+ className="terminal-prompt-picker-btn"
494
+ title="Insert prompt"
495
+ aria-label="Insert prompt"
496
+ onClick={() => {
497
+ setIsPromptPickerOpen((prev) => !prev);
498
+ }}
499
+ >
500
+ <FileText size={13} />
501
+ <span className="terminal-prompt-picker-label">Prompts</span>
502
+ </button>
503
+ <TerminalPromptPicker
504
+ isOpen={isPromptPickerOpen}
505
+ anchorRef={promptPickerBtnRef}
506
+ onClose={() => {
507
+ setIsPromptPickerOpen(false);
508
+ }}
509
+ onSelectPrompt={handlePromptPickerSelect}
510
+ />
511
+ </div>
512
+ )}
513
+ <AgentStateBadge state={agentState} />
514
+ </div>
515
+ </div>
516
+ <div
517
+ ref={containerRef}
518
+ className="terminal-mount"
519
+ data-testid={`terminal-${terminalId}`}
520
+ aria-label={`Terminal ${terminalId}`}
521
+ />
522
+ </div>
523
+ );
524
+ };
@@ -0,0 +1,140 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+
3
+ import type { PromptDetail, PromptLibraryEntry } from "../app/types";
4
+ import { buildPromptItemUrl, buildPromptsUrl } from "../runtime/runtimeEndpoints";
5
+
6
+ type TerminalPromptPickerProps = {
7
+ isOpen: boolean;
8
+ anchorRef: React.RefObject<HTMLButtonElement | null>;
9
+ onClose: () => void;
10
+ onSelectPrompt: (content: string) => void;
11
+ };
12
+
13
+ export const TerminalPromptPicker = ({
14
+ isOpen,
15
+ anchorRef,
16
+ onClose,
17
+ onSelectPrompt,
18
+ }: TerminalPromptPickerProps) => {
19
+ const [prompts, setPrompts] = useState<PromptLibraryEntry[]>([]);
20
+ const [isLoading, setIsLoading] = useState(false);
21
+ const popoverRef = useRef<HTMLDivElement>(null);
22
+ const [style, setStyle] = useState<React.CSSProperties>({});
23
+
24
+ useEffect(() => {
25
+ if (!isOpen || !anchorRef.current) return;
26
+
27
+ const rect = anchorRef.current.getBoundingClientRect();
28
+ setStyle({
29
+ position: "fixed",
30
+ top: rect.bottom + 2,
31
+ right: window.innerWidth - rect.right,
32
+ });
33
+ }, [isOpen, anchorRef]);
34
+
35
+ useEffect(() => {
36
+ if (!isOpen) return;
37
+
38
+ setIsLoading(true);
39
+ fetch(buildPromptsUrl())
40
+ .then(async (res) => {
41
+ if (!res.ok) return;
42
+ const data = (await res.json()) as { prompts: PromptLibraryEntry[] };
43
+ setPrompts(data.prompts);
44
+ })
45
+ .catch(() => {
46
+ // Silently fail
47
+ })
48
+ .finally(() => {
49
+ setIsLoading(false);
50
+ });
51
+ }, [isOpen]);
52
+
53
+ useEffect(() => {
54
+ if (!isOpen) return;
55
+
56
+ const handleClickOutside = (e: MouseEvent) => {
57
+ if (
58
+ popoverRef.current &&
59
+ !popoverRef.current.contains(e.target as Node) &&
60
+ anchorRef.current &&
61
+ !anchorRef.current.contains(e.target as Node)
62
+ ) {
63
+ onClose();
64
+ }
65
+ };
66
+
67
+ document.addEventListener("mousedown", handleClickOutside);
68
+ return () => {
69
+ document.removeEventListener("mousedown", handleClickOutside);
70
+ };
71
+ }, [isOpen, onClose, anchorRef]);
72
+
73
+ const handleSelectPrompt = useCallback(
74
+ async (name: string) => {
75
+ try {
76
+ const res = await fetch(buildPromptItemUrl(name));
77
+ if (!res.ok) return;
78
+ const data = (await res.json()) as PromptDetail;
79
+ onSelectPrompt(data.content);
80
+ onClose();
81
+ } catch {
82
+ // Silently fail
83
+ }
84
+ },
85
+ [onSelectPrompt, onClose],
86
+ );
87
+
88
+ if (!isOpen) return null;
89
+
90
+ const userPrompts = prompts.filter((p) => p.source === "user");
91
+ const builtinPrompts = prompts.filter((p) => p.source === "builtin");
92
+
93
+ return (
94
+ <div className="prompt-picker-popover" ref={popoverRef} style={style}>
95
+ <div className="prompt-picker-header">Insert Prompt</div>
96
+ {isLoading ? (
97
+ <div className="prompt-picker-loading">Loading...</div>
98
+ ) : prompts.length === 0 ? (
99
+ <div className="prompt-picker-empty">No prompts available</div>
100
+ ) : (
101
+ <div className="prompt-picker-list">
102
+ {userPrompts.length > 0 && (
103
+ <div className="prompt-picker-group">
104
+ <div className="prompt-picker-group-label">My Prompts</div>
105
+ {userPrompts.map((p) => (
106
+ <button
107
+ key={p.name}
108
+ type="button"
109
+ className="prompt-picker-item"
110
+ onClick={() => {
111
+ void handleSelectPrompt(p.name);
112
+ }}
113
+ >
114
+ {p.name}.md
115
+ </button>
116
+ ))}
117
+ </div>
118
+ )}
119
+ {builtinPrompts.length > 0 && (
120
+ <div className="prompt-picker-group">
121
+ <div className="prompt-picker-group-label">Built-in</div>
122
+ {builtinPrompts.map((p) => (
123
+ <button
124
+ key={p.name}
125
+ type="button"
126
+ className="prompt-picker-item"
127
+ onClick={() => {
128
+ void handleSelectPrompt(p.name);
129
+ }}
130
+ >
131
+ {p.name}.md
132
+ </button>
133
+ ))}
134
+ </div>
135
+ )}
136
+ </div>
137
+ )}
138
+ </div>
139
+ );
140
+ };