@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,613 @@
1
+ import { type ReactNode, useCallback, useEffect, useMemo, useRef, useState } from "react";
2
+
3
+ import type {
4
+ DeckAvailableSkill,
5
+ DeckTentacleSummary,
6
+ WorkspaceSetupSnapshot,
7
+ WorkspaceSetupStepId,
8
+ } from "@octogent/core";
9
+ import { useClickOutside } from "../app/hooks/useClickOutside";
10
+ import type { TerminalAgentProvider } from "../app/types";
11
+ import {
12
+ buildDeckSkillsUrl,
13
+ buildDeckTentacleSkillsUrl,
14
+ buildDeckTentacleUrl,
15
+ buildDeckTentaclesUrl,
16
+ buildDeckTodoToggleUrl,
17
+ buildDeckVaultFileUrl,
18
+ buildTerminalsUrl,
19
+ } from "../runtime/runtimeEndpoints";
20
+ import { OctopusGlyph } from "./EmptyOctopus";
21
+ import { Terminal } from "./Terminal";
22
+ import { ActionCards } from "./deck/ActionCards";
23
+ import { AddTentacleForm } from "./deck/AddTentacleForm";
24
+ import type { OctopusAppearancePayload } from "./deck/AddTentacleForm";
25
+ import { DeckBottomActions } from "./deck/DeckBottomActions";
26
+ import { TentaclePod } from "./deck/TentaclePod";
27
+ import { WorkspaceSetupCard } from "./deck/WorkspaceSetupCard";
28
+ import { type OctopusVisuals, deriveOctopusVisuals } from "./deck/octopusVisuals";
29
+ import { MarkdownContent } from "./ui/MarkdownContent";
30
+
31
+ export type { OctopusAppearancePayload } from "./deck/AddTentacleForm";
32
+
33
+ const normalizeDeckAvailableSkill = (value: unknown): DeckAvailableSkill | null => {
34
+ if (value === null || typeof value !== "object") return null;
35
+ const record = value as Record<string, unknown>;
36
+ if (typeof record.name !== "string") return null;
37
+
38
+ return {
39
+ name: record.name,
40
+ description: typeof record.description === "string" ? record.description : "",
41
+ source: record.source === "project" ? "project" : "user",
42
+ };
43
+ };
44
+
45
+ // ─── Main view ───────────────────────────────────────────────────────────────
46
+
47
+ type FocusState =
48
+ | { type: "vault-browser"; tentacleId: string }
49
+ | { type: "vault"; tentacleId: string; fileName: string }
50
+ | { type: "terminal"; agentId: string; terminalLabel: string };
51
+
52
+ type EmptyViewMode = "idle" | "adding";
53
+
54
+ type DeckPrimaryViewProps = {
55
+ onSidebarContent?: ((content: ReactNode) => void) | undefined;
56
+ workspaceSetup: WorkspaceSetupSnapshot | null;
57
+ isWorkspaceSetupLoading: boolean;
58
+ workspaceSetupError: string | null;
59
+ onRefreshWorkspaceSetup: () => Promise<WorkspaceSetupSnapshot | null>;
60
+ onRunWorkspaceSetupStep: (stepId: WorkspaceSetupStepId) => Promise<WorkspaceSetupSnapshot | null>;
61
+ suppressWorkspaceSetupCard?: boolean;
62
+ };
63
+
64
+ export const DeckPrimaryView = ({
65
+ onSidebarContent,
66
+ workspaceSetup,
67
+ isWorkspaceSetupLoading,
68
+ workspaceSetupError,
69
+ onRefreshWorkspaceSetup,
70
+ onRunWorkspaceSetupStep,
71
+ suppressWorkspaceSetupCard = false,
72
+ }: DeckPrimaryViewProps) => {
73
+ const [tentacles, setTentacles] = useState<DeckTentacleSummary[]>([]);
74
+ const [focus, setFocus] = useState<FocusState | null>(null);
75
+ const [vaultContent, setVaultContent] = useState<string | null>(null);
76
+ const [loadingVault, setLoadingVault] = useState(false);
77
+ const [emptyViewMode, setEmptyViewMode] = useState<EmptyViewMode>("idle");
78
+ const [isCreating, setIsCreating] = useState(false);
79
+ const [createError, setCreateError] = useState<string | null>(null);
80
+ const [availableSkills, setAvailableSkills] = useState<DeckAvailableSkill[]>([]);
81
+ const [savingTentacleSkillsId, setSavingTentacleSkillsId] = useState<string | null>(null);
82
+
83
+ const [selectedAgent, setSelectedAgent] = useState<TerminalAgentProvider>("claude-code");
84
+ const [agentMenuOpen, setAgentMenuOpen] = useState(false);
85
+ const agentMenuRef = useRef<HTMLDivElement>(null);
86
+ const [isLaunchingAgent, setIsLaunchingAgent] = useState(false);
87
+ const [runningSetupStepId, setRunningSetupStepId] = useState<
88
+ | "initialize-workspace"
89
+ | "ensure-gitignore"
90
+ | "check-claude"
91
+ | "check-git"
92
+ | "check-curl"
93
+ | "create-tentacles"
94
+ | null
95
+ >(null);
96
+
97
+ // Fetch tentacle list
98
+ const fetchTentacles = useCallback(async () => {
99
+ try {
100
+ const response = await fetch(buildDeckTentaclesUrl(), {
101
+ headers: { Accept: "application/json" },
102
+ });
103
+ if (!response.ok) return;
104
+ const data = await response.json();
105
+ setTentacles(data);
106
+ await onRefreshWorkspaceSetup();
107
+ } catch {
108
+ // silently ignore
109
+ }
110
+ }, [onRefreshWorkspaceSetup]);
111
+
112
+ useEffect(() => {
113
+ void fetchTentacles();
114
+ }, [fetchTentacles]);
115
+
116
+ useEffect(() => {
117
+ let cancelled = false;
118
+
119
+ const fetchSkills = async () => {
120
+ try {
121
+ const response = await fetch(buildDeckSkillsUrl(), {
122
+ headers: { Accept: "application/json" },
123
+ });
124
+ if (!response.ok) return;
125
+ const payload = (await response.json()) as unknown;
126
+ if (!Array.isArray(payload) || cancelled) return;
127
+ const skills = payload
128
+ .map((entry) => normalizeDeckAvailableSkill(entry))
129
+ .filter((entry): entry is DeckAvailableSkill => entry !== null);
130
+ if (!cancelled) {
131
+ setAvailableSkills(skills);
132
+ }
133
+ } catch {
134
+ // silently ignore
135
+ }
136
+ };
137
+
138
+ void fetchSkills();
139
+ return () => {
140
+ cancelled = true;
141
+ };
142
+ }, []);
143
+
144
+ // Precompute visuals for all tentacles
145
+ const visualsMap = useMemo(() => {
146
+ const map = new Map<string, OctopusVisuals>();
147
+ for (const t of tentacles) {
148
+ map.set(t.tentacleId, deriveOctopusVisuals(t));
149
+ }
150
+ return map;
151
+ }, [tentacles]);
152
+
153
+ // Fetch vault file content when focus changes
154
+ useEffect(() => {
155
+ if (!focus || focus.type !== "vault") {
156
+ setVaultContent(null);
157
+ return;
158
+ }
159
+
160
+ let cancelled = false;
161
+ setLoadingVault(true);
162
+ const fetchVault = async () => {
163
+ try {
164
+ const response = await fetch(buildDeckVaultFileUrl(focus.tentacleId, focus.fileName), {
165
+ headers: { Accept: "text/markdown" },
166
+ });
167
+ if (cancelled) return;
168
+ if (!response.ok) {
169
+ setVaultContent(null);
170
+ setLoadingVault(false);
171
+ return;
172
+ }
173
+ const text = await response.text();
174
+ if (!cancelled) {
175
+ setVaultContent(text);
176
+ setLoadingVault(false);
177
+ }
178
+ } catch {
179
+ if (!cancelled) {
180
+ setVaultContent(null);
181
+ setLoadingVault(false);
182
+ }
183
+ }
184
+ };
185
+ void fetchVault();
186
+ return () => {
187
+ cancelled = true;
188
+ };
189
+ }, [focus]);
190
+
191
+ // Agent menu click-outside/escape
192
+ const handleDismissAgentMenu = useCallback(() => setAgentMenuOpen(false), []);
193
+ useClickOutside(agentMenuRef, agentMenuOpen, handleDismissAgentMenu);
194
+
195
+ const handleVaultFileClick = useCallback((tentacleId: string, fileName: string) => {
196
+ setFocus({ type: "vault", tentacleId, fileName });
197
+ }, []);
198
+
199
+ const handleClose = useCallback(() => {
200
+ setFocus(null);
201
+ }, []);
202
+
203
+ const handleLaunchAgent = useCallback(async () => {
204
+ setIsLaunchingAgent(true);
205
+ try {
206
+ const response = await fetch(buildTerminalsUrl(), {
207
+ method: "POST",
208
+ headers: { "Content-Type": "application/json", Accept: "application/json" },
209
+ body: JSON.stringify({
210
+ name: "tentacle-planner",
211
+ workspaceMode: "shared",
212
+ agentProvider: selectedAgent,
213
+ promptTemplate: "tentacle-planner",
214
+ }),
215
+ });
216
+ if (!response.ok) return;
217
+ const data = await response.json();
218
+ const agentId = (data.terminalId ?? data.tentacleId) as string;
219
+ setFocus({ type: "terminal", agentId, terminalLabel: "Tentacle Planner" });
220
+ await fetchTentacles();
221
+ } catch {
222
+ // silently ignore
223
+ } finally {
224
+ setIsLaunchingAgent(false);
225
+ }
226
+ }, [selectedAgent, fetchTentacles]);
227
+
228
+ const handleRunSetupStep = useCallback(
229
+ async (
230
+ stepId:
231
+ | "initialize-workspace"
232
+ | "ensure-gitignore"
233
+ | "check-claude"
234
+ | "check-git"
235
+ | "check-curl"
236
+ | "create-tentacles",
237
+ ) => {
238
+ setRunningSetupStepId(stepId);
239
+ try {
240
+ await onRunWorkspaceSetupStep(stepId);
241
+ if (stepId === "initialize-workspace" || stepId === "ensure-gitignore") {
242
+ await fetchTentacles();
243
+ }
244
+ } finally {
245
+ setRunningSetupStepId(null);
246
+ }
247
+ },
248
+ [fetchTentacles, onRunWorkspaceSetupStep],
249
+ );
250
+
251
+ const handleCreateTentacle = useCallback(
252
+ async (
253
+ name: string,
254
+ description: string,
255
+ color: string,
256
+ octopus: OctopusAppearancePayload,
257
+ suggestedSkills: string[],
258
+ ) => {
259
+ setIsCreating(true);
260
+ setCreateError(null);
261
+ try {
262
+ const response = await fetch(buildDeckTentaclesUrl(), {
263
+ method: "POST",
264
+ headers: { "Content-Type": "application/json", Accept: "application/json" },
265
+ body: JSON.stringify({ name, description, color, octopus, suggestedSkills }),
266
+ });
267
+ if (!response.ok) {
268
+ const body = await response.json().catch(() => null);
269
+ const msg =
270
+ body && typeof body === "object" && "error" in body && typeof body.error === "string"
271
+ ? body.error
272
+ : "Failed to create tentacle";
273
+ setCreateError(msg);
274
+ return;
275
+ }
276
+ setEmptyViewMode("idle");
277
+ await fetchTentacles();
278
+ await onRefreshWorkspaceSetup();
279
+ } catch {
280
+ setCreateError("Network error");
281
+ } finally {
282
+ setIsCreating(false);
283
+ }
284
+ },
285
+ [fetchTentacles, onRefreshWorkspaceSetup],
286
+ );
287
+
288
+ const handleTentacleSkillsSave = useCallback(
289
+ async (tentacleId: string, suggestedSkills: string[]) => {
290
+ setSavingTentacleSkillsId(tentacleId);
291
+ try {
292
+ const response = await fetch(buildDeckTentacleSkillsUrl(tentacleId), {
293
+ method: "PATCH",
294
+ headers: { "Content-Type": "application/json", Accept: "application/json" },
295
+ body: JSON.stringify({ suggestedSkills }),
296
+ });
297
+ if (!response.ok) return false;
298
+ await fetchTentacles();
299
+ return true;
300
+ } catch {
301
+ return false;
302
+ } finally {
303
+ setSavingTentacleSkillsId((current) => (current === tentacleId ? null : current));
304
+ }
305
+ },
306
+ [fetchTentacles],
307
+ );
308
+
309
+ const [deletingTentacleId, setDeletingTentacleId] = useState<string | null>(null);
310
+
311
+ const handleDeleteTentacle = useCallback(
312
+ async (tentacleId: string) => {
313
+ setDeletingTentacleId(tentacleId);
314
+ try {
315
+ const response = await fetch(buildDeckTentacleUrl(tentacleId), { method: "DELETE" });
316
+ if (!response.ok) return;
317
+ await fetchTentacles();
318
+ } catch {
319
+ // silently ignore
320
+ } finally {
321
+ setDeletingTentacleId(null);
322
+ }
323
+ },
324
+ [fetchTentacles],
325
+ );
326
+
327
+ const handleTodoToggle = useCallback(
328
+ async (tentacleId: string, itemIndex: number, done: boolean) => {
329
+ try {
330
+ const response = await fetch(buildDeckTodoToggleUrl(tentacleId), {
331
+ method: "PATCH",
332
+ headers: { "Content-Type": "application/json" },
333
+ body: JSON.stringify({ itemIndex, done }),
334
+ });
335
+ if (!response.ok) return;
336
+ await fetchTentacles();
337
+ } catch {
338
+ // silently ignore
339
+ }
340
+ },
341
+ [fetchTentacles],
342
+ );
343
+
344
+ const focusedTentacle =
345
+ focus?.type === "vault" || focus?.type === "vault-browser"
346
+ ? tentacles.find((t) => t.tentacleId === focus.tentacleId)
347
+ : null;
348
+ const mode = focus ? "detail" : "grid";
349
+ const shouldShowWorkspaceSetup =
350
+ !suppressWorkspaceSetupCard && tentacles.length === 0 && workspaceSetup?.shouldShowSetupCard;
351
+
352
+ // Push sidebar content to the shared sidebar
353
+ const sidebarContent = useMemo(
354
+ () =>
355
+ tentacles.length > 0 || focus?.type === "terminal" || shouldShowWorkspaceSetup ? (
356
+ <div className="deck-sidebar-content">
357
+ <div className="deck-sidebar-content-top">
358
+ {shouldShowWorkspaceSetup ? (
359
+ <WorkspaceSetupCard
360
+ compact
361
+ workspaceSetup={workspaceSetup}
362
+ isLoading={isWorkspaceSetupLoading}
363
+ error={workspaceSetupError}
364
+ onRunStep={handleRunSetupStep}
365
+ onLaunchClaudeCode={handleLaunchAgent}
366
+ isLaunchingAgent={isLaunchingAgent}
367
+ isRunningStepId={runningSetupStepId}
368
+ />
369
+ ) : (
370
+ <ActionCards
371
+ compact
372
+ selectedAgent={selectedAgent}
373
+ setSelectedAgent={setSelectedAgent}
374
+ agentMenuOpen={agentMenuOpen}
375
+ setAgentMenuOpen={setAgentMenuOpen}
376
+ agentMenuRef={agentMenuRef}
377
+ onAddManually={() => {
378
+ setEmptyViewMode("adding");
379
+ setCreateError(null);
380
+ }}
381
+ onLaunchAgent={handleLaunchAgent}
382
+ isLaunchingAgent={isLaunchingAgent}
383
+ />
384
+ )}
385
+ </div>
386
+ {tentacles.length > 0 && (
387
+ <div className="deck-sidebar-content-bottom">
388
+ <DeckBottomActions
389
+ onClearAll={async () => {
390
+ for (const t of tentacles) {
391
+ await fetch(buildDeckTentacleUrl(t.tentacleId), { method: "DELETE" });
392
+ }
393
+ await fetchTentacles();
394
+ }}
395
+ />
396
+ </div>
397
+ )}
398
+ </div>
399
+ ) : null,
400
+ [
401
+ agentMenuOpen,
402
+ fetchTentacles,
403
+ focus?.type,
404
+ handleLaunchAgent,
405
+ handleRunSetupStep,
406
+ isLaunchingAgent,
407
+ isWorkspaceSetupLoading,
408
+ runningSetupStepId,
409
+ selectedAgent,
410
+ shouldShowWorkspaceSetup,
411
+ tentacles,
412
+ workspaceSetup,
413
+ workspaceSetupError,
414
+ ],
415
+ );
416
+
417
+ useEffect(() => {
418
+ onSidebarContent?.(sidebarContent);
419
+ return () => onSidebarContent?.(null);
420
+ }, [onSidebarContent, sidebarContent]);
421
+
422
+ // ─── Empty state (no tentacles) ─────────────────────────────────────────────
423
+
424
+ if (tentacles.length === 0 && focus?.type !== "terminal") {
425
+ return (
426
+ <section
427
+ className="deck-view"
428
+ data-mode="grid"
429
+ data-empty-mode={emptyViewMode}
430
+ aria-label="Deck"
431
+ >
432
+ <div className="deck-empty-state">
433
+ <div className="deck-empty-left">
434
+ <div className="deck-empty-octopus">
435
+ <OctopusGlyph
436
+ color="#d4a017"
437
+ animation="walk"
438
+ expression="happy"
439
+ accessory="none"
440
+ scale={20}
441
+ />
442
+ </div>
443
+ {shouldShowWorkspaceSetup ? (
444
+ <WorkspaceSetupCard
445
+ workspaceSetup={workspaceSetup}
446
+ isLoading={isWorkspaceSetupLoading}
447
+ error={workspaceSetupError}
448
+ onRunStep={handleRunSetupStep}
449
+ onLaunchClaudeCode={handleLaunchAgent}
450
+ isLaunchingAgent={isLaunchingAgent}
451
+ isRunningStepId={runningSetupStepId}
452
+ />
453
+ ) : (
454
+ <ActionCards
455
+ selectedAgent={selectedAgent}
456
+ setSelectedAgent={setSelectedAgent}
457
+ agentMenuOpen={agentMenuOpen}
458
+ setAgentMenuOpen={setAgentMenuOpen}
459
+ agentMenuRef={agentMenuRef}
460
+ onAddManually={() => {
461
+ setEmptyViewMode("adding");
462
+ setCreateError(null);
463
+ }}
464
+ onLaunchAgent={handleLaunchAgent}
465
+ isLaunchingAgent={isLaunchingAgent}
466
+ />
467
+ )}
468
+ </div>
469
+ {emptyViewMode === "adding" && (
470
+ <div className="deck-empty-right">
471
+ <AddTentacleForm
472
+ onSubmit={handleCreateTentacle}
473
+ onCancel={() => setEmptyViewMode("idle")}
474
+ isSubmitting={isCreating}
475
+ error={createError}
476
+ availableSkills={availableSkills}
477
+ />
478
+ </div>
479
+ )}
480
+ </div>
481
+ </section>
482
+ );
483
+ }
484
+
485
+ // ─── Populated state ────────────────────────────────────────────────────────
486
+
487
+ return (
488
+ <section
489
+ className="deck-view"
490
+ data-mode={mode}
491
+ data-has-pods={tentacles.length > 0}
492
+ aria-label="Deck"
493
+ >
494
+ <div className="deck-pods-container">
495
+ {tentacles.map((t) => {
496
+ const isThis =
497
+ (focus?.type === "vault" || focus?.type === "vault-browser") &&
498
+ focus.tentacleId === t.tentacleId;
499
+ return (
500
+ <div
501
+ key={t.tentacleId}
502
+ className="deck-pod-slot"
503
+ data-pod-role={isThis ? "focused" : focus ? "other" : "idle"}
504
+ >
505
+ <TentaclePod
506
+ tentacle={t}
507
+ visuals={visualsMap.get(t.tentacleId) as OctopusVisuals}
508
+ isFocused={isThis}
509
+ activeFileName={focus?.type === "vault" && isThis ? focus.fileName : undefined}
510
+ onVaultFileClick={(fileName) =>
511
+ setFocus({ type: "vault", tentacleId: t.tentacleId, fileName })
512
+ }
513
+ onVaultBrowse={() => setFocus({ type: "vault-browser", tentacleId: t.tentacleId })}
514
+ onClose={handleClose}
515
+ onDelete={() => handleDeleteTentacle(t.tentacleId)}
516
+ isDeleting={deletingTentacleId === t.tentacleId}
517
+ onTodoToggle={handleTodoToggle}
518
+ availableSkills={availableSkills}
519
+ isSavingSkills={savingTentacleSkillsId === t.tentacleId}
520
+ onSaveSuggestedSkills={handleTentacleSkillsSave}
521
+ />
522
+ </div>
523
+ );
524
+ })}
525
+ </div>
526
+
527
+ <div className="deck-detail-main">
528
+ {focus?.type === "vault-browser" && focusedTentacle && (
529
+ <>
530
+ <header className="deck-detail-main-header">
531
+ <button type="button" className="deck-add-form-back" onClick={handleClose}>
532
+ ← Back
533
+ </button>
534
+ <span className="deck-detail-main-path">
535
+ <strong>{focusedTentacle.displayName}</strong> / vault
536
+ </span>
537
+ </header>
538
+ <div className="deck-detail-main-content deck-vault-browser">
539
+ <pre className="deck-vault-tree">
540
+ <span className="deck-vault-tree-dir">
541
+ .octogent/tentacles/{focusedTentacle.tentacleId}/
542
+ </span>
543
+ {(() => {
544
+ const files = [...focusedTentacle.vaultFiles, "CONTEXT.md"];
545
+ return files.map((file, i) => {
546
+ const isLast = i === files.length - 1;
547
+ const prefix = isLast ? "└── " : "├── ";
548
+ return (
549
+ <span key={file} className="deck-vault-tree-row">
550
+ <span className="deck-vault-tree-branch">{prefix}</span>
551
+ <button
552
+ type="button"
553
+ className="deck-vault-tree-file"
554
+ onClick={() =>
555
+ setFocus({
556
+ type: "vault",
557
+ tentacleId: focus.tentacleId,
558
+ fileName: file,
559
+ })
560
+ }
561
+ >
562
+ {file}
563
+ </button>
564
+ </span>
565
+ );
566
+ });
567
+ })()}
568
+ </pre>
569
+ </div>
570
+ </>
571
+ )}
572
+ {focus?.type === "vault" && focusedTentacle && (
573
+ <>
574
+ <header className="deck-detail-main-header">
575
+ <button
576
+ type="button"
577
+ className="deck-add-form-back"
578
+ onClick={() => setFocus({ type: "vault-browser", tentacleId: focus.tentacleId })}
579
+ >
580
+ ← Back
581
+ </button>
582
+ <span className="deck-detail-main-path">
583
+ {focusedTentacle.displayName} / <strong>{focus.fileName}</strong>
584
+ </span>
585
+ </header>
586
+ <div className="deck-detail-main-content" key={`${focus.tentacleId}/${focus.fileName}`}>
587
+ {loadingVault ? (
588
+ <span className="deck-detail-loading">Loading…</span>
589
+ ) : vaultContent !== null ? (
590
+ <MarkdownContent content={vaultContent} className="deck-detail-markdown" />
591
+ ) : (
592
+ <span className="deck-detail-loading">File not found.</span>
593
+ )}
594
+ </div>
595
+ </>
596
+ )}
597
+ {focus?.type === "terminal" && (
598
+ <div className="deck-detail-terminal" key={focus.agentId}>
599
+ <header className="deck-detail-main-header">
600
+ <button type="button" className="deck-add-form-back" onClick={handleClose}>
601
+ ← Back
602
+ </button>
603
+ <span className="deck-detail-main-path">
604
+ <strong>{focus.terminalLabel}</strong>
605
+ </span>
606
+ </header>
607
+ <Terminal terminalId={focus.agentId} terminalLabel={focus.terminalLabel} />
608
+ </div>
609
+ )}
610
+ </div>
611
+ </section>
612
+ );
613
+ };
@@ -0,0 +1,91 @@
1
+ import { useEffect, useState } from "react";
2
+
3
+ import type { PendingDeleteTerminal } from "../app/hooks/useTerminalMutations";
4
+ import { ConfirmationDialog } from "./ui/ConfirmationDialog";
5
+
6
+ type DeleteTentacleDialogProps = {
7
+ pendingDeleteTerminal: PendingDeleteTerminal;
8
+ isDeletingTerminalId: string | null;
9
+ onCancel: () => void;
10
+ onConfirmDelete: () => void;
11
+ };
12
+
13
+ export const DeleteTentacleDialog = ({
14
+ pendingDeleteTerminal,
15
+ isDeletingTerminalId,
16
+ onCancel,
17
+ onConfirmDelete,
18
+ }: DeleteTentacleDialogProps) => {
19
+ const [cleanupConfirmationInput, setCleanupConfirmationInput] = useState("");
20
+ const isCleanupIntent =
21
+ pendingDeleteTerminal.intent === "cleanup-worktree" &&
22
+ pendingDeleteTerminal.workspaceMode === "worktree";
23
+ const isCleanupConfirmationValid =
24
+ !isCleanupIntent || cleanupConfirmationInput.trim() === pendingDeleteTerminal.terminalId;
25
+ const isDeleting = isDeletingTerminalId !== null;
26
+ const isThisDeleting = isDeletingTerminalId === pendingDeleteTerminal.terminalId;
27
+ const dialogResetKey = `${pendingDeleteTerminal.terminalId}:${pendingDeleteTerminal.intent}`;
28
+
29
+ useEffect(() => {
30
+ void dialogResetKey;
31
+ setCleanupConfirmationInput("");
32
+ }, [dialogResetKey]);
33
+
34
+ return (
35
+ <ConfirmationDialog
36
+ title={isCleanupIntent ? "Cleanup Worktree Tentacle" : "Delete Tentacle"}
37
+ ariaLabel={`Delete confirmation for ${pendingDeleteTerminal.terminalId}`}
38
+ message={
39
+ isCleanupIntent ? (
40
+ <>
41
+ Cleanup <strong>{pendingDeleteTerminal.tentacleName}</strong> and delete the tentacle
42
+ session metadata.
43
+ </>
44
+ ) : (
45
+ <>
46
+ Delete <strong>{pendingDeleteTerminal.tentacleName}</strong> and terminate all of its
47
+ active sessions.
48
+ </>
49
+ )
50
+ }
51
+ warning={
52
+ isCleanupIntent
53
+ ? "This action removes the worktree directory and local branch."
54
+ : "This action cannot be undone."
55
+ }
56
+ confirmLabel={isThisDeleting ? "Deleting..." : isCleanupIntent ? "Cleanup" : "Delete"}
57
+ isConfirmDisabled={isDeleting || !isCleanupConfirmationValid}
58
+ isBusy={isDeleting}
59
+ cancelAriaLabel="Cancel delete"
60
+ onCancel={onCancel}
61
+ onConfirm={onConfirmDelete}
62
+ >
63
+ <dl className="delete-confirm-details">
64
+ <div>
65
+ <dt>Name</dt>
66
+ <dd>{pendingDeleteTerminal.tentacleName}</dd>
67
+ </div>
68
+ <div>
69
+ <dt>ID</dt>
70
+ <dd>{pendingDeleteTerminal.terminalId}</dd>
71
+ </div>
72
+ <div>
73
+ <dt>Mode</dt>
74
+ <dd>{pendingDeleteTerminal.workspaceMode === "worktree" ? "worktree" : "shared"}</dd>
75
+ </div>
76
+ </dl>
77
+ {isCleanupIntent && (
78
+ <div className="delete-confirm-typed-check">
79
+ <label htmlFor="cleanup-confirm-id-input">Type tentacle ID to confirm cleanup</label>
80
+ <input
81
+ aria-label="Type tentacle ID to confirm cleanup"
82
+ id="cleanup-confirm-id-input"
83
+ onChange={(event) => setCleanupConfirmationInput(event.target.value)}
84
+ type="text"
85
+ value={cleanupConfirmationInput}
86
+ />
87
+ </div>
88
+ )}
89
+ </ConfirmationDialog>
90
+ );
91
+ };