@agentprojectcontext/apx 1.25.0 → 1.27.2

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 (718) hide show
  1. package/package.json +42 -12
  2. package/skills/apx/SKILL.md +50 -119
  3. package/skills/apx-agency-agents/SKILL.md +141 -0
  4. package/skills/apx-agent/SKILL.md +100 -0
  5. package/skills/apx-mcp/SKILL.md +114 -0
  6. package/skills/apx-mcp-builder/SKILL.md +186 -0
  7. package/skills/apx-project/SKILL.md +100 -0
  8. package/skills/apx-routine/SKILL.md +138 -0
  9. package/skills/apx-runtime/SKILL.md +115 -0
  10. package/skills/apx-sessions/SKILL.md +281 -0
  11. package/skills/apx-skill-builder/SKILL.md +149 -0
  12. package/skills/apx-task/SKILL.md +95 -0
  13. package/skills/apx-telegram/SKILL.md +115 -0
  14. package/skills/apx-voice/SKILL.md +135 -0
  15. package/src/core/agent/constants.js +3 -0
  16. package/src/core/agent/ghost-guard.js +24 -0
  17. package/src/core/agent/index.js +35 -0
  18. package/src/core/agent/model-router.js +257 -0
  19. package/src/core/agent/prompt-builder.js +313 -0
  20. package/src/core/agent/prompts/channels/api.md +7 -0
  21. package/src/core/agent/prompts/channels/cli.md +6 -0
  22. package/src/core/agent/prompts/channels/code.md +20 -0
  23. package/src/core/agent/prompts/channels/deck.md +6 -0
  24. package/src/core/agent/prompts/channels/desktop.md +24 -0
  25. package/src/core/agent/prompts/channels/routine.md +9 -0
  26. package/src/core/agent/prompts/channels/telegram.md +9 -0
  27. package/src/core/agent/prompts/channels/terminal.md +16 -0
  28. package/src/core/agent/prompts/channels/web.md +7 -0
  29. package/src/core/agent/prompts/channels/web_sidebar.md +7 -0
  30. package/src/core/agent/prompts/modes/voice.md +4 -0
  31. package/src/core/agent/prompts/super-agent-base.md +42 -0
  32. package/src/core/agent/pseudo-tools.js +40 -0
  33. package/src/core/agent/retry.js +85 -0
  34. package/src/core/agent/run-agent.js +423 -0
  35. package/src/core/agent/self-memory.js +155 -0
  36. package/src/{daemon → core/agent}/tool-call-parser.js +83 -10
  37. package/src/core/agent/tools-overlap.js +66 -0
  38. package/src/core/apc-skill-sync.js +97 -0
  39. package/src/core/code-sessions-store.js +150 -0
  40. package/src/core/config.js +473 -11
  41. package/src/core/desktop/autostart.js +162 -0
  42. package/src/core/engines/_health.js +63 -0
  43. package/src/{daemon → core}/engines/anthropic.js +16 -0
  44. package/src/core/engines/gemini.js +168 -0
  45. package/src/core/engines/groq.js +8 -0
  46. package/src/{daemon → core}/engines/index.js +3 -1
  47. package/src/{daemon → core}/engines/mock.js +22 -0
  48. package/src/{daemon → core}/engines/ollama.js +35 -0
  49. package/src/core/engines/openai-compatible.js +145 -0
  50. package/src/core/engines/openai.js +8 -0
  51. package/src/core/engines/openrouter.js +8 -0
  52. package/src/core/git-baseline.js +147 -0
  53. package/src/core/identity.js +21 -0
  54. package/src/core/logging.js +1 -1
  55. package/src/core/mcp/index.js +14 -0
  56. package/src/{daemon/mcp-runner.js → core/mcp/runner.js} +18 -6
  57. package/src/core/mcp/sources.js +246 -0
  58. package/src/core/memory/active-threads.js +124 -0
  59. package/src/core/memory/broker.js +144 -0
  60. package/src/core/memory/compactor.js +186 -0
  61. package/src/core/memory/embed-engines/gemini.js +62 -0
  62. package/src/core/memory/embed-engines/index.js +148 -0
  63. package/src/core/memory/embed-engines/ollama.js +55 -0
  64. package/src/core/memory/embed-engines/openai.js +64 -0
  65. package/src/core/memory/embed-engines/tf.js +20 -0
  66. package/src/core/memory/embeddings.js +132 -0
  67. package/src/core/memory/index.js +161 -0
  68. package/src/core/memory/indexer.js +257 -0
  69. package/src/core/memory/store.js +231 -0
  70. package/src/core/messages-store.js +143 -25
  71. package/src/core/parser.js +78 -16
  72. package/src/core/scaffold.js +175 -79
  73. package/src/core/tasks-store.js +264 -0
  74. package/src/core/telegram-identity.js +126 -0
  75. package/src/core/tools/index.js +6 -0
  76. package/src/core/voice/engines/elevenlabs.js +96 -0
  77. package/src/core/voice/engines/gemini.js +148 -0
  78. package/src/core/voice/engines/index.js +144 -0
  79. package/src/core/voice/engines/mock.js +59 -0
  80. package/src/core/voice/engines/openai.js +82 -0
  81. package/src/core/voice/engines/piper.js +93 -0
  82. package/src/core/voice/index.js +3 -0
  83. package/src/core/voice/tts.js +89 -0
  84. package/src/{daemon → host/daemon}/apc-runtime-context.js +1 -1
  85. package/src/host/daemon/api/admin-config.js +159 -0
  86. package/src/host/daemon/api/admin.js +72 -0
  87. package/src/host/daemon/api/agents.js +284 -0
  88. package/src/host/daemon/api/artifacts.js +52 -0
  89. package/src/host/daemon/api/code.js +351 -0
  90. package/src/host/daemon/api/config.js +104 -0
  91. package/src/host/daemon/api/connections.js +42 -0
  92. package/src/host/daemon/api/conversations.js +161 -0
  93. package/src/host/daemon/api/deck.js +511 -0
  94. package/src/host/daemon/api/desktop.js +71 -0
  95. package/src/host/daemon/api/embeddings.js +65 -0
  96. package/src/host/daemon/api/engines.js +80 -0
  97. package/src/host/daemon/api/exec.js +193 -0
  98. package/src/host/daemon/api/health.js +10 -0
  99. package/src/host/daemon/api/identity.js +36 -0
  100. package/src/host/daemon/api/mcps.js +205 -0
  101. package/src/host/daemon/api/messages.js +83 -0
  102. package/src/host/daemon/api/pairing.js +194 -0
  103. package/src/host/daemon/api/plugins.js +19 -0
  104. package/src/host/daemon/api/projects.js +35 -0
  105. package/src/host/daemon/api/routines.js +84 -0
  106. package/src/host/daemon/api/run.js +55 -0
  107. package/src/host/daemon/api/runtimes.js +219 -0
  108. package/src/host/daemon/api/sessions-search.js +177 -0
  109. package/src/host/daemon/api/sessions.js +115 -0
  110. package/src/host/daemon/api/shared.js +217 -0
  111. package/src/host/daemon/api/super-agent.js +208 -0
  112. package/src/host/daemon/api/tasks.js +118 -0
  113. package/src/host/daemon/api/telegram.js +325 -0
  114. package/src/host/daemon/api/tools.js +21 -0
  115. package/src/host/daemon/api/top-level.js +131 -0
  116. package/src/host/daemon/api/transcribe.js +35 -0
  117. package/src/host/daemon/api/tts.js +44 -0
  118. package/src/host/daemon/api/voice.js +519 -0
  119. package/src/host/daemon/api/web.js +123 -0
  120. package/src/host/daemon/api.js +152 -0
  121. package/src/{daemon → host/daemon}/compact.js +1 -1
  122. package/src/{daemon → host/daemon}/db.js +19 -5
  123. package/src/{daemon/overlay-ws.js → host/daemon/desktop-ws.js} +7 -7
  124. package/src/host/daemon/engine-sessions.js +245 -0
  125. package/src/{daemon → host/daemon}/index.js +27 -10
  126. package/src/{daemon/plugins/overlay.js → host/daemon/plugins/desktop.js} +36 -28
  127. package/src/{daemon → host/daemon}/plugins/index.js +2 -2
  128. package/src/{daemon → host/daemon}/plugins/telegram.js +165 -33
  129. package/src/{daemon → host/daemon}/project-config.js +31 -7
  130. package/src/{daemon → host/daemon}/routines.js +27 -8
  131. package/src/{daemon → host/daemon}/skills-loader.js +4 -2
  132. package/src/{daemon → host/daemon}/smoke.js +9 -5
  133. package/src/{daemon → host/daemon}/super-agent-tools/helpers.js +1 -1
  134. package/src/host/daemon/super-agent-tools/index.js +157 -0
  135. package/src/{daemon → host/daemon}/super-agent-tools/registry-bridge.js +1 -1
  136. package/src/{daemon → host/daemon}/super-agent-tools/tools/add-project.js +2 -2
  137. package/src/{daemon → host/daemon}/super-agent-tools/tools/ask-questions.js +4 -0
  138. package/src/{daemon → host/daemon}/super-agent-tools/tools/call-agent.js +5 -2
  139. package/src/{daemon → host/daemon}/super-agent-tools/tools/call-runtime.js +117 -8
  140. package/src/host/daemon/super-agent-tools/tools/create-task.js +52 -0
  141. package/src/{daemon → host/daemon}/super-agent-tools/tools/import-agent.js +2 -3
  142. package/src/{daemon → host/daemon}/super-agent-tools/tools/list-agents.js +1 -1
  143. package/src/host/daemon/super-agent-tools/tools/list-tasks.js +52 -0
  144. package/src/{daemon → host/daemon}/super-agent-tools/tools/list-vault-agents.js +1 -1
  145. package/src/host/daemon/super-agent-tools/tools/read-self-memory.js +21 -0
  146. package/src/host/daemon/super-agent-tools/tools/remember.js +40 -0
  147. package/src/{daemon → host/daemon}/super-agent-tools/tools/search-messages.js +1 -1
  148. package/src/host/daemon/super-agent-tools/tools/search-sessions.js +134 -0
  149. package/src/{daemon → host/daemon}/super-agent-tools/tools/send-telegram.js +2 -2
  150. package/src/{daemon → host/daemon}/super-agent-tools/tools/set-identity.js +1 -1
  151. package/src/{daemon → host/daemon}/super-agent-tools/tools/set-permission-mode.js +1 -1
  152. package/src/{daemon → host/daemon}/super-agent-tools/tools/tail-messages.js +1 -1
  153. package/src/host/daemon/super-agent.js +129 -0
  154. package/src/host/daemon/token-store.js +118 -0
  155. package/src/host/daemon/tool-call-parser.js +2 -0
  156. package/src/{daemon → host/daemon}/transcription.js +1 -1
  157. package/src/{daemon → host/daemon}/wakeup.js +2 -2
  158. package/src/interfaces/cli/claude-permissions.js +33 -0
  159. package/src/{cli → interfaces/cli}/commands/agent.js +43 -8
  160. package/src/{cli → interfaces/cli}/commands/command.js +1 -1
  161. package/src/{cli → interfaces/cli}/commands/config.js +1 -1
  162. package/src/{cli → interfaces/cli}/commands/daemon.js +67 -0
  163. package/src/interfaces/cli/commands/desktop.js +335 -0
  164. package/src/interfaces/cli/commands/exec.js +92 -0
  165. package/src/{cli → interfaces/cli}/commands/identity.js +6 -63
  166. package/src/{cli → interfaces/cli}/commands/init.js +1 -1
  167. package/src/{cli → interfaces/cli}/commands/mcp.js +69 -10
  168. package/src/{cli → interfaces/cli}/commands/memory.js +2 -2
  169. package/src/interfaces/cli/commands/model.js +136 -0
  170. package/src/interfaces/cli/commands/pair.js +170 -0
  171. package/src/interfaces/cli/commands/project-config.js +131 -0
  172. package/src/{cli → interfaces/cli}/commands/project.js +1 -1
  173. package/src/{cli → interfaces/cli}/commands/search.js +1 -1
  174. package/src/interfaces/cli/commands/session.js +892 -0
  175. package/src/interfaces/cli/commands/sessions.js +997 -0
  176. package/src/{cli → interfaces/cli}/commands/setup.js +98 -4
  177. package/src/{cli → interfaces/cli}/commands/skills.js +117 -9
  178. package/src/{cli → interfaces/cli}/commands/status.js +9 -1
  179. package/src/{cli → interfaces/cli}/commands/sys.js +96 -17
  180. package/src/interfaces/cli/commands/task.js +179 -0
  181. package/src/interfaces/cli/commands/telegram.js +366 -0
  182. package/src/{cli → interfaces/cli}/commands/update.js +1 -1
  183. package/src/interfaces/cli/commands/voice.js +258 -0
  184. package/src/{cli → interfaces/cli}/http.js +6 -2
  185. package/src/{cli → interfaces/cli}/index.js +955 -63
  186. package/src/interfaces/cli/postinstall.js +34 -0
  187. package/src/interfaces/desktop/assets/app-icon-180.png +0 -0
  188. package/src/interfaces/desktop/assets/app-icon-32.png +0 -0
  189. package/src/interfaces/desktop/assets/app-icon.png +0 -0
  190. package/src/interfaces/desktop/assets/apx-logo.png +0 -0
  191. package/src/interfaces/desktop/assets/superagent.png +0 -0
  192. package/src/interfaces/desktop/assets/tray-icon.png +0 -0
  193. package/src/interfaces/desktop/index.html +18 -0
  194. package/src/interfaces/desktop/main.js +652 -0
  195. package/src/interfaces/desktop/preload.js +48 -0
  196. package/src/interfaces/desktop/renderer.js +1006 -0
  197. package/src/interfaces/desktop/style.css +400 -0
  198. package/src/{mcp → interfaces/mcp-server}/index.js +2 -2
  199. package/src/interfaces/tui/_shims/util-which.ts +53 -0
  200. package/src/{tui → interfaces/tui}/app.tsx +2 -2
  201. package/src/{tui → interfaces/tui}/component/prompt/index.tsx +4 -1
  202. package/src/{tui → interfaces/tui}/context/sdk-apx.tsx +84 -16
  203. package/src/interfaces/tui/context/sync-apx.tsx +398 -0
  204. package/src/interfaces/tui/routes/session/index.tsx +368 -0
  205. package/src/interfaces/tui/routes/session/message-actions.tsx +58 -0
  206. package/src/interfaces/tui/routes/session/sidebar-apx.tsx +114 -0
  207. package/src/{tui → interfaces/tui}/tsconfig.json +1 -0
  208. package/src/{tui → interfaces/tui}/util/clipboard.ts +1 -1
  209. package/src/interfaces/web/README.md +102 -0
  210. package/src/interfaces/web/coming-soon.html +65 -0
  211. package/src/interfaces/web/components.json +25 -0
  212. package/src/interfaces/web/dist/assets/index-BDUsA6L6.css +1 -0
  213. package/src/interfaces/web/dist/assets/index-CfWyjPBa.js +548 -0
  214. package/src/interfaces/web/dist/assets/index-CfWyjPBa.js.map +1 -0
  215. package/src/interfaces/web/dist/favicon/dark/android-chrome-192x192.png +0 -0
  216. package/src/interfaces/web/dist/favicon/dark/android-chrome-512x512.png +0 -0
  217. package/src/interfaces/web/dist/favicon/dark/apple-touch-icon.png +0 -0
  218. package/src/interfaces/web/dist/favicon/dark/favicon-16x16.png +0 -0
  219. package/src/interfaces/web/dist/favicon/dark/favicon-32x32.png +0 -0
  220. package/src/interfaces/web/dist/favicon/dark/favicon-48x48.png +0 -0
  221. package/src/interfaces/web/dist/favicon/dark/favicon.ico +0 -0
  222. package/src/interfaces/web/dist/favicon/dark/favicon.webp +0 -0
  223. package/src/interfaces/web/dist/favicon/dark/site.webmanifest +18 -0
  224. package/src/interfaces/web/dist/favicon/white/android-chrome-192x192.png +0 -0
  225. package/src/interfaces/web/dist/favicon/white/android-chrome-512x512.png +0 -0
  226. package/src/interfaces/web/dist/favicon/white/apple-touch-icon.png +0 -0
  227. package/src/interfaces/web/dist/favicon/white/favicon-16x16.png +0 -0
  228. package/src/interfaces/web/dist/favicon/white/favicon-32x32.png +0 -0
  229. package/src/interfaces/web/dist/favicon/white/favicon-48x48.png +0 -0
  230. package/src/interfaces/web/dist/favicon/white/favicon.ico +0 -0
  231. package/src/interfaces/web/dist/favicon/white/favicon.webp +0 -0
  232. package/src/interfaces/web/dist/favicon/white/site.webmanifest +18 -0
  233. package/src/interfaces/web/dist/index.html +27 -0
  234. package/src/interfaces/web/dist/logo/logo_dark.webp +0 -0
  235. package/src/interfaces/web/dist/logo/logo_only_dark.webp +0 -0
  236. package/src/interfaces/web/dist/logo/logo_only_white.webp +0 -0
  237. package/src/interfaces/web/dist/logo/logo_vertical_dark.webp +0 -0
  238. package/src/interfaces/web/dist/logo/logo_vertical_white.webp +0 -0
  239. package/src/interfaces/web/dist/logo/logo_white.webp +0 -0
  240. package/src/interfaces/web/dist/modules/superagent.png +0 -0
  241. package/src/interfaces/web/index.html +26 -0
  242. package/src/interfaces/web/package-lock.json +4253 -0
  243. package/src/interfaces/web/package.json +55 -0
  244. package/src/interfaces/web/playwright.config.ts +45 -0
  245. package/src/interfaces/web/pnpm-lock.yaml +2946 -0
  246. package/src/interfaces/web/public/favicon/dark/android-chrome-192x192.png +0 -0
  247. package/src/interfaces/web/public/favicon/dark/android-chrome-512x512.png +0 -0
  248. package/src/interfaces/web/public/favicon/dark/apple-touch-icon.png +0 -0
  249. package/src/interfaces/web/public/favicon/dark/favicon-16x16.png +0 -0
  250. package/src/interfaces/web/public/favicon/dark/favicon-32x32.png +0 -0
  251. package/src/interfaces/web/public/favicon/dark/favicon-48x48.png +0 -0
  252. package/src/interfaces/web/public/favicon/dark/favicon.ico +0 -0
  253. package/src/interfaces/web/public/favicon/dark/favicon.webp +0 -0
  254. package/src/interfaces/web/public/favicon/dark/site.webmanifest +18 -0
  255. package/src/interfaces/web/public/favicon/white/android-chrome-192x192.png +0 -0
  256. package/src/interfaces/web/public/favicon/white/android-chrome-512x512.png +0 -0
  257. package/src/interfaces/web/public/favicon/white/apple-touch-icon.png +0 -0
  258. package/src/interfaces/web/public/favicon/white/favicon-16x16.png +0 -0
  259. package/src/interfaces/web/public/favicon/white/favicon-32x32.png +0 -0
  260. package/src/interfaces/web/public/favicon/white/favicon-48x48.png +0 -0
  261. package/src/interfaces/web/public/favicon/white/favicon.ico +0 -0
  262. package/src/interfaces/web/public/favicon/white/favicon.webp +0 -0
  263. package/src/interfaces/web/public/favicon/white/site.webmanifest +18 -0
  264. package/src/interfaces/web/public/logo/logo_dark.webp +0 -0
  265. package/src/interfaces/web/public/logo/logo_only_dark.webp +0 -0
  266. package/src/interfaces/web/public/logo/logo_only_white.webp +0 -0
  267. package/src/interfaces/web/public/logo/logo_vertical_dark.webp +0 -0
  268. package/src/interfaces/web/public/logo/logo_vertical_white.webp +0 -0
  269. package/src/interfaces/web/public/logo/logo_white.webp +0 -0
  270. package/src/interfaces/web/public/modules/superagent.png +0 -0
  271. package/src/interfaces/web/src/App.tsx +199 -0
  272. package/src/interfaces/web/src/components/AddProjectDialog.tsx +121 -0
  273. package/src/interfaces/web/src/components/ModelCombobox.tsx +96 -0
  274. package/src/interfaces/web/src/components/RobyBubble.tsx +213 -0
  275. package/src/interfaces/web/src/components/Section.tsx +44 -0
  276. package/src/interfaces/web/src/components/TelegramChannelDialog.tsx +97 -0
  277. package/src/interfaces/web/src/components/TelegramSendDialog.tsx +48 -0
  278. package/src/interfaces/web/src/components/Toast.tsx +84 -0
  279. package/src/interfaces/web/src/components/UiSelect.tsx +74 -0
  280. package/src/interfaces/web/src/components/chat/Composer.tsx +43 -0
  281. package/src/interfaces/web/src/components/chat/ContextBar.tsx +111 -0
  282. package/src/interfaces/web/src/components/chat/MessageBubble.tsx +95 -0
  283. package/src/interfaces/web/src/components/chat/MessageList.tsx +35 -0
  284. package/src/interfaces/web/src/components/chat/ModelPicker.tsx +145 -0
  285. package/src/interfaces/web/src/components/chat/ToolCall.tsx +141 -0
  286. package/src/interfaces/web/src/components/code/CodeChangesTab.tsx +87 -0
  287. package/src/interfaces/web/src/components/code/CodeComposer.tsx +87 -0
  288. package/src/interfaces/web/src/components/code/CodeContextTab.tsx +83 -0
  289. package/src/interfaces/web/src/components/code/CodeProjectPicker.tsx +39 -0
  290. package/src/interfaces/web/src/components/code/CodeSessionList.tsx +97 -0
  291. package/src/interfaces/web/src/components/code/CodeSidePanel.tsx +44 -0
  292. package/src/interfaces/web/src/components/code/CodeToolTrail.tsx +29 -0
  293. package/src/interfaces/web/src/components/code/DiffView.tsx +67 -0
  294. package/src/interfaces/web/src/components/common/Qr.tsx +27 -0
  295. package/src/interfaces/web/src/components/common/TabLayout.tsx +46 -0
  296. package/src/interfaces/web/src/components/common/TabNav.tsx +113 -0
  297. package/src/interfaces/web/src/components/config/ConfigTabsEditor.tsx +202 -0
  298. package/src/interfaces/web/src/components/config/GlobalConfigEditor.tsx +42 -0
  299. package/src/interfaces/web/src/components/config/global-config-sections.ts +60 -0
  300. package/src/interfaces/web/src/components/config/project-config-sections.ts +58 -0
  301. package/src/interfaces/web/src/components/deck/DaemonCard.tsx +58 -0
  302. package/src/interfaces/web/src/components/deck/DesktopGroup.tsx +33 -0
  303. package/src/interfaces/web/src/components/deck/WidgetRow.tsx +100 -0
  304. package/src/interfaces/web/src/components/layout/Logo.tsx +59 -0
  305. package/src/interfaces/web/src/components/layout/ProjectAvatar.tsx +116 -0
  306. package/src/interfaces/web/src/components/layout/ProjectSidebar.tsx +151 -0
  307. package/src/interfaces/web/src/components/settings/AdvancedPanel.tsx +45 -0
  308. package/src/interfaces/web/src/components/settings/AppearancePanel.tsx +72 -0
  309. package/src/interfaces/web/src/components/settings/DefaultRouterCard.tsx +232 -0
  310. package/src/interfaces/web/src/components/settings/DevicesPanel.tsx +60 -0
  311. package/src/interfaces/web/src/components/settings/EnginesPanel.tsx +127 -0
  312. package/src/interfaces/web/src/components/settings/IdentityPanel.tsx +69 -0
  313. package/src/interfaces/web/src/components/settings/MemoryPanel.tsx +226 -0
  314. package/src/interfaces/web/src/components/settings/PairDeviceDialog.tsx +175 -0
  315. package/src/interfaces/web/src/components/settings/SuperAgentPanel.tsx +93 -0
  316. package/src/interfaces/web/src/components/settings/TelegramChannelsPanel.tsx +90 -0
  317. package/src/interfaces/web/src/components/settings/TelegramContactsPanel.tsx +101 -0
  318. package/src/interfaces/web/src/components/settings/TelegramGlobalPanel.tsx +100 -0
  319. package/src/interfaces/web/src/components/settings/TelegramRolesPanel.tsx +108 -0
  320. package/src/interfaces/web/src/components/settings/TelegramSettingsTabs.tsx +55 -0
  321. package/src/interfaces/web/src/components/settings/providers/ProviderCard.tsx +95 -0
  322. package/src/interfaces/web/src/components/settings/providers/ProviderModal.tsx +405 -0
  323. package/src/interfaces/web/src/components/settings/providers/typeStyles.ts +155 -0
  324. package/src/interfaces/web/src/components/settings/providers/types.ts +26 -0
  325. package/src/interfaces/web/src/components/ui/accordion.tsx +72 -0
  326. package/src/interfaces/web/src/components/ui/alert-dialog.tsx +187 -0
  327. package/src/interfaces/web/src/components/ui/alert.tsx +76 -0
  328. package/src/interfaces/web/src/components/ui/aspect-ratio.tsx +22 -0
  329. package/src/interfaces/web/src/components/ui/avatar.tsx +107 -0
  330. package/src/interfaces/web/src/components/ui/badge.tsx +52 -0
  331. package/src/interfaces/web/src/components/ui/breadcrumb.tsx +125 -0
  332. package/src/interfaces/web/src/components/ui/button-group.tsx +87 -0
  333. package/src/interfaces/web/src/components/ui/button.tsx +58 -0
  334. package/src/interfaces/web/src/components/ui/calendar.tsx +221 -0
  335. package/src/interfaces/web/src/components/ui/card.tsx +103 -0
  336. package/src/interfaces/web/src/components/ui/carousel.tsx +242 -0
  337. package/src/interfaces/web/src/components/ui/chart.tsx +371 -0
  338. package/src/interfaces/web/src/components/ui/chat-input.tsx +122 -0
  339. package/src/interfaces/web/src/components/ui/checkbox.tsx +29 -0
  340. package/src/interfaces/web/src/components/ui/collapsible.tsx +19 -0
  341. package/src/interfaces/web/src/components/ui/combobox.tsx +295 -0
  342. package/src/interfaces/web/src/components/ui/command.tsx +196 -0
  343. package/src/interfaces/web/src/components/ui/context-menu.tsx +271 -0
  344. package/src/interfaces/web/src/components/ui/dialog.tsx +158 -0
  345. package/src/interfaces/web/src/components/ui/direction.tsx +4 -0
  346. package/src/interfaces/web/src/components/ui/drawer.tsx +134 -0
  347. package/src/interfaces/web/src/components/ui/dropdown-menu.tsx +266 -0
  348. package/src/interfaces/web/src/components/ui/empty.tsx +104 -0
  349. package/src/interfaces/web/src/components/ui/field.tsx +236 -0
  350. package/src/interfaces/web/src/components/ui/hover-card.tsx +51 -0
  351. package/src/interfaces/web/src/components/ui/input-group.tsx +158 -0
  352. package/src/interfaces/web/src/components/ui/input-otp.tsx +85 -0
  353. package/src/interfaces/web/src/components/ui/input.tsx +20 -0
  354. package/src/interfaces/web/src/components/ui/item.tsx +201 -0
  355. package/src/interfaces/web/src/components/ui/kbd.tsx +26 -0
  356. package/src/interfaces/web/src/components/ui/label.tsx +20 -0
  357. package/src/interfaces/web/src/components/ui/menubar.tsx +280 -0
  358. package/src/interfaces/web/src/components/ui/native-select.tsx +61 -0
  359. package/src/interfaces/web/src/components/ui/navigation-menu.tsx +168 -0
  360. package/src/interfaces/web/src/components/ui/pagination.tsx +130 -0
  361. package/src/interfaces/web/src/components/ui/popover.tsx +88 -0
  362. package/src/interfaces/web/src/components/ui/progress.tsx +83 -0
  363. package/src/interfaces/web/src/components/ui/radio-group.tsx +36 -0
  364. package/src/interfaces/web/src/components/ui/resizable.tsx +50 -0
  365. package/src/interfaces/web/src/components/ui/scroll-area.tsx +53 -0
  366. package/src/interfaces/web/src/components/ui/select.tsx +201 -0
  367. package/src/interfaces/web/src/components/ui/separator.tsx +23 -0
  368. package/src/interfaces/web/src/components/ui/sheet.tsx +138 -0
  369. package/src/interfaces/web/src/components/ui/sidebar.tsx +723 -0
  370. package/src/interfaces/web/src/components/ui/skeleton.tsx +13 -0
  371. package/src/interfaces/web/src/components/ui/slider.tsx +52 -0
  372. package/src/interfaces/web/src/components/ui/sonner.tsx +49 -0
  373. package/src/interfaces/web/src/components/ui/spinner.tsx +10 -0
  374. package/src/interfaces/web/src/components/ui/switch.tsx +30 -0
  375. package/src/interfaces/web/src/components/ui/table.tsx +116 -0
  376. package/src/interfaces/web/src/components/ui/tabs.tsx +72 -0
  377. package/src/interfaces/web/src/components/ui/textarea.tsx +18 -0
  378. package/src/interfaces/web/src/components/ui/tip.tsx +21 -0
  379. package/src/interfaces/web/src/components/ui/toggle-group.tsx +87 -0
  380. package/src/interfaces/web/src/components/ui/toggle.tsx +45 -0
  381. package/src/interfaces/web/src/components/ui/tooltip.tsx +64 -0
  382. package/src/interfaces/web/src/components/ui.tsx +211 -0
  383. package/src/interfaces/web/src/components/voice/VoiceProviderList.tsx +197 -0
  384. package/src/interfaces/web/src/components/voice/VoiceProviderModal.tsx +213 -0
  385. package/src/interfaces/web/src/components/voice/VoiceSttCard.tsx +72 -0
  386. package/src/interfaces/web/src/components/voice/VoiceTestCard.tsx +112 -0
  387. package/src/interfaces/web/src/components/voice/useTtsPlayer.ts +59 -0
  388. package/src/interfaces/web/src/constants/index.ts +91 -0
  389. package/src/interfaces/web/src/hooks/use-mobile.ts +19 -0
  390. package/src/interfaces/web/src/hooks/useChat.ts +276 -0
  391. package/src/interfaces/web/src/hooks/useDaemonStatus.ts +12 -0
  392. package/src/interfaces/web/src/hooks/useDevices.ts +12 -0
  393. package/src/interfaces/web/src/hooks/useEngines.ts +10 -0
  394. package/src/interfaces/web/src/hooks/useGlobalConfig.ts +24 -0
  395. package/src/interfaces/web/src/hooks/useIdentity.ts +16 -0
  396. package/src/interfaces/web/src/hooks/useProjects.ts +27 -0
  397. package/src/interfaces/web/src/hooks/useTelegram.ts +35 -0
  398. package/src/interfaces/web/src/hooks/useTheme.tsx +57 -0
  399. package/src/interfaces/web/src/hooks/useTokenBootstrap.ts +122 -0
  400. package/src/interfaces/web/src/i18n/en.ts +767 -0
  401. package/src/interfaces/web/src/i18n/es.ts +770 -0
  402. package/src/interfaces/web/src/i18n/index.ts +86 -0
  403. package/src/interfaces/web/src/lib/api/admin.ts +30 -0
  404. package/src/interfaces/web/src/lib/api/agents.ts +46 -0
  405. package/src/interfaces/web/src/lib/api/code.ts +122 -0
  406. package/src/interfaces/web/src/lib/api/conversations.ts +16 -0
  407. package/src/interfaces/web/src/lib/api/deck.ts +106 -0
  408. package/src/interfaces/web/src/lib/api/desktop.ts +54 -0
  409. package/src/interfaces/web/src/lib/api/embeddings.ts +44 -0
  410. package/src/interfaces/web/src/lib/api/engines.ts +17 -0
  411. package/src/interfaces/web/src/lib/api/filesystem.ts +12 -0
  412. package/src/interfaces/web/src/lib/api/health.ts +6 -0
  413. package/src/interfaces/web/src/lib/api/identity.ts +7 -0
  414. package/src/interfaces/web/src/lib/api/mcps.ts +29 -0
  415. package/src/interfaces/web/src/lib/api/messages.ts +24 -0
  416. package/src/interfaces/web/src/lib/api/projects.ts +29 -0
  417. package/src/interfaces/web/src/lib/api/routines.ts +14 -0
  418. package/src/interfaces/web/src/lib/api/sessions.ts +16 -0
  419. package/src/interfaces/web/src/lib/api/super_agent.ts +29 -0
  420. package/src/interfaces/web/src/lib/api/tasks.ts +19 -0
  421. package/src/interfaces/web/src/lib/api/telegram.ts +57 -0
  422. package/src/interfaces/web/src/lib/api/tools.ts +13 -0
  423. package/src/interfaces/web/src/lib/api/voice.ts +169 -0
  424. package/src/interfaces/web/src/lib/api.ts +48 -0
  425. package/src/interfaces/web/src/lib/cn.ts +6 -0
  426. package/src/interfaces/web/src/lib/code-context.ts +83 -0
  427. package/src/interfaces/web/src/lib/config-values.ts +29 -0
  428. package/src/interfaces/web/src/lib/device.ts +10 -0
  429. package/src/interfaces/web/src/lib/http.ts +104 -0
  430. package/src/interfaces/web/src/lib/secrets.ts +15 -0
  431. package/src/interfaces/web/src/lib/utils.ts +6 -0
  432. package/src/interfaces/web/src/main.tsx +16 -0
  433. package/src/interfaces/web/src/screens/ApxAdminScreen.tsx +174 -0
  434. package/src/interfaces/web/src/screens/PairingScreen.tsx +105 -0
  435. package/src/interfaces/web/src/screens/ProjectScreen.tsx +178 -0
  436. package/src/interfaces/web/src/screens/SettingsScreen.tsx +111 -0
  437. package/src/interfaces/web/src/screens/base/AgentDefaultsTab.tsx +274 -0
  438. package/src/interfaces/web/src/screens/base/ComingSoon.tsx +16 -0
  439. package/src/interfaces/web/src/screens/base/GlobalTasksTab.tsx +53 -0
  440. package/src/interfaces/web/src/screens/base/LogsTab.tsx +188 -0
  441. package/src/interfaces/web/src/screens/base/ModelsTab.tsx +13 -0
  442. package/src/interfaces/web/src/screens/base/SessionsTab.tsx +58 -0
  443. package/src/interfaces/web/src/screens/base/WorkspacesTab.tsx +49 -0
  444. package/src/interfaces/web/src/screens/modules/CodeScreen.tsx +295 -0
  445. package/src/interfaces/web/src/screens/modules/DeckScreen.tsx +173 -0
  446. package/src/interfaces/web/src/screens/modules/DesktopScreen.tsx +304 -0
  447. package/src/interfaces/web/src/screens/modules/VoiceScreen.tsx +174 -0
  448. package/src/interfaces/web/src/screens/project/AgentBrainGraph.tsx +152 -0
  449. package/src/interfaces/web/src/screens/project/AgentDetailScreen.tsx +455 -0
  450. package/src/interfaces/web/src/screens/project/AgentsTab.tsx +364 -0
  451. package/src/interfaces/web/src/screens/project/ChatTab.tsx +198 -0
  452. package/src/interfaces/web/src/screens/project/ConfigTab.tsx +94 -0
  453. package/src/interfaces/web/src/screens/project/McpsTab.tsx +149 -0
  454. package/src/interfaces/web/src/screens/project/MemoriesTab.tsx +134 -0
  455. package/src/interfaces/web/src/screens/project/Overview.tsx +37 -0
  456. package/src/interfaces/web/src/screens/project/RoutinesTab.tsx +386 -0
  457. package/src/interfaces/web/src/screens/project/TasksTab.tsx +116 -0
  458. package/src/interfaces/web/src/screens/project/TelegramTab.tsx +126 -0
  459. package/src/interfaces/web/src/screens/project/ThreadsTab.tsx +100 -0
  460. package/src/interfaces/web/src/styles.css +128 -0
  461. package/src/interfaces/web/src/types/daemon.ts +289 -0
  462. package/src/interfaces/web/tailwind.config.js +53 -0
  463. package/src/interfaces/web/tsconfig.json +24 -0
  464. package/src/interfaces/web/vite.config.ts +50 -0
  465. package/src/cli/commands/exec.js +0 -56
  466. package/src/cli/commands/overlay.js +0 -253
  467. package/src/cli/commands/session.js +0 -395
  468. package/src/cli/commands/sessions.js +0 -517
  469. package/src/cli/commands/telegram.js +0 -77
  470. package/src/cli/postinstall.js +0 -75
  471. package/src/cli-ts/commands/agent.ts +0 -173
  472. package/src/cli-ts/commands/chat.ts +0 -119
  473. package/src/cli-ts/commands/daemon.ts +0 -112
  474. package/src/cli-ts/commands/exec.ts +0 -109
  475. package/src/cli-ts/commands/mcp.ts +0 -235
  476. package/src/cli-ts/commands/session.ts +0 -224
  477. package/src/cli-ts/commands/status.ts +0 -61
  478. package/src/cli-ts/http.ts +0 -36
  479. package/src/cli-ts/index.ts +0 -73
  480. package/src/cli-ts/ui.ts +0 -107
  481. package/src/daemon/api.js +0 -1558
  482. package/src/daemon/engines/gemini.js +0 -56
  483. package/src/daemon/engines/openai.js +0 -79
  484. package/src/daemon/mcp-sources.js +0 -114
  485. package/src/daemon/super-agent-tools/index.js +0 -84
  486. package/src/daemon/super-agent-tools.js +0 -1
  487. package/src/daemon/super-agent.js +0 -541
  488. package/src/overlay/index.html +0 -44
  489. package/src/overlay/main.js +0 -480
  490. package/src/overlay/preload.js +0 -34
  491. package/src/overlay/renderer.js +0 -371
  492. package/src/overlay/style.css +0 -250
  493. package/src/tui/context/sync-apx.tsx +0 -284
  494. package/src/tui/routes/session/index.tsx +0 -274
  495. package/src/tui/routes/session/sidebar-apx.tsx +0 -90
  496. /package/src/{daemon → core}/tools/browser.js +0 -0
  497. /package/src/{daemon → core}/tools/fetch.js +0 -0
  498. /package/src/{daemon → core}/tools/glob.js +0 -0
  499. /package/src/{daemon → core}/tools/grep.js +0 -0
  500. /package/src/{daemon → core}/tools/registry.js +0 -0
  501. /package/src/{daemon → core}/tools/search.js +0 -0
  502. /package/src/{daemon → host/daemon}/conversations.js +0 -0
  503. /package/src/{daemon → host/daemon}/env-detect.js +0 -0
  504. /package/src/{daemon → host/daemon}/runtimes/_spawn.js +0 -0
  505. /package/src/{daemon → host/daemon}/runtimes/aider.js +0 -0
  506. /package/src/{daemon → host/daemon}/runtimes/claude-code.js +0 -0
  507. /package/src/{daemon → host/daemon}/runtimes/codex.js +0 -0
  508. /package/src/{daemon → host/daemon}/runtimes/cursor-agent.js +0 -0
  509. /package/src/{daemon → host/daemon}/runtimes/gemini-cli.js +0 -0
  510. /package/src/{daemon → host/daemon}/runtimes/index.js +0 -0
  511. /package/src/{daemon → host/daemon}/runtimes/opencode.js +0 -0
  512. /package/src/{daemon → host/daemon}/runtimes/qwen-code.js +0 -0
  513. /package/src/{daemon → host/daemon}/super-agent-tools/tools/call-mcp.js +0 -0
  514. /package/src/{daemon → host/daemon}/super-agent-tools/tools/edit-file.js +0 -0
  515. /package/src/{daemon → host/daemon}/super-agent-tools/tools/list-files.js +0 -0
  516. /package/src/{daemon → host/daemon}/super-agent-tools/tools/list-mcps.js +0 -0
  517. /package/src/{daemon → host/daemon}/super-agent-tools/tools/list-projects.js +0 -0
  518. /package/src/{daemon → host/daemon}/super-agent-tools/tools/list-skills.js +0 -0
  519. /package/src/{daemon → host/daemon}/super-agent-tools/tools/load-skill.js +0 -0
  520. /package/src/{daemon → host/daemon}/super-agent-tools/tools/read-agent-memory.js +0 -0
  521. /package/src/{daemon → host/daemon}/super-agent-tools/tools/read-file.js +0 -0
  522. /package/src/{daemon → host/daemon}/super-agent-tools/tools/run-shell.js +0 -0
  523. /package/src/{daemon → host/daemon}/super-agent-tools/tools/search-files.js +0 -0
  524. /package/src/{daemon → host/daemon}/super-agent-tools/tools/transcribe-audio.js +0 -0
  525. /package/src/{daemon → host/daemon}/super-agent-tools/tools/write-file.js +0 -0
  526. /package/src/{daemon → host/daemon}/thinking.js +0 -0
  527. /package/src/{daemon → host/daemon}/whisper-server.py +0 -0
  528. /package/src/{daemon → host/daemon}/whisper-transcribe.py +0 -0
  529. /package/src/{cli → interfaces/cli}/commands/a2a.js +0 -0
  530. /package/src/{cli → interfaces/cli}/commands/artifact.js +0 -0
  531. /package/src/{cli → interfaces/cli}/commands/chat.js +0 -0
  532. /package/src/{cli → interfaces/cli}/commands/log.js +0 -0
  533. /package/src/{cli → interfaces/cli}/commands/messages.js +0 -0
  534. /package/src/{cli → interfaces/cli}/commands/plugins.js +0 -0
  535. /package/src/{cli → interfaces/cli}/commands/routine.js +0 -0
  536. /package/src/{cli → interfaces/cli}/commands/runtime.js +0 -0
  537. /package/src/{cli → interfaces/cli}/terminal-chat/renderer.js +0 -0
  538. /package/src/{overlay → interfaces/desktop}/package.json +0 -0
  539. /package/src/{tui → interfaces/tui}/_shims/cli-error.ts +0 -0
  540. /package/src/{tui → interfaces/tui}/_shims/cli-logo.ts +0 -0
  541. /package/src/{tui → interfaces/tui}/_shims/cli-ui.ts +0 -0
  542. /package/src/{tui → interfaces/tui}/_shims/config-console-state.ts +0 -0
  543. /package/src/{tui → interfaces/tui}/_shims/core-any.ts +0 -0
  544. /package/src/{tui → interfaces/tui}/_shims/core-binary.ts +0 -0
  545. /package/src/{tui → interfaces/tui}/_shims/core-flag.ts +0 -0
  546. /package/src/{tui → interfaces/tui}/_shims/core-log.ts +0 -0
  547. /package/src/{tui → interfaces/tui}/_shims/lsp-language.ts +0 -0
  548. /package/src/{tui → interfaces/tui}/_shims/opencode-any.ts +0 -0
  549. /package/src/{tui → interfaces/tui}/_shims/opencode-sdk-v2.ts +0 -0
  550. /package/src/{tui → interfaces/tui}/_shims/plugin-tui.ts +0 -0
  551. /package/src/{tui → interfaces/tui}/_shims/prompt-display.ts +0 -0
  552. /package/src/{tui → interfaces/tui}/_shims/provider-provider.ts +0 -0
  553. /package/src/{tui → interfaces/tui}/_shims/session-retry.ts +0 -0
  554. /package/src/{tui → interfaces/tui}/_shims/session-schema.ts +0 -0
  555. /package/src/{tui → interfaces/tui}/_shims/session-session.ts +0 -0
  556. /package/src/{tui → interfaces/tui}/_shims/snapshot.ts +0 -0
  557. /package/src/{tui → interfaces/tui}/_shims/tool-any.ts +0 -0
  558. /package/src/{tui → interfaces/tui}/_shims/util-error.ts +0 -0
  559. /package/src/{tui → interfaces/tui}/_shims/util-filesystem.ts +0 -0
  560. /package/src/{tui → interfaces/tui}/_shims/util-format.ts +0 -0
  561. /package/src/{tui → interfaces/tui}/_shims/util-iife.ts +0 -0
  562. /package/src/{tui → interfaces/tui}/_shims/util-locale.ts +0 -0
  563. /package/src/{tui → interfaces/tui}/_shims/util-process.ts +0 -0
  564. /package/src/{tui → interfaces/tui}/asset/charge.wav +0 -0
  565. /package/src/{tui → interfaces/tui}/asset/pulse-a.wav +0 -0
  566. /package/src/{tui → interfaces/tui}/asset/pulse-b.wav +0 -0
  567. /package/src/{tui → interfaces/tui}/asset/pulse-c.wav +0 -0
  568. /package/src/{tui → interfaces/tui}/attach.ts +0 -0
  569. /package/src/{tui → interfaces/tui}/component/bg-pulse-render.ts +0 -0
  570. /package/src/{tui → interfaces/tui}/component/bg-pulse.tsx +0 -0
  571. /package/src/{tui → interfaces/tui}/component/border.tsx +0 -0
  572. /package/src/{tui → interfaces/tui}/component/dialog-agent.tsx +0 -0
  573. /package/src/{tui → interfaces/tui}/component/dialog-console-org.tsx +0 -0
  574. /package/src/{tui → interfaces/tui}/component/dialog-mcp.tsx +0 -0
  575. /package/src/{tui → interfaces/tui}/component/dialog-model.tsx +0 -0
  576. /package/src/{tui → interfaces/tui}/component/dialog-provider.tsx +0 -0
  577. /package/src/{tui → interfaces/tui}/component/dialog-retry-action.tsx +0 -0
  578. /package/src/{tui → interfaces/tui}/component/dialog-session-delete-failed.tsx +0 -0
  579. /package/src/{tui → interfaces/tui}/component/dialog-session-list.tsx +0 -0
  580. /package/src/{tui → interfaces/tui}/component/dialog-session-rename.tsx +0 -0
  581. /package/src/{tui → interfaces/tui}/component/dialog-skill.tsx +0 -0
  582. /package/src/{tui → interfaces/tui}/component/dialog-stash.tsx +0 -0
  583. /package/src/{tui → interfaces/tui}/component/dialog-status.tsx +0 -0
  584. /package/src/{tui → interfaces/tui}/component/dialog-tag.tsx +0 -0
  585. /package/src/{tui → interfaces/tui}/component/dialog-theme-list.tsx +0 -0
  586. /package/src/{tui → interfaces/tui}/component/dialog-variant.tsx +0 -0
  587. /package/src/{tui → interfaces/tui}/component/dialog-workspace-create.tsx +0 -0
  588. /package/src/{tui → interfaces/tui}/component/dialog-workspace-file-changes.tsx +0 -0
  589. /package/src/{tui → interfaces/tui}/component/dialog-workspace-unavailable.tsx +0 -0
  590. /package/src/{tui → interfaces/tui}/component/error-component.tsx +0 -0
  591. /package/src/{tui → interfaces/tui}/component/logo.tsx +0 -0
  592. /package/src/{tui → interfaces/tui}/component/plugin-route-missing.tsx +0 -0
  593. /package/src/{tui → interfaces/tui}/component/prompt/autocomplete.tsx +0 -0
  594. /package/src/{tui → interfaces/tui}/component/prompt/cwd.ts +0 -0
  595. /package/src/{tui → interfaces/tui}/component/prompt/frecency.tsx +0 -0
  596. /package/src/{tui → interfaces/tui}/component/prompt/history.tsx +0 -0
  597. /package/src/{tui → interfaces/tui}/component/prompt/part.ts +0 -0
  598. /package/src/{tui → interfaces/tui}/component/prompt/stash.tsx +0 -0
  599. /package/src/{tui → interfaces/tui}/component/prompt/traits.ts +0 -0
  600. /package/src/{tui → interfaces/tui}/component/spinner.tsx +0 -0
  601. /package/src/{tui → interfaces/tui}/component/startup-loading.tsx +0 -0
  602. /package/src/{tui → interfaces/tui}/component/todo-item.tsx +0 -0
  603. /package/src/{tui → interfaces/tui}/component/use-connected.tsx +0 -0
  604. /package/src/{tui → interfaces/tui}/component/workspace-label.tsx +0 -0
  605. /package/src/{tui → interfaces/tui}/config/cwd.ts +0 -0
  606. /package/src/{tui → interfaces/tui}/config/keybind.ts +0 -0
  607. /package/src/{tui → interfaces/tui}/config/tui-migrate.ts +0 -0
  608. /package/src/{tui → interfaces/tui}/config/tui-schema.ts +0 -0
  609. /package/src/{tui → interfaces/tui}/config/tui.ts +0 -0
  610. /package/src/{tui → interfaces/tui}/context/aggregate-failures.ts +0 -0
  611. /package/src/{tui → interfaces/tui}/context/args.tsx +0 -0
  612. /package/src/{tui → interfaces/tui}/context/command-palette.tsx +0 -0
  613. /package/src/{tui → interfaces/tui}/context/directory.ts +0 -0
  614. /package/src/{tui → interfaces/tui}/context/editor-zed.ts +0 -0
  615. /package/src/{tui → interfaces/tui}/context/editor.ts +0 -0
  616. /package/src/{tui → interfaces/tui}/context/event-apx.ts +0 -0
  617. /package/src/{tui → interfaces/tui}/context/event.ts +0 -0
  618. /package/src/{tui → interfaces/tui}/context/exit.tsx +0 -0
  619. /package/src/{tui → interfaces/tui}/context/helper.tsx +0 -0
  620. /package/src/{tui → interfaces/tui}/context/kv.tsx +0 -0
  621. /package/src/{tui → interfaces/tui}/context/local.tsx +0 -0
  622. /package/src/{tui → interfaces/tui}/context/path-format.tsx +0 -0
  623. /package/src/{tui → interfaces/tui}/context/project-apx.tsx +0 -0
  624. /package/src/{tui → interfaces/tui}/context/project.tsx +0 -0
  625. /package/src/{tui → interfaces/tui}/context/prompt.tsx +0 -0
  626. /package/src/{tui → interfaces/tui}/context/route.tsx +0 -0
  627. /package/src/{tui → interfaces/tui}/context/sdk.tsx +0 -0
  628. /package/src/{tui → interfaces/tui}/context/sync-v2.tsx +0 -0
  629. /package/src/{tui → interfaces/tui}/context/sync.tsx +0 -0
  630. /package/src/{tui → interfaces/tui}/context/theme/aura.json +0 -0
  631. /package/src/{tui → interfaces/tui}/context/theme/ayu.json +0 -0
  632. /package/src/{tui → interfaces/tui}/context/theme/carbonfox.json +0 -0
  633. /package/src/{tui → interfaces/tui}/context/theme/catppuccin-frappe.json +0 -0
  634. /package/src/{tui → interfaces/tui}/context/theme/catppuccin-macchiato.json +0 -0
  635. /package/src/{tui → interfaces/tui}/context/theme/catppuccin.json +0 -0
  636. /package/src/{tui → interfaces/tui}/context/theme/cobalt2.json +0 -0
  637. /package/src/{tui → interfaces/tui}/context/theme/cursor.json +0 -0
  638. /package/src/{tui → interfaces/tui}/context/theme/dracula.json +0 -0
  639. /package/src/{tui → interfaces/tui}/context/theme/everforest.json +0 -0
  640. /package/src/{tui → interfaces/tui}/context/theme/flexoki.json +0 -0
  641. /package/src/{tui → interfaces/tui}/context/theme/github.json +0 -0
  642. /package/src/{tui → interfaces/tui}/context/theme/gruvbox.json +0 -0
  643. /package/src/{tui → interfaces/tui}/context/theme/kanagawa.json +0 -0
  644. /package/src/{tui → interfaces/tui}/context/theme/lucent-orng.json +0 -0
  645. /package/src/{tui → interfaces/tui}/context/theme/material.json +0 -0
  646. /package/src/{tui → interfaces/tui}/context/theme/matrix.json +0 -0
  647. /package/src/{tui → interfaces/tui}/context/theme/mercury.json +0 -0
  648. /package/src/{tui → interfaces/tui}/context/theme/monokai.json +0 -0
  649. /package/src/{tui → interfaces/tui}/context/theme/nightowl.json +0 -0
  650. /package/src/{tui → interfaces/tui}/context/theme/nord.json +0 -0
  651. /package/src/{tui → interfaces/tui}/context/theme/one-dark.json +0 -0
  652. /package/src/{tui → interfaces/tui}/context/theme/opencode.json +0 -0
  653. /package/src/{tui → interfaces/tui}/context/theme/orng.json +0 -0
  654. /package/src/{tui → interfaces/tui}/context/theme/osaka-jade.json +0 -0
  655. /package/src/{tui → interfaces/tui}/context/theme/palenight.json +0 -0
  656. /package/src/{tui → interfaces/tui}/context/theme/rosepine.json +0 -0
  657. /package/src/{tui → interfaces/tui}/context/theme/solarized.json +0 -0
  658. /package/src/{tui → interfaces/tui}/context/theme/synthwave84.json +0 -0
  659. /package/src/{tui → interfaces/tui}/context/theme/tokyonight.json +0 -0
  660. /package/src/{tui → interfaces/tui}/context/theme/vercel.json +0 -0
  661. /package/src/{tui → interfaces/tui}/context/theme/vesper.json +0 -0
  662. /package/src/{tui → interfaces/tui}/context/theme/zenburn.json +0 -0
  663. /package/src/{tui → interfaces/tui}/context/theme.tsx +0 -0
  664. /package/src/{tui → interfaces/tui}/context/tui-config.tsx +0 -0
  665. /package/src/{tui → interfaces/tui}/event.ts +0 -0
  666. /package/src/{tui → interfaces/tui}/feature-plugins/home/footer.tsx +0 -0
  667. /package/src/{tui → interfaces/tui}/feature-plugins/home/tips-view.tsx +0 -0
  668. /package/src/{tui → interfaces/tui}/feature-plugins/home/tips.tsx +0 -0
  669. /package/src/{tui → interfaces/tui}/feature-plugins/sidebar/context.tsx +0 -0
  670. /package/src/{tui → interfaces/tui}/feature-plugins/sidebar/files.tsx +0 -0
  671. /package/src/{tui → interfaces/tui}/feature-plugins/sidebar/footer.tsx +0 -0
  672. /package/src/{tui → interfaces/tui}/feature-plugins/sidebar/lsp.tsx +0 -0
  673. /package/src/{tui → interfaces/tui}/feature-plugins/sidebar/mcp.tsx +0 -0
  674. /package/src/{tui → interfaces/tui}/feature-plugins/sidebar/todo.tsx +0 -0
  675. /package/src/{tui → interfaces/tui}/feature-plugins/system/plugins.tsx +0 -0
  676. /package/src/{tui → interfaces/tui}/feature-plugins/system/session-v2.tsx +0 -0
  677. /package/src/{tui → interfaces/tui}/feature-plugins/system/which-key.tsx +0 -0
  678. /package/src/{tui → interfaces/tui}/keymap.tsx +0 -0
  679. /package/src/{tui → interfaces/tui}/layer.ts +0 -0
  680. /package/src/{tui → interfaces/tui}/plugin/api.tsx +0 -0
  681. /package/src/{tui → interfaces/tui}/plugin/command-shim.ts +0 -0
  682. /package/src/{tui → interfaces/tui}/plugin/internal.ts +0 -0
  683. /package/src/{tui → interfaces/tui}/plugin/runtime.ts +0 -0
  684. /package/src/{tui → interfaces/tui}/plugin/slots.tsx +0 -0
  685. /package/src/{tui → interfaces/tui}/routes/home.tsx +0 -0
  686. /package/src/{tui → interfaces/tui}/routes/session/dialog-fork-from-timeline.tsx +0 -0
  687. /package/src/{tui → interfaces/tui}/routes/session/dialog-message.tsx +0 -0
  688. /package/src/{tui → interfaces/tui}/routes/session/dialog-subagent.tsx +0 -0
  689. /package/src/{tui → interfaces/tui}/routes/session/dialog-timeline.tsx +0 -0
  690. /package/src/{tui → interfaces/tui}/routes/session/footer.tsx +0 -0
  691. /package/src/{tui → interfaces/tui}/routes/session/permission.tsx +0 -0
  692. /package/src/{tui → interfaces/tui}/routes/session/question.tsx +0 -0
  693. /package/src/{tui → interfaces/tui}/routes/session/sidebar.tsx +0 -0
  694. /package/src/{tui → interfaces/tui}/routes/session/subagent-footer.tsx +0 -0
  695. /package/src/{tui → interfaces/tui}/run.ts +0 -0
  696. /package/src/{tui → interfaces/tui}/thread.ts +0 -0
  697. /package/src/{tui → interfaces/tui}/ui/dialog-alert.tsx +0 -0
  698. /package/src/{tui → interfaces/tui}/ui/dialog-confirm.tsx +0 -0
  699. /package/src/{tui → interfaces/tui}/ui/dialog-export-options.tsx +0 -0
  700. /package/src/{tui → interfaces/tui}/ui/dialog-help.tsx +0 -0
  701. /package/src/{tui → interfaces/tui}/ui/dialog-prompt.tsx +0 -0
  702. /package/src/{tui → interfaces/tui}/ui/dialog-select.tsx +0 -0
  703. /package/src/{tui → interfaces/tui}/ui/dialog.tsx +0 -0
  704. /package/src/{tui → interfaces/tui}/ui/link.tsx +0 -0
  705. /package/src/{tui → interfaces/tui}/ui/spinner.ts +0 -0
  706. /package/src/{tui → interfaces/tui}/ui/toast.tsx +0 -0
  707. /package/src/{tui → interfaces/tui}/util/editor.ts +0 -0
  708. /package/src/{tui → interfaces/tui}/util/model.ts +0 -0
  709. /package/src/{tui → interfaces/tui}/util/provider-origin.ts +0 -0
  710. /package/src/{tui → interfaces/tui}/util/revert-diff.ts +0 -0
  711. /package/src/{tui → interfaces/tui}/util/scroll.ts +0 -0
  712. /package/src/{tui → interfaces/tui}/util/selection.ts +0 -0
  713. /package/src/{tui → interfaces/tui}/util/signal.ts +0 -0
  714. /package/src/{tui → interfaces/tui}/util/sound.ts +0 -0
  715. /package/src/{tui → interfaces/tui}/util/transcript.ts +0 -0
  716. /package/src/{tui → interfaces/tui}/validate-session.ts +0 -0
  717. /package/src/{tui → interfaces/tui}/win32.ts +0 -0
  718. /package/src/{tui → interfaces/tui}/worker.ts +0 -0
