neural-loom 0.2.19 → 0.2.41

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 (226) hide show
  1. package/.next/build-manifest.json +3 -3
  2. package/.next/cache/.previewinfo +1 -1
  3. package/.next/cache/.rscinfo +1 -1
  4. package/.next/cache/.tsbuildinfo +1 -1
  5. package/.next/diagnostics/build-diagnostics.json +1 -1
  6. package/.next/fallback-build-manifest.json +3 -3
  7. package/.next/server/app/_global-error/page.js +6 -7
  8. package/.next/server/app/_global-error/page.js.nft.json +1 -1
  9. package/.next/server/app/_not-found/page.js +6 -7
  10. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  11. package/.next/server/app/api/context/aider/route.js +2 -2
  12. package/.next/server/app/api/context/aider/route.js.nft.json +1 -1
  13. package/.next/server/app/api/context/claude/route.js +2 -2
  14. package/.next/server/app/api/context/claude/route.js.nft.json +1 -1
  15. package/.next/server/app/api/context/route.js +2 -2
  16. package/.next/server/app/api/context/route.js.nft.json +1 -1
  17. package/.next/server/app/api/context/ssh/route.js +2 -2
  18. package/.next/server/app/api/context/ssh/route.js.nft.json +1 -1
  19. package/.next/server/app/api/files/route.js +2 -2
  20. package/.next/server/app/api/files/route.js.nft.json +1 -1
  21. package/.next/server/app/api/git/route.js +2 -2
  22. package/.next/server/app/api/git/route.js.nft.json +1 -1
  23. package/.next/server/app/api/recents/route.js +2 -2
  24. package/.next/server/app/api/recents/route.js.nft.json +1 -1
  25. package/.next/server/app/api/sessions/inject/route.js +2 -2
  26. package/.next/server/app/api/sessions/inject/route.js.nft.json +1 -1
  27. package/.next/server/app/api/sessions/input/route.js +2 -2
  28. package/.next/server/app/api/sessions/input/route.js.nft.json +1 -1
  29. package/.next/server/app/api/sessions/launch/route.js +2 -2
  30. package/.next/server/app/api/sessions/launch/route.js.nft.json +1 -1
  31. package/.next/server/app/api/sessions/route.js +2 -2
  32. package/.next/server/app/api/sessions/route.js.nft.json +1 -1
  33. package/.next/server/app/api/sessions/scope/route.js +2 -2
  34. package/.next/server/app/api/sessions/scope/route.js.nft.json +1 -1
  35. package/.next/server/app/api/sessions/start/route.js +2 -2
  36. package/.next/server/app/api/sessions/start/route.js.nft.json +1 -1
  37. package/.next/server/app/api/sessions/stats/route.js +2 -2
  38. package/.next/server/app/api/sessions/stats/route.js.nft.json +1 -1
  39. package/.next/server/app/api/sessions/stop/route.js +2 -2
  40. package/.next/server/app/api/sessions/stop/route.js.nft.json +1 -1
  41. package/.next/server/app/page/react-loadable-manifest.json +4 -4
  42. package/.next/server/app/page.js +6 -7
  43. package/.next/server/app/page.js.nft.json +1 -1
  44. package/.next/server/app/page_client-reference-manifest.js +1 -1
  45. package/.next/server/app-paths-manifest.json +0 -1
  46. package/.next/server/chunks/{[externals]_next_dist_0arv.vj._.js → [externals]__048y_op._.js} +2 -2
  47. package/.next/server/chunks/[root-of-the-server]__005xmeg._.js +15 -0
  48. package/.next/server/chunks/{[root-of-the-server]__0iqaxhx._.js.map → [root-of-the-server]__005xmeg._.js.map} +1 -1
  49. package/.next/server/chunks/{[root-of-the-server]__0k6w___._.js → [root-of-the-server]__0656ruo._.js} +3 -3
  50. package/.next/server/chunks/{[root-of-the-server]__0k6w___._.js.map → [root-of-the-server]__0656ruo._.js.map} +1 -1
  51. package/.next/server/chunks/[root-of-the-server]__0969ozy._.js +3 -0
  52. package/.next/server/chunks/{[root-of-the-server]__0l7c-gn._.js.map → [root-of-the-server]__0969ozy._.js.map} +1 -1
  53. package/.next/server/chunks/[root-of-the-server]__0_~zjnf._.js +15 -0
  54. package/.next/server/chunks/{[root-of-the-server]__0qz~w0~._.js.map → [root-of-the-server]__0_~zjnf._.js.map} +1 -1
  55. package/.next/server/chunks/[root-of-the-server]__0d0pykb._.js +9 -9
  56. package/.next/server/chunks/[root-of-the-server]__0d0pykb._.js.map +1 -1
  57. package/.next/server/chunks/[root-of-the-server]__0hl8jxx._.js +15 -0
  58. package/.next/server/chunks/{[root-of-the-server]__0bi3d5z._.js.map → [root-of-the-server]__0hl8jxx._.js.map} +1 -1
  59. package/.next/server/chunks/[root-of-the-server]__0ho7s6e._.js +15 -0
  60. package/.next/server/chunks/{[root-of-the-server]__0-lisav._.js.map → [root-of-the-server]__0ho7s6e._.js.map} +1 -1
  61. package/.next/server/chunks/{[root-of-the-server]__0j8-xkl._.js → [root-of-the-server]__0i83~95._.js} +2 -2
  62. package/.next/server/chunks/{[root-of-the-server]__0j8-xkl._.js.map → [root-of-the-server]__0i83~95._.js.map} +1 -1
  63. package/.next/server/chunks/[root-of-the-server]__0kn5tap._.js +4 -0
  64. package/.next/server/chunks/{[root-of-the-server]__0ntt3om._.js.map → [root-of-the-server]__0kn5tap._.js.map} +1 -1
  65. package/.next/server/chunks/[root-of-the-server]__0lh_jn-._.js +15 -0
  66. package/.next/server/chunks/{[root-of-the-server]__0__9rdk._.js.map → [root-of-the-server]__0lh_jn-._.js.map} +1 -1
  67. package/.next/server/chunks/[root-of-the-server]__0mq3k0u._.js +15 -0
  68. package/.next/server/chunks/{[root-of-the-server]__0_2_i_q._.js.map → [root-of-the-server]__0mq3k0u._.js.map} +1 -1
  69. package/.next/server/chunks/[root-of-the-server]__0n-zban._.js +3 -0
  70. package/.next/server/chunks/{[root-of-the-server]__0p~u94k._.js.map → [root-of-the-server]__0n-zban._.js.map} +1 -1
  71. package/.next/server/chunks/[root-of-the-server]__0rr36fm._.js +15 -0
  72. package/.next/server/chunks/{[root-of-the-server]__0m91xif._.js.map → [root-of-the-server]__0rr36fm._.js.map} +1 -1
  73. package/.next/server/chunks/[root-of-the-server]__0sa_gpm._.js +3 -0
  74. package/.next/server/chunks/[root-of-the-server]__0sa_gpm._.js.map +1 -0
  75. package/.next/server/chunks/[root-of-the-server]__0vp8-ka._.js +3 -0
  76. package/.next/server/chunks/{[root-of-the-server]__0qyrt6_._.js.map → [root-of-the-server]__0vp8-ka._.js.map} +1 -1
  77. package/.next/server/chunks/[root-of-the-server]__0xcrc-1._.js +15 -0
  78. package/.next/server/chunks/[root-of-the-server]__0xcrc-1._.js.map +1 -0
  79. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0ev3h.z.js +1 -1
  80. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0ev3h.z.js.map +1 -1
  81. package/.next/server/chunks/ssr/[root-of-the-server]__0cbmrds._.js +3 -0
  82. package/.next/server/chunks/ssr/[root-of-the-server]__0cbmrds._.js.map +1 -0
  83. package/.next/server/chunks/ssr/[root-of-the-server]__0ni-l5l._.js +3 -0
  84. package/.next/server/chunks/ssr/[root-of-the-server]__0ni-l5l._.js.map +1 -0
  85. package/.next/server/chunks/ssr/{[root-of-the-server]__089dc4i._.js → [root-of-the-server]__0tcyn68._.js} +2 -2
  86. package/.next/server/chunks/ssr/[root-of-the-server]__0tcyn68._.js.map +1 -0
  87. package/.next/server/chunks/ssr/[root-of-the-server]__0v73tbn._.js +1 -1
  88. package/.next/server/chunks/ssr/[root-of-the-server]__0v73tbn._.js.map +1 -1
  89. package/.next/server/chunks/ssr/[root-of-the-server]__0yj_dfr._.js +3 -0
  90. package/.next/server/chunks/ssr/[root-of-the-server]__0yj_dfr._.js.map +1 -0
  91. package/.next/server/chunks/ssr/_0t7oqy6._.js +1 -1
  92. package/.next/server/chunks/ssr/_0t7oqy6._.js.map +1 -1
  93. package/.next/server/chunks/ssr/{node_modules_next_dist_0ppctuh._.js → node_modules_next_dist_0-g.jog._.js} +2 -2
  94. package/.next/server/chunks/ssr/node_modules_next_dist_0-g.jog._.js.map +1 -0
  95. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0bj8dkg.js +4 -0
  96. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0bj8dkg.js.map +1 -0
  97. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0cvrgh7.js +4 -0
  98. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0cvrgh7.js.map +1 -0
  99. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0rc3ul_.js +4 -0
  100. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0rc3ul_.js.map +1 -0
  101. package/.next/server/middleware-build-manifest.js +3 -3
  102. package/.next/server/pages-manifest.json +1 -4
  103. package/.next/server/server-reference-manifest.js +1 -1
  104. package/.next/server/server-reference-manifest.json +1 -1
  105. package/.next/static/ZtSBLhTiGqKpNetcymWiC/_ssgManifest.js +1 -0
  106. package/.next/static/chunks/{0x__nd4avi0fg.js → 070hz362~_h8n.js} +1 -1
  107. package/.next/static/chunks/0bclk7hf35ac4.js +1 -0
  108. package/.next/static/chunks/0kkoif8x_kxrq.js +1 -0
  109. package/.next/static/chunks/{0pp.lp89pntpv.css → 0m-_sw1425nkp.css} +1 -1
  110. package/.next/static/chunks/17jifiroq0_q..js +1 -0
  111. package/package.json +1 -1
  112. package/public/logo.png +0 -0
  113. package/public/manifest.json +22 -0
  114. package/public/sw.js +12 -0
  115. package/src/app/api/context/aider/route.ts +6 -1
  116. package/src/app/api/files/route.ts +20 -8
  117. package/src/app/api/git/route.ts +117 -1
  118. package/src/app/api/sessions/route.ts +4 -1
  119. package/src/app/components/AiderWizard.tsx +19 -1
  120. package/src/app/components/IdeLayout.tsx +1215 -112
  121. package/src/app/components/MarkdownPreview.tsx +528 -0
  122. package/src/app/components/TerminalConsole.tsx +2 -2
  123. package/src/app/layout.tsx +5 -0
  124. package/src/app/page.module.css +2 -0
  125. package/src/app/page.tsx +42 -19
  126. package/src/lib/agents/AiderRunner.ts +83 -44
  127. package/src/lib/agents/ClaudeRunner.ts +43 -18
  128. package/src/lib/agents/DockerRunner.ts +1 -3
  129. package/src/lib/agents/SSHRunner.ts +1 -3
  130. package/src/lib/agents/SessionManager.ts +18 -9
  131. package/src/lib/agents/SessionPersister.ts +10 -0
  132. package/src/lib/agents/ShellRunner.ts +1 -3
  133. package/src/lib/agents/WebSocketServer.ts +20 -13
  134. package/.next/BUILD_ID +0 -1
  135. package/.next/app-path-routes-manifest.json +0 -21
  136. package/.next/diagnostics/route-bundle-stats.json +0 -25
  137. package/.next/export-marker.json +0 -6
  138. package/.next/images-manifest.json +0 -68
  139. package/.next/prerender-manifest.json +0 -114
  140. package/.next/required-server-files.js +0 -335
  141. package/.next/required-server-files.json +0 -335
  142. package/.next/routes-manifest.json +0 -159
  143. package/.next/server/app/_global-error.html +0 -1
  144. package/.next/server/app/_global-error.meta +0 -15
  145. package/.next/server/app/_global-error.rsc +0 -15
  146. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +0 -5
  147. package/.next/server/app/_global-error.segments/_full.segment.rsc +0 -15
  148. package/.next/server/app/_global-error.segments/_head.segment.rsc +0 -6
  149. package/.next/server/app/_global-error.segments/_index.segment.rsc +0 -5
  150. package/.next/server/app/_global-error.segments/_tree.segment.rsc +0 -1
  151. package/.next/server/app/_not-found.html +0 -1
  152. package/.next/server/app/_not-found.meta +0 -16
  153. package/.next/server/app/_not-found.rsc +0 -16
  154. package/.next/server/app/_not-found.segments/_full.segment.rsc +0 -16
  155. package/.next/server/app/_not-found.segments/_head.segment.rsc +0 -6
  156. package/.next/server/app/_not-found.segments/_index.segment.rsc +0 -5
  157. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +0 -5
  158. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +0 -5
  159. package/.next/server/app/_not-found.segments/_tree.segment.rsc +0 -2
  160. package/.next/server/app/favicon.ico/route/app-paths-manifest.json +0 -3
  161. package/.next/server/app/favicon.ico/route/build-manifest.json +0 -9
  162. package/.next/server/app/favicon.ico/route.js +0 -7
  163. package/.next/server/app/favicon.ico/route.js.map +0 -5
  164. package/.next/server/app/favicon.ico/route.js.nft.json +0 -1
  165. package/.next/server/app/favicon.ico.body +0 -0
  166. package/.next/server/app/favicon.ico.meta +0 -1
  167. package/.next/server/app/index.html +0 -1
  168. package/.next/server/app/index.meta +0 -14
  169. package/.next/server/app/index.rsc +0 -21
  170. package/.next/server/app/index.segments/__PAGE__.segment.rsc +0 -10
  171. package/.next/server/app/index.segments/_full.segment.rsc +0 -21
  172. package/.next/server/app/index.segments/_head.segment.rsc +0 -6
  173. package/.next/server/app/index.segments/_index.segment.rsc +0 -5
  174. package/.next/server/app/index.segments/_tree.segment.rsc +0 -5
  175. package/.next/server/chunks/[externals]__1334_78._.js +0 -3
  176. package/.next/server/chunks/[externals]_next_dist_0arv.vj._.js.map +0 -1
  177. package/.next/server/chunks/[root-of-the-server]__0-lisav._.js +0 -15
  178. package/.next/server/chunks/[root-of-the-server]__0_2_i_q._.js +0 -15
  179. package/.next/server/chunks/[root-of-the-server]__0__9rdk._.js +0 -15
  180. package/.next/server/chunks/[root-of-the-server]__0bi3d5z._.js +0 -15
  181. package/.next/server/chunks/[root-of-the-server]__0iqaxhx._.js +0 -15
  182. package/.next/server/chunks/[root-of-the-server]__0l7c-gn._.js +0 -3
  183. package/.next/server/chunks/[root-of-the-server]__0m91xif._.js +0 -15
  184. package/.next/server/chunks/[root-of-the-server]__0ntt3om._.js +0 -3
  185. package/.next/server/chunks/[root-of-the-server]__0p~u94k._.js +0 -3
  186. package/.next/server/chunks/[root-of-the-server]__0qyrt6_._.js +0 -3
  187. package/.next/server/chunks/[root-of-the-server]__0qz~w0~._.js +0 -15
  188. package/.next/server/chunks/[root-of-the-server]__0ty8hwz._.js +0 -15
  189. package/.next/server/chunks/[root-of-the-server]__0ty8hwz._.js.map +0 -1
  190. package/.next/server/chunks/[root-of-the-server]__0ylcu31._.js +0 -3
  191. package/.next/server/chunks/[root-of-the-server]__0ylcu31._.js.map +0 -1
  192. package/.next/server/chunks/_next-internal_server_app_favicon_ico_route_actions_095lj93.js +0 -3
  193. package/.next/server/chunks/_next-internal_server_app_favicon_ico_route_actions_095lj93.js.map +0 -1
  194. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0m.429v.js +0 -3
  195. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0m.429v.js.map +0 -1
  196. package/.next/server/chunks/ssr/[root-of-the-server]__089dc4i._.js.map +0 -1
  197. package/.next/server/chunks/ssr/[root-of-the-server]__0_7i5h0._.js +0 -3
  198. package/.next/server/chunks/ssr/[root-of-the-server]__0_7i5h0._.js.map +0 -1
  199. package/.next/server/chunks/ssr/[root-of-the-server]__0hw~y-4._.js +0 -3
  200. package/.next/server/chunks/ssr/[root-of-the-server]__0hw~y-4._.js.map +0 -1
  201. package/.next/server/chunks/ssr/[root-of-the-server]__0~y8ue.._.js +0 -3
  202. package/.next/server/chunks/ssr/[root-of-the-server]__0~y8ue.._.js.map +0 -1
  203. package/.next/server/chunks/ssr/node_modules_05l396c._.js +0 -3
  204. package/.next/server/chunks/ssr/node_modules_05l396c._.js.map +0 -1
  205. package/.next/server/chunks/ssr/node_modules_next_dist_0ppctuh._.js.map +0 -1
  206. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_03-z2qq.js +0 -4
  207. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_03-z2qq.js.map +0 -1
  208. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_07vh7rm.js +0 -4
  209. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_07vh7rm.js.map +0 -1
  210. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0qp4u6g.js +0 -4
  211. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0qp4u6g.js.map +0 -1
  212. package/.next/server/functions-config-manifest.json +0 -4
  213. package/.next/server/pages/404.html +0 -1
  214. package/.next/server/pages/500.html +0 -1
  215. package/.next/server/prefetch-hints.json +0 -1
  216. package/.next/static/W3UxhE_D02EcHxTzdXKHX/_ssgManifest.js +0 -1
  217. package/.next/static/chunks/01.1lqu6kmllv.js +0 -1
  218. package/.next/static/chunks/0ek0280331wie.js +0 -1
  219. package/.next/static/chunks/0jxar8nsw_py3.js +0 -1
  220. package/.next/static/media/favicon.0x3dzn~oxb6tn.ico +0 -0
  221. package/.next/trace +0 -1
  222. package/.next/trace-build +0 -1
  223. package/src/app/favicon.ico +0 -0
  224. /package/.next/server/chunks/{[externals]__1334_78._.js.map → [externals]__048y_op._.js.map} +0 -0
  225. /package/.next/static/{W3UxhE_D02EcHxTzdXKHX → ZtSBLhTiGqKpNetcymWiC}/_buildManifest.js +0 -0
  226. /package/.next/static/{W3UxhE_D02EcHxTzdXKHX → ZtSBLhTiGqKpNetcymWiC}/_clientMiddlewareManifest.js +0 -0
