atoo-studio 0.0.1 → 0.0.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 (408) hide show
  1. package/LICENSE +21 -0
  2. package/README.github.md +322 -0
  3. package/README.md +112 -0
  4. package/README.npm.md +112 -0
  5. package/bin/atoo-studio.js +90 -0
  6. package/dist/src/agents/claude-code-terminal/adapter.d.ts +42 -0
  7. package/dist/src/agents/claude-code-terminal/adapter.js +166 -0
  8. package/dist/src/agents/claude-code-terminal/index.d.ts +13 -0
  9. package/dist/src/agents/claude-code-terminal/index.js +45 -0
  10. package/dist/src/agents/claude-code-terminal/spawner.d.ts +9 -0
  11. package/dist/src/agents/claude-code-terminal/spawner.js +37 -0
  12. package/dist/src/agents/claude-code-terminal-chatro/adapter.d.ts +51 -0
  13. package/dist/src/agents/claude-code-terminal-chatro/adapter.js +301 -0
  14. package/dist/src/agents/claude-code-terminal-chatro/index.d.ts +13 -0
  15. package/dist/src/agents/claude-code-terminal-chatro/index.js +45 -0
  16. package/dist/src/agents/claude-code-terminal-chatro/jsonl-watcher.d.ts +67 -0
  17. package/dist/src/agents/claude-code-terminal-chatro/jsonl-watcher.js +431 -0
  18. package/dist/src/agents/claude-code-terminal-chatro/spawner.d.ts +9 -0
  19. package/dist/src/agents/claude-code-terminal-chatro/spawner.js +37 -0
  20. package/dist/src/agents/codex-terminal/adapter.d.ts +40 -0
  21. package/dist/src/agents/codex-terminal/adapter.js +160 -0
  22. package/dist/src/agents/codex-terminal/index.d.ts +13 -0
  23. package/dist/src/agents/codex-terminal/index.js +47 -0
  24. package/dist/src/agents/codex-terminal/spawner.d.ts +9 -0
  25. package/dist/src/agents/codex-terminal/spawner.js +56 -0
  26. package/dist/src/agents/codex-terminal-chatro/adapter.d.ts +58 -0
  27. package/dist/src/agents/codex-terminal-chatro/adapter.js +266 -0
  28. package/dist/src/agents/codex-terminal-chatro/index.d.ts +13 -0
  29. package/dist/src/agents/codex-terminal-chatro/index.js +50 -0
  30. package/dist/src/agents/codex-terminal-chatro/jsonl-watcher.d.ts +36 -0
  31. package/dist/src/agents/codex-terminal-chatro/jsonl-watcher.js +205 -0
  32. package/dist/src/agents/codex-terminal-chatro/spawner.d.ts +9 -0
  33. package/dist/src/agents/codex-terminal-chatro/spawner.js +57 -0
  34. package/dist/src/agents/lib/chain-builder.d.ts +21 -0
  35. package/dist/src/agents/lib/chain-builder.js +139 -0
  36. package/dist/src/agents/lib/claude/fs-sessions.d.ts +31 -0
  37. package/dist/src/agents/lib/claude/fs-sessions.js +329 -0
  38. package/dist/src/agents/lib/claude/jsonl-writer.d.ts +32 -0
  39. package/dist/src/agents/lib/claude/jsonl-writer.js +342 -0
  40. package/dist/src/agents/lib/claude/workspace-trust.d.ts +1 -0
  41. package/dist/src/agents/lib/claude/workspace-trust.js +29 -0
  42. package/dist/src/agents/lib/codex/fs-sessions.d.ts +34 -0
  43. package/dist/src/agents/lib/codex/fs-sessions.js +255 -0
  44. package/dist/src/agents/lib/codex/jsonl-mapper.d.ts +11 -0
  45. package/dist/src/agents/lib/codex/jsonl-mapper.js +154 -0
  46. package/dist/src/agents/lib/codex/jsonl-writer.d.ts +8 -0
  47. package/dist/src/agents/lib/codex/jsonl-writer.js +440 -0
  48. package/dist/src/agents/lib/fs-tracking.d.ts +36 -0
  49. package/dist/src/agents/lib/fs-tracking.js +109 -0
  50. package/dist/src/agents/lib/pty-activity-tracker.d.ts +37 -0
  51. package/dist/src/agents/lib/pty-activity-tracker.js +105 -0
  52. package/dist/src/agents/lib/session-id-utils.d.ts +46 -0
  53. package/dist/src/agents/lib/session-id-utils.js +147 -0
  54. package/dist/src/agents/lib/session-precreate.d.ts +17 -0
  55. package/dist/src/agents/lib/session-precreate.js +177 -0
  56. package/dist/src/agents/registry.d.ts +72 -0
  57. package/dist/src/agents/registry.js +337 -0
  58. package/dist/src/agents/types.d.ts +135 -0
  59. package/dist/src/agents/types.js +1 -0
  60. package/dist/src/auth/crypto-key.d.ts +6 -0
  61. package/dist/src/auth/crypto-key.js +45 -0
  62. package/dist/src/auth/middleware.d.ts +18 -0
  63. package/dist/src/auth/middleware.js +54 -0
  64. package/dist/src/auth/password.d.ts +2 -0
  65. package/dist/src/auth/password.js +12 -0
  66. package/dist/src/auth/session.d.ts +10 -0
  67. package/dist/src/auth/session.js +33 -0
  68. package/dist/src/auth/totp.d.ts +12 -0
  69. package/dist/src/auth/totp.js +61 -0
  70. package/dist/src/auth/webauthn.d.ts +6 -0
  71. package/dist/src/auth/webauthn.js +117 -0
  72. package/dist/src/config.d.ts +10 -0
  73. package/dist/src/config.js +16 -0
  74. package/dist/src/database/connection-manager.d.ts +25 -0
  75. package/dist/src/database/connection-manager.js +211 -0
  76. package/dist/src/database/discovery/container.d.ts +6 -0
  77. package/dist/src/database/discovery/container.js +226 -0
  78. package/dist/src/database/discovery/env-parser.d.ts +9 -0
  79. package/dist/src/database/discovery/env-parser.js +525 -0
  80. package/dist/src/database/discovery/local-files.d.ts +6 -0
  81. package/dist/src/database/discovery/local-files.js +58 -0
  82. package/dist/src/database/discovery/port-scan.d.ts +7 -0
  83. package/dist/src/database/discovery/port-scan.js +61 -0
  84. package/dist/src/database/drivers/cassandra.d.ts +12 -0
  85. package/dist/src/database/drivers/cassandra.js +91 -0
  86. package/dist/src/database/drivers/clickhouse.d.ts +11 -0
  87. package/dist/src/database/drivers/clickhouse.js +127 -0
  88. package/dist/src/database/drivers/elasticsearch.d.ts +12 -0
  89. package/dist/src/database/drivers/elasticsearch.js +169 -0
  90. package/dist/src/database/drivers/influxdb.d.ts +14 -0
  91. package/dist/src/database/drivers/influxdb.js +194 -0
  92. package/dist/src/database/drivers/memcached.d.ts +11 -0
  93. package/dist/src/database/drivers/memcached.js +117 -0
  94. package/dist/src/database/drivers/mongodb.d.ts +12 -0
  95. package/dist/src/database/drivers/mongodb.js +128 -0
  96. package/dist/src/database/drivers/mysql.d.ts +11 -0
  97. package/dist/src/database/drivers/mysql.js +112 -0
  98. package/dist/src/database/drivers/neo4j.d.ts +11 -0
  99. package/dist/src/database/drivers/neo4j.js +158 -0
  100. package/dist/src/database/drivers/postgresql.d.ts +11 -0
  101. package/dist/src/database/drivers/postgresql.js +133 -0
  102. package/dist/src/database/drivers/redis.d.ts +11 -0
  103. package/dist/src/database/drivers/redis.js +91 -0
  104. package/dist/src/database/drivers/sqlite.d.ts +10 -0
  105. package/dist/src/database/drivers/sqlite.js +100 -0
  106. package/dist/src/database/query-stream.d.ts +5 -0
  107. package/dist/src/database/query-stream.js +75 -0
  108. package/dist/src/database/types.d.ts +71 -0
  109. package/dist/src/database/types.js +1 -0
  110. package/dist/src/events/index.d.ts +3 -0
  111. package/dist/src/events/index.js +3 -0
  112. package/dist/src/events/types.d.ts +214 -0
  113. package/dist/src/events/types.js +22 -0
  114. package/dist/src/events/wire.d.ts +114 -0
  115. package/dist/src/events/wire.js +296 -0
  116. package/dist/src/fs-monitor-types.d.ts +24 -0
  117. package/dist/src/fs-monitor-types.js +1 -0
  118. package/dist/src/fs-monitor.d.ts +80 -0
  119. package/dist/src/fs-monitor.js +637 -0
  120. package/dist/src/handlers/auth.d.ts +1 -0
  121. package/dist/src/handlers/auth.js +170 -0
  122. package/dist/src/handlers/changes.d.ts +1 -0
  123. package/dist/src/handlers/changes.js +203 -0
  124. package/dist/src/handlers/containers.d.ts +12 -0
  125. package/dist/src/handlers/containers.js +379 -0
  126. package/dist/src/handlers/databases.d.ts +3 -0
  127. package/dist/src/handlers/databases.js +327 -0
  128. package/dist/src/handlers/environments.d.ts +3 -0
  129. package/dist/src/handlers/environments.js +286 -0
  130. package/dist/src/handlers/github.d.ts +1 -0
  131. package/dist/src/handlers/github.js +153 -0
  132. package/dist/src/handlers/projects.d.ts +1 -0
  133. package/dist/src/handlers/projects.js +895 -0
  134. package/dist/src/handlers/ssh.d.ts +1 -0
  135. package/dist/src/handlers/ssh.js +162 -0
  136. package/dist/src/handlers/users.d.ts +1 -0
  137. package/dist/src/handlers/users.js +195 -0
  138. package/dist/src/index.d.ts +1 -0
  139. package/dist/src/index.js +228 -0
  140. package/dist/src/mcp/config.d.ts +32 -0
  141. package/dist/src/mcp/config.js +227 -0
  142. package/dist/src/mcp/server.d.ts +1 -0
  143. package/dist/src/mcp/server.js +574 -0
  144. package/dist/src/serial/cuse-device.d.ts +19 -0
  145. package/dist/src/serial/cuse-device.js +260 -0
  146. package/dist/src/serial/manager.d.ts +63 -0
  147. package/dist/src/serial/manager.js +206 -0
  148. package/dist/src/serial/pty-pair.d.ts +16 -0
  149. package/dist/src/serial/pty-pair.js +68 -0
  150. package/dist/src/services/fs-browser.d.ts +14 -0
  151. package/dist/src/services/fs-browser.js +98 -0
  152. package/dist/src/services/git-ops.d.ts +78 -0
  153. package/dist/src/services/git-ops.js +288 -0
  154. package/dist/src/services/github-ops.d.ts +104 -0
  155. package/dist/src/services/github-ops.js +192 -0
  156. package/dist/src/services/obfuscation.d.ts +2 -0
  157. package/dist/src/services/obfuscation.js +16 -0
  158. package/dist/src/services/preview/headless-backend.d.ts +62 -0
  159. package/dist/src/services/preview/headless-backend.js +698 -0
  160. package/dist/src/services/preview/injected-scripts.d.ts +9 -0
  161. package/dist/src/services/preview/injected-scripts.js +232 -0
  162. package/dist/src/services/preview/preview-backend.d.ts +92 -0
  163. package/dist/src/services/preview/preview-backend.js +15 -0
  164. package/dist/src/services/preview/universal-setter.d.ts +7 -0
  165. package/dist/src/services/preview/universal-setter.js +46 -0
  166. package/dist/src/services/preview-manager.d.ts +50 -0
  167. package/dist/src/services/preview-manager.js +216 -0
  168. package/dist/src/services/project-watcher.d.ts +6 -0
  169. package/dist/src/services/project-watcher.js +307 -0
  170. package/dist/src/services/remote-fs-browser.d.ts +11 -0
  171. package/dist/src/services/remote-fs-browser.js +50 -0
  172. package/dist/src/services/remote-git-ops.d.ts +71 -0
  173. package/dist/src/services/remote-git-ops.js +215 -0
  174. package/dist/src/services/session-search.d.ts +56 -0
  175. package/dist/src/services/session-search.js +303 -0
  176. package/dist/src/services/ssh-manager.d.ts +44 -0
  177. package/dist/src/services/ssh-manager.js +359 -0
  178. package/dist/src/session-writer.d.ts +9 -0
  179. package/dist/src/session-writer.js +66 -0
  180. package/dist/src/spawner.d.ts +56 -0
  181. package/dist/src/spawner.js +135 -0
  182. package/dist/src/state/db.d.ts +214 -0
  183. package/dist/src/state/db.js +897 -0
  184. package/dist/src/state/store.d.ts +37 -0
  185. package/dist/src/state/store.js +108 -0
  186. package/dist/src/state/types.d.ts +13 -0
  187. package/dist/src/state/types.js +1 -0
  188. package/dist/src/web/devtools-proxy.d.ts +7 -0
  189. package/dist/src/web/devtools-proxy.js +176 -0
  190. package/dist/src/web/port-proxy.d.ts +15 -0
  191. package/dist/src/web/port-proxy.js +124 -0
  192. package/dist/src/web/preview-ws.d.ts +5 -0
  193. package/dist/src/web/preview-ws.js +207 -0
  194. package/dist/src/web/server.d.ts +6 -0
  195. package/dist/src/web/server.js +1694 -0
  196. package/dist/src/ws/agent-ws.d.ts +5 -0
  197. package/dist/src/ws/agent-ws.js +93 -0
  198. package/frontend/dist/assets/_basePickBy-B-LibQ4-.js +1 -0
  199. package/frontend/dist/assets/_baseUniq-CprifHap.js +1 -0
  200. package/frontend/dist/assets/_createAssigner-ByDUqGii.js +1 -0
  201. package/frontend/dist/assets/abap-DuT-3z4x.js +1 -0
  202. package/frontend/dist/assets/addon-fit-CxQet2ja.js +1 -0
  203. package/frontend/dist/assets/addon-web-links-D_jRkPIl.js +1 -0
  204. package/frontend/dist/assets/apex-B-em86xX.js +1 -0
  205. package/frontend/dist/assets/api-SUPuHhSY.js +2 -0
  206. package/frontend/dist/assets/arc-Z0_eVteO.js +1 -0
  207. package/frontend/dist/assets/architecture-PBZL5I3N-hvVXGhqd.js +1 -0
  208. package/frontend/dist/assets/architectureDiagram-2XIMDMQ5-DiHPxX4j.js +36 -0
  209. package/frontend/dist/assets/array-CwG8vNfn.js +1 -0
  210. package/frontend/dist/assets/auth-store-R7eW5SVu.js +1 -0
  211. package/frontend/dist/assets/azcli-Bg9wQloi.js +1 -0
  212. package/frontend/dist/assets/bat-BM46z99L.js +1 -0
  213. package/frontend/dist/assets/bicep-DcBsJUfh.js +2 -0
  214. package/frontend/dist/assets/blockDiagram-WCTKOSBZ-C40u_hLo.js +132 -0
  215. package/frontend/dist/assets/c4Diagram-IC4MRINW-Ct7LjWFQ.js +10 -0
  216. package/frontend/dist/assets/cameligo-zw7JTtim.js +1 -0
  217. package/frontend/dist/assets/channel-ClCsE6HN.js +1 -0
  218. package/frontend/dist/assets/chunk-4BX2VUAB-zZ6P90VO.js +1 -0
  219. package/frontend/dist/assets/chunk-55IACEB6-DXllTDQl.js +1 -0
  220. package/frontend/dist/assets/chunk-7E7YKBS2-7zRaOLjj.js +1 -0
  221. package/frontend/dist/assets/chunk-7R4GIKGN-Csst1274.js +80 -0
  222. package/frontend/dist/assets/chunk-C72U2L5F-_JbQPbLN.js +1 -0
  223. package/frontend/dist/assets/chunk-CFjPhJqf.js +1 -0
  224. package/frontend/dist/assets/chunk-EGIJ26TM-B--aFyPw.js +1 -0
  225. package/frontend/dist/assets/chunk-FMBD7UC4-DVR34RNb.js +15 -0
  226. package/frontend/dist/assets/chunk-GEFDOKGD-CnmN6cC8.js +2 -0
  227. package/frontend/dist/assets/chunk-JSJVCQXG-CWxHBzeJ.js +1 -0
  228. package/frontend/dist/assets/chunk-KX2RTZJC-DkRk56s7.js +1 -0
  229. package/frontend/dist/assets/chunk-KYZI473N-DCCsG2dK.js +53 -0
  230. package/frontend/dist/assets/chunk-L3YUKLVL-C-DkZTMr.js +1 -0
  231. package/frontend/dist/assets/chunk-MX3YWQON-OUdzv5sZ.js +1 -0
  232. package/frontend/dist/assets/chunk-NQ4KR5QH-Bpu9FsM7.js +220 -0
  233. package/frontend/dist/assets/chunk-O4XLMI2P-BMLK6_ib.js +7 -0
  234. package/frontend/dist/assets/chunk-OZEHJAEY-CNNiJtG0.js +1 -0
  235. package/frontend/dist/assets/chunk-PQ6SQG4A-evVHD3KM.js +1 -0
  236. package/frontend/dist/assets/chunk-PU5JKC2W-DPFTYuvl.js +70 -0
  237. package/frontend/dist/assets/chunk-QZHKN3VN-JRdddPvu.js +1 -0
  238. package/frontend/dist/assets/chunk-R5LLSJPH-CHQzVVOV.js +1 -0
  239. package/frontend/dist/assets/chunk-WL4C6EOR-BNFU6IIi.js +189 -0
  240. package/frontend/dist/assets/chunk-XIRO2GV7-98T93G85.js +1 -0
  241. package/frontend/dist/assets/chunk-XZSTWKYB-BcW3cyNp.js +94 -0
  242. package/frontend/dist/assets/chunk-YBOYWFTD-BgKO1qAJ.js +1 -0
  243. package/frontend/dist/assets/classDiagram-VBA2DB6C-DikXzgcD.js +1 -0
  244. package/frontend/dist/assets/classDiagram-v2-RAHNMMFH-D7E3tQUK.js +1 -0
  245. package/frontend/dist/assets/clojure-FspFoNNQ.js +1 -0
  246. package/frontend/dist/assets/clone-mOXuZa7C.js +1 -0
  247. package/frontend/dist/assets/codicon-ngg6Pgfi.ttf +0 -0
  248. package/frontend/dist/assets/coffee-13n8Bk2W.js +1 -0
  249. package/frontend/dist/assets/cose-bilkent-S5V4N54A-zUOWQqLe.js +1 -0
  250. package/frontend/dist/assets/cpp-BVm2xGEs.js +1 -0
  251. package/frontend/dist/assets/csharp-D2kAWmUm.js +1 -0
  252. package/frontend/dist/assets/csp-Ezvgpf0e.js +1 -0
  253. package/frontend/dist/assets/css-CYxRwcFy.js +3 -0
  254. package/frontend/dist/assets/css.worker-Cd5h-ZOL.js +89 -0
  255. package/frontend/dist/assets/cssMode-CrXej49V.js +1 -0
  256. package/frontend/dist/assets/cypher-jg3SGErc.js +1 -0
  257. package/frontend/dist/assets/cytoscape.esm-kyyvzxNV.js +321 -0
  258. package/frontend/dist/assets/dagre-DH4bgZO7.js +1 -0
  259. package/frontend/dist/assets/dagre-KLK3FWXG-DNSqDkwT.js +4 -0
  260. package/frontend/dist/assets/dart-179jqhK4.js +1 -0
  261. package/frontend/dist/assets/defaultLocale-Dda4OpKy.js +1 -0
  262. package/frontend/dist/assets/diagram-E7M64L7V-RqPNT5Vs.js +24 -0
  263. package/frontend/dist/assets/diagram-IFDJBPK2-B-5NRyaE.js +43 -0
  264. package/frontend/dist/assets/diagram-P4PSJMXO-BrP69Hk0.js +24 -0
  265. package/frontend/dist/assets/dist-CU_Nb1G5.js +1 -0
  266. package/frontend/dist/assets/dockerfile-CIAtSGxS.js +1 -0
  267. package/frontend/dist/assets/ecl-CGVKfDxD.js +1 -0
  268. package/frontend/dist/assets/editor-Br_kD0ds.css +1 -0
  269. package/frontend/dist/assets/editor.api2-YXkDn0Gm.js +872 -0
  270. package/frontend/dist/assets/editor.main-fBaXZjJ0.js +6 -0
  271. package/frontend/dist/assets/elixir-BZ-6w0y3.js +1 -0
  272. package/frontend/dist/assets/erDiagram-INFDFZHY-BYiB9NYg.js +70 -0
  273. package/frontend/dist/assets/flow9-CVuOjTMv.js +1 -0
  274. package/frontend/dist/assets/flowDiagram-PKNHOUZH-Cwq47rsR.js +162 -0
  275. package/frontend/dist/assets/freemarker2-DM-pztJU.js +3 -0
  276. package/frontend/dist/assets/fsharp-q0pGJYr6.js +1 -0
  277. package/frontend/dist/assets/ganttDiagram-A5KZAMGK-Dnx3szD9.js +292 -0
  278. package/frontend/dist/assets/gitGraph-HDMCJU4V-COlTQ7bA.js +1 -0
  279. package/frontend/dist/assets/gitGraphDiagram-K3NZZRJ6-BaUxboNc.js +65 -0
  280. package/frontend/dist/assets/go-dzSPfdEO.js +1 -0
  281. package/frontend/dist/assets/graphlib-kEFlkt3U.js +1 -0
  282. package/frontend/dist/assets/graphql-CG4OUoEV.js +1 -0
  283. package/frontend/dist/assets/handlebars-BbK53Vec.js +1 -0
  284. package/frontend/dist/assets/hcl-Cy14JPk3.js +1 -0
  285. package/frontend/dist/assets/html-DYtTQNOG.js +1 -0
  286. package/frontend/dist/assets/html.worker-BjVEKLoU.js +502 -0
  287. package/frontend/dist/assets/htmlMode-C6GTouth.js +1 -0
  288. package/frontend/dist/assets/index-DMLxes_u.js +157 -0
  289. package/frontend/dist/assets/index-DmzeqkB1.css +1 -0
  290. package/frontend/dist/assets/info-3K5VOQVL-DBtHyA4C.js +1 -0
  291. package/frontend/dist/assets/infoDiagram-LFFYTUFH-yBXLgMPI.js +2 -0
  292. package/frontend/dist/assets/ini-Pbg8HGVD.js +1 -0
  293. package/frontend/dist/assets/init-D6KNwrax.js +1 -0
  294. package/frontend/dist/assets/ishikawaDiagram-PHBUUO56-Bld4two_.js +70 -0
  295. package/frontend/dist/assets/java-BmVu6Qrl.js +1 -0
  296. package/frontend/dist/assets/javascript-PbfQEdcJ.js +1 -0
  297. package/frontend/dist/assets/journeyDiagram-4ABVD52K-4HyMd4R2.js +139 -0
  298. package/frontend/dist/assets/json.worker-DqU5Wxnl.js +58 -0
  299. package/frontend/dist/assets/jsonMode-CASsGppE.js +7 -0
  300. package/frontend/dist/assets/julia-3cGnieBq.js +1 -0
  301. package/frontend/dist/assets/kanban-definition-K7BYSVSG-DpgsZmpG.js +89 -0
  302. package/frontend/dist/assets/katex-CEw3x5bf.js +261 -0
  303. package/frontend/dist/assets/kotlin-BuWkVcfV.js +1 -0
  304. package/frontend/dist/assets/less-CJ_VPy2C.js +2 -0
  305. package/frontend/dist/assets/lexon-BygAuZPu.js +1 -0
  306. package/frontend/dist/assets/line-CA_wh_TY.js +1 -0
  307. package/frontend/dist/assets/linear-BAcLW45z.js +1 -0
  308. package/frontend/dist/assets/liquid-kz84dle6.js +1 -0
  309. package/frontend/dist/assets/lspLanguageFeatures-C7hAHFn1.js +4 -0
  310. package/frontend/dist/assets/lua-C8Xs3dCx.js +1 -0
  311. package/frontend/dist/assets/m3-DTJeKBk4.js +1 -0
  312. package/frontend/dist/assets/markdown-QCgx8JqZ.js +1 -0
  313. package/frontend/dist/assets/math-D0YcMJAn.js +1 -0
  314. package/frontend/dist/assets/mdx-yRw0ap-E.js +1 -0
  315. package/frontend/dist/assets/mermaid-parser.core-DAeTodBQ.js +4 -0
  316. package/frontend/dist/assets/mindmap-definition-YRQLILUH-CoNlFyVl.js +68 -0
  317. package/frontend/dist/assets/mips-DopWaYgE.js +1 -0
  318. package/frontend/dist/assets/monaco.contribution-DeY0Qei-.js +2 -0
  319. package/frontend/dist/assets/msdax-BDis4ARV.js +1 -0
  320. package/frontend/dist/assets/mysql-BV6MLsOI.js +1 -0
  321. package/frontend/dist/assets/objective-c-B1UuzKs6.js +1 -0
  322. package/frontend/dist/assets/ordinal-jM7S0YHN.js +1 -0
  323. package/frontend/dist/assets/packet-RMMSAZCW-FF6-Tmai.js +1 -0
  324. package/frontend/dist/assets/pascal-BkvESCrc.js +1 -0
  325. package/frontend/dist/assets/pascaligo-lTy0kZYr.js +1 -0
  326. package/frontend/dist/assets/path-DNPd7Py7.js +1 -0
  327. package/frontend/dist/assets/perl-CrtUPXLV.js +1 -0
  328. package/frontend/dist/assets/pgsql-B9IbNWx2.js +1 -0
  329. package/frontend/dist/assets/php-CXvQBY2p.js +1 -0
  330. package/frontend/dist/assets/pie-UPGHQEXC-CFvXY2o-.js +1 -0
  331. package/frontend/dist/assets/pieDiagram-SKSYHLDU-CM_hbCcn.js +30 -0
  332. package/frontend/dist/assets/pla-DxBxuqWu.js +1 -0
  333. package/frontend/dist/assets/postiats-OkEuT5YF.js +1 -0
  334. package/frontend/dist/assets/powerquery-CMx5Tq4K.js +1 -0
  335. package/frontend/dist/assets/powershell-CstRxrEc.js +1 -0
  336. package/frontend/dist/assets/preload-helper-D4M6sveU.js +1 -0
  337. package/frontend/dist/assets/protobuf-Bx0Z-uRj.js +2 -0
  338. package/frontend/dist/assets/pug--W8vanWl.js +1 -0
  339. package/frontend/dist/assets/python-DA0rnlw3.js +1 -0
  340. package/frontend/dist/assets/qsharp-CRtr0YbN.js +1 -0
  341. package/frontend/dist/assets/quadrantDiagram-337W2JSQ-B3n3IUhC.js +7 -0
  342. package/frontend/dist/assets/r-C6E1d6iv.js +1 -0
  343. package/frontend/dist/assets/radar-KQ55EAFF-MPZu7SdX.js +1 -0
  344. package/frontend/dist/assets/razor-yd73uata.js +1 -0
  345. package/frontend/dist/assets/redis-Dx13voP3.js +1 -0
  346. package/frontend/dist/assets/redshift-D66HwlyV.js +1 -0
  347. package/frontend/dist/assets/requirementDiagram-Z7DCOOCP-CorP7L7F.js +73 -0
  348. package/frontend/dist/assets/restructuredtext-DQT2NKJ2.js +1 -0
  349. package/frontend/dist/assets/rough.esm-DxAX5Vpo.js +1 -0
  350. package/frontend/dist/assets/ruby-iFXI8hwH.js +1 -0
  351. package/frontend/dist/assets/rust-CSKiei34.js +1 -0
  352. package/frontend/dist/assets/sankeyDiagram-WA2Y5GQK-RDx6Bd-B.js +10 -0
  353. package/frontend/dist/assets/sb-Bo3ttdP2.js +1 -0
  354. package/frontend/dist/assets/scala-BC1D-Nxp.js +1 -0
  355. package/frontend/dist/assets/scheme-Z4OAo4Lv.js +1 -0
  356. package/frontend/dist/assets/scss-BvrdPs6B.js +3 -0
  357. package/frontend/dist/assets/sequenceDiagram-2WXFIKYE-JMqJSFq6.js +145 -0
  358. package/frontend/dist/assets/shell-Bh_aCyF-.js +1 -0
  359. package/frontend/dist/assets/solidity-CWHj6tSe.js +1 -0
  360. package/frontend/dist/assets/sophia-raoNtKtm.js +1 -0
  361. package/frontend/dist/assets/sparql-XzmoGnue.js +1 -0
  362. package/frontend/dist/assets/sql-BD0i9Gvg.js +1 -0
  363. package/frontend/dist/assets/src-Bn-kKzs7.js +1 -0
  364. package/frontend/dist/assets/st-DtVKyms6.js +1 -0
  365. package/frontend/dist/assets/stateDiagram-RAJIS63D-CgFfENdy.js +1 -0
  366. package/frontend/dist/assets/stateDiagram-v2-FVOUBMTO-C4Hh2P-U.js +1 -0
  367. package/frontend/dist/assets/swift--UZs77wT.js +1 -0
  368. package/frontend/dist/assets/systemverilog-CDnBSWUd.js +1 -0
  369. package/frontend/dist/assets/tcl-DdCEuTHZ.js +1 -0
  370. package/frontend/dist/assets/timeline-definition-YZTLITO2-BnatPBR5.js +61 -0
  371. package/frontend/dist/assets/treemap-KZPCXAKY-qb1Pl9la.js +1 -0
  372. package/frontend/dist/assets/ts.worker-DyPAEIuH.js +67719 -0
  373. package/frontend/dist/assets/tsMode-iuvyEpyO.js +11 -0
  374. package/frontend/dist/assets/twig-SSL-Altf.js +1 -0
  375. package/frontend/dist/assets/typescript-17918Hud.js +1 -0
  376. package/frontend/dist/assets/typespec-BT7S0ETg.js +1 -0
  377. package/frontend/dist/assets/vb-CrIgucua.js +1 -0
  378. package/frontend/dist/assets/vennDiagram-LZ73GAT5-DygS4Zzd.js +34 -0
  379. package/frontend/dist/assets/wgsl-BeKc3oEp.js +298 -0
  380. package/frontend/dist/assets/workers-DTfwKVoM.js +1 -0
  381. package/frontend/dist/assets/xml-CBMr_Wbw.js +1 -0
  382. package/frontend/dist/assets/xterm-BrP-ENHg.css +1 -0
  383. package/frontend/dist/assets/xterm-CBX2m0YM.js +36 -0
  384. package/frontend/dist/assets/xychartDiagram-JWTSCODW-D6wY1Jwd.js +7 -0
  385. package/frontend/dist/assets/yaml-CTjCH7Bv.js +1 -0
  386. package/frontend/dist/fonts/inter-300.ttf +0 -0
  387. package/frontend/dist/fonts/inter-400.ttf +0 -0
  388. package/frontend/dist/fonts/inter-500.ttf +0 -0
  389. package/frontend/dist/fonts/inter-600.ttf +0 -0
  390. package/frontend/dist/fonts/inter-700.ttf +0 -0
  391. package/frontend/dist/index.html +49 -0
  392. package/frontend/dist/logo_192x192.png +0 -0
  393. package/frontend/dist/logo_32x32.png +0 -0
  394. package/frontend/dist/logo_512x512.png +0 -0
  395. package/frontend/dist/logo_64x64.png +0 -0
  396. package/frontend/dist/logobg_192x192.png +0 -0
  397. package/frontend/dist/logobg_512x512.png +0 -0
  398. package/frontend/dist/logobg_64x64.png +0 -0
  399. package/frontend/dist/manifest.json +25 -0
  400. package/frontend/dist/sw.js +22 -0
  401. package/package.json +74 -7
  402. package/preload/Makefile +12 -0
  403. package/preload/atoo-studio-preload.c +647 -0
  404. package/preload/atoo-studio-preload.so +0 -0
  405. package/setup-cuse.sh +260 -0
  406. package/setup.sh +81 -0
  407. package/src/serial/native/binding.gyp +10 -0
  408. package/src/serial/native/pty_pair.c +222 -0
@@ -0,0 +1,574 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { z } from 'zod';
4
+ const WEB_PORT = process.env.ATOO_WEB_PORT || '3010';
5
+ const WEB_PROTO = process.env.ATOO_WEB_PROTO || 'https';
6
+ const MCP_TOKEN = process.env.ATOO_MCP_TOKEN || '';
7
+ /** Build headers for MCP API requests, including the auth token. */
8
+ function mcpHeaders() {
9
+ const headers = { 'Content-Type': 'application/json' };
10
+ if (MCP_TOKEN)
11
+ headers['Authorization'] = `Bearer ${MCP_TOKEN}`;
12
+ return headers;
13
+ }
14
+ const PROTOCOLS = [
15
+ 'http', 'https', 'ws', 'wss', 'tcp', 'grpc', 'smtp', 'imap', 'ftp', 'other',
16
+ ];
17
+ const server = new McpServer({
18
+ name: 'atoo-studio',
19
+ version: '1.0.0',
20
+ });
21
+ server.tool('report_tcp_services', `MANDATORY: You MUST call this tool EVERY TIME you start ANY service, server, or process that listens on a TCP port. This includes dev servers, databases, API servers, preview servers, build watchers with a dev server, etc. Call this immediately after starting the service. No exceptions — failure to report started services breaks the user's workflow.`, {
22
+ services: z.array(z.object({
23
+ name: z.string().describe('Short name of the service (e.g. "vite-dev-server", "express-api", "postgres")'),
24
+ description: z.string().describe('Brief description of what this service does'),
25
+ port: z.number().int().min(1).max(65535).describe('TCP port the service is listening on'),
26
+ protocol: z.enum(PROTOCOLS).describe('Communication protocol used by the service'),
27
+ host: z.string().optional().describe('Custom hostname for the Host header in the preview browser (e.g. "myapp.local"). If set, the preview will send this as the Host header to the service.'),
28
+ })).min(1).describe('Array of services that were just started'),
29
+ }, async ({ services }) => {
30
+ try {
31
+ const res = await fetch(`${WEB_PROTO}://localhost:${WEB_PORT}/api/mcp/report-services`, {
32
+ method: 'POST',
33
+ headers: mcpHeaders(),
34
+ body: JSON.stringify({ services, cwd: process.cwd() }),
35
+ });
36
+ if (!res.ok) {
37
+ return { content: [{ type: 'text', text: `Warning: failed to report services (HTTP ${res.status})` }] };
38
+ }
39
+ return { content: [{ type: 'text', text: `Reported ${services.length} service(s) to atoo-studio UI.` }] };
40
+ }
41
+ catch (err) {
42
+ return { content: [{ type: 'text', text: `Warning: could not reach atoo-studio (${err.message}). Services may not appear in UI.` }] };
43
+ }
44
+ });
45
+ server.tool('generate_certificate', `Generate TLS certificate files signed by the atoo-studio CA. Use this when you need to start an HTTPS server — the generated cert will be trusted by the preview browser. Writes cert.pem, key.pem, and ca.pem to the specified directory.`, {
46
+ hostnames: z.array(z.string()).min(1).describe('Hostnames/domains for the certificate SAN (e.g. ["localhost", "myapp.local"])'),
47
+ output_dir: z.string().describe('Absolute path to the directory where cert.pem, key.pem, and ca.pem will be written'),
48
+ }, async ({ hostnames, output_dir }) => {
49
+ try {
50
+ const res = await fetch(`${WEB_PROTO}://localhost:${WEB_PORT}/api/mcp/generate-cert`, {
51
+ method: 'POST',
52
+ headers: mcpHeaders(),
53
+ body: JSON.stringify({ hostnames, output_dir }),
54
+ });
55
+ if (!res.ok) {
56
+ const err = await res.json().catch(() => ({ error: 'Unknown error' }));
57
+ return { content: [{ type: 'text', text: `Failed to generate certificate: ${err.error}` }] };
58
+ }
59
+ const data = await res.json();
60
+ return {
61
+ content: [
62
+ { type: 'text', text: `Certificate generated for: ${hostnames.join(', ')}\n\nFiles written:\n cert: ${data.cert_path}\n key: ${data.key_path}\n ca: ${data.ca_path}` },
63
+ ],
64
+ };
65
+ }
66
+ catch (err) {
67
+ return { content: [{ type: 'text', text: `Failed to generate certificate: ${err.message}` }] };
68
+ }
69
+ });
70
+ server.tool('request_serial_device', `Request access to a serial device (ESP32, Arduino, etc.) connected to the user's local machine via USB. The user will be prompted in their browser to select and connect a serial port. Returns the path to a virtual serial device (PTY) that you can use with any serial tool (screen, minicom, esptool.py, idf.py monitor, etc.). The tool blocks until the user connects a device or a 30-second timeout expires.`, {
71
+ baudRate: z.number().int().min(300).max(3000000).default(115200).describe('Baud rate (default: 115200)'),
72
+ dataBits: z.number().int().min(7).max(8).default(8).describe('Data bits: 7 or 8 (default: 8)'),
73
+ stopBits: z.number().int().min(1).max(2).default(1).describe('Stop bits: 1 or 2 (default: 1)'),
74
+ parity: z.enum(['none', 'even', 'odd']).default('none').describe('Parity: none, even, or odd (default: none)'),
75
+ description: z.string().optional().describe('Description shown to the user (e.g. "ESP32 for firmware flashing")'),
76
+ }, async ({ baudRate, dataBits, stopBits, parity, description }) => {
77
+ try {
78
+ const res = await fetch(`${WEB_PROTO}://localhost:${WEB_PORT}/api/mcp/request-serial`, {
79
+ method: 'POST',
80
+ headers: mcpHeaders(),
81
+ body: JSON.stringify({ baudRate, dataBits, stopBits, parity, description }),
82
+ });
83
+ const data = await res.json();
84
+ if (!res.ok) {
85
+ return { content: [{ type: 'text', text: `Serial device request failed: ${data.error}` }] };
86
+ }
87
+ const signalNote = data.controlSignalsSupported
88
+ ? `\n\nDTR/RTS control signals are fully supported and automatically forwarded to the physical device.`
89
+ : `\n\nNote: Control signals (DTR/RTS) are NOT available (PTY fallback mode). Auto-reset will not work. To flash, hold the BOOT button on the device during reset. To enable control signals, run setup-cuse.sh as root.`;
90
+ return {
91
+ content: [{
92
+ type: 'text',
93
+ text: `Serial device connected and ready.\n\nVirtual serial port: ${data.ptyPath}\nBaud rate: ${baudRate}\n\nUse this path as your serial port, e.g.:\n screen ${data.ptyPath} ${baudRate}\n esptool.py --port ${data.ptyPath} flash_id\n idf.py -p ${data.ptyPath} monitor${signalNote}`,
94
+ }],
95
+ };
96
+ }
97
+ catch (err) {
98
+ return { content: [{ type: 'text', text: `Serial device request failed: ${err.message}` }] };
99
+ }
100
+ });
101
+ server.tool('search_session_history', `Search or fetch messages from session history (chat logs) of the current project. Results use abstract session:message addressing — no file paths are exposed.
102
+
103
+ Two modes:
104
+
105
+ SEARCH MODE (provide "query"):
106
+ Regex search across sessions. Returns matches as session:message references.
107
+ Example result: "2:15 [assistant] the database schema uses..."
108
+ → session 2, message 15
109
+
110
+ RANGE MODE (provide "session" or "target_session_uuid" + "from" + "to"):
111
+ Fetch full messages by range. Use after search to get context around a match.
112
+ Prefer target_session_uuid (stable) over session number (can shift between calls).
113
+ Example: target_session_uuid="a1b2c3d4-...", from=12, to=18
114
+
115
+ Typical workflow:
116
+ 1. Search → results include a Sessions header mapping session numbers to UUIDs
117
+ 2. Fetch range using the UUID → get full context around the match
118
+ Done in 2 calls.
119
+
120
+ Session numbering:
121
+ - CurrentSessionChain: sessions are 1-indexed from oldest ancestor. Numbering is stable.
122
+ - FullProjectSearch: sessions are numbered in sort order (1 = first in sort). Use UUIDs for stable references.
123
+
124
+ Search types:
125
+ - "FullProjectSearch" (default): searches ALL sessions for the project
126
+ - "CurrentSessionChain": searches only previous sessions in the current chain (excludes current session)
127
+
128
+ IMPORTANT: Prefer to delegate to a subagent if your client supports it, so the main context is not polluted with large results.`, {
129
+ type: z.enum(['FullProjectSearch', 'CurrentSessionChain']).default('FullProjectSearch')
130
+ .describe('Search scope: FullProjectSearch (all sessions) or CurrentSessionChain (only sessions in the current chain)'),
131
+ query: z.union([z.string(), z.array(z.string())]).optional()
132
+ .describe('Search mode: query or array of queries (regex supported, falls back to text if invalid) — e.g. "port 3000", ["database schema", "migration"]'),
133
+ max_results_per_query: z.number().int().min(1).max(200).default(50)
134
+ .describe('Search mode: maximum results per query (default: 50)'),
135
+ sort: z.enum(['newest_first', 'oldest_first']).default('newest_first')
136
+ .describe('Sort order: newest_first (default) or oldest_first'),
137
+ session: z.number().int().min(1).optional()
138
+ .describe('Range mode: session/chainlink number to fetch from (1-indexed)'),
139
+ target_session_uuid: z.string().optional()
140
+ .describe('Range mode: UUID of the session to fetch from (alternative to session number — stable across calls)'),
141
+ from: z.number().int().min(1).optional()
142
+ .describe('Range mode: start message number (inclusive, 1-indexed)'),
143
+ to: z.number().int().min(1).optional()
144
+ .describe('Range mode: end message number (inclusive, 1-indexed)'),
145
+ }, async ({ type, query, max_results_per_query, sort, session, target_session_uuid, from, to }) => {
146
+ try {
147
+ const sessionUuid = process.env.ATOO_CURRENT_SESSION_UUID || undefined;
148
+ // Determine mode: range if (session or target_session_uuid)+from+to provided, search if query provided
149
+ const isRangeMode = (session != null || target_session_uuid != null) && from != null && to != null;
150
+ const isSearchMode = query != null;
151
+ if (!isRangeMode && !isSearchMode) {
152
+ return { content: [{ type: 'text', text: 'Either "query" (search mode) or "session"/"target_session_uuid"+"from"+"to" (range mode) is required.' }] };
153
+ }
154
+ if (isRangeMode) {
155
+ // Range mode: fetch full messages
156
+ const res = await fetch(`${WEB_PROTO}://localhost:${WEB_PORT}/api/mcp/fetch-history-range`, {
157
+ method: 'POST',
158
+ headers: mcpHeaders(),
159
+ body: JSON.stringify({
160
+ type,
161
+ session_uuid: sessionUuid,
162
+ sort,
163
+ session,
164
+ target_session_uuid,
165
+ from,
166
+ to,
167
+ cwd: process.cwd(),
168
+ }),
169
+ });
170
+ if (!res.ok) {
171
+ const err = await res.json().catch(() => ({ error: 'Unknown error' }));
172
+ return { content: [{ type: 'text', text: `Range fetch failed: ${err.error}` }] };
173
+ }
174
+ const data = await res.json();
175
+ if (!data.messages.length) {
176
+ return { content: [{ type: 'text', text: `No messages found for session ${session ?? target_session_uuid} range ${from}-${to}.` }] };
177
+ }
178
+ const lines = data.messages.map(m => `${data.session}:${m.message} ${m.text}`);
179
+ let output = '';
180
+ if (data.uuid) {
181
+ output += `Session ${data.session} [${data.uuid}]\n\n`;
182
+ }
183
+ output += lines.join('\n\n');
184
+ output += `\n\n(${data.messages.length} message(s) from session ${data.session}, ${data.totalMessages} total messages in session)`;
185
+ return { content: [{ type: 'text', text: output }] };
186
+ }
187
+ else {
188
+ // Search mode
189
+ const res = await fetch(`${WEB_PROTO}://localhost:${WEB_PORT}/api/mcp/search-history`, {
190
+ method: 'POST',
191
+ headers: mcpHeaders(),
192
+ body: JSON.stringify({
193
+ query,
194
+ max_results_per_query,
195
+ type,
196
+ session_uuid: sessionUuid,
197
+ sort,
198
+ cwd: process.cwd(),
199
+ }),
200
+ });
201
+ if (!res.ok) {
202
+ const err = await res.json().catch(() => ({ error: 'Unknown error' }));
203
+ return { content: [{ type: 'text', text: `Search failed: ${err.error}` }] };
204
+ }
205
+ const data = await res.json();
206
+ if (!data.results.length) {
207
+ const queryStr = Array.isArray(query) ? query.join('", "') : query;
208
+ return { content: [{ type: 'text', text: `No matches found for "${queryStr}" across ${data.sessionsSearched} session(s) (scope: ${type}).` }] };
209
+ }
210
+ // Build session header for UUID mapping (deduplicated)
211
+ let output = '';
212
+ if (data.sessions?.length) {
213
+ output += 'Sessions:\n';
214
+ for (const s of data.sessions) {
215
+ output += ` ${s.number}: ${s.uuid}\n`;
216
+ }
217
+ output += '\n';
218
+ }
219
+ const lines = data.results.map(r => `${r.session}:${r.message} ${r.text}`);
220
+ output += lines.join('\n');
221
+ if (data.totalMatches > data.results.length) {
222
+ output += `\n\n(Showing ${data.results.length} of ${data.totalMatches} total matches across ${data.sessionsSearched} session(s))`;
223
+ }
224
+ else {
225
+ output += `\n\n(${data.results.length} match(es) across ${data.sessionsSearched} session(s))`;
226
+ }
227
+ return { content: [{ type: 'text', text: output }] };
228
+ }
229
+ }
230
+ catch (err) {
231
+ return { content: [{ type: 'text', text: `Failed: ${err.message}` }] };
232
+ }
233
+ });
234
+ server.tool('suggest_continue_in_other_session', `Suggest to the user that they should continue their current task in an existing session that already has relevant context.
235
+
236
+ Use this BEFORE planning or implementing when you discover (via search_session_history) that another session has already worked on the same feature, file, or bug. The user will see a popup with three options:
237
+ - Reject: Stay in the current session (you should proceed normally)
238
+ - Open: Switch to the target session (your current session stays open)
239
+ - Open & Close Current: Switch to the target session and close this one
240
+
241
+ The tool blocks until the user responds. If rejected, continue working in the current session.
242
+
243
+ IMPORTANT: Always search session history first to find the relevant session UUID before calling this tool.`, {
244
+ session_uuid: z.string()
245
+ .describe('UUID of the session that has relevant context. The tool automatically resolves the chain head (most recent session in the chain).'),
246
+ refined_prompt: z.string()
247
+ .describe('A refined version of the user\'s request, ready to be sent in the target session. Should be clear and self-contained.'),
248
+ }, async ({ session_uuid, refined_prompt }) => {
249
+ try {
250
+ const sourceSessionId = process.env.ATOO_CURRENT_SESSION_UUID || undefined;
251
+ const res = await fetch(`${WEB_PROTO}://localhost:${WEB_PORT}/api/mcp/suggest-session-switch`, {
252
+ method: 'POST',
253
+ headers: mcpHeaders(),
254
+ body: JSON.stringify({
255
+ session_uuid,
256
+ refined_prompt,
257
+ cwd: process.cwd(),
258
+ source_session_id: sourceSessionId,
259
+ }),
260
+ });
261
+ if (!res.ok) {
262
+ const err = await res.json().catch(() => ({ error: 'Unknown error' }));
263
+ return { content: [{ type: 'text', text: `Session switch suggestion failed: ${err.error}` }] };
264
+ }
265
+ const data = await res.json();
266
+ if (data.action === 'rejected') {
267
+ return { content: [{ type: 'text', text: 'User rejected the suggestion. Continue working in the current session.' }] };
268
+ }
269
+ else if (data.action === 'open') {
270
+ return { content: [{ type: 'text', text: `User accepted. They are switching to session ${data.targetSessionUuid}. The refined prompt has been placed in that session's input. You can stop working on this task — the user will continue in the other session.` }] };
271
+ }
272
+ else if (data.action === 'open_and_close') {
273
+ return { content: [{ type: 'text', text: `User accepted and chose to close this session. They are switching to session ${data.targetSessionUuid}. Stop all work immediately.` }] };
274
+ }
275
+ return { content: [{ type: 'text', text: `Unknown action: ${data.action}` }] };
276
+ }
277
+ catch (err) {
278
+ return { content: [{ type: 'text', text: `Failed: ${err.message}` }] };
279
+ }
280
+ });
281
+ server.tool('open_file', `Open a file in the user's browser editor. The user will be prompted to confirm before the file is opened. Use this when you want the user to see or review a specific file. The tool blocks until the user responds (approve or reject). Provide the full absolute path to the file.`, {
282
+ file_path: z.string().describe('Absolute path to the file to open (e.g. "/home/user/project/src/main.ts")'),
283
+ }, async ({ file_path }) => {
284
+ try {
285
+ const res = await fetch(`${WEB_PROTO}://localhost:${WEB_PORT}/api/mcp/open-file`, {
286
+ method: 'POST',
287
+ headers: mcpHeaders(),
288
+ body: JSON.stringify({ file_path }),
289
+ });
290
+ const data = await res.json();
291
+ if (!res.ok) {
292
+ return { content: [{ type: 'text', text: `Failed to open file: ${data.error}` }] };
293
+ }
294
+ if (data.action === 'rejected') {
295
+ return { content: [{ type: 'text', text: `User rejected opening the file: ${file_path}` }] };
296
+ }
297
+ return { content: [{ type: 'text', text: `File opened in the user's browser: ${file_path}` }] };
298
+ }
299
+ catch (err) {
300
+ return { content: [{ type: 'text', text: `Failed to open file: ${err.message}` }] };
301
+ }
302
+ });
303
+ server.tool('get_session_metadata', `Get metadata for the current session chain. Returns the merged metadata across all sessions in the chain: name (most recent), description (most recent), and tags (deduplicated from all chain sessions). Call this before set_session_metadata to see what's already set.`, {}, async () => {
304
+ try {
305
+ const sessionUuid = process.env.ATOO_CURRENT_SESSION_UUID || undefined;
306
+ if (!sessionUuid) {
307
+ return { content: [{ type: 'text', text: 'No session UUID available.' }] };
308
+ }
309
+ const res = await fetch(`${WEB_PROTO}://localhost:${WEB_PORT}/api/mcp/get-metadata`, {
310
+ method: 'POST',
311
+ headers: mcpHeaders(),
312
+ body: JSON.stringify({ session_uuid: sessionUuid, cwd: process.cwd() }),
313
+ });
314
+ if (!res.ok) {
315
+ const err = await res.json().catch(() => ({ error: 'Unknown error' }));
316
+ return { content: [{ type: 'text', text: `Failed: ${err.error}` }] };
317
+ }
318
+ const data = await res.json();
319
+ const parts = [];
320
+ if (data.name)
321
+ parts.push(`Name: ${data.name}`);
322
+ if (data.description)
323
+ parts.push(`Description: ${data.description}`);
324
+ if (data.tags.length)
325
+ parts.push(`Tags: ${data.tags.join(', ')}`);
326
+ if (!parts.length)
327
+ return { content: [{ type: 'text', text: 'No metadata set on this session chain.' }] };
328
+ return { content: [{ type: 'text', text: parts.join('\n') }] };
329
+ }
330
+ catch (err) {
331
+ return { content: [{ type: 'text', text: `Failed: ${err.message}` }] };
332
+ }
333
+ });
334
+ server.tool('set_session_metadata', `Set metadata on the current session. Any provided property overwrites the existing value in the database. Omitted properties are left unchanged.
335
+
336
+ Properties:
337
+ - name: Short session name (displayed as tab title and session card title). Keep it concise.
338
+ - description: Markdown description of what this session is working on. Viewable via a button in the toolbar.
339
+ - tags: Array of short tags (max 5 words each, shorter is better). Displayed as badges in the toolbar.
340
+
341
+ IMPORTANT: Always call get_session_metadata first to check existing metadata before setting, to avoid overwriting or duplicating.
342
+
343
+ Good tags: "auth refactor", "fix login bug", "API endpoints"
344
+ Bad tags: "working on implementing the new authentication system" (too long)`, {
345
+ name: z.string().optional().describe('Session name — displayed as tab title and session card title'),
346
+ description: z.string().optional().describe('Session description in markdown — viewable via toolbar button'),
347
+ tags: z.preprocess((val) => {
348
+ if (typeof val === 'string') {
349
+ try {
350
+ return JSON.parse(val);
351
+ }
352
+ catch {
353
+ return [val];
354
+ }
355
+ }
356
+ return val;
357
+ }, z.array(z.string())).optional().describe('Array of tags (max 5 words each) — displayed as badges in toolbar'),
358
+ }, async ({ name, description, tags }) => {
359
+ try {
360
+ const sessionUuid = process.env.ATOO_CURRENT_SESSION_UUID || undefined;
361
+ if (!sessionUuid) {
362
+ return { content: [{ type: 'text', text: 'No session UUID available.' }] };
363
+ }
364
+ const body = { session_uuid: sessionUuid, cwd: process.cwd() };
365
+ if (name !== undefined)
366
+ body.name = name;
367
+ if (description !== undefined)
368
+ body.description = description;
369
+ if (tags !== undefined)
370
+ body.tags = tags;
371
+ const res = await fetch(`${WEB_PROTO}://localhost:${WEB_PORT}/api/mcp/set-metadata`, {
372
+ method: 'POST',
373
+ headers: mcpHeaders(),
374
+ body: JSON.stringify(body),
375
+ });
376
+ if (!res.ok) {
377
+ const err = await res.json().catch(() => ({ error: 'Unknown error' }));
378
+ return { content: [{ type: 'text', text: `Failed: ${err.error}` }] };
379
+ }
380
+ const data = await res.json();
381
+ const parts = ['Metadata updated.'];
382
+ if (data.name)
383
+ parts.push(`Name: ${data.name}`);
384
+ if (data.description)
385
+ parts.push(`Description set (${data.description.length} chars)`);
386
+ if (data.tags.length)
387
+ parts.push(`Tags: ${data.tags.join(', ')}`);
388
+ return { content: [{ type: 'text', text: parts.join('\n') }] };
389
+ }
390
+ catch (err) {
391
+ return { content: [{ type: 'text', text: `Failed: ${err.message}` }] };
392
+ }
393
+ });
394
+ server.tool('github_issue_pr_changed', `MANDATORY: You MUST call this tool EVERY TIME you make ANY change to a GitHub issue or pull request. This includes: commenting, editing title/body/description, changing state (open/close/merge), adding/removing labels, adding/removing assignees, changing milestone, requesting reviewers, or any other modification via the gh CLI or GitHub API. Call this immediately after the change is made. No exceptions — failure to report changes means the UI won't update.`, {
395
+ repository: z.string().describe('Repository in owner/repo format (e.g. "octocat/hello-world")'),
396
+ type: z.enum(['issue', 'pr']).describe('Whether the changed item is an issue or pull request'),
397
+ number: z.number().int().min(1).describe('The issue or pull request number'),
398
+ }, async ({ repository, type, number }) => {
399
+ try {
400
+ const sessionUuid = process.env.ATOO_CURRENT_SESSION_UUID || undefined;
401
+ const res = await fetch(`${WEB_PROTO}://localhost:${WEB_PORT}/api/mcp/github-changed`, {
402
+ method: 'POST',
403
+ headers: mcpHeaders(),
404
+ body: JSON.stringify({ repository, type, number, sessionUuid }),
405
+ });
406
+ if (!res.ok) {
407
+ return { content: [{ type: 'text', text: `Warning: failed to notify UI of GitHub change (HTTP ${res.status})` }] };
408
+ }
409
+ return { content: [{ type: 'text', text: `Notified atoo-studio UI that ${type} #${number} in ${repository} was changed.` }] };
410
+ }
411
+ catch (err) {
412
+ return { content: [{ type: 'text', text: `Warning: could not reach atoo-studio (${err.message}). UI may not reflect the change.` }] };
413
+ }
414
+ });
415
+ server.tool('track_project_changes', `MANDATORY: You MUST use this tool to help the user keep track of what was accomplished. This is NON-NEGOTIABLE.
416
+
417
+ The user often runs multiple agents in parallel on the same project. When they are done, they need to know what was actually done across all sessions so they can review and test everything. This tool provides that overview.
418
+
419
+ Each entry has:
420
+ - short_description: max 10 words — headline shown on the collapsed card
421
+ - long_description: max 50 words — details shown when expanded, what to review/test
422
+ - tags: array of short labels (max 3 words each, max 10 tags) — shown as badges
423
+ - approx_files_affected: number
424
+
425
+ If your work needs more than 50 words to describe, split it into multiple entries.
426
+
427
+ Write from the user's perspective — NOT file-level noise like "modified src/foo.ts".
428
+ Good: "Fixed login redirect loop" + long: "Test login with expired tokens, check redirect after password reset"
429
+ Good: "Added dark mode toggle" + tags: ["settings page", "UI"] + long: "Review UI in both themes, check contrast on all panels"
430
+ Bad: "Modified 3 files" or "Made changes"
431
+
432
+ Modes:
433
+ - "get": List all existing entries for the project. Call this first to see context.
434
+ - "set": Create or update an entry. If id is provided, updates that entry; if omitted, creates a new one.
435
+ - "delete": Delete a specific entry by id.`, {
436
+ mode: z.enum(['get', 'set', 'delete']).describe('Operation mode'),
437
+ id: z.string().optional().describe('ID of existing entry to update or delete. Leave empty to create new.'),
438
+ short_description: z.string().optional().describe('Headline, max 10 words (required for "set" mode)'),
439
+ long_description: z.string().optional().describe('Details on what to review/test, max 50 words'),
440
+ tags: z.array(z.string()).optional().describe('Short labels (max 3 words each, max 10 tags)'),
441
+ approx_files_affected: z.number().int().min(0).optional().describe('Approximate number of files affected (required for "set" mode)'),
442
+ }, async ({ mode, id, short_description, long_description, tags, approx_files_affected }) => {
443
+ try {
444
+ const res = await fetch(`${WEB_PROTO}://localhost:${WEB_PORT}/api/mcp/track-changes`, {
445
+ method: 'POST',
446
+ headers: mcpHeaders(),
447
+ body: JSON.stringify({
448
+ mode,
449
+ id,
450
+ short_description,
451
+ long_description,
452
+ tags,
453
+ approx_files_affected,
454
+ session_uuid: process.env.ATOO_CURRENT_SESSION_UUID || undefined,
455
+ cwd: process.cwd(),
456
+ }),
457
+ });
458
+ const data = await res.json();
459
+ if (!res.ok) {
460
+ return { content: [{ type: 'text', text: `Failed: ${data.error}` }] };
461
+ }
462
+ if (mode === 'get') {
463
+ if (!data.changes || data.changes.length === 0) {
464
+ return { content: [{ type: 'text', text: 'No change entries tracked yet for this project.' }] };
465
+ }
466
+ const lines = data.changes.map((c) => {
467
+ const t = c.tags_json ? JSON.parse(c.tags_json) : [];
468
+ const tagStr = t.length ? ` [${t.join(', ')}]` : '';
469
+ return `[${c.id}] ${c.short_description}${tagStr} (~${c.approx_files_affected} files) — ${c.created_at}`;
470
+ });
471
+ return { content: [{ type: 'text', text: `Project changes:\n${lines.join('\n')}` }] };
472
+ }
473
+ else if (mode === 'set') {
474
+ const c = data.change;
475
+ return { content: [{ type: 'text', text: `Change ${id ? 'updated' : 'created'}: [${c.id}] ${c.short_description} (~${c.approx_files_affected} files)` }] };
476
+ }
477
+ else {
478
+ return { content: [{ type: 'text', text: data.message || 'Change deleted.' }] };
479
+ }
480
+ }
481
+ catch (err) {
482
+ return { content: [{ type: 'text', text: `Failed: ${err.message}` }] };
483
+ }
484
+ });
485
+ const DB_TYPES = [
486
+ 'postgresql', 'mysql', 'mariadb', 'sqlite', 'redis', 'mongodb',
487
+ 'elasticsearch', 'opensearch', 'clickhouse', 'cockroachdb',
488
+ 'cassandra', 'scylladb', 'neo4j', 'influxdb', 'memcached',
489
+ ];
490
+ server.tool('connect_database', `Connect to a database and run queries, inspect schemas, or list tables. Supports PostgreSQL, MySQL/MariaDB, SQLite, Redis, MongoDB, and more. The agent figures out connection parameters from project files (docker-compose.yml, .env, config files) and passes them here. Atoo Studio manages the connection lifecycle.
491
+
492
+ Actions:
493
+ - "connect": Establish a new connection. Returns connection_id for reuse.
494
+ - "disconnect": Close a connection.
495
+ - "query": Run a SQL query (or Redis command, MongoDB find, etc.)
496
+ - "tables": List all tables/collections.
497
+ - "describe": Show structure of a specific table/collection.
498
+ - "schema": Get full database schema (all tables + columns).`, {
499
+ action: z.enum(['connect', 'disconnect', 'query', 'schema', 'tables', 'describe'])
500
+ .describe('Action to perform'),
501
+ db_type: z.enum(DB_TYPES).optional()
502
+ .describe('Database type (required for "connect")'),
503
+ connection: z.object({
504
+ host: z.string().optional(),
505
+ port: z.number().int().optional(),
506
+ username: z.string().optional(),
507
+ password: z.string().optional(),
508
+ database: z.string().optional(),
509
+ filename: z.string().optional().describe('For SQLite — path to database file'),
510
+ connection_string: z.string().optional().describe('Full connection URI'),
511
+ ssh_connection_id: z.string().optional().describe('Tunnel through an existing Atoo Studio SSH connection (pass the SSH connection ID)'),
512
+ ssh_remote_host: z.string().optional().describe('Remote host to connect to through SSH tunnel (default: 127.0.0.1)'),
513
+ ssh_remote_port: z.number().int().optional().describe('Remote port to tunnel (defaults to DB default port)'),
514
+ }).optional().describe('Connection parameters (for "connect" action)'),
515
+ query: z.string().optional().describe('SQL query, Redis command, or MongoDB query'),
516
+ table: z.string().optional().describe('Table/collection name (for "describe" action)'),
517
+ connection_id: z.string().optional().describe('Reuse an existing connection by ID'),
518
+ options: z.object({
519
+ limit: z.number().int().default(100).optional(),
520
+ timeout_ms: z.number().int().default(30000).optional().describe('Query timeout in milliseconds (default: 30000)'),
521
+ readonly: z.boolean().default(true).optional(),
522
+ }).optional(),
523
+ }, async ({ action, db_type, connection, query, table, connection_id, options }) => {
524
+ try {
525
+ const res = await fetch(`${WEB_PROTO}://localhost:${WEB_PORT}/api/mcp/connect-database`, {
526
+ method: 'POST',
527
+ headers: mcpHeaders(),
528
+ body: JSON.stringify({ action, db_type, connection, query, table, connection_id, options }),
529
+ });
530
+ const data = await res.json();
531
+ if (!res.ok) {
532
+ return { content: [{ type: 'text', text: `Database error: ${data.error}` }] };
533
+ }
534
+ // Format output
535
+ let text = '';
536
+ if (data.connection_id)
537
+ text += `Connection ID: ${data.connection_id}\n`;
538
+ if (data.message)
539
+ text += `${data.message}\n`;
540
+ if (data.tables && Array.isArray(data.tables)) {
541
+ text += `\nTables (${data.tables.length}):\n`;
542
+ for (const t of data.tables) {
543
+ text += ` ${t.name}${t.row_count != null ? ` (${t.row_count} rows)` : ''}${t.type ? ` [${t.type}]` : ''}\n`;
544
+ }
545
+ }
546
+ if (data.columns && data.rows) {
547
+ text += `\nColumns: ${data.columns.join(', ')}\n`;
548
+ text += `Rows: ${data.row_count}${data.truncated ? ' (truncated)' : ''}\n`;
549
+ text += `Time: ${data.execution_time_ms}ms\n\n`;
550
+ // Format as table
551
+ const maxRows = Math.min(data.rows.length, 50);
552
+ for (let i = 0; i < maxRows; i++) {
553
+ const row = data.rows[i];
554
+ text += data.columns.map((c) => `${c}: ${JSON.stringify(row[c])}`).join(' | ') + '\n';
555
+ }
556
+ if (data.rows.length > 50)
557
+ text += `... and ${data.rows.length - 50} more rows\n`;
558
+ }
559
+ if (data.schemas) {
560
+ for (const s of data.schemas) {
561
+ text += `\n## ${s.table}\n`;
562
+ for (const col of s.columns) {
563
+ text += ` ${col.name} ${col.type}${col.nullable ? ' NULL' : ' NOT NULL'}${col.primary_key ? ' PK' : ''}${col.default_value ? ` DEFAULT ${col.default_value}` : ''}\n`;
564
+ }
565
+ }
566
+ }
567
+ return { content: [{ type: 'text', text: text.trim() || JSON.stringify(data, null, 2) }] };
568
+ }
569
+ catch (err) {
570
+ return { content: [{ type: 'text', text: `Database error: ${err.message}` }] };
571
+ }
572
+ });
573
+ const transport = new StdioServerTransport();
574
+ server.connect(transport);
@@ -0,0 +1,19 @@
1
+ export interface CuseDevice {
2
+ devicePath: string;
3
+ write(data: Buffer): number;
4
+ read(): Buffer | null;
5
+ getModemBits(): {
6
+ dtr: boolean;
7
+ rts: boolean;
8
+ };
9
+ setModemBits(dtr: boolean, rts: boolean): void;
10
+ onModemBitsChanged: ((bits: {
11
+ dtr: boolean;
12
+ rts: boolean;
13
+ }) => void) | null;
14
+ close(): void;
15
+ closed: boolean;
16
+ controlSignalsSupported: true;
17
+ }
18
+ export declare function isCuseAvailable(): boolean;
19
+ export declare function createCuseDevice(): Promise<CuseDevice>;