package/src/daemon/api.js DELETED
@@ -1,1558 +0,0 @@
1
- // Express REST API for APX. See APC docs reference/apx-daemon.
2
- import fs from "node:fs";
3
- import os from "node:os";
4
- import path from "node:path";
5
- import { randomUUID } from "node:crypto";
6
- import { execFile } from "node:child_process";
7
- import express from "express";
8
- import { buildBrowserRouter } from "./tools/browser.js";
9
- import { buildFetchRouter } from "./tools/fetch.js";
10
- import { buildSearchRouter } from "./tools/search.js";
11
- import { buildRegistryRouter } from "./tools/registry.js";
12
- import { buildGlobRouter } from "./tools/glob.js";
13
- import { buildGrepRouter } from "./tools/grep.js";
14
- import { readApfMcps, writeApfMcps, SOURCES } from "./mcp-sources.js";
15
- import { callEngine, ENGINE_IDS } from "./engines/index.js";
16
- import { getRuntime, RUNTIME_IDS } from "./runtimes/index.js";
17
- import { detectAll } from "./env-detect.js";
18
- import {
19
- startConversation,
20
- appendTurn,
21
- readConversation,
22
- listConversations,
23
- conversationPath,
24
- setStatus,
25
- } from "./conversations.js";
26
- import { compactConversation } from "./compact.js";
27
- import {
28
- readProjectConfig,
29
- writeProjectConfig,
30
- setDottedKey,
31
- unsetDottedKey,
32
- } from "./project-config.js";
33
- import {
34
- listRoutines,
35
- getRoutine,
36
- upsertRoutine,
37
- deleteRoutine,
38
- setEnabled as setRoutineEnabled,
39
- runRoutineNow,
40
- } from "./routines.js";
41
- import {
42
- buildApfHint,
43
- createRuntimeSession,
44
- closeRuntimeSession,
45
- extractApfResult,
46
- } from "./apc-runtime-context.js";
47
- import { readSessionFrontmatter } from "../core/session-store.js";
48
- import { runSuperAgent, isSuperAgentEnabled } from "./super-agent.js";
49
- import { readGlobalMessages, readProjectMessages, searchProjectMessages } from "../core/messages-store.js";
50
- import { readAgents } from "../core/parser.js";
51
- import { parseSessionFrontmatter } from "../core/parser.js";
52
- import { writeAgentFile, ensureAgentDir, regenerateAgentsMd } from "../core/scaffold.js";
53
- import { buildAgentSystem } from "../core/agent-system.js";
54
- import { appendErrorTrace, previewText } from "../core/logging.js";
55
- import {
56
- createArtifact,
57
- listArtifacts,
58
- readArtifact,
59
- removeArtifact,
60
- } from "../core/artifacts-store.js";
61
-
62
- const nowIso = () => new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
63
-
64
- function appendSuperAgentErrorTrace(req, error, details = {}) {
65
- appendErrorTrace({
66
- trace_id: req.apxTraceId,
67
- surface: "daemon_api",
68
- route: `${req.method} ${req.route?.path || req.path}`,
69
- project_id: req.params?.pid || null,
70
- channel: /Channel:\s*([^\n]+)/i.exec(details.contextNote || "")?.[1]?.trim() || null,
71
- model: details.model || null,
72
- stream: !!details.stream,
73
- prompt_preview: previewText(details.prompt),
74
- previous_messages: Array.isArray(details.previousMessages) ? details.previousMessages.length : 0,
75
- error: {
76
- message: error?.message || String(error),
77
- stack: error?.stack || null,
78
- },
79
- });
80
- }
81
-
82
- export function buildApi({ projects, registries, plugins, scheduler, version, startedAt, addProjectGlobally, config, token }) {
83
- const telegram = plugins?.get("telegram");
84
-
85
- const app = express();
86
- app.use(express.json({ limit: "2mb" }));
87
- app.use((req, res, next) => {
88
- req.apxTraceId = req.get("x-apx-trace-id") || randomUUID();
89
- res.setHeader("x-apx-trace-id", req.apxTraceId);
90
- next();
91
- });
92
-
93
- // Token auth — skip only /health so the CLI can ping before reading the token.
94
- if (token) {
95
- app.use((req, res, next) => {
96
- if (req.path === "/health") return next();
97
- const auth = req.get("authorization") || "";
98
- const provided = auth.startsWith("Bearer ") ? auth.slice(7) : "";
99
- if (provided !== token) return res.status(401).json({ error: "unauthorized" });
100
- next();
101
- });
102
- }
103
-
104
- // ---- Tool routers (fetch / browser / search / glob / grep / registry) ----
105
- // fetch = native HTTP, no Chromium → fast, cheap, default for REST/HTML
106
- // browser = Puppeteer-backed → heavy, lazy-launched, for JS-rendered pages
107
- app.use("/tools/fetch", buildFetchRouter(express));
108
- app.use("/tools/browser", buildBrowserRouter(express));
109
- app.use("/tools/search", buildSearchRouter(express));
110
- app.use("/tools/glob", buildGlobRouter(express));
111
- app.use("/tools/grep", buildGrepRouter(express));
112
- // Registry MUST be mounted after specific routers so /:name wildcard
113
- // doesn't shadow /tools/browser, /tools/fetch, /tools/search, etc.
114
- app.use("/tools", buildRegistryRouter(express, { projects, registries }));
115
-
116
- // ---- Health -------------------------------------------------------
117
- app.get("/health", (_req, res) => {
118
- res.json({
119
- status: "ok",
120
- version,
121
- uptime_s: Math.round((Date.now() - startedAt) / 1000),
122
- });
123
- });
124
-
125
- // ---- Projects -----------------------------------------------------
126
- app.get("/projects", (_req, res) => res.json(projects.list()));
127
-
128
- app.post("/projects", (req, res) => {
129
- const { path: p } = req.body || {};
130
- if (!p) return res.status(400).json({ error: "path required" });
131
- try {
132
- const entry = projects.register(p);
133
- addProjectGlobally(entry.path);
134
- registries.ensure(entry);
135
- res.status(201).json({ id: entry.id, path: entry.path });
136
- } catch (e) {
137
- res.status(400).json({ error: e.message });
138
- }
139
- });
140
-
141
- app.delete("/projects/:id", (req, res) => {
142
- const ok = projects.unregister(req.params.id);
143
- res.status(ok ? 204 : 404).end();
144
- });
145
-
146
- app.post("/projects/:id/rebuild", (req, res) => {
147
- try {
148
- const result = projects.rebuild(req.params.id);
149
- res.json({ ok: true, ...result });
150
- } catch (e) {
151
- res.status(400).json({ error: e.message });
152
- }
153
- });
154
-
155
- // ---- Helper -------------------------------------------------------
156
- function project(req, res) {
157
- const p = projects.get(req.params.pid);
158
- if (!p) {
159
- res.status(404).json({ error: "project not found" });
160
- return null;
161
- }
162
- return p;
163
- }
164
-
165
- // ---- Agents -------------------------------------------------------
166
- app.get("/projects/:pid/agents", (req, res) => {
167
- const p = project(req, res);
168
- if (!p) return;
169
- res.json(readAgents(p.path).map(agentToResponse));
170
- });
171
-
172
- app.get("/projects/:pid/agents/:slug", (req, res) => {
173
- const p = project(req, res);
174
- if (!p) return;
175
- const agents = readAgents(p.path);
176
- const a = agents.find((x) => x.slug === req.params.slug);
177
- if (!a) return res.status(404).json({ error: "agent not found" });
178
- const memPath = path.join(p.path, ".apc", "agents", a.slug, "memory.md");
179
- const memory = fs.existsSync(memPath) ? fs.readFileSync(memPath, "utf8") : "";
180
- res.json({ ...agentToResponse(a), memory });
181
- });
182
-
183
- app.post("/projects/:pid/agents", (req, res) => {
184
- const p = project(req, res);
185
- if (!p) return;
186
- const { slug, role, model, skills, language, description, tools } = req.body || {};
187
- if (!slug) return res.status(400).json({ error: "slug required" });
188
- if (!/^[a-z][a-z0-9_-]*$/.test(slug))
189
- return res.status(400).json({ error: "invalid slug" });
190
- const existing = readAgents(p.path).find((a) => a.slug === slug);
191
- if (existing) return res.status(400).json({ error: `agent ${slug} already exists` });
192
- try {
193
- writeAgentFile(p.path, slug, {
194
- Role: role || null,
195
- Model: model || null,
196
- Language: language || null,
197
- Description: description || null,
198
- Skills: skills || [],
199
- Tools: tools || [],
200
- });
201
- ensureAgentDir(p.path, slug);
202
- regenerateAgentsMd(p.path);
203
- projects.rebuild(p.id);
204
- const created = readAgents(p.path).find((a) => a.slug === slug);
205
- res.status(201).json(agentToResponse(created));
206
- } catch (e) {
207
- res.status(400).json({ error: e.message });
208
- }
209
- });
210
-
211
- // ---- Memory -------------------------------------------------------
212
- app.get("/projects/:pid/agents/:slug/memory", (req, res) => {
213
- const p = project(req, res);
214
- if (!p) return;
215
- const memPath = path.join(p.path, ".apc", "agents", req.params.slug, "memory.md");
216
- if (!fs.existsSync(memPath)) return res.json({ body: "" });
217
- res.json({ body: fs.readFileSync(memPath, "utf8") });
218
- });
219
-
220
- app.put("/projects/:pid/agents/:slug/memory", (req, res) => {
221
- const p = project(req, res);
222
- if (!p) return;
223
- const { body } = req.body || {};
224
- if (typeof body !== "string")
225
- return res.status(400).json({ error: "body must be string" });
226
- const dir = path.join(p.path, ".apc", "agents", req.params.slug);
227
- fs.mkdirSync(path.join(dir, "sessions"), { recursive: true });
228
- const memPath = path.join(dir, "memory.md");
229
- fs.writeFileSync(memPath, body);
230
- projects.rebuild(p.id);
231
- res.json({ ok: true, bytes: Buffer.byteLength(body, "utf8") });
232
- });
233
-
234
- // ---- Sessions -----------------------------------------------------
235
- app.get("/projects/:pid/agents/:slug/sessions", (req, res) => {
236
- const p = project(req, res);
237
- if (!p) return;
238
- const agents = readAgents(p.path);
239
- if (!agents.find((a) => a.slug === req.params.slug))
240
- return res.status(404).json({ error: "agent not found" });
241
- const sessionsDir = path.join(p.storagePath, "agents", req.params.slug, "sessions");
242
- if (!fs.existsSync(sessionsDir)) return res.json([]);
243
- const sessions = fs
244
- .readdirSync(sessionsDir)
245
- .filter((f) => f.endsWith(".md"))
246
- .sort()
247
- .reverse()
248
- .map((f) => {
249
- const text = fs.readFileSync(path.join(sessionsDir, f), "utf8");
250
- const fm = parseSessionFrontmatter(text);
251
- const titleFromFile = f.replace(/^\d{4}-\d{2}-\d{2}-/, "").replace(/\.md$/, "");
252
- return {
253
- filename: f,
254
- title: fm.title || titleFromFile,
255
- started_at: fm.started || null,
256
- ended_at: fm.ended || null,
257
- };
258
- });
259
- res.json(sessions);
260
- });
261
-
262
- app.post("/projects/:pid/agents/:slug/sessions", (req, res) => {
263
- const p = project(req, res);
264
- if (!p) return;
265
- const { title, body = "" } = req.body || {};
266
- if (!title) return res.status(400).json({ error: "title required" });
267
- const sessionsDir = path.join(p.storagePath, "agents", req.params.slug, "sessions");
268
- fs.mkdirSync(sessionsDir, { recursive: true });
269
- const titleSlug =
270
- title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "session";
271
- const today = new Date().toISOString().slice(0, 10);
272
- let candidate = path.join(sessionsDir, `${today}-${titleSlug}.md`);
273
- let n = 2;
274
- while (fs.existsSync(candidate)) {
275
- candidate = path.join(sessionsDir, `${today}-${titleSlug}-${n}.md`);
276
- n++;
277
- }
278
- const started = nowIso();
279
- const content = `---\ntitle: ${title}\nstarted: ${started}\n---\n\n# ${title}\n\n${body}\n`;
280
- fs.writeFileSync(candidate, content);
281
- projects.rebuild(p.id);
282
- res.status(201).json({ filename: path.basename(candidate), path: candidate });
283
- });
284
-
285
- // GET session by filename (sid may include or omit the .md extension)
286
- app.get("/projects/:pid/sessions/:sid", (req, res) => {
287
- const p = project(req, res);
288
- if (!p) return;
289
- const sid = req.params.sid;
290
- const filename = sid.endsWith(".md") ? sid : `${sid}.md`;
291
- const agentsDir = path.join(p.storagePath, "agents");
292
- let found = null;
293
- if (fs.existsSync(agentsDir)) {
294
- for (const slug of fs.readdirSync(agentsDir)) {
295
- const f = path.join(agentsDir, slug, "sessions", filename);
296
- if (fs.existsSync(f)) {
297
- const text = fs.readFileSync(f, "utf8");
298
- const fm = parseSessionFrontmatter(text);
299
- found = { filename, agent: slug, ...fm, body_md: text };
300
- break;
301
- }
302
- }
303
- }
304
- if (!found) return res.status(404).json({ error: "session not found" });
305
- res.json(found);
306
- });
307
-
308
- // ---- MCPs ---------------------------------------------------------
309
- app.get("/projects/:pid/mcps", (req, res) => {
310
- const p = project(req, res);
311
- if (!p) return;
312
- res.json(registries.for(p).list());
313
- });
314
-
315
- app.post("/projects/:pid/mcps", (req, res) => {
316
- const p = project(req, res);
317
- if (!p) return;
318
- const { name, command, args, env, url, headers, enabled } = req.body || {};
319
- if (!name) return res.status(400).json({ error: "name required" });
320
- if (!command && !url)
321
- return res.status(400).json({ error: "either command or url required" });
322
-
323
- const json = readApfMcps(p.path);
324
- json.mcpServers = json.mcpServers || {};
325
- const existing = json.mcpServers[name] || {};
326
- json.mcpServers[name] = {
327
- ...existing,
328
- ...(command !== undefined ? { command } : {}),
329
- ...(args !== undefined ? { args } : {}),
330
- ...(env !== undefined ? { env } : {}),
331
- ...(url !== undefined ? { url } : {}),
332
- ...(headers !== undefined ? { headers } : {}),
333
- ...(enabled !== undefined ? { enabled } : {}),
334
- };
335
- writeApfMcps(p.path, json);
336
- registries.for(p).evict(name);
337
- projects.rebuild(p.id);
338
- const entry = registries.for(p).getByName(name);
339
- res.status(201).json(entry);
340
- });
341
-
342
- app.delete("/projects/:pid/mcps/:name", (req, res) => {
343
- const p = project(req, res);
344
- if (!p) return;
345
- const json = readApfMcps(p.path);
346
- if (!json.mcpServers || !(req.params.name in (json.mcpServers || {}))) {
347
- const all = registries.for(p).list();
348
- const m = all.find((x) => x.name === req.params.name);
349
- if (m && m.source !== "apc") {
350
- return res.status(409).json({
351
- error: `MCP "${req.params.name}" comes from "${m.source}" config — not APC-owned, cannot be removed by apx. Edit ${SOURCES.find((s) => s.id === m.source)?.file} directly.`,
352
- });
353
- }
354
- return res.status(404).end();
355
- }
356
- delete json.mcpServers[req.params.name];
357
- writeApfMcps(p.path, json);
358
- registries.for(p).evict(req.params.name);
359
- projects.rebuild(p.id);
360
- res.status(204).end();
361
- });
362
-
363
- app.get("/projects/:pid/mcps/check", (req, res) => {
364
- const p = project(req, res);
365
- if (!p) return;
366
- const reg = registries.for(p);
367
- res.json({
368
- sources: SOURCES.map((s) => ({
369
- id: s.id,
370
- file: s.file,
371
- present: fs.existsSync(path.join(p.path, s.file)),
372
- })),
373
- entries: reg.list().map((m) => ({
374
- name: m.name,
375
- source: m.source,
376
- transport: m.transport,
377
- enabled: m.enabled,
378
- })),
379
- conflicts: reg.conflicts(),
380
- });
381
- });
382
-
383
- app.post("/projects/:pid/mcps/:name/call", async (req, res) => {
384
- const p = project(req, res);
385
- if (!p) return;
386
- const { tool, params } = req.body || {};
387
- if (!tool) return res.status(400).json({ error: "tool required" });
388
- try {
389
- const result = await registries.for(p).call(req.params.name, tool, params);
390
- res.json({ result });
391
- } catch (e) {
392
- res.status(500).json({ error: e.message });
393
- }
394
- });
395
-
396
- // ---- Messages -----------------------------------------------------
397
- app.get("/projects/:pid/messages", (req, res) => {
398
- const p = project(req, res);
399
- if (!p) return;
400
- const { agent, channel, since, limit = "100" } = req.query;
401
- const rows = readProjectMessages(p.storagePath, {
402
- channel: channel || undefined,
403
- agent_slug: agent || undefined,
404
- since: since || undefined,
405
- limit: Math.min(parseInt(limit, 10) || 100, 1000),
406
- });
407
- res.json(rows);
408
- });
409
-
410
- app.post("/projects/:pid/messages", (req, res) => {
411
- const p = project(req, res);
412
- if (!p) return;
413
- const { channel, direction, type, actor_id, agent_slug, body, meta = {}, author = null } =
414
- req.body || {};
415
- if (!channel || !direction || !body)
416
- return res.status(400).json({ error: "channel, direction, body required" });
417
- if (!["in", "out"].includes(direction))
418
- return res.status(400).json({ error: "direction must be in|out" });
419
- const r = p.logMessage({ agent_slug: agent_slug || null, channel, direction, type, actor_id, author, body, meta });
420
- res.status(201).json({ ok: true, ts: r.ts });
421
- });
422
-
423
- app.get("/projects/:pid/messages/search", (req, res) => {
424
- const p = project(req, res);
425
- if (!p) return;
426
- const { q, limit = "50" } = req.query;
427
- if (!q) return res.status(400).json({ error: "q required" });
428
- res.json(searchProjectMessages(p.storagePath, q, Math.min(parseInt(limit, 10) || 50, 500)));
429
- });
430
-
431
- // ---- Global messages (cross-project channels: telegram, direct, …) ----
432
- app.get("/messages/global", (req, res) => {
433
- const { channel, limit = "100", since } = req.query;
434
- const lim = Math.min(parseInt(limit, 10) || 100, 1000);
435
- const rows = readGlobalMessages({ channel: channel || undefined, limit: lim, since });
436
- res.json(rows);
437
- });
438
-
439
- // ---- Telegram -----------------------------------------------------
440
- app.get("/telegram/status", (_req, res) => {
441
- if (!telegram) return res.json({ enabled: false, channels: [] });
442
- res.json(telegram.status());
443
- });
444
-
445
- // POST /telegram/start — (re)start polling for every configured channel.
446
- app.post("/telegram/start", (_req, res) => {
447
- if (!telegram) return res.status(503).json({ error: "telegram plugin not loaded" });
448
- try {
449
- telegram.start();
450
- res.json({ ok: true, status: telegram.status() });
451
- } catch (e) {
452
- res.status(502).json({ error: e.message });
453
- }
454
- });
455
-
456
- // POST /telegram/stop — stop polling on every channel (config stays intact).
457
- app.post("/telegram/stop", (_req, res) => {
458
- if (!telegram) return res.status(503).json({ error: "telegram plugin not loaded" });
459
- try {
460
- telegram.stop();
461
- res.json({ ok: true, status: telegram.status() });
462
- } catch (e) {
463
- res.status(502).json({ error: e.message });
464
- }
465
- });
466
-
467
- app.post("/telegram/send", async (req, res) => {
468
- const { chat_id, text, channel } = req.body || {};
469
- if (!text) return res.status(400).json({ error: "text required" });
470
- if (!telegram) return res.status(503).json({ error: "telegram plugin not loaded" });
471
- try {
472
- const r = await telegram.send({ chat_id, text, channel });
473
- res.status(202).json({ ok: true, message_id: r.message_id });
474
- } catch (e) {
475
- res.status(502).json({ error: e.message });
476
- }
477
- });
478
-
479
- // POST /telegram/send_photo { chat_id?, photo (path|url), caption?, channel? }
480
- app.post("/telegram/send_photo", async (req, res) => {
481
- const { chat_id, photo, caption, parse_mode, channel } = req.body || {};
482
- if (!photo) return res.status(400).json({ error: "photo required (path or url)" });
483
- if (!telegram) return res.status(503).json({ error: "telegram plugin not loaded" });
484
- try {
485
- const r = await telegram.sendPhoto({ chat_id, photo, caption, parse_mode, channel });
486
- res.status(202).json({ ok: true, message_id: r?.message_id });
487
- } catch (e) {
488
- res.status(502).json({ error: e.message });
489
- }
490
- });
491
-
492
- // POST /telegram/send_voice { chat_id?, audio (path), caption?, duration?, channel? }
493
- app.post("/telegram/send_voice", async (req, res) => {
494
- const { chat_id, audio, caption, duration, channel } = req.body || {};
495
- if (!audio) return res.status(400).json({ error: "audio required (path)" });
496
- if (!telegram) return res.status(503).json({ error: "telegram plugin not loaded" });
497
- try {
498
- const r = await telegram.sendVoice({ chat_id, audio, caption, duration, channel });
499
- res.status(202).json({ ok: true, message_id: r?.message_id });
500
- } catch (e) {
501
- res.status(502).json({ error: e.message });
502
- }
503
- });
504
-
505
- // POST /telegram/send_audio { chat_id?, audio (path), caption?, title?, performer?, channel? }
506
- app.post("/telegram/send_audio", async (req, res) => {
507
- const { chat_id, audio, caption, title, performer, channel } = req.body || {};
508
- if (!audio) return res.status(400).json({ error: "audio required (path)" });
509
- if (!telegram) return res.status(503).json({ error: "telegram plugin not loaded" });
510
- try {
511
- const r = await telegram.sendAudio({ chat_id, audio, caption, title, performer, channel });
512
- res.status(202).json({ ok: true, message_id: r?.message_id });
513
- } catch (e) {
514
- res.status(502).json({ error: e.message });
515
- }
516
- });
517
-
518
- // POST /telegram/notify — alias for /telegram/send for proactive daemon notifications
519
- // Any internal daemon code (routines, error handlers, MCP failure hooks) can POST here
520
- // to push a message to the user without waiting for a user-initiated request.
521
- app.post("/telegram/notify", async (req, res) => {
522
- const { chat_id, text, channel } = req.body || {};
523
- if (!text) return res.status(400).json({ error: "text required" });
524
- if (!telegram) return res.status(503).json({ error: "telegram plugin not loaded" });
525
- try {
526
- const r = await telegram.send({ chat_id, text, channel });
527
- res.status(202).json({ ok: true, message_id: r.message_id, via: "notify" });
528
- } catch (e) {
529
- res.status(502).json({ error: e.message });
530
- }
531
- });
532
-
533
- // ---- Plugins -----------------------------------------------------
534
- app.get("/plugins", (_req, res) => {
535
- if (!plugins) return res.json({});
536
- res.json(plugins.status());
537
- });
538
-
539
- app.get("/plugins/:id/status", (req, res) => {
540
- if (!plugins) return res.status(404).end();
541
- const inst = plugins.get(req.params.id);
542
- if (!inst) return res.status(404).json({ error: `plugin ${req.params.id} not loaded` });
543
- res.json(inst.status?.() || {});
544
- });
545
-
546
- // ---- Engines & Conversations -------------------------------------
547
- app.get("/engines", (_req, res) => res.json({ engines: ENGINE_IDS }));
548
-
549
- // POST /projects/:pid/agents/:slug/exec
550
- app.post("/projects/:pid/agents/:slug/exec", async (req, res) => {
551
- const p = project(req, res);
552
- if (!p) return;
553
- const { prompt, model: modelOverride, temperature, maxTokens } = req.body || {};
554
- if (!prompt) return res.status(400).json({ error: "prompt required" });
555
- const agents = readAgents(p.path);
556
- const agent = agents.find((a) => a.slug === req.params.slug);
557
- if (!agent) return res.status(404).json({ error: "agent not found" });
558
- const modelId = modelOverride || agent.fields.Model;
559
- if (!modelId) return res.status(400).json({ error: "agent has no model and none provided" });
560
-
561
- try {
562
- const system = buildAgentSystem(p, agent, { invocation: "engine" });
563
- const conv = startConversation({ storagePath: p.storagePath, agentSlug: agent.slug, engine: modelId, system });
564
- appendTurn({ filePath: conv.path, role: "user", content: prompt });
565
-
566
- const result = await callEngine({
567
- modelId,
568
- system,
569
- messages: [{ role: "user", content: prompt }],
570
- config: p.config || config,
571
- temperature,
572
- maxTokens,
573
- });
574
-
575
- appendTurn({ filePath: conv.path, role: "assistant", content: result.text });
576
- setStatus(conv.path, "closed");
577
-
578
- p.logMessage({ agent_slug: agent.slug, channel: "engine", direction: "in", author: "user", body: prompt, meta: { conversation: conv.id } });
579
- p.logMessage({ agent_slug: agent.slug, channel: "engine", direction: "out", author: agent.slug, body: result.text, meta: { conversation: conv.id, usage: result.usage } });
580
-
581
- projects.rebuild(p.id);
582
- res.json({
583
- conversation: { id: conv.id, filename: conv.filename, path: conv.path },
584
- text: result.text,
585
- usage: result.usage,
586
- engine: modelId,
587
- });
588
- } catch (e) {
589
- res.status(500).json({ error: e.message });
590
- }
591
- });
592
-
593
- // POST /projects/:pid/agents/:slug/chat
594
- app.post("/projects/:pid/agents/:slug/chat", async (req, res) => {
595
- const p = project(req, res);
596
- if (!p) return;
597
- const { prompt, conversation_id, model: modelOverride, temperature, maxTokens } = req.body || {};
598
- if (!prompt) return res.status(400).json({ error: "prompt required" });
599
- const agents = readAgents(p.path);
600
- const agent = agents.find((a) => a.slug === req.params.slug);
601
- if (!agent) return res.status(404).json({ error: "agent not found" });
602
- const modelId = modelOverride || agent.fields.Model;
603
- if (!modelId) return res.status(400).json({ error: "agent has no model and none provided" });
604
-
605
- try {
606
- let convPath;
607
- let convId;
608
- let history = [];
609
- let compactSummary = null;
610
-
611
- if (conversation_id) {
612
- const existing = readConversation(p.storagePath, agent.slug, conversation_id);
613
- if (!existing) return res.status(404).json({ error: `conversation ${conversation_id} not found` });
614
- convPath = existing.path;
615
- convId = conversation_id;
616
- // Extract compact summary if present — inject into system instead of messages.
617
- const compactTurn = existing.turns.find((t) => t.role === "compact");
618
- if (compactTurn) {
619
- // Strip the "[Compacted N turns on ...]" header line from the summary body
620
- compactSummary = compactTurn.content.replace(/^\[Compacted \d+ turns.*?\]\n\n?/, "").trim();
621
- }
622
- history = existing.turns
623
- .filter((t) => t.role === "user" || t.role === "assistant")
624
- .map((t) => ({ role: t.role, content: t.content }));
625
- }
626
-
627
- // Build system prompt — inject compact summary if this conversation was compacted.
628
- const extraParts = compactSummary
629
- ? [`## Previous Conversation Context (Compacted)\n${compactSummary}`]
630
- : [];
631
- const system = buildAgentSystem(p, agent, { invocation: "engine", extraParts });
632
-
633
- if (!conversation_id) {
634
- const conv = startConversation({ storagePath: p.storagePath, agentSlug: agent.slug, engine: modelId, system });
635
- convPath = conv.path;
636
- convId = conv.id;
637
- }
638
-
639
- appendTurn({ filePath: convPath, role: "user", content: prompt });
640
- history.push({ role: "user", content: prompt });
641
-
642
- const result = await callEngine({ modelId, system, messages: history, config: p.config || config, temperature, maxTokens });
643
- appendTurn({ filePath: convPath, role: "assistant", content: result.text });
644
- projects.rebuild(p.id);
645
-
646
- res.json({
647
- conversation_id: convId,
648
- text: result.text,
649
- usage: result.usage,
650
- engine: modelId,
651
- compacted: !!compactSummary,
652
- });
653
- } catch (e) {
654
- res.status(500).json({ error: e.message });
655
- }
656
- });
657
-
658
- // POST /projects/:pid/super-agent/chat
659
- app.post("/projects/:pid/super-agent/chat/stream", async (req, res) => {
660
- const p = project(req, res);
661
- if (!p) return;
662
- const { prompt, contextNote, previousMessages, model } = req.body || {};
663
- if (!prompt) return res.status(400).json({ error: "prompt required" });
664
-
665
- res.setHeader("content-type", "application/x-ndjson; charset=utf-8");
666
- res.setHeader("cache-control", "no-cache, no-transform");
667
- res.setHeader("x-accel-buffering", "no");
668
- res.flushHeaders?.();
669
-
670
- const send = (event) => {
671
- res.write(JSON.stringify(event) + "\n");
672
- };
673
-
674
- try {
675
- const saResult = await runSuperAgent({
676
- globalConfig: config,
677
- projects,
678
- plugins,
679
- registries,
680
- prompt,
681
- contextNote: contextNote || `Context: Project ${p.id} (${p.name}) at ${p.path}`,
682
- previousMessages: previousMessages || [],
683
- overrideModel: model,
684
- onEvent: send,
685
- });
686
- projects.rebuild(p.id);
687
- send({
688
- type: "final",
689
- result: {
690
- text: saResult.text,
691
- usage: saResult.usage,
692
- name: saResult.name,
693
- trace: saResult.trace,
694
- },
695
- });
696
- res.end();
697
- } catch (e) {
698
- appendSuperAgentErrorTrace(req, e, { prompt, contextNote, previousMessages, model, stream: true });
699
- send({ type: "error", trace_id: req.apxTraceId, error: `${e.message} (trace: ${req.apxTraceId})` });
700
- res.end();
701
- }
702
- });
703
-
704
- app.post("/projects/:pid/super-agent/chat", async (req, res) => {
705
- const p = project(req, res);
706
- if (!p) return;
707
- const { prompt, contextNote, previousMessages, model } = req.body || {};
708
- if (!prompt) return res.status(400).json({ error: "prompt required" });
709
- try {
710
- const saResult = await runSuperAgent({
711
- globalConfig: config,
712
- projects,
713
- plugins,
714
- registries,
715
- prompt,
716
- contextNote: contextNote || `Context: Project ${p.id} (${p.name}) at ${p.path}`,
717
- previousMessages: previousMessages || [],
718
- overrideModel: model,
719
- });
720
- projects.rebuild(p.id);
721
- res.json({
722
- text: saResult.text,
723
- usage: saResult.usage,
724
- name: saResult.name,
725
- trace: saResult.trace,
726
- });
727
- } catch (e) {
728
- appendSuperAgentErrorTrace(req, e, { prompt, contextNote, previousMessages, model, stream: false });
729
- res.status(500).json({ error: e.message, trace_id: req.apxTraceId });
730
- }
731
- });
732
-
733
- // GET /projects/:pid/agents/:slug/conversations
734
- app.get("/projects/:pid/agents/:slug/conversations", (req, res) => {
735
- const p = project(req, res);
736
- if (!p) return;
737
- const agents = readAgents(p.path);
738
- if (!agents.find((a) => a.slug === req.params.slug))
739
- return res.status(404).json({ error: "agent not found" });
740
- res.json(listConversations(p.storagePath, req.params.slug));
741
- });
742
-
743
- // GET /projects/:pid/agents/:slug/conversations/:id
744
- app.get("/projects/:pid/agents/:slug/conversations/:id", (req, res) => {
745
- const p = project(req, res);
746
- if (!p) return;
747
- const conv = readConversation(p.storagePath, req.params.slug, req.params.id);
748
- if (!conv) return res.status(404).json({ error: "conversation not found" });
749
- res.json(conv);
750
- });
751
-
752
- // POST /projects/:pid/agents/:slug/compact ← compacts the latest conversation
753
- // POST /projects/:pid/agents/:slug/conversations/:id/compact ← compacts a specific one
754
- async function handleCompact(req, res, filename) {
755
- const p = project(req, res);
756
- if (!p) return;
757
- const agents = readAgents(p.path);
758
- const agent = agents.find((a) => a.slug === req.params.slug);
759
- if (!agent) return res.status(404).json({ error: "agent not found" });
760
- const modelId = (req.body || {}).model || agent.fields.Model;
761
- if (!modelId) return res.status(400).json({ error: "agent has no model" });
762
- try {
763
- const result = await compactConversation({
764
- storagePath: p.storagePath,
765
- agentSlug: agent.slug,
766
- filename: filename || null,
767
- modelId,
768
- config: p.config || config,
769
- });
770
- res.json(result);
771
- } catch (e) {
772
- res.status(500).json({ error: e.message });
773
- }
774
- }
775
-
776
- app.post("/projects/:pid/agents/:slug/compact", (req, res) =>
777
- handleCompact(req, res, null)
778
- );
779
-
780
- app.post("/projects/:pid/agents/:slug/conversations/:id/compact", (req, res) =>
781
- handleCompact(req, res, req.params.id)
782
- );
783
-
784
- // ---- Agent-to-agent routing --------------------------------------
785
- app.post("/projects/:pid/send", async (req, res) => {
786
- const p = project(req, res);
787
- if (!p) return;
788
- const { from, to, body, deliver = false, _depth = 0 } = req.body || {};
789
- if (!from || !to || !body)
790
- return res.status(400).json({ error: "from, to, body required" });
791
- if (_depth > 3)
792
- return res.status(429).json({ error: "a2a depth limit (3) exceeded" });
793
-
794
- const agents = readAgents(p.path);
795
- const fromAgent = agents.find((a) => a.slug === from);
796
- const toAgent = agents.find((a) => a.slug === to);
797
- if (!fromAgent) return res.status(404).json({ error: `from agent "${from}" not found` });
798
- if (!toAgent) return res.status(404).json({ error: `to agent "${to}" not found` });
799
-
800
- const ts = nowIso();
801
- p.logMessage({ agent_slug: from, channel: "a2a", direction: "out", author: from, body, meta: { to, depth: _depth }, ts });
802
- p.logMessage({ agent_slug: to, channel: "a2a", direction: "in", author: from, body, meta: { from, depth: _depth }, ts });
803
-
804
- let reply = null;
805
- if (deliver && toAgent.fields.Model) {
806
- try {
807
- const tf = toAgent.fields;
808
- const parts = [];
809
- if (tf.Description) parts.push(tf.Description);
810
- if (tf.Role) parts.push(`Role: ${tf.Role}`);
811
- if (tf.Language) parts.push(`Default language: ${tf.Language}`);
812
- parts.push(`You are ${toAgent.slug}. You just received a message from ${fromAgent.slug}. Reply concisely.`);
813
- const memPath = path.join(p.path, ".apc", "agents", toAgent.slug, "memory.md");
814
- if (fs.existsSync(memPath)) parts.push("## Memory\n" + fs.readFileSync(memPath, "utf8"));
815
-
816
- const result = await callEngine({
817
- modelId: toAgent.fields.Model,
818
- system: parts.join("\n\n"),
819
- messages: [{ role: "user", content: `From ${fromAgent.slug}:\n\n${body}` }],
820
- config: p.config || config,
821
- });
822
-
823
- p.logMessage({ agent_slug: to, channel: "a2a", direction: "out", author: to, body: result.text, meta: { to: from, depth: _depth + 1, reply_to: fromAgent.slug, usage: result.usage } });
824
- p.logMessage({ agent_slug: from, channel: "a2a", direction: "in", author: to, body: result.text, meta: { from: to, depth: _depth + 1 } });
825
- reply = { text: result.text, usage: result.usage };
826
- } catch (e) {
827
- reply = { error: e.message };
828
- }
829
- }
830
-
831
- res.json({ from, to, body, ts, reply });
832
- });
833
-
834
- // GET /projects/:pid/agents/:slug/connections
835
- app.get("/projects/:pid/agents/:slug/connections", (req, res) => {
836
- const p = project(req, res);
837
- if (!p) return;
838
- const agents = readAgents(p.path);
839
- if (!agents.find((a) => a.slug === req.params.slug))
840
- return res.status(404).json({ error: "agent not found" });
841
-
842
- const messages = readProjectMessages(p.storagePath, { agent_slug: req.params.slug });
843
- const peers = new Map();
844
- for (const m of messages) {
845
- const peer = m.meta?.from || m.meta?.to || null;
846
- if (!peer) continue;
847
- const key = `${peer}|${m.channel}|${m.direction}`;
848
- const existing = peers.get(key);
849
- if (!existing) {
850
- peers.set(key, { peer, channel: m.channel, direction: m.direction, n: 1, last_ts: m.ts });
851
- } else {
852
- existing.n++;
853
- if (m.ts > existing.last_ts) existing.last_ts = m.ts;
854
- }
855
- }
856
- res.json(
857
- Array.from(peers.values()).sort((a, b) => (b.last_ts || "").localeCompare(a.last_ts || ""))
858
- );
859
- });
860
-
861
- // ---- Runtimes (external CLI agents) -------------------------------
862
- app.get("/runtimes", (_req, res) => res.json({ runtimes: RUNTIME_IDS }));
863
-
864
- app.get("/env/detect", async (_req, res) => {
865
- const detected = await detectAll();
866
- res.json(detected);
867
- });
868
-
869
- // POST /projects/:pid/agents/:slug/runtime
870
- app.post("/projects/:pid/agents/:slug/runtime", async (req, res) => {
871
- const p = project(req, res);
872
- if (!p) return;
873
- const { runtime, prompt, timeoutMs } = req.body || {};
874
- if (!runtime || !prompt)
875
- return res.status(400).json({ error: "runtime and prompt required" });
876
-
877
- const agents = readAgents(p.path);
878
- const agent = agents.find((a) => a.slug === req.params.slug);
879
- if (!agent) return res.status(404).json({ error: "agent not found" });
880
-
881
- let rt;
882
- try {
883
- rt = getRuntime(runtime);
884
- } catch (e) {
885
- return res.status(400).json({ error: e.message });
886
- }
887
-
888
- let projectName = path.basename(p.path);
889
- try {
890
- const meta = JSON.parse(fs.readFileSync(path.join(p.path, ".apc", "project.json"), "utf8"));
891
- if (meta.name) projectName = meta.name;
892
- } catch {}
893
-
894
- const session = createRuntimeSession({
895
- projectRoot: p.path,
896
- storageRoot: p.storagePath,
897
- agentSlug: agent.slug,
898
- runtime,
899
- title: req.body?.title,
900
- taskRef: req.body?.task_ref || "",
901
- });
902
-
903
- const system = buildAgentSystem(p, agent, {
904
- invocation: "runtime",
905
- runtime,
906
- extraParts: [
907
- buildApfHint({
908
- projectName,
909
- projectPath: p.path,
910
- agentSlug: agent.slug,
911
- sessionId: session.id,
912
- }),
913
- ],
914
- });
915
-
916
- try {
917
- const r = await rt.run({
918
- system,
919
- prompt,
920
- cwd: p.path,
921
- timeoutMs: timeoutMs || 5 * 60 * 1000,
922
- });
923
-
924
- const apfResult = extractApfResult(r.output) || (r.output || "").slice(0, 200);
925
- closeRuntimeSession({ filePath: session.path, externalSessionPath: r.externalSessionPath || null, exitCode: r.exitCode, result: apfResult });
926
-
927
- p.logMessage({ agent_slug: agent.slug, channel: "runtime", direction: "in", author: "user", body: prompt, meta: { runtime, apc_session: session.id } });
928
- p.logMessage({ agent_slug: agent.slug, channel: "runtime", direction: "out", author: agent.slug, body: r.output || "", meta: { runtime, exit_code: r.exitCode, external_session_path: r.externalSessionPath || null, session_id: r.sessionId || null, apc_session: session.id } });
929
- projects.rebuild(p.id);
930
-
931
- res.json({
932
- runtime,
933
- exit_code: r.exitCode,
934
- output: r.output,
935
- stderr: r.stderr,
936
- external_session_path: r.externalSessionPath || null,
937
- session_id: r.sessionId || null,
938
- apc_session: session.id,
939
- });
940
- } catch (e) {
941
- try {
942
- closeRuntimeSession({ filePath: session.path, exitCode: -1, result: `error: ${e.message.slice(0, 200)}` });
943
- } catch {}
944
- res.status(500).json({ error: e.message, apc_session: session.id });
945
- }
946
- });
947
-
948
- // ---- Session resume -----------------------------------------------
949
- app.get("/projects/:pid/sessions/:id/resume", async (req, res) => {
950
- const p = project(req, res);
951
- if (!p) return;
952
- const { id } = req.params;
953
-
954
- const sessionRoots = [
955
- path.join(p.storagePath || p.path, "agents"),
956
- path.join(p.path, ".apc", "agents"),
957
- ];
958
- let sessionFile = null;
959
- let agentSlug = null;
960
- for (const agentsDir of sessionRoots) {
961
- if (!fs.existsSync(agentsDir)) continue;
962
- for (const slug of fs.readdirSync(agentsDir)) {
963
- const f = path.join(agentsDir, slug, "sessions", `${id}.md`);
964
- if (fs.existsSync(f)) {
965
- sessionFile = f;
966
- agentSlug = slug;
967
- break;
968
- }
969
- }
970
- if (sessionFile) break;
971
- }
972
- if (!sessionFile) return res.status(404).json({ error: `session ${id} not found` });
973
-
974
- const session = readSessionFrontmatter(sessionFile);
975
- const out = {
976
- id,
977
- agent: agentSlug,
978
- session_path: sessionFile,
979
- frontmatter: session?.fm || {},
980
- external_transcript: null,
981
- summary: null,
982
- };
983
-
984
- const externalPath = session?.fm?.external_session_path;
985
- if (externalPath && fs.existsSync(externalPath)) {
986
- const stat = fs.statSync(externalPath);
987
- const raw = fs.readFileSync(externalPath, "utf8");
988
- out.external_transcript = {
989
- path: externalPath,
990
- size: stat.size,
991
- tail: raw.length > 32 * 1024 ? raw.slice(-32 * 1024) : raw,
992
- };
993
- }
994
-
995
- if (req.query.summarize === "true" && isSuperAgentEnabled(config)) {
996
- try {
997
- const prompt =
998
- `Summarize what happened in this APC session in 4 concrete bullets.\n\n` +
999
- `Frontmatter:\n${JSON.stringify(out.frontmatter, null, 2)}\n\n` +
1000
- (out.external_transcript
1001
- ? `External transcript (last ${out.external_transcript.tail.length} chars):\n${out.external_transcript.tail}`
1002
- : `(no external transcript)`);
1003
- const sa = await runSuperAgent({ globalConfig: config, projects, plugins, registries, prompt, contextNote: `Resume request for session ${id}.` });
1004
- out.summary = sa.text;
1005
- } catch (e) {
1006
- out.summary = `(super-agent failed: ${e.message})`;
1007
- }
1008
- }
1009
-
1010
- res.json(out);
1011
- });
1012
-
1013
- // ---- Routines (per-project scheduled tasks) ----------------------
1014
- app.get("/projects/:pid/routines", (req, res) => {
1015
- const p = project(req, res);
1016
- if (!p) return;
1017
- res.json(listRoutines(p.storagePath));
1018
- });
1019
-
1020
- app.get("/projects/:pid/routines/:name", (req, res) => {
1021
- const p = project(req, res);
1022
- if (!p) return;
1023
- const r = getRoutine(p.storagePath, req.params.name);
1024
- if (!r) return res.status(404).json({ error: "routine not found" });
1025
- res.json(r);
1026
- });
1027
-
1028
- app.post("/projects/:pid/routines", (req, res) => {
1029
- const p = project(req, res);
1030
- if (!p) return;
1031
- try {
1032
- // Pass all fields including pipeline extensions.
1033
- const r = upsertRoutine(p.storagePath, req.body || {});
1034
- res.status(201).json(r);
1035
- } catch (e) {
1036
- res.status(400).json({ error: e.message });
1037
- }
1038
- });
1039
-
1040
- // ---- Artifacts (managed files in storagePath/artifacts/) ---------
1041
- app.get("/projects/:pid/artifacts", (req, res) => {
1042
- const p = project(req, res);
1043
- if (!p) return;
1044
- res.json(listArtifacts(p.storagePath));
1045
- });
1046
-
1047
- app.post("/projects/:pid/artifacts", (req, res) => {
1048
- const p = project(req, res);
1049
- if (!p) return;
1050
- const { name, content = "" } = req.body || {};
1051
- if (!name) return res.status(400).json({ error: "name required" });
1052
- try {
1053
- const filePath = createArtifact(p.storagePath, name, content);
1054
- res.status(201).json({ name, path: filePath });
1055
- } catch (e) {
1056
- res.status(400).json({ error: e.message });
1057
- }
1058
- });
1059
-
1060
- app.get("/projects/:pid/artifacts/:name", (req, res) => {
1061
- const p = project(req, res);
1062
- if (!p) return;
1063
- try {
1064
- res.json(readArtifact(p.storagePath, decodeURIComponent(req.params.name)));
1065
- } catch (e) {
1066
- res.status(404).json({ error: e.message });
1067
- }
1068
- });
1069
-
1070
- app.delete("/projects/:pid/artifacts/:name", (req, res) => {
1071
- const p = project(req, res);
1072
- if (!p) return;
1073
- const ok = removeArtifact(p.storagePath, decodeURIComponent(req.params.name));
1074
- res.status(ok ? 204 : 404).end();
1075
- });
1076
-
1077
- app.delete("/projects/:pid/routines/:name", (req, res) => {
1078
- const p = project(req, res);
1079
- if (!p) return;
1080
- const ok = deleteRoutine(p.storagePath, req.params.name);
1081
- res.status(ok ? 204 : 404).end();
1082
- });
1083
-
1084
- app.post("/projects/:pid/routines/:name/enable", (req, res) => {
1085
- const p = project(req, res);
1086
- if (!p) return;
1087
- setRoutineEnabled(p.storagePath, req.params.name, true);
1088
- res.json({ ok: true });
1089
- });
1090
-
1091
- app.post("/projects/:pid/routines/:name/disable", (req, res) => {
1092
- const p = project(req, res);
1093
- if (!p) return;
1094
- setRoutineEnabled(p.storagePath, req.params.name, false);
1095
- res.json({ ok: true });
1096
- });
1097
-
1098
- app.post("/projects/:pid/routines/:name/run", async (req, res) => {
1099
- const p = project(req, res);
1100
- if (!p) return;
1101
- const r = getRoutine(p.storagePath, req.params.name);
1102
- if (!r) return res.status(404).json({ error: "routine not found" });
1103
- try {
1104
- const result = await runRoutineNow({ project: p, projects, plugins, registries, globalConfig: config }, r);
1105
- res.json(result);
1106
- } catch (e) {
1107
- res.status(500).json({ error: e.message });
1108
- }
1109
- });
1110
-
1111
- // ---- Per-project config (.apc/config.json) -----------------------
1112
- app.get("/projects/:pid/config", (req, res) => {
1113
- const p = project(req, res);
1114
- if (!p) return;
1115
- res.json({
1116
- effective: p.config || {},
1117
- project_only: readProjectConfig(p.path),
1118
- project_config_path: path.join(p.path, ".apc", "config.json"),
1119
- });
1120
- });
1121
-
1122
- app.put("/projects/:pid/config", (req, res) => {
1123
- const p = project(req, res);
1124
- if (!p) return;
1125
- const body = req.body || {};
1126
- if (typeof body !== "object" || Array.isArray(body))
1127
- return res.status(400).json({ error: "body must be a JSON object" });
1128
- writeProjectConfig(p.path, body);
1129
- projects.rebuild(p.id);
1130
- res.json({ ok: true });
1131
- });
1132
-
1133
- app.patch("/projects/:pid/config", (req, res) => {
1134
- const p = project(req, res);
1135
- if (!p) return;
1136
- const { set, unset } = req.body || {};
1137
- const cfg = readProjectConfig(p.path);
1138
- if (set && typeof set === "object") {
1139
- for (const [k, v] of Object.entries(set)) setDottedKey(cfg, k, v);
1140
- }
1141
- if (Array.isArray(unset)) {
1142
- for (const k of unset) unsetDottedKey(cfg, k);
1143
- }
1144
- writeProjectConfig(p.path, cfg);
1145
- projects.rebuild(p.id);
1146
- res.json({ ok: true, project_only: cfg });
1147
- });
1148
-
1149
- // ---- Run (bash execution) -----------------------------------------
1150
- // POST /run { cmd, cwd?, project?, timeout_ms? }
1151
- // Executes a shell command and returns stdout + stderr.
1152
- // `cwd` defaults to the project path (by id or first registered), or process.cwd().
1153
- app.post("/run", (req, res) => {
1154
- const { cmd, cwd: cwdOverride, project: projectRef, timeout_ms = 30000 } = req.body || {};
1155
- if (!cmd) return res.status(400).json({ error: "cmd required" });
1156
-
1157
- // Resolve working directory
1158
- let cwd = cwdOverride || null;
1159
- if (!cwd) {
1160
- let entry = null;
1161
- if (projectRef !== undefined && projectRef !== null) {
1162
- const all = projects.list();
1163
- const ref = String(projectRef);
1164
- entry = all.find((p) => String(p.id) === ref || p.path === path.resolve(ref));
1165
- }
1166
- if (!entry) {
1167
- const all = projects.list().filter((p) => p.id !== 0);
1168
- entry = all[0] || projects.get(0);
1169
- }
1170
- cwd = entry ? entry.path : process.cwd();
1171
- }
1172
-
1173
- const timeout = Math.min(Math.max(parseInt(timeout_ms, 10) || 30000, 1000), 300000);
1174
-
1175
- execFile("bash", ["-c", cmd], { cwd, timeout, maxBuffer: 4 * 1024 * 1024 }, (err, stdout, stderr) => {
1176
- const exit_code = err?.code ?? (err ? 1 : 0);
1177
- res.json({
1178
- ok: !err || exit_code === 0,
1179
- exit_code,
1180
- stdout: stdout || "",
1181
- stderr: stderr || "",
1182
- cwd,
1183
- });
1184
- });
1185
- });
1186
-
1187
- // ---- Top-level memory shortcuts -----------------------------------
1188
- // GET /memory?project=<id> → reads default agent memory.md
1189
- // POST /memory?project=<id> { body } → writes it
1190
- //
1191
- // Targets the *first non-default agent* of the resolved project,
1192
- // or falls back to a bare memory.md in .apc/ root.
1193
-
1194
- function resolveTopProject(query) {
1195
- const ref = query?.project;
1196
- if (ref !== undefined && ref !== null) {
1197
- const all = projects.list();
1198
- const r = String(ref);
1199
- return projects.get(all.find((p) => String(p.id) === r || p.path === path.resolve(r))?.id);
1200
- }
1201
- const all = projects.list().filter((p) => p.id !== 0);
1202
- return all.length ? projects.get(all[0].id) : projects.get(0);
1203
- }
1204
-
1205
- function resolveMemoryPath(p) {
1206
- const agentsDir = path.join(p.path, ".apc", "agents");
1207
- if (fs.existsSync(agentsDir)) {
1208
- const slugs = fs.readdirSync(agentsDir).filter((s) => {
1209
- const mp = path.join(agentsDir, s, "memory.md");
1210
- return fs.statSync(path.join(agentsDir, s)).isDirectory();
1211
- });
1212
- if (slugs.length) return path.join(agentsDir, slugs[0], "memory.md");
1213
- }
1214
- return path.join(p.path, ".apc", "memory.md");
1215
- }
1216
-
1217
- app.get("/memory", (req, res) => {
1218
- const p = resolveTopProject(req.query);
1219
- if (!p) return res.status(404).json({ error: "no project registered" });
1220
- const memPath = resolveMemoryPath(p);
1221
- const body = fs.existsSync(memPath) ? fs.readFileSync(memPath, "utf8") : "";
1222
- res.json({ project_id: p.id, path: memPath, body });
1223
- });
1224
-
1225
- app.post("/memory", (req, res) => {
1226
- const p = resolveTopProject(req.query);
1227
- if (!p) return res.status(404).json({ error: "no project registered" });
1228
- const { body } = req.body || {};
1229
- if (typeof body !== "string") return res.status(400).json({ error: "body must be string" });
1230
- const memPath = resolveMemoryPath(p);
1231
- fs.mkdirSync(path.dirname(memPath), { recursive: true });
1232
- fs.writeFileSync(memPath, body);
1233
- try { projects.rebuild(p.id); } catch {}
1234
- res.json({ ok: true, path: memPath, bytes: Buffer.byteLength(body, "utf8") });
1235
- });
1236
-
1237
- // ---- Top-level file shortcuts -------------------------------------
1238
- // GET /files?path=<rel>&project=<id> → read file contents
1239
- // POST /files?project=<id> { path, content } → write file
1240
-
1241
- app.get("/files", (req, res) => {
1242
- const p = resolveTopProject(req.query);
1243
- if (!p) return res.status(404).json({ error: "no project registered" });
1244
- const rel = req.query.path;
1245
- if (!rel) {
1246
- // List top-level files of the project
1247
- try {
1248
- const entries = fs.readdirSync(p.path).map((name) => {
1249
- const full = path.join(p.path, name);
1250
- const stat = fs.statSync(full);
1251
- return { name, type: stat.isDirectory() ? "dir" : "file", size: stat.isDirectory() ? null : stat.size };
1252
- });
1253
- return res.json({ project_id: p.id, cwd: p.path, entries });
1254
- } catch (e) {
1255
- return res.status(500).json({ error: e.message });
1256
- }
1257
- }
1258
- const abs = path.resolve(p.path, rel);
1259
- if (!abs.startsWith(path.resolve(p.path))) return res.status(403).json({ error: "path escapes project root" });
1260
- if (!fs.existsSync(abs)) return res.status(404).json({ error: "not found" });
1261
- const stat = fs.statSync(abs);
1262
- if (stat.isDirectory()) {
1263
- const entries = fs.readdirSync(abs).map((name) => {
1264
- const s = fs.statSync(path.join(abs, name));
1265
- return { name, type: s.isDirectory() ? "dir" : "file", size: s.isDirectory() ? null : s.size };
1266
- });
1267
- return res.json({ project_id: p.id, path: rel, type: "dir", entries });
1268
- }
1269
- const content = fs.readFileSync(abs, "utf8");
1270
- res.json({ project_id: p.id, path: rel, type: "file", size: stat.size, content });
1271
- });
1272
-
1273
- app.post("/files", (req, res) => {
1274
- const p = resolveTopProject(req.query);
1275
- if (!p) return res.status(404).json({ error: "no project registered" });
1276
- const { path: rel, content } = req.body || {};
1277
- if (!rel) return res.status(400).json({ error: "path required" });
1278
- if (typeof content !== "string") return res.status(400).json({ error: "content must be string" });
1279
- const abs = path.resolve(p.path, rel);
1280
- if (!abs.startsWith(path.resolve(p.path))) return res.status(403).json({ error: "path escapes project root" });
1281
- fs.mkdirSync(path.dirname(abs), { recursive: true });
1282
- fs.writeFileSync(abs, content);
1283
- res.json({ ok: true, path: rel, bytes: Buffer.byteLength(content, "utf8") });
1284
- });
1285
-
1286
- // ---- Top-level MCP shortcuts --------------------------------------
1287
- // GET /mcp?project=<id> → list MCPs
1288
- // POST /mcp/run { project?, name, tool, params } → call MCP tool
1289
-
1290
- app.get("/mcp", (req, res) => {
1291
- const p = resolveTopProject(req.query);
1292
- if (!p) return res.status(404).json({ error: "no project registered" });
1293
- res.json(registries.for(p).list());
1294
- });
1295
-
1296
- app.post("/mcp/run", async (req, res) => {
1297
- const { project: projectRef, name, tool, params } = req.body || {};
1298
- if (!name) return res.status(400).json({ error: "name required" });
1299
- if (!tool) return res.status(400).json({ error: "tool required" });
1300
- const p = resolveTopProject({ project: projectRef });
1301
- if (!p) return res.status(404).json({ error: "no project registered" });
1302
- try {
1303
- const result = await registries.for(p).call(name, tool, params);
1304
- res.json({ ok: true, result });
1305
- } catch (e) {
1306
- res.status(500).json({ error: e.message });
1307
- }
1308
- });
1309
-
1310
- // ---- Session search (cross-agent, cross-conversation) ------------
1311
- // GET /sessions/search?q=...&project=...&limit=20
1312
- // Searches session files (.apc/agents/{slug}/sessions/*.md) and
1313
- // conversation files (~/.apx/.../conversations/*.md) by text content.
1314
- app.get("/sessions/search", (req, res) => {
1315
- const { q, project: projectRef, limit = "20" } = req.query;
1316
- if (!q) return res.status(400).json({ error: "q required" });
1317
- const lim = Math.min(parseInt(limit, 10) || 20, 200);
1318
- const needle = q.toLowerCase();
1319
-
1320
- // Resolve project (or search all)
1321
- const allProjects = projects.list();
1322
- const targetProjects = (() => {
1323
- if (projectRef != null) {
1324
- const ref = String(projectRef);
1325
- const found = allProjects.find((p) => String(p.id) === ref || p.path === path.resolve(ref));
1326
- return found ? [projects.get(found.id)] : [];
1327
- }
1328
- return allProjects.map((p) => projects.get(p.id)).filter(Boolean);
1329
- })();
1330
-
1331
- const matches = [];
1332
-
1333
- for (const p of targetProjects) {
1334
- if (!p) continue;
1335
-
1336
- // 1. Search session files in project (.apc/agents/{slug}/sessions/)
1337
- const sessionAgentsDir = path.join(p.path, ".apc", "agents");
1338
- if (fs.existsSync(sessionAgentsDir)) {
1339
- for (const slug of fs.readdirSync(sessionAgentsDir)) {
1340
- const sessionsDir = path.join(sessionAgentsDir, slug, "sessions");
1341
- if (!fs.existsSync(sessionsDir)) continue;
1342
- for (const f of fs.readdirSync(sessionsDir).filter((x) => x.endsWith(".md"))) {
1343
- const filePath = path.join(sessionsDir, f);
1344
- try {
1345
- const text = fs.readFileSync(filePath, "utf8");
1346
- if (text.toLowerCase().includes(needle)) {
1347
- // Find matching excerpt
1348
- const lines = text.split("\n");
1349
- const matchLine = lines.findIndex((l) => l.toLowerCase().includes(needle));
1350
- const excerpt = lines.slice(Math.max(0, matchLine - 1), matchLine + 3).join("\n");
1351
- matches.push({
1352
- type: "session",
1353
- project: p.id,
1354
- agent: slug,
1355
- filename: f,
1356
- path: filePath,
1357
- excerpt: excerpt.slice(0, 300),
1358
- });
1359
- if (matches.length >= lim) break;
1360
- }
1361
- } catch {}
1362
- }
1363
- if (matches.length >= lim) break;
1364
- }
1365
- }
1366
-
1367
- if (matches.length >= lim) break;
1368
-
1369
- // 2. Search conversation files in daemon storage (~/.apx/.../conversations/)
1370
- const convAgentsDir = path.join(p.storagePath, "agents");
1371
- if (fs.existsSync(convAgentsDir)) {
1372
- for (const slug of fs.readdirSync(convAgentsDir)) {
1373
- const convDir = path.join(convAgentsDir, slug, "conversations");
1374
- if (!fs.existsSync(convDir)) continue;
1375
- for (const f of fs.readdirSync(convDir).filter((x) => x.endsWith(".md"))) {
1376
- const filePath = path.join(convDir, f);
1377
- try {
1378
- const text = fs.readFileSync(filePath, "utf8");
1379
- if (text.toLowerCase().includes(needle)) {
1380
- const lines = text.split("\n");
1381
- const matchLine = lines.findIndex((l) => l.toLowerCase().includes(needle));
1382
- const excerpt = lines.slice(Math.max(0, matchLine - 1), matchLine + 3).join("\n");
1383
- matches.push({
1384
- type: "conversation",
1385
- project: p.id,
1386
- agent: slug,
1387
- filename: f,
1388
- path: filePath,
1389
- excerpt: excerpt.slice(0, 300),
1390
- });
1391
- if (matches.length >= lim) break;
1392
- }
1393
- } catch {}
1394
- }
1395
- if (matches.length >= lim) break;
1396
- }
1397
- }
1398
-
1399
- if (matches.length >= lim) break;
1400
- }
1401
-
1402
- res.json({ q, count: matches.length, results: matches });
1403
- });
1404
-
1405
- // POST /sessions/:id/compact
1406
- // Shortcut: resolves which project/agent owns the session file,
1407
- // then delegates to the existing compactConversation logic.
1408
- // Body: { project?, model? }
1409
- app.post("/sessions/:id/compact", async (req, res) => {
1410
- const { id } = req.params;
1411
- const { model: modelOverride, project: projectRef } = req.body || {};
1412
-
1413
- // Find which project/agent owns this session ID
1414
- const allProjects = projectRef != null
1415
- ? (() => {
1416
- const ref = String(projectRef);
1417
- const found = projects.list().find((p) => String(p.id) === ref || p.path === path.resolve(ref));
1418
- return found ? [projects.get(found.id)] : [];
1419
- })()
1420
- : projects.list().map((p) => projects.get(p.id)).filter(Boolean);
1421
-
1422
- let found = null;
1423
- const filename = id.endsWith(".md") ? id : `${id}.md`;
1424
-
1425
- for (const p of allProjects) {
1426
- if (!p) continue;
1427
- // Search in daemon conversation storage
1428
- const agentsDir = path.join(p.storagePath, "agents");
1429
- if (fs.existsSync(agentsDir)) {
1430
- for (const slug of fs.readdirSync(agentsDir)) {
1431
- const f = path.join(agentsDir, slug, "conversations", filename);
1432
- if (fs.existsSync(f)) {
1433
- found = { p, slug };
1434
- break;
1435
- }
1436
- }
1437
- }
1438
- if (found) break;
1439
- }
1440
-
1441
- if (!found) {
1442
- return res.status(404).json({ error: `session/conversation "${id}" not found` });
1443
- }
1444
-
1445
- const { p, slug } = found;
1446
- const { readAgents: _readAgents } = await import("../core/parser.js");
1447
- const agents = _readAgents(p.path);
1448
- const agent = agents.find((a) => a.slug === slug);
1449
- const modelId = modelOverride || agent?.fields?.Model;
1450
- if (!modelId) return res.status(400).json({ error: "agent has no model; pass model in body" });
1451
-
1452
- try {
1453
- const { compactConversation } = await import("./compact.js");
1454
- const result = await compactConversation({
1455
- storagePath: p.storagePath,
1456
- agentSlug: slug,
1457
- filename,
1458
- modelId,
1459
- config: p.config || config,
1460
- });
1461
- res.json(result);
1462
- } catch (e) {
1463
- res.status(500).json({ error: e.message });
1464
- }
1465
- });
1466
-
1467
- // ---- Transcription chunk (shared: overlay, Telegram, any channel) -
1468
- // POST /transcribe/chunk ← raw audio bytes (webm, ogg, wav, mp3 …)
1469
- // Headers: X-Audio-Format, X-Language (ISO or "auto"), X-Provider (auto|local|openai)
1470
- // Returns: { ok, text, backend, language, … }
1471
- app.post("/transcribe/chunk", async (req, res) => {
1472
- const chunks = [];
1473
- req.on("data", (c) => chunks.push(c));
1474
- req.on("end", async () => {
1475
- const buf = Buffer.concat(chunks);
1476
- if (!buf.length) return res.status(400).json({ ok: false, error: "empty body" });
1477
- const format = req.headers["x-audio-format"] || "webm";
1478
- const language = req.headers["x-language"] || "auto";
1479
- const provider = req.headers["x-provider"];
1480
- try {
1481
- const { transcribeBuffer } = await import("./transcription.js");
1482
- const result = await transcribeBuffer(buf, format, {
1483
- language: language === "auto" ? undefined : language,
1484
- beam_size: 3,
1485
- ...(provider ? { provider } : {}),
1486
- });
1487
- res.json(result);
1488
- } catch (e) {
1489
- res.status(500).json({ ok: false, error: e.message });
1490
- }
1491
- });
1492
- req.on("error", (e) => res.status(500).json({ ok: false, error: e.message }));
1493
- });
1494
-
1495
- // ---- Overlay channel (voice/floating window) ----------------------
1496
- app.get("/overlay/status", (_req, res) => {
1497
- // Lazy import to avoid hard dep
1498
- import("./overlay-ws.js").then(({ overlayClients }) => {
1499
- res.json({ ok: true, connected_clients: overlayClients.size });
1500
- }).catch(() => res.json({ ok: true, connected_clients: 0 }));
1501
- });
1502
-
1503
- // POST /overlay/message ← text sent by the overlay after transcription
1504
- // Runs the super-agent and streams tokens back via WebSocket.
1505
- app.post("/overlay/message", async (req, res) => {
1506
- const { text, previousMessages = [] } = req.body || {};
1507
- if (!text) return res.status(400).json({ error: "text required" });
1508
- res.json({ ok: true }); // respond immediately; result comes via WebSocket
1509
-
1510
- // Inline execution — the overlay plugin handles the heavy lift;
1511
- // here we just trigger it if the plugin is registered.
1512
- try {
1513
- const overlayPlugin = plugins.instances.get("overlay");
1514
- if (overlayPlugin?.handleMessage) {
1515
- await overlayPlugin.handleMessage({ text, previousMessages });
1516
- }
1517
- } catch (e) {
1518
- import("./overlay-ws.js").then(({ broadcastOverlay }) => {
1519
- broadcastOverlay({ type: "error", message: e.message });
1520
- }).catch(() => {});
1521
- }
1522
- });
1523
-
1524
- // ---- Admin --------------------------------------------------------
1525
- app.post("/admin/shutdown", (_req, res) => {
1526
- res.json({ ok: true });
1527
- setTimeout(() => process.exit(0), 50);
1528
- });
1529
-
1530
- // ---- 404 catchall -------------------------------------------------
1531
- app.use((req, res) => res.status(404).json({ error: `no route ${req.method} ${req.path}` }));
1532
-
1533
- return app;
1534
- }
1535
-
1536
- // ---------------------------------------------------------------------
1537
- // Helpers
1538
- // ---------------------------------------------------------------------
1539
-
1540
- function agentToResponse(a) {
1541
- if (!a) return null;
1542
- const f = a.fields || {};
1543
- const reserved = new Set(["Role", "Model", "Language", "Description", "Skills", "Tools"]);
1544
- const extra = {};
1545
- for (const [k, v] of Object.entries(f)) {
1546
- if (!reserved.has(k)) extra[k] = v;
1547
- }
1548
- return {
1549
- slug: a.slug,
1550
- role: f.Role || null,
1551
- model: f.Model || null,
1552
- language: f.Language || null,
1553
- description: f.Description || null,
1554
- skills: Array.isArray(f.Skills) ? f.Skills : [],
1555
- tools: Array.isArray(f.Tools) ? f.Tools : [],
1556
- extra,
1557
- };
1558
- }