@@ -1,13 +1,12 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
+ import { exec } from "child_process";
3
4
  import type { IPty } from "node-pty";
4
5
  import { AgentRunner, RunnerStatus } from "./AgentRunner";
5
6
  import { SessionPersister } from "./SessionPersister";
6
7
 
7
8
  function isWindows(): boolean {
8
- if (typeof process === "undefined") return false;
9
- const key = Object.keys(process).find(k => k.startsWith("plat") && k.endsWith("form"));
10
- return !!key && (process as unknown as Record<string, unknown>)[key] === "win32";
9
+ return typeof process !== "undefined" && process.platform === "win32";
11
10
  }
12
11
 
13
12
  function findGitBash(): string | null {
@@ -28,6 +27,46 @@ function findGitBash(): string | null {
28
27
  return candidates.find(p => fs.existsSync(p)) || null;
29
28
  }
30
29
 
30
+ function getFilesForAider(dir: string): string {
31
+ const maxFiles = 150;
32
+ const files: string[] = [];
33
+
34
+ function walk(current: string) {
35
+ if (files.length >= maxFiles) return;
36
+ try {
37
+ const entries = fs.readdirSync(current, { withFileTypes: true });
38
+ for (const entry of entries) {
39
+ const name = entry.name;
40
+ if (
41
+ name.startsWith(".") ||
42
+ name === "node_modules" ||
43
+ name === "out" ||
44
+ name === ".next" ||
45
+ name === "bin" ||
46
+ name === "obj" ||
47
+ name === "dist" ||
48
+ name === "build"
49
+ ) {
50
+ continue;
51
+ }
52
+ const fullPath = path.join(current, name);
53
+ if (entry.isDirectory()) {
54
+ walk(fullPath);
55
+ } else {
56
+ const relPath = path.relative(dir, fullPath);
57
+ files.push(relPath);
58
+ if (files.length >= maxFiles) return;
59
+ }
60
+ }
61
+ } catch (err) {
62
+ console.error("Error reading dir for Aider files list:", err);
63
+ }
64
+ }
65
+
66
+ walk(dir);
67
+ return files.map(f => `"${f.replace(/"/g, '\\"')}"`).join(" ");
68
+ }
69
+
31
70
  export class AiderRunner extends AgentRunner {
32
71
  id: string;
33
72
  name: string;
@@ -65,12 +104,14 @@ export class AiderRunner extends AgentRunner {
65
104
  this.appendLog(`\x1b[1;36m NEURALLOOM AIDER AGENT ROUTE (${this.type.toUpperCase()}) \x1b[0m\r\n`);
66
105
  this.appendLog("\x1b[1;35m==================================================\x1b[0m\r\n");
67
106
 
68
- const bashPath = findGitBash();
69
- if (!bashPath) {
107
+ const useCmd = isWindows();
108
+ const shellPath = useCmd ? (process.env.COMSPEC || "cmd.exe") : findGitBash();
109
+ if (!shellPath) {
70
110
  this.status = 'stopped';
71
- this.appendLog("\x1b[1;31m[System Error] Git Bash not found. Cannot spawn terminal.\x1b[0m\r\n");
111
+ this.appendLog("\x1b[1;31m[System Error] Shell not found. Cannot spawn terminal.\x1b[0m\r\n");
72
112
  return;
73
113
  }
114
+ const shellArgs = useCmd ? ["/c"] : ["-c"];
74
115
 
75
116
  try {
76
117
  if (!this.ptyModule) {
@@ -84,6 +125,7 @@ export class AiderRunner extends AgentRunner {
84
125
  geminiApiKey: "",
85
126
  model: "claude-3-5-sonnet",
86
127
  extraFlags: "",
128
+ loadAllFiles: true,
87
129
  };
88
130
 
89
131
  const aiderConfigPath = path.join(process.env.ORIGINAL_CWD || process.cwd(), ".ai", "neural-loom", "aider.json");
@@ -100,6 +142,7 @@ export class AiderRunner extends AgentRunner {
100
142
  ...process.env,
101
143
  TERM: "xterm-256color",
102
144
  COLORTERM: "truecolor",
145
+ NEURAL_LOOM: "true",
103
146
  } as Record<string, string>;
104
147
 
105
148
  if (aiderConfig.openaiApiKey) {
@@ -112,34 +155,36 @@ export class AiderRunner extends AgentRunner {
112
155
  customEnv.GEMINI_API_KEY = aiderConfig.geminiApiKey;
113
156
  }
114
157
 
115
- const modelFlag = aiderConfig.model ? `--model ${aiderConfig.model}` : "";
116
- const extraFlags = aiderConfig.extraFlags || "";
117
-
118
158
  const targetCwd = (this.workspaceRoot && fs.existsSync(this.workspaceRoot))
119
159
  ? this.workspaceRoot
120
160
  : process.env.ORIGINAL_CWD || process.cwd();
121
161
 
162
+ const modelFlag = aiderConfig.model ? `--model ${aiderConfig.model}` : "";
163
+ const extraFlags = aiderConfig.extraFlags || "";
164
+
165
+ let loadAllFilesFlag = "";
166
+ if (aiderConfig.loadAllFiles !== false) {
167
+ if (extraFlags.includes("--no-git")) {
168
+ loadAllFilesFlag = getFilesForAider(targetCwd);
169
+ } else {
170
+ loadAllFilesFlag = ".";
171
+ }
172
+ }
173
+
122
174
  if (this.type === "aider-docker") {
123
175
  this.appendLog("[System] Verifying Docker environment accessibility...\r\n");
124
176
 
125
- // Check if docker executable exists by spawning `docker -v`
126
- const testPty = this.ptyModule!.spawn(bashPath, ["-c", "docker --version"], {
127
- name: "xterm-256color",
128
- cols: 80,
129
- rows: 10,
130
- cwd: targetCwd,
131
- });
132
-
133
- let hasDocker = false;
134
- testPty.onData((data) => {
135
- if (data.toLowerCase().includes("docker version")) {
136
- hasDocker = true;
137
- }
177
+ // Check if docker executable exists by running `docker --version`
178
+ const hasDocker = await new Promise<boolean>((resolve) => {
179
+ exec("docker --version", { env: process.env }, (error: Error | null, stdout: string) => {
180
+ if (!error && stdout.toLowerCase().includes("version")) {
181
+ resolve(true);
182
+ } else {
183
+ resolve(false);
184
+ }
185
+ });
138
186
  });
139
187
 
140
- await new Promise(resolve => setTimeout(resolve, 800));
141
- testPty.kill();
142
-
143
188
  if (!hasDocker) {
144
189
  this.status = 'stopped';
145
190
  this.appendLog("\x1b[1;31m[Dependency Warning] Docker command not recognized in local PATH.\x1b[0m\r\n");
@@ -152,6 +197,7 @@ export class AiderRunner extends AgentRunner {
152
197
  if (aiderConfig.openaiApiKey) envFlags.push("-e OPENAI_API_KEY");
153
198
  if (aiderConfig.anthropicApiKey) envFlags.push("-e ANTHROPIC_API_KEY");
154
199
  if (aiderConfig.geminiApiKey) envFlags.push("-e GEMINI_API_KEY");
200
+ envFlags.push("-e NEURAL_LOOM=true");
155
201
  const envFlagsStr = envFlags.join(" ");
156
202
 
157
203
  // Volume mounts for primary workspace and each scoped directory
@@ -166,9 +212,9 @@ export class AiderRunner extends AgentRunner {
166
212
  }
167
213
  const mountsStr = mounts.join(" ");
168
214
 
169
- const dockerCmd = `docker run -it --name neural-loom-session-${this.id} --rm ${mountsStr} -w /workspace ${envFlagsStr} paulgauthier/aider ${modelFlag} ${extraFlags}`.trim();
215
+ const dockerCmd = `docker run -it --name neural-loom-session-${this.id} --rm ${mountsStr} -w /workspace ${envFlagsStr} paulgauthier/aider ${modelFlag} ${extraFlags} --no-fancy-input ${loadAllFilesFlag}`.trim();
170
216
 
171
- this.ptyProcess = this.ptyModule!.spawn(bashPath, ["-c", dockerCmd], {
217
+ this.ptyProcess = this.ptyModule!.spawn(shellPath, [...shellArgs, dockerCmd], {
172
218
  name: "xterm-256color",
173
219
  cols: 120,
174
220
  rows: 30,
@@ -179,23 +225,16 @@ export class AiderRunner extends AgentRunner {
179
225
  this.appendLog("[System] Verifying 'aider' command availability in local PATH...\r\n");
180
226
 
181
227
  // Check if aider executable exists by running `aider --version`
182
- const testPty = this.ptyModule!.spawn(bashPath, ["-c", "aider --version"], {
183
- name: "xterm-256color",
184
- cols: 80,
185
- rows: 10,
186
- cwd: targetCwd,
187
- });
188
-
189
- let hasAider = false;
190
- testPty.onData((data) => {
191
- if (data.toLowerCase().includes("aider")) {
192
- hasAider = true;
193
- }
228
+ const hasAider = await new Promise<boolean>((resolve) => {
229
+ exec("aider --version", { env: process.env }, (error: Error | null, stdout: string) => {
230
+ if (!error && stdout.toLowerCase().includes("aider")) {
231
+ resolve(true);
232
+ } else {
233
+ resolve(false);
234
+ }
235
+ });
194
236
  });
195
237
 
196
- await new Promise(resolve => setTimeout(resolve, 800));
197
- testPty.kill();
198
-
199
238
  if (!hasAider) {
200
239
  this.status = 'stopped';
201
240
  this.appendLog("\x1b[1;31m[Dependency Warning] 'aider' executable not found on local PATH.\x1b[0m\r\n");
@@ -204,9 +243,9 @@ export class AiderRunner extends AgentRunner {
204
243
  }
205
244
 
206
245
  this.appendLog("[System] Spawning local Aider CLI...\r\n");
207
- const localCmd = `aider ${modelFlag} ${extraFlags}`.trim();
246
+ const localCmd = `aider ${modelFlag} ${extraFlags} --no-fancy-input ${loadAllFilesFlag}`.trim();
208
247
 
209
- this.ptyProcess = this.ptyModule!.spawn(bashPath, ["-c", localCmd], {
248
+ this.ptyProcess = this.ptyModule!.spawn(shellPath, [...shellArgs, localCmd], {
210
249
  name: "xterm-256color",
211
250
  cols: 120,
212
251
  rows: 30,
@@ -1,13 +1,13 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
+ import os from "os";
4
+ import { execSync } from "child_process";
3
5
  import type { IPty } from "node-pty";
4
6
  import { AgentRunner, RunnerStatus } from "./AgentRunner";
5
7
  import { SessionPersister } from "./SessionPersister";
6
8
 
7
9
  function isWindows(): boolean {
8
- if (typeof process === "undefined") return false;
9
- const key = Object.keys(process).find(k => k.startsWith("plat") && k.endsWith("form"));
10
- return !!key && (process as unknown as Record<string, unknown>)[key] === "win32";
10
+ return typeof process !== "undefined" && process.platform === "win32";
11
11
  }
12
12
 
13
13
  function findGitBash(): string | null {
@@ -60,12 +60,14 @@ export class ClaudeRunner extends AgentRunner {
60
60
  if (this.status === 'running') return;
61
61
 
62
62
  // Detect Git Bash on Windows
63
- const bashPath = findGitBash();
64
- if (!bashPath) {
63
+ const useCmd = isWindows();
64
+ const shellPath = useCmd ? (process.env.COMSPEC || "cmd.exe") : findGitBash();
65
+ if (!shellPath) {
65
66
  this.status = 'stopped';
66
- this.appendLog("\x1b[1;31m[System Error] Git Bash not found. Please install Git for Windows.\x1b[0m\r\n");
67
+ this.appendLog("\x1b[1;31m[System Error] Shell not found. Cannot spawn terminal.\x1b[0m\r\n");
67
68
  return;
68
69
  }
70
+ const shellArgs = useCmd ? ["/c"] : ["-c"];
69
71
 
70
72
  try {
71
73
  // Dynamic import to prevent bundler SSR/Turbopack errors on server start
@@ -96,24 +98,47 @@ export class ClaudeRunner extends AgentRunner {
96
98
  }
97
99
  }
98
100
 
99
- const claudeCmd = `claude ${extraFlags}`.trim();
101
+ // Setup process environment with injected keys
102
+ const customEnv = {
103
+ ...process.env,
104
+ TERM: "xterm-256color",
105
+ COLORTERM: "truecolor",
106
+ } as Record<string, string>;
107
+
108
+ if (isWindows()) {
109
+ const vsNode = "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Microsoft\\VisualStudio\\NodeJs";
110
+ const localNpm = path.join(os.homedir(), "AppData", "Local", "npm");
111
+ const existingPath = process.env.Path || process.env.PATH || "";
112
+ const winPath = [vsNode, localNpm, existingPath].filter(Boolean).join(";");
113
+
114
+ for (const key of Object.keys(customEnv)) {
115
+ if (key.toLowerCase() === "path") {
116
+ delete customEnv[key];
117
+ }
118
+ }
119
+ customEnv.Path = winPath;
120
+ customEnv.PATH = winPath;
121
+ }
122
+
123
+ // Check if 'claude' command exists in PATH, fallback to npx if not
124
+ let baseCmd = "claude";
125
+ try {
126
+ const checkCmd = isWindows() ? "where.exe claude" : "which claude";
127
+ execSync(checkCmd, { env: customEnv, stdio: "ignore" });
128
+ } catch {
129
+ baseCmd = "npx -y @anthropic-ai/claude-code";
130
+ }
131
+
132
+ const claudeCmd = `${baseCmd} ${extraFlags}`.trim();
100
133
  this.appendLog(`[System] Spawning command: ${claudeCmd}\r\n`);
101
134
 
102
- // Spawn bash and run 'claude' command
103
- this.ptyProcess = this.ptyModule!.spawn(bashPath, ["-c", claudeCmd], {
135
+ // Spawn shell and run 'claude' command
136
+ this.ptyProcess = this.ptyModule!.spawn(shellPath, [...shellArgs, claudeCmd], {
104
137
  name: "xterm-256color",
105
138
  cols: 120,
106
139
  rows: 30,
107
140
  cwd: targetCwd,
108
- env: {
109
- ...process.env,
110
- TERM: "xterm-256color",
111
- COLORTERM: "truecolor",
112
- // Inject custom path just in case child processes need Visual Studio Node on Windows
113
- ...(isWindows() ? {
114
- PATH: "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Microsoft\\VisualStudio\\NodeJs;" + process.env.PATH
115
- } : {})
116
- },
141
+ env: customEnv,
117
142
  });
118
143
 
119
144
  // Capture output
@@ -5,9 +5,7 @@ import { AgentRunner, RunnerStatus } from "./AgentRunner";
5
5
  import { SessionPersister } from "./SessionPersister";
6
6
 
7
7
  function isWindows(): boolean {
8
- if (typeof process === "undefined") return false;
9
- const key = Object.keys(process).find(k => k.startsWith("plat") && k.endsWith("form"));
10
- return !!key && (process as unknown as Record<string, unknown>)[key] === "win32";
8
+ return typeof process !== "undefined" && process.platform === "win32";
11
9
  }
12
10
 
13
11
  function findGitBash(): string | null {
@@ -5,9 +5,7 @@ import { AgentRunner, RunnerStatus } from "./AgentRunner";
5
5
  import { SessionPersister } from "./SessionPersister";
6
6
 
7
7
  function isWindows(): boolean {
8
- if (typeof process === "undefined") return false;
9
- const key = Object.keys(process).find(k => k.startsWith("plat") && k.endsWith("form"));
10
- return !!key && (process as unknown as Record<string, unknown>)[key] === "win32";
8
+ return typeof process !== "undefined" && process.platform === "win32";
11
9
  }
12
10
 
13
11
  function findGitBash(): string | null {
@@ -11,6 +11,10 @@ import { SessionPersister } from "./SessionPersister";
11
11
  import { ShellRunner } from "./ShellRunner";
12
12
  import { getWorkspaceFileFolders } from "../workspaceParser";
13
13
 
14
+ declare global {
15
+ var sessionManager: SessionManager | undefined;
16
+ }
17
+
14
18
  export class SessionManager {
15
19
  private static instance: SessionManager | null = null;
16
20
  private sessions = new Map<string, AgentRunner>();
@@ -29,6 +33,16 @@ export class SessionManager {
29
33
  try {
30
34
  const saved = SessionPersister.loadAllSessions();
31
35
  for (const data of saved) {
36
+ // Automatically clean up stopped sessions older than 24 hours to avoid clutter
37
+ if (data.status === "stopped") {
38
+ const createdTime = new Date(data.createdAt).getTime();
39
+ const ageHours = (Date.now() - createdTime) / (1000 * 60 * 60);
40
+ if (ageHours > 24) {
41
+ SessionPersister.deleteSession(data.id);
42
+ continue;
43
+ }
44
+ }
45
+
32
46
  let runner: AgentRunner;
33
47
  if (data.type === "mock") {
34
48
  runner = new MockRunner(data.id, data.name);
@@ -49,11 +63,6 @@ export class SessionManager {
49
63
  runner.scopedDirs = data.scopedDirs;
50
64
  runner.lastSyncedWorkspaceFolders = data.lastSyncedWorkspaceFolders;
51
65
 
52
- // Auto-resume mock runner if running
53
- if (data.type === "mock" && data.status === "running") {
54
- runner.start();
55
- }
56
-
57
66
  this.sessions.set(data.id, runner);
58
67
  }
59
68
  } catch (err) {
@@ -62,12 +71,12 @@ export class SessionManager {
62
71
  }
63
72
 
64
73
  public static getInstance(): SessionManager {
65
- if (!SessionManager.instance) {
66
- SessionManager.instance = new SessionManager();
74
+ if (!globalThis.sessionManager) {
75
+ globalThis.sessionManager = new SessionManager();
67
76
  // Initialize WebSocket gateway server on port 3001
68
- initWebSocketServer(3001, (id) => SessionManager.getInstance().getSession(id));
77
+ initWebSocketServer(3001, (id) => globalThis.sessionManager!.getSession(id));
69
78
  }
70
- return SessionManager.instance;
79
+ return globalThis.sessionManager;
71
80
  }
72
81
 
73
82
  private generateId(): string {
@@ -116,7 +116,17 @@ export class SessionPersister {
116
116
  }
117
117
  }
118
118
 
119
+ public static cancelPendingSave(id: string) {
120
+ const timer = this.pendingSaves.get(id);
121
+ if (timer) {
122
+ clearTimeout(timer);
123
+ this.pendingSaves.delete(id);
124
+ }
125
+ this.pendingData.delete(id);
126
+ }
127
+
119
128
  public static deleteSession(id: string) {
129
+ this.cancelPendingSave(id);
120
130
  try {
121
131
  const dir = this.getSessionsDir();
122
132
  const filePath = path.join(dir, `${id}.json`);
@@ -4,9 +4,7 @@ import type { IPty } from "node-pty";
4
4
  import { AgentRunner, RunnerStatus } from "./AgentRunner";
5
5
 
6
6
  function isWindows(): boolean {
7
- if (typeof process === "undefined") return false;
8
- const key = Object.keys(process).find(k => k.startsWith("plat") && k.endsWith("form"));
9
- return !!key && (process as unknown as Record<string, unknown>)[key] === "win32";
7
+ return typeof process !== "undefined" && process.platform === "win32";
10
8
  }
11
9
 
12
10
  function findGitBash(): string | null {
@@ -44,11 +44,9 @@ export function initWebSocketServer(port = 3001, getSession?: (id: string) => Ag
44
44
  console.log(`[WebSocketServer] WebSocket gateway successfully listening on port ${currentPort}.`);
45
45
  });
46
46
 
47
- wss.on("connection", (ws: WebSocket & { sessionId?: string }) => {
47
+ wss.on("connection", (ws: WebSocket & { sessionId?: string; outputListener?: (data: string) => void }) => {
48
48
  console.log("[WebSocketServer] New client connected via gateway.");
49
49
 
50
- let activeSessionId: string | null = null;
51
- let outputListener: ((data: string) => void) | null = null;
52
50
  let mockBuffer = "";
53
51
 
54
52
  ws.on("message", async (rawMsg) => {
@@ -58,20 +56,29 @@ export function initWebSocketServer(port = 3001, getSession?: (id: string) => Ag
58
56
  // Client handshake to establish connection to a specific session
59
57
  if (msg.type === "handshake") {
60
58
  const { sessionId } = msg;
59
+
60
+ // Clean up previous registration for this connection if it exists
61
+ if (ws.sessionId && ws.outputListener) {
62
+ const oldSession = getSessionCallback ? getSessionCallback(ws.sessionId) : null;
63
+ if (oldSession) {
64
+ oldSession.offOutput(ws.outputListener);
65
+ }
66
+ }
67
+
61
68
  const session = getSessionCallback ? getSessionCallback(sessionId) : null;
62
69
 
63
70
  if (session) {
64
- activeSessionId = sessionId;
65
71
  ws.sessionId = sessionId;
66
72
  console.log(`[WebSocketServer] Client connected to active session: ${sessionId}`);
67
73
 
68
74
  // Subscribe to runner output events
69
- outputListener = (data: string) => {
75
+ const listener = (data: string) => {
70
76
  if (ws.readyState === WebSocket.OPEN) {
71
77
  ws.send(JSON.stringify({ type: "output", data }));
72
78
  }
73
79
  };
74
- session.onOutput(outputListener);
80
+ ws.outputListener = listener;
81
+ session.onOutput(listener);
75
82
 
76
83
  // Send handshake acknowledgment and full historical logs
77
84
  ws.send(
@@ -87,8 +94,8 @@ export function initWebSocketServer(port = 3001, getSession?: (id: string) => Ag
87
94
  }
88
95
 
89
96
  // User terminal input routing
90
- if (msg.type === "input" && activeSessionId) {
91
- const session = getSessionCallback ? getSessionCallback(activeSessionId) : null;
97
+ if (msg.type === "input" && ws.sessionId) {
98
+ const session = getSessionCallback ? getSessionCallback(ws.sessionId) : null;
92
99
  if (session && session.status === "running") {
93
100
  if (session.type === "mock") {
94
101
  // Buffer input for simulated command parsing in MockRunner
@@ -115,9 +122,9 @@ export function initWebSocketServer(port = 3001, getSession?: (id: string) => Ag
115
122
  }
116
123
 
117
124
  // User terminal resize routing
118
- if (msg.type === "resize" && activeSessionId) {
125
+ if (msg.type === "resize" && ws.sessionId) {
119
126
  const { cols, rows } = msg;
120
- const session = getSessionCallback ? getSessionCallback(activeSessionId) : null;
127
+ const session = getSessionCallback ? getSessionCallback(ws.sessionId) : null;
121
128
  if (session) {
122
129
  session.resize(cols, rows);
123
130
  }
@@ -128,10 +135,10 @@ export function initWebSocketServer(port = 3001, getSession?: (id: string) => Ag
128
135
  });
129
136
 
130
137
  ws.on("close", () => {
131
- if (activeSessionId && outputListener) {
132
- const session = getSessionCallback ? getSessionCallback(activeSessionId) : null;
138
+ if (ws.sessionId && ws.outputListener) {
139
+ const session = getSessionCallback ? getSessionCallback(ws.sessionId) : null;
133
140
  if (session) {
134
- session.offOutput(outputListener);
141
+ session.offOutput(ws.outputListener);
135
142
  }
136
143
  }
137
144
  console.log("[WebSocketServer] Client connection closed.");
package/.next/BUILD_ID DELETED
@@ -1 +0,0 @@
1
- W3UxhE_D02EcHxTzdXKHX
@@ -1,21 +0,0 @@
1
- {
2
- "/_global-error/page": "/_global-error",
3
- "/_not-found/page": "/_not-found",
4
- "/api/context/aider/route": "/api/context/aider",
5
- "/api/context/claude/route": "/api/context/claude",
6
- "/api/context/route": "/api/context",
7
- "/api/context/ssh/route": "/api/context/ssh",
8
- "/api/files/route": "/api/files",
9
- "/api/git/route": "/api/git",
10
- "/api/recents/route": "/api/recents",
11
- "/api/sessions/inject/route": "/api/sessions/inject",
12
- "/api/sessions/input/route": "/api/sessions/input",
13
- "/api/sessions/launch/route": "/api/sessions/launch",
14
- "/api/sessions/route": "/api/sessions",
15
- "/api/sessions/scope/route": "/api/sessions/scope",
16
- "/api/sessions/start/route": "/api/sessions/start",
17
- "/api/sessions/stats/route": "/api/sessions/stats",
18
- "/api/sessions/stop/route": "/api/sessions/stop",
19
- "/favicon.ico/route": "/favicon.ico",
20
- "/page": "/"
21
- }
@@ -1,25 +0,0 @@
1
- [
2
- {
3
- "route": "/",
4
- "firstLoadUncompressedJsBytes": 536432,
5
- "firstLoadChunkPaths": [
6
- ".next\\static\\chunks\\0dbhjjzl8qfwv.js",
7
- ".next\\static\\chunks\\01.1lqu6kmllv.js",
8
- ".next\\static\\chunks\\0fpki3y6aj230.js",
9
- ".next\\static\\chunks\\140ovxvjat1ch.js",
10
- ".next\\static\\chunks\\07lhk_q6pmm3r.js",
11
- ".next\\static\\chunks\\turbopack-08fpdsd.-ns2y.js"
12
- ]
13
- },
14
- {
15
- "route": "/_not-found",
16
- "firstLoadUncompressedJsBytes": 514388,
17
- "firstLoadChunkPaths": [
18
- ".next\\static\\chunks\\0dbhjjzl8qfwv.js",
19
- ".next\\static\\chunks\\0fpki3y6aj230.js",
20
- ".next\\static\\chunks\\140ovxvjat1ch.js",
21
- ".next\\static\\chunks\\07lhk_q6pmm3r.js",
22
- ".next\\static\\chunks\\turbopack-08fpdsd.-ns2y.js"
23
- ]
24
- }
25
- ]
@@ -1,6 +0,0 @@
1
- {
2
- "version": 1,
3
- "hasExportPathMap": false,
4
- "exportTrailingSlash": false,
5
- "isNextImageImported": false
6
- }
@@ -1,68 +0,0 @@
1
- {
2
- "version": 1,
3
- "images": {
4
- "deviceSizes": [
5
- 640,
6
- 750,
7
- 828,
8
- 1080,
9
- 1200,
10
- 1920,
11
- 2048,
12
- 3840
13
- ],
14
- "imageSizes": [
15
- 32,
16
- 48,
17
- 64,
18
- 96,
19
- 128,
20
- 256,
21
- 384
22
- ],
23
- "path": "/_next/image",
24
- "loader": "default",
25
- "loaderFile": "",
26
- "domains": [],
27
- "disableStaticImages": false,
28
- "minimumCacheTTL": 14400,
29
- "formats": [
30
- "image/webp"
31
- ],
32
- "maximumRedirects": 3,
33
- "maximumResponseBody": 50000000,
34
- "dangerouslyAllowLocalIP": false,
35
- "dangerouslyAllowSVG": false,
36
- "contentSecurityPolicy": "script-src 'none'; frame-src 'none'; sandbox;",
37
- "contentDispositionType": "attachment",
38
- "localPatterns": [
39
- {
40
- "pathname": "^(?:(?!(?:^|\\/)\\.{1,2}(?:\\/|$))(?:(?:(?!(?:^|\\/)\\.{1,2}(?:\\/|$)).)*?)\\/?)$",
41
- "search": ""
42
- }
43
- ],
44
- "remotePatterns": [],
45
- "qualities": [
46
- 75
47
- ],
48
- "unoptimized": false,
49
- "customCacheHandler": false,
50
- "sizes": [
51
- 640,
52
- 750,
53
- 828,
54
- 1080,
55
- 1200,
56
- 1920,
57
- 2048,
58
- 3840,
59
- 32,
60
- 48,
61
- 64,
62
- 96,
63
- 128,
64
- 256,
65
- 384
66
- ]
67
- }
68
- }