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,327 @@
1
+ import { Router } from 'express';
2
+ import { spawn } from 'child_process';
3
+ import { connectionManager } from '../database/connection-manager.js';
4
+ import { discoverLocalFiles } from '../database/discovery/local-files.js';
5
+ import { discoverContainerDatabases, parseComposeFile } from '../database/discovery/container.js';
6
+ import { discoverFromEnvFiles } from '../database/discovery/env-parser.js';
7
+ import { scanLocalPorts } from '../database/discovery/port-scan.js';
8
+ import { db } from '../state/db.js';
9
+ import { obfuscate, deobfuscate } from '../services/obfuscation.js';
10
+ /** Obfuscate sensitive fields before persisting */
11
+ function obfuscateParams(params) {
12
+ const p = { ...params };
13
+ if (p.password)
14
+ p.password = obfuscate(p.password);
15
+ if (p.connection_string)
16
+ p.connection_string = obfuscate(p.connection_string);
17
+ return p;
18
+ }
19
+ /** Deobfuscate sensitive fields after loading from DB */
20
+ function deobfuscateParams(params) {
21
+ const p = { ...params };
22
+ if (p.password)
23
+ try {
24
+ p.password = deobfuscate(p.password);
25
+ }
26
+ catch { }
27
+ if (p.connection_string)
28
+ try {
29
+ p.connection_string = deobfuscate(p.connection_string);
30
+ }
31
+ catch { }
32
+ return p;
33
+ }
34
+ export const databasesRouter = Router();
35
+ // --- Discovery ---
36
+ let discoveryCache = null;
37
+ const DISCOVERY_CACHE_TTL = 15_000;
38
+ /** Invalidate discovery cache so next request re-scans */
39
+ function invalidateDiscoveryCache() {
40
+ discoveryCache = null;
41
+ }
42
+ // --- Container event hooks ---
43
+ // Watch for docker/podman container start/stop to auto-invalidate discovery cache.
44
+ function startContainerWatcher() {
45
+ for (const runtime of ['docker', 'podman']) {
46
+ try {
47
+ const child = spawn(runtime, ['events', '--filter', 'type=container', '--filter', 'event=start', '--filter', 'event=stop', '--filter', 'event=die', '--format', '{{.Status}}'], {
48
+ stdio: ['ignore', 'pipe', 'ignore'],
49
+ });
50
+ child.stdout?.on('data', () => {
51
+ // Any container start/stop/die event invalidates cache
52
+ invalidateDiscoveryCache();
53
+ });
54
+ child.on('error', () => { }); // runtime not installed, ignore
55
+ child.unref(); // Don't prevent process exit
56
+ }
57
+ catch { }
58
+ }
59
+ }
60
+ // Start watching container events in background
61
+ startContainerWatcher();
62
+ async function runDiscovery(projectDir) {
63
+ const now = Date.now();
64
+ if (discoveryCache && now - discoveryCache.time < DISCOVERY_CACHE_TTL) {
65
+ return discoveryCache.result;
66
+ }
67
+ const [localFiles, containerDbs, composeDbs, envDbs] = await Promise.all([
68
+ Promise.resolve(projectDir ? discoverLocalFiles(projectDir) : []),
69
+ discoverContainerDatabases(),
70
+ Promise.resolve(projectDir ? parseComposeFile(projectDir) : []),
71
+ Promise.resolve(projectDir ? discoverFromEnvFiles(projectDir) : []),
72
+ ]);
73
+ // Deduplicate compose vs running containers
74
+ const seen = new Set(containerDbs.map(d => `${d.db_type}:${d.params.port}`));
75
+ const uniqueCompose = composeDbs.filter(d => !seen.has(`${d.db_type}:${d.params.port}`));
76
+ // Deduplicate env discoveries vs already-found
77
+ for (const d of [...containerDbs, ...uniqueCompose])
78
+ seen.add(`${d.db_type}:${d.params.port}`);
79
+ const uniqueEnv = envDbs.filter(d => !d.params.port || !seen.has(`${d.db_type}:${d.params.port}`));
80
+ // Collect ports already found to exclude from port scanning
81
+ const knownPorts = new Set();
82
+ for (const d of [...localFiles, ...containerDbs, ...uniqueCompose, ...uniqueEnv]) {
83
+ if (d.params.port)
84
+ knownPorts.add(d.params.port);
85
+ }
86
+ // Port scan as fallback
87
+ const portResults = await scanLocalPorts(knownPorts);
88
+ const result = [...localFiles, ...containerDbs, ...uniqueCompose, ...uniqueEnv, ...portResults];
89
+ discoveryCache = { result, time: now };
90
+ return result;
91
+ }
92
+ databasesRouter.get('/api/databases/discover', async (req, res) => {
93
+ try {
94
+ const projectDir = req.query.project_dir;
95
+ const discovered = await runDiscovery(projectDir);
96
+ const savedConnections = db.getSavedDbConnections().map(c => ({
97
+ ...c,
98
+ params: deobfuscateParams(c.params),
99
+ }));
100
+ // Strip passwords from the response — frontend doesn't need them for display
101
+ const safeSaved = savedConnections.map(c => ({
102
+ id: c.id, name: c.name, db_type: c.db_type,
103
+ params: { ...c.params, password: c.params.password ? '••••' : undefined, connection_string: undefined },
104
+ }));
105
+ res.json({
106
+ discovered,
107
+ connections: connectionManager.getActiveConnections(),
108
+ saved: safeSaved,
109
+ });
110
+ }
111
+ catch (e) {
112
+ res.status(500).json({ error: e.message });
113
+ }
114
+ });
115
+ // --- Connection management ---
116
+ databasesRouter.post('/api/databases/connect', async (req, res) => {
117
+ try {
118
+ const { db_type, connection, name, save } = req.body;
119
+ if (!db_type)
120
+ return res.status(400).json({ error: 'db_type is required' });
121
+ if (!connection)
122
+ return res.status(400).json({ error: 'connection params are required' });
123
+ const connectionId = await connectionManager.connect(db_type, connection, name);
124
+ // Save to persistent storage if requested or always for manual connections
125
+ if (save !== false) {
126
+ const connName = name || `${db_type}@${connection.host || connection.filename || 'localhost'}`;
127
+ db.saveDbConnection(connectionId, connName, db_type, obfuscateParams(connection));
128
+ }
129
+ db.touchDbConnection(connectionId);
130
+ res.json({ connection_id: connectionId });
131
+ }
132
+ catch (e) {
133
+ res.status(500).json({ error: e.message });
134
+ }
135
+ });
136
+ databasesRouter.post('/api/databases/disconnect', async (req, res) => {
137
+ try {
138
+ const { connection_id } = req.body;
139
+ if (!connection_id)
140
+ return res.status(400).json({ error: 'connection_id is required' });
141
+ await connectionManager.disconnect(connection_id);
142
+ res.json({ ok: true });
143
+ }
144
+ catch (e) {
145
+ res.status(500).json({ error: e.message });
146
+ }
147
+ });
148
+ // Reconnect a saved connection
149
+ databasesRouter.post('/api/databases/reconnect', async (req, res) => {
150
+ try {
151
+ const { saved_id } = req.body;
152
+ if (!saved_id)
153
+ return res.status(400).json({ error: 'saved_id is required' });
154
+ const saved = db.getSavedDbConnections().find(c => c.id === saved_id);
155
+ if (!saved)
156
+ return res.status(404).json({ error: 'Saved connection not found' });
157
+ const connectionId = await connectionManager.connect(saved.db_type, deobfuscateParams(saved.params), saved.name);
158
+ db.touchDbConnection(saved_id);
159
+ res.json({ connection_id: connectionId });
160
+ }
161
+ catch (e) {
162
+ res.status(500).json({ error: e.message });
163
+ }
164
+ });
165
+ // Delete a saved connection
166
+ databasesRouter.delete('/api/databases/saved/:id', async (req, res) => {
167
+ try {
168
+ db.deleteDbConnection(req.params.id);
169
+ res.json({ ok: true });
170
+ }
171
+ catch (e) {
172
+ res.status(500).json({ error: e.message });
173
+ }
174
+ });
175
+ databasesRouter.get('/api/databases/connections', (_req, res) => {
176
+ res.json(connectionManager.getActiveConnections());
177
+ });
178
+ // --- Query & Schema ---
179
+ databasesRouter.post('/api/databases/query', async (req, res) => {
180
+ try {
181
+ const { connection_id, query, limit, timeout_ms } = req.body;
182
+ if (!connection_id)
183
+ return res.status(400).json({ error: 'connection_id is required' });
184
+ if (!query)
185
+ return res.status(400).json({ error: 'query is required' });
186
+ const result = await connectionManager.query(connection_id, query, limit || 100, timeout_ms);
187
+ res.json(result);
188
+ }
189
+ catch (e) {
190
+ res.status(500).json({ error: e.message });
191
+ }
192
+ });
193
+ // Update a single cell value (for inline editing)
194
+ databasesRouter.post('/api/databases/update-cell', async (req, res) => {
195
+ try {
196
+ const { connection_id, table, primary_key, column, value } = req.body;
197
+ if (!connection_id)
198
+ return res.status(400).json({ error: 'connection_id is required' });
199
+ if (!table)
200
+ return res.status(400).json({ error: 'table is required' });
201
+ if (!primary_key || typeof primary_key !== 'object')
202
+ return res.status(400).json({ error: 'primary_key object is required (e.g. {"id": 1})' });
203
+ if (!column)
204
+ return res.status(400).json({ error: 'column is required' });
205
+ // Build WHERE clause from primary key
206
+ const pkEntries = Object.entries(primary_key);
207
+ if (pkEntries.length === 0)
208
+ return res.status(400).json({ error: 'primary_key must have at least one field' });
209
+ const whereClause = pkEntries.map(([k], i) => `"${k}" = $${i + 2}`).join(' AND ');
210
+ const sql = `UPDATE "${table}" SET "${column}" = $1 WHERE ${whereClause}`;
211
+ const params = [value, ...pkEntries.map(([, v]) => v)];
212
+ // Use raw query with parameterized values — for now use a simple approach
213
+ // since our driver interface only supports string queries
214
+ const escapedValue = value === null ? 'NULL' : typeof value === 'number' ? String(value) : `'${String(value).replace(/'/g, "''")}'`;
215
+ const escapedWhere = pkEntries.map(([k, v]) => {
216
+ const ev = v === null ? 'IS NULL' : typeof v === 'number' ? `= ${v}` : `= '${String(v).replace(/'/g, "''")}'`;
217
+ return `"${k}" ${ev}`;
218
+ }).join(' AND ');
219
+ const rawSql = `UPDATE "${table}" SET "${column}" = ${escapedValue} WHERE ${escapedWhere}`;
220
+ const result = await connectionManager.query(connection_id, rawSql, 1);
221
+ res.json({ ok: true, affected: result.row_count });
222
+ }
223
+ catch (e) {
224
+ res.status(500).json({ error: e.message });
225
+ }
226
+ });
227
+ databasesRouter.get('/api/databases/:connectionId/tables', async (req, res) => {
228
+ try {
229
+ const tables = await connectionManager.getTables(req.params.connectionId);
230
+ res.json(tables);
231
+ }
232
+ catch (e) {
233
+ res.status(500).json({ error: e.message });
234
+ }
235
+ });
236
+ databasesRouter.get('/api/databases/:connectionId/tables/:table', async (req, res) => {
237
+ try {
238
+ const schema = await connectionManager.describeTable(req.params.connectionId, req.params.table);
239
+ res.json(schema);
240
+ }
241
+ catch (e) {
242
+ res.status(500).json({ error: e.message });
243
+ }
244
+ });
245
+ databasesRouter.get('/api/databases/:connectionId/databases', async (req, res) => {
246
+ try {
247
+ const databases = await connectionManager.getDatabases(req.params.connectionId);
248
+ res.json(databases);
249
+ }
250
+ catch (e) {
251
+ res.status(500).json({ error: e.message });
252
+ }
253
+ });
254
+ // --- MCP endpoint (called by MCP server process) ---
255
+ // NOTE: This is exported separately and registered in server.ts BEFORE the auth
256
+ // middleware, alongside other /api/mcp/* routes. It must NOT be on databasesRouter
257
+ // because that router is mounted after requireAuth.
258
+ export async function handleMcpConnectDatabase(req, res) {
259
+ try {
260
+ const { action, db_type, connection, query, table, connection_id, options } = req.body;
261
+ const limit = options?.limit || 100;
262
+ const timeoutMs = options?.timeout_ms || 30000;
263
+ const readonly = options?.readonly !== false; // default true
264
+ switch (action) {
265
+ case 'connect': {
266
+ if (!db_type)
267
+ return res.status(400).json({ error: 'db_type is required for connect' });
268
+ const id = await connectionManager.connect(db_type, connection || {}, undefined, readonly);
269
+ const tables = await connectionManager.getTables(id);
270
+ res.json({ connection_id: id, tables, message: `Connected to ${db_type} (${readonly ? 'read-only' : 'read-write'}). ${tables.length} tables found.` });
271
+ break;
272
+ }
273
+ case 'disconnect': {
274
+ if (!connection_id)
275
+ return res.status(400).json({ error: 'connection_id is required' });
276
+ await connectionManager.disconnect(connection_id);
277
+ res.json({ message: 'Disconnected' });
278
+ break;
279
+ }
280
+ case 'query': {
281
+ if (!connection_id)
282
+ return res.status(400).json({ error: 'connection_id is required' });
283
+ if (!query)
284
+ return res.status(400).json({ error: 'query is required' });
285
+ const result = await connectionManager.query(connection_id, query, limit, timeoutMs);
286
+ res.json(result);
287
+ break;
288
+ }
289
+ case 'tables': {
290
+ if (!connection_id)
291
+ return res.status(400).json({ error: 'connection_id is required' });
292
+ const tables = await connectionManager.getTables(connection_id);
293
+ res.json({ tables });
294
+ break;
295
+ }
296
+ case 'describe': {
297
+ if (!connection_id)
298
+ return res.status(400).json({ error: 'connection_id is required' });
299
+ if (!table)
300
+ return res.status(400).json({ error: 'table is required' });
301
+ const schema = await connectionManager.describeTable(connection_id, table);
302
+ res.json(schema);
303
+ break;
304
+ }
305
+ case 'schema': {
306
+ if (!connection_id)
307
+ return res.status(400).json({ error: 'connection_id is required' });
308
+ const allTables = await connectionManager.getTables(connection_id);
309
+ const schemas = [];
310
+ for (const t of allTables.slice(0, 50)) {
311
+ try {
312
+ const s = await connectionManager.describeTable(connection_id, t.name);
313
+ schemas.push(s);
314
+ }
315
+ catch { }
316
+ }
317
+ res.json({ tables: allTables, schemas });
318
+ break;
319
+ }
320
+ default:
321
+ res.status(400).json({ error: `Unknown action: ${action}` });
322
+ }
323
+ }
324
+ catch (e) {
325
+ res.status(500).json({ error: e.message });
326
+ }
327
+ }
@@ -0,0 +1,3 @@
1
+ export declare const environmentsRouter: import("express-serve-static-core").Router;
2
+ export declare let broadcastSettingsChange: (scope: string, key: string, settings: any, excludeWs?: any) => void;
3
+ export declare function setBroadcastSettingsChange(fn: typeof broadcastSettingsChange): void;
@@ -0,0 +1,286 @@
1
+ import { Router } from 'express';
2
+ import fs from 'fs';
3
+ import fsp from 'fs/promises';
4
+ import path from 'path';
5
+ import { db } from '../state/db.js';
6
+ import * as gitOps from '../services/git-ops.js';
7
+ import { watchProject } from '../services/project-watcher.js';
8
+ import { isAuthEnabled } from '../auth/middleware.js';
9
+ export const environmentsRouter = Router();
10
+ // Broadcast function — set by server.ts when /ws/settings is initialized
11
+ export let broadcastSettingsChange = () => { };
12
+ export function setBroadcastSettingsChange(fn) {
13
+ broadcastSettingsChange = fn;
14
+ }
15
+ // ═══════════════════════════════════════════════════
16
+ // ENVIRONMENT ENDPOINTS
17
+ // ═══════════════════════════════════════════════════
18
+ // List environments (filtered by user when auth is enabled)
19
+ environmentsRouter.get('/api/environments', (req, res) => {
20
+ if (isAuthEnabled() && req.user) {
21
+ const envs = db.listEnvironmentsForUser(req.user.id);
22
+ return res.json(envs);
23
+ }
24
+ const envs = db.listEnvironments();
25
+ res.json(envs);
26
+ });
27
+ // Create environment
28
+ environmentsRouter.post('/api/environments', (req, res) => {
29
+ const { name } = req.body;
30
+ if (!name)
31
+ return res.status(400).json({ error: 'name is required' });
32
+ if (isAuthEnabled() && req.user) {
33
+ const env = db.createEnvironmentWithOwner(name, req.user.id);
34
+ return res.json(env);
35
+ }
36
+ const env = db.createEnvironment(name);
37
+ res.json(env);
38
+ });
39
+ // Delete environment (owner only when auth is enabled)
40
+ environmentsRouter.delete('/api/environments/:id', (req, res) => {
41
+ if (isAuthEnabled() && req.user) {
42
+ const owner = db.getEnvironmentOwner(req.params.id);
43
+ if (owner !== req.user.id) {
44
+ return res.status(403).json({ error: 'Only the environment owner can delete it' });
45
+ }
46
+ }
47
+ const deleted = db.deleteEnvironment(req.params.id);
48
+ if (!deleted)
49
+ return res.status(404).json({ error: 'Environment not found' });
50
+ res.json({ success: true });
51
+ });
52
+ // ═══════════════════════════════════════════════════
53
+ // ENVIRONMENT SHARING
54
+ // ═══════════════════════════════════════════════════
55
+ // List shares for an environment
56
+ environmentsRouter.get('/api/environments/:id/shares', (req, res) => {
57
+ if (isAuthEnabled() && req.user) {
58
+ if (!db.canAccessEnvironment(req.user.id, req.params.id)) {
59
+ return res.status(403).json({ error: 'Access denied' });
60
+ }
61
+ }
62
+ const shares = db.listEnvironmentShares(req.params.id);
63
+ res.json(shares);
64
+ });
65
+ // Share environment with a user (owner only)
66
+ environmentsRouter.post('/api/environments/:id/shares', (req, res) => {
67
+ const { user_id } = req.body;
68
+ if (!user_id)
69
+ return res.status(400).json({ error: 'user_id is required' });
70
+ if (isAuthEnabled() && req.user) {
71
+ const owner = db.getEnvironmentOwner(req.params.id);
72
+ if (owner !== req.user.id) {
73
+ return res.status(403).json({ error: 'Only the environment owner can share it' });
74
+ }
75
+ }
76
+ const targetUser = db.getUser(user_id);
77
+ if (!targetUser)
78
+ return res.status(404).json({ error: 'User not found' });
79
+ db.shareEnvironment(req.params.id, user_id, req.user?.id || 'system');
80
+ res.json({ ok: true });
81
+ });
82
+ // Revoke share
83
+ environmentsRouter.delete('/api/environments/:id/shares/:userId', (req, res) => {
84
+ if (isAuthEnabled() && req.user) {
85
+ const owner = db.getEnvironmentOwner(req.params.id);
86
+ if (owner !== req.user.id) {
87
+ return res.status(403).json({ error: 'Only the environment owner can manage shares' });
88
+ }
89
+ }
90
+ const deleted = db.unshareEnvironment(req.params.id, req.params.userId);
91
+ if (!deleted)
92
+ return res.status(404).json({ error: 'Share not found' });
93
+ res.json({ ok: true });
94
+ });
95
+ // ═══════════════════════════════════════════════════
96
+ // PROJECTS IN ENVIRONMENT
97
+ // ═══════════════════════════════════════════════════
98
+ // Get projects in an environment (with live isGit + pe_id)
99
+ environmentsRouter.get('/api/environments/:id/projects', async (req, res) => {
100
+ if (isAuthEnabled() && req.user && !db.canAccessEnvironment(req.user.id, req.params.id)) {
101
+ return res.status(403).json({ error: 'Access denied' });
102
+ }
103
+ const env = db.getEnvironment(req.params.id);
104
+ if (!env)
105
+ return res.status(404).json({ error: 'Environment not found' });
106
+ const projects = db.getProjectsForEnvironment(req.params.id);
107
+ const withGit = await Promise.all(projects.map(async (p) => {
108
+ if (p.ssh_connection_id) {
109
+ // Remote project — skip local fs checks and watching
110
+ return { ...p, isGit: false };
111
+ }
112
+ let isGit = false;
113
+ try {
114
+ await fsp.access(path.join(p.path, '.git'));
115
+ isGit = true;
116
+ }
117
+ catch { }
118
+ return { ...p, isGit };
119
+ }));
120
+ res.json(withGit);
121
+ });
122
+ // Create project + link to environment
123
+ environmentsRouter.post('/api/environments/:id/projects', async (req, res) => {
124
+ if (isAuthEnabled() && req.user && !db.canAccessEnvironment(req.user.id, req.params.id)) {
125
+ return res.status(403).json({ error: 'Access denied' });
126
+ }
127
+ const env = db.getEnvironment(req.params.id);
128
+ if (!env)
129
+ return res.status(404).json({ error: 'Environment not found' });
130
+ const { name, path: projectPath, initGit, remoteUrl, ssh_connection_id, remote_path } = req.body;
131
+ if (!name || !projectPath) {
132
+ return res.status(400).json({ error: 'name and path are required' });
133
+ }
134
+ try {
135
+ if (ssh_connection_id) {
136
+ // Remote project — skip local fs checks
137
+ const { sshManager } = await import('../services/ssh-manager.js');
138
+ const remoteGit = await import('../services/remote-git-ops.js');
139
+ if (initGit && remoteUrl) {
140
+ try {
141
+ await remoteGit.gitClone(ssh_connection_id, remoteUrl, projectPath);
142
+ }
143
+ catch { }
144
+ }
145
+ else {
146
+ // Ensure remote directory exists
147
+ try {
148
+ await sshManager.exec(ssh_connection_id, `mkdir -p '${projectPath.replace(/'/g, "'\\''")}'`);
149
+ }
150
+ catch { }
151
+ if (initGit) {
152
+ try {
153
+ await remoteGit.gitInit(ssh_connection_id, projectPath);
154
+ }
155
+ catch { }
156
+ }
157
+ }
158
+ const project = db.createProject(name, projectPath, {
159
+ sshConnectionId: ssh_connection_id,
160
+ remotePath: remote_path || projectPath,
161
+ });
162
+ const peId = db.linkProject(project.id, req.params.id);
163
+ let isGit = false;
164
+ try {
165
+ await sshManager.exec(ssh_connection_id, `test -d '${projectPath.replace(/'/g, "'\\''")}'/.git`);
166
+ isGit = true;
167
+ }
168
+ catch { }
169
+ res.json({ ...project, pe_id: peId, isGit });
170
+ }
171
+ else {
172
+ // Local project
173
+ const resolved = path.resolve(projectPath);
174
+ if (initGit && remoteUrl && !fs.existsSync(path.join(resolved, '.git'))) {
175
+ // Clone into target directory (git clone creates it if needed)
176
+ await gitOps.gitClone(remoteUrl, resolved);
177
+ }
178
+ else {
179
+ if (!fs.existsSync(resolved)) {
180
+ fs.mkdirSync(resolved, { recursive: true });
181
+ }
182
+ if (initGit && !fs.existsSync(path.join(resolved, '.git'))) {
183
+ await gitOps.gitInit(resolved);
184
+ }
185
+ }
186
+ const project = db.createProject(name, projectPath);
187
+ const peId = db.linkProject(project.id, req.params.id);
188
+ let isGit = false;
189
+ try {
190
+ isGit = fs.existsSync(path.join(resolved, '.git'));
191
+ }
192
+ catch { }
193
+ // Start watching the new project
194
+ watchProject(project.id, resolved);
195
+ res.json({ ...project, pe_id: peId, isGit });
196
+ }
197
+ }
198
+ catch (err) {
199
+ res.status(500).json({ error: err.message });
200
+ }
201
+ });
202
+ // Connect an existing project from another environment
203
+ environmentsRouter.post('/api/environments/:id/connect-project', (req, res) => {
204
+ const env = db.getEnvironment(req.params.id);
205
+ if (!env)
206
+ return res.status(404).json({ error: 'Environment not found' });
207
+ const { project_id } = req.body;
208
+ if (!project_id)
209
+ return res.status(400).json({ error: 'project_id is required' });
210
+ const project = db.getProject(project_id);
211
+ if (!project)
212
+ return res.status(404).json({ error: 'Project not found' });
213
+ const peId = db.linkProject(project_id, req.params.id);
214
+ res.json({ success: true, pe_id: peId });
215
+ });
216
+ // Unlink project from environment by PE ID
217
+ environmentsRouter.delete('/api/project-links/:peId', (req, res) => {
218
+ const pe = db.getProjectEnvironment(req.params.peId);
219
+ if (!pe)
220
+ return res.status(404).json({ error: 'Link not found' });
221
+ const deleteProject = req.query.deleteProject === 'true';
222
+ const deleteFiles = req.query.deleteFiles === 'true';
223
+ db.unlinkProject(req.params.peId);
224
+ // Check remaining links
225
+ const remainingEnvs = db.getEnvironmentsForProject(pe.project_id);
226
+ if (remainingEnvs.length === 0 && deleteProject) {
227
+ // Delete working directory if requested
228
+ if (deleteFiles) {
229
+ const project = db.getProject(pe.project_id);
230
+ if (project && !project.ssh_connection_id) {
231
+ try {
232
+ fs.rmSync(project.path, { recursive: true, force: true });
233
+ }
234
+ catch { }
235
+ }
236
+ }
237
+ db.deleteProject(pe.project_id);
238
+ }
239
+ res.json({ success: true, remainingLinks: remainingEnvs.length });
240
+ });
241
+ // Resolve a project-environment link (for URL-based routing)
242
+ environmentsRouter.get('/api/project-links/:peId', (req, res) => {
243
+ const pe = db.getProjectEnvironment(req.params.peId);
244
+ if (!pe)
245
+ return res.status(404).json({ error: 'Project link not found' });
246
+ const project = db.getProject(pe.project_id);
247
+ const environment = db.getEnvironment(pe.environment_id);
248
+ res.json({ ...pe, project, environment });
249
+ });
250
+ // ═══════════════════════════════════════════════════
251
+ // ENVIRONMENT SETTINGS
252
+ // ═══════════════════════════════════════════════════
253
+ environmentsRouter.get('/api/environments/:id/settings', (req, res) => {
254
+ const settings = db.getEnvironmentSettings(req.params.id);
255
+ if (!settings)
256
+ return res.status(404).json({ error: 'Environment not found' });
257
+ res.json(settings);
258
+ });
259
+ environmentsRouter.put('/api/environments/:id/settings', (req, res) => {
260
+ db.updateEnvironmentSettings(req.params.id, req.body);
261
+ const settings = db.getEnvironmentSettings(req.params.id);
262
+ broadcastSettingsChange('environment', req.params.id, settings, req._settingsWs);
263
+ res.json(settings);
264
+ });
265
+ // ═══════════════════════════════════════════════════
266
+ // PROJECT SETTINGS (by project-environment link ID)
267
+ // ═══════════════════════════════════════════════════
268
+ environmentsRouter.get('/api/project-links/:peId/settings', (req, res) => {
269
+ const settings = db.getProjectSettings(req.params.peId);
270
+ res.json(settings);
271
+ });
272
+ environmentsRouter.put('/api/project-links/:peId/settings', (req, res) => {
273
+ try {
274
+ db.updateProjectSettings(req.params.peId, req.body);
275
+ }
276
+ catch (e) {
277
+ if (e.code === 'SQLITE_CONSTRAINT_FOREIGNKEY') {
278
+ res.status(404).json({ error: 'Project link not found' });
279
+ return;
280
+ }
281
+ throw e;
282
+ }
283
+ const settings = db.getProjectSettings(req.params.peId);
284
+ broadcastSettingsChange('project', req.params.peId, settings, req._settingsWs);
285
+ res.json(settings);
286
+ });
@@ -0,0 +1 @@
1
+ export declare const githubRouter: import("express-serve-static-core").Router;