neural-loom 0.2.19 → 0.2.40

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 (201) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +0 -1
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/cache/.previewinfo +1 -1
  5. package/.next/cache/.rscinfo +1 -1
  6. package/.next/cache/.tsbuildinfo +1 -1
  7. package/.next/diagnostics/route-bundle-stats.json +2 -2
  8. package/.next/fallback-build-manifest.json +3 -3
  9. package/.next/prerender-manifest.json +3 -32
  10. package/.next/routes-manifest.json +0 -6
  11. package/.next/server/app/_global-error/page.js +6 -7
  12. package/.next/server/app/_global-error/page.js.nft.json +1 -1
  13. package/.next/server/app/_global-error.html +1 -1
  14. package/.next/server/app/_global-error.rsc +2 -3
  15. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  16. package/.next/server/app/_global-error.segments/_full.segment.rsc +2 -3
  17. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -2
  18. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  19. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  20. package/.next/server/app/_not-found/page.js +6 -7
  21. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  22. package/.next/server/app/_not-found.html +1 -1
  23. package/.next/server/app/_not-found.rsc +2 -2
  24. package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  25. package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  26. package/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  27. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  28. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  29. package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  30. package/.next/server/app/api/context/aider/route.js +2 -2
  31. package/.next/server/app/api/context/aider/route.js.nft.json +1 -1
  32. package/.next/server/app/api/context/claude/route.js +2 -2
  33. package/.next/server/app/api/context/claude/route.js.nft.json +1 -1
  34. package/.next/server/app/api/context/route.js +2 -2
  35. package/.next/server/app/api/context/route.js.nft.json +1 -1
  36. package/.next/server/app/api/context/ssh/route.js +2 -2
  37. package/.next/server/app/api/context/ssh/route.js.nft.json +1 -1
  38. package/.next/server/app/api/files/route.js +2 -2
  39. package/.next/server/app/api/files/route.js.nft.json +1 -1
  40. package/.next/server/app/api/git/route.js +2 -2
  41. package/.next/server/app/api/git/route.js.nft.json +1 -1
  42. package/.next/server/app/api/recents/route.js +2 -2
  43. package/.next/server/app/api/recents/route.js.nft.json +1 -1
  44. package/.next/server/app/api/sessions/inject/route.js +2 -2
  45. package/.next/server/app/api/sessions/inject/route.js.nft.json +1 -1
  46. package/.next/server/app/api/sessions/input/route.js +2 -2
  47. package/.next/server/app/api/sessions/input/route.js.nft.json +1 -1
  48. package/.next/server/app/api/sessions/launch/route.js +2 -2
  49. package/.next/server/app/api/sessions/launch/route.js.nft.json +1 -1
  50. package/.next/server/app/api/sessions/route.js +2 -2
  51. package/.next/server/app/api/sessions/route.js.nft.json +1 -1
  52. package/.next/server/app/api/sessions/scope/route.js +2 -2
  53. package/.next/server/app/api/sessions/scope/route.js.nft.json +1 -1
  54. package/.next/server/app/api/sessions/start/route.js +2 -2
  55. package/.next/server/app/api/sessions/start/route.js.nft.json +1 -1
  56. package/.next/server/app/api/sessions/stats/route.js +2 -2
  57. package/.next/server/app/api/sessions/stats/route.js.nft.json +1 -1
  58. package/.next/server/app/api/sessions/stop/route.js +2 -2
  59. package/.next/server/app/api/sessions/stop/route.js.nft.json +1 -1
  60. package/.next/server/app/index.html +1 -1
  61. package/.next/server/app/index.rsc +4 -4
  62. package/.next/server/app/index.segments/__PAGE__.segment.rsc +3 -3
  63. package/.next/server/app/index.segments/_full.segment.rsc +4 -4
  64. package/.next/server/app/index.segments/_head.segment.rsc +1 -1
  65. package/.next/server/app/index.segments/_index.segment.rsc +1 -1
  66. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  67. package/.next/server/app/page/react-loadable-manifest.json +2 -2
  68. package/.next/server/app/page.js +6 -7
  69. package/.next/server/app/page.js.nft.json +1 -1
  70. package/.next/server/app/page_client-reference-manifest.js +1 -1
  71. package/.next/server/app-paths-manifest.json +0 -1
  72. package/.next/server/chunks/{[externals]_next_dist_0arv.vj._.js → [externals]__048y_op._.js} +2 -2
  73. package/.next/server/chunks/{[root-of-the-server]__0-lisav._.js → [root-of-the-server]__0-vx6-s._.js} +3 -3
  74. package/.next/server/chunks/{[root-of-the-server]__0-lisav._.js.map → [root-of-the-server]__0-vx6-s._.js.map} +1 -1
  75. package/.next/server/chunks/{[root-of-the-server]__0k6w___._.js → [root-of-the-server]__0656ruo._.js} +3 -3
  76. package/.next/server/chunks/{[root-of-the-server]__0k6w___._.js.map → [root-of-the-server]__0656ruo._.js.map} +1 -1
  77. package/.next/server/chunks/[root-of-the-server]__0969ozy._.js +3 -0
  78. package/.next/server/chunks/{[root-of-the-server]__0l7c-gn._.js.map → [root-of-the-server]__0969ozy._.js.map} +1 -1
  79. package/.next/server/chunks/[root-of-the-server]__0d0pykb._.js +4 -4
  80. package/.next/server/chunks/[root-of-the-server]__0d0pykb._.js.map +1 -1
  81. package/.next/server/chunks/{[root-of-the-server]__0iqaxhx._.js → [root-of-the-server]__0d9_-7g._.js} +3 -3
  82. package/.next/server/chunks/{[root-of-the-server]__0iqaxhx._.js.map → [root-of-the-server]__0d9_-7g._.js.map} +1 -1
  83. package/.next/server/chunks/{[root-of-the-server]__0qz~w0~._.js → [root-of-the-server]__0fhv7.1._.js} +3 -3
  84. package/.next/server/chunks/{[root-of-the-server]__0qz~w0~._.js.map → [root-of-the-server]__0fhv7.1._.js.map} +1 -1
  85. package/.next/server/chunks/{[root-of-the-server]__0j8-xkl._.js → [root-of-the-server]__0i83~95._.js} +2 -2
  86. package/.next/server/chunks/{[root-of-the-server]__0j8-xkl._.js.map → [root-of-the-server]__0i83~95._.js.map} +1 -1
  87. package/.next/server/chunks/[root-of-the-server]__0kn5tap._.js +4 -0
  88. package/.next/server/chunks/{[root-of-the-server]__0ntt3om._.js.map → [root-of-the-server]__0kn5tap._.js.map} +1 -1
  89. package/.next/server/chunks/[root-of-the-server]__0n-zban._.js +3 -0
  90. package/.next/server/chunks/{[root-of-the-server]__0p~u94k._.js.map → [root-of-the-server]__0n-zban._.js.map} +1 -1
  91. package/.next/server/chunks/[root-of-the-server]__0qqnqov._.js +15 -0
  92. package/.next/server/chunks/{[root-of-the-server]__0m91xif._.js.map → [root-of-the-server]__0qqnqov._.js.map} +1 -1
  93. package/.next/server/chunks/[root-of-the-server]__0sa_gpm._.js +3 -0
  94. package/.next/server/chunks/[root-of-the-server]__0sa_gpm._.js.map +1 -0
  95. package/.next/server/chunks/[root-of-the-server]__0t_~on0._.js +15 -0
  96. package/.next/server/chunks/[root-of-the-server]__0t_~on0._.js.map +1 -0
  97. package/.next/server/chunks/[root-of-the-server]__0vp8-ka._.js +3 -0
  98. package/.next/server/chunks/{[root-of-the-server]__0qyrt6_._.js.map → [root-of-the-server]__0vp8-ka._.js.map} +1 -1
  99. package/.next/server/chunks/{[root-of-the-server]__0__9rdk._.js → [root-of-the-server]__0xr~y1f._.js} +3 -3
  100. package/.next/server/chunks/{[root-of-the-server]__0__9rdk._.js.map → [root-of-the-server]__0xr~y1f._.js.map} +1 -1
  101. package/.next/server/chunks/{[root-of-the-server]__0_2_i_q._.js → [root-of-the-server]__0zkcq9q._.js} +3 -3
  102. package/.next/server/chunks/{[root-of-the-server]__0_2_i_q._.js.map → [root-of-the-server]__0zkcq9q._.js.map} +1 -1
  103. package/.next/server/chunks/{[root-of-the-server]__0bi3d5z._.js → [root-of-the-server]__0~zauvq._.js} +3 -3
  104. package/.next/server/chunks/{[root-of-the-server]__0bi3d5z._.js.map → [root-of-the-server]__0~zauvq._.js.map} +1 -1
  105. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0ev3h.z.js +1 -1
  106. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0ev3h.z.js.map +1 -1
  107. package/.next/server/chunks/ssr/[root-of-the-server]__0cbmrds._.js +3 -0
  108. package/.next/server/chunks/ssr/[root-of-the-server]__0cbmrds._.js.map +1 -0
  109. package/.next/server/chunks/ssr/[root-of-the-server]__0ni-l5l._.js +3 -0
  110. package/.next/server/chunks/ssr/[root-of-the-server]__0ni-l5l._.js.map +1 -0
  111. package/.next/server/chunks/ssr/{[root-of-the-server]__089dc4i._.js → [root-of-the-server]__0tcyn68._.js} +2 -2
  112. package/.next/server/chunks/ssr/[root-of-the-server]__0tcyn68._.js.map +1 -0
  113. package/.next/server/chunks/ssr/[root-of-the-server]__0v73tbn._.js +1 -1
  114. package/.next/server/chunks/ssr/[root-of-the-server]__0v73tbn._.js.map +1 -1
  115. package/.next/server/chunks/ssr/[root-of-the-server]__0yj_dfr._.js +3 -0
  116. package/.next/server/chunks/ssr/[root-of-the-server]__0yj_dfr._.js.map +1 -0
  117. package/.next/server/chunks/ssr/_0t7oqy6._.js +1 -1
  118. package/.next/server/chunks/ssr/_0t7oqy6._.js.map +1 -1
  119. package/.next/server/chunks/ssr/{node_modules_next_dist_0ppctuh._.js → node_modules_next_dist_0-g.jog._.js} +2 -2
  120. package/.next/server/chunks/ssr/node_modules_next_dist_0-g.jog._.js.map +1 -0
  121. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0bj8dkg.js +4 -0
  122. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0bj8dkg.js.map +1 -0
  123. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0cvrgh7.js +4 -0
  124. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0cvrgh7.js.map +1 -0
  125. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0rc3ul_.js +4 -0
  126. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0rc3ul_.js.map +1 -0
  127. package/.next/server/middleware-build-manifest.js +3 -3
  128. package/.next/server/pages/404.html +1 -1
  129. package/.next/server/pages/500.html +1 -1
  130. package/.next/server/server-reference-manifest.js +1 -1
  131. package/.next/server/server-reference-manifest.json +1 -1
  132. package/.next/static/chunks/07-tub5vqy.fk.js +1 -0
  133. package/.next/static/chunks/0kkoif8x_kxrq.js +1 -0
  134. package/.next/static/chunks/{0pp.lp89pntpv.css → 0m-_sw1425nkp.css} +1 -1
  135. package/.next/static/chunks/0wq3_34inbzj6.js +1 -0
  136. package/.next/trace +1 -1
  137. package/.next/trace-build +1 -1
  138. package/package.json +1 -1
  139. package/public/logo.png +0 -0
  140. package/public/manifest.json +22 -0
  141. package/public/sw.js +12 -0
  142. package/src/app/api/context/aider/route.ts +6 -1
  143. package/src/app/api/files/route.ts +20 -8
  144. package/src/app/api/git/route.ts +117 -1
  145. package/src/app/api/sessions/route.ts +4 -1
  146. package/src/app/components/AiderWizard.tsx +19 -1
  147. package/src/app/components/IdeLayout.tsx +715 -87
  148. package/src/app/components/MarkdownPreview.tsx +528 -0
  149. package/src/app/layout.tsx +6 -0
  150. package/src/app/page.module.css +2 -0
  151. package/src/app/page.tsx +34 -19
  152. package/src/lib/agents/AiderRunner.ts +75 -36
  153. package/src/lib/agents/SessionManager.ts +18 -9
  154. package/src/lib/agents/SessionPersister.ts +10 -0
  155. package/.next/server/app/favicon.ico/route/app-paths-manifest.json +0 -3
  156. package/.next/server/app/favicon.ico/route/build-manifest.json +0 -9
  157. package/.next/server/app/favicon.ico/route.js +0 -7
  158. package/.next/server/app/favicon.ico/route.js.map +0 -5
  159. package/.next/server/app/favicon.ico/route.js.nft.json +0 -1
  160. package/.next/server/app/favicon.ico.body +0 -0
  161. package/.next/server/app/favicon.ico.meta +0 -1
  162. package/.next/server/chunks/[externals]__1334_78._.js +0 -3
  163. package/.next/server/chunks/[externals]_next_dist_0arv.vj._.js.map +0 -1
  164. package/.next/server/chunks/[root-of-the-server]__0l7c-gn._.js +0 -3
  165. package/.next/server/chunks/[root-of-the-server]__0m91xif._.js +0 -15
  166. package/.next/server/chunks/[root-of-the-server]__0ntt3om._.js +0 -3
  167. package/.next/server/chunks/[root-of-the-server]__0p~u94k._.js +0 -3
  168. package/.next/server/chunks/[root-of-the-server]__0qyrt6_._.js +0 -3
  169. package/.next/server/chunks/[root-of-the-server]__0ty8hwz._.js +0 -15
  170. package/.next/server/chunks/[root-of-the-server]__0ty8hwz._.js.map +0 -1
  171. package/.next/server/chunks/[root-of-the-server]__0ylcu31._.js +0 -3
  172. package/.next/server/chunks/[root-of-the-server]__0ylcu31._.js.map +0 -1
  173. package/.next/server/chunks/_next-internal_server_app_favicon_ico_route_actions_095lj93.js +0 -3
  174. package/.next/server/chunks/_next-internal_server_app_favicon_ico_route_actions_095lj93.js.map +0 -1
  175. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0m.429v.js +0 -3
  176. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0m.429v.js.map +0 -1
  177. package/.next/server/chunks/ssr/[root-of-the-server]__089dc4i._.js.map +0 -1
  178. package/.next/server/chunks/ssr/[root-of-the-server]__0_7i5h0._.js +0 -3
  179. package/.next/server/chunks/ssr/[root-of-the-server]__0_7i5h0._.js.map +0 -1
  180. package/.next/server/chunks/ssr/[root-of-the-server]__0hw~y-4._.js +0 -3
  181. package/.next/server/chunks/ssr/[root-of-the-server]__0hw~y-4._.js.map +0 -1
  182. package/.next/server/chunks/ssr/[root-of-the-server]__0~y8ue.._.js +0 -3
  183. package/.next/server/chunks/ssr/[root-of-the-server]__0~y8ue.._.js.map +0 -1
  184. package/.next/server/chunks/ssr/node_modules_05l396c._.js +0 -3
  185. package/.next/server/chunks/ssr/node_modules_05l396c._.js.map +0 -1
  186. package/.next/server/chunks/ssr/node_modules_next_dist_0ppctuh._.js.map +0 -1
  187. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_03-z2qq.js +0 -4
  188. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_03-z2qq.js.map +0 -1
  189. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_07vh7rm.js +0 -4
  190. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_07vh7rm.js.map +0 -1
  191. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0qp4u6g.js +0 -4
  192. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0qp4u6g.js.map +0 -1
  193. package/.next/static/chunks/01.1lqu6kmllv.js +0 -1
  194. package/.next/static/chunks/0ek0280331wie.js +0 -1
  195. package/.next/static/chunks/0jxar8nsw_py3.js +0 -1
  196. package/.next/static/media/favicon.0x3dzn~oxb6tn.ico +0 -0
  197. package/src/app/favicon.ico +0 -0
  198. /package/.next/server/chunks/{[externals]__1334_78._.js.map → [externals]__048y_op._.js.map} +0 -0
  199. /package/.next/static/{W3UxhE_D02EcHxTzdXKHX → 5uGIuH8oXybqivkeHIrqb}/_buildManifest.js +0 -0
  200. /package/.next/static/{W3UxhE_D02EcHxTzdXKHX → 5uGIuH8oXybqivkeHIrqb}/_clientMiddlewareManifest.js +0 -0
  201. /package/.next/static/{W3UxhE_D02EcHxTzdXKHX → 5uGIuH8oXybqivkeHIrqb}/_ssgManifest.js +0 -0
@@ -0,0 +1,528 @@
1
+ "use client";
2
+
3
+ import React, { useMemo, useState } from "react";
4
+
5
+ interface MarkdownPreviewProps {
6
+ content: string;
7
+ }
8
+
9
+ interface Block {
10
+ type: "p" | "h" | "code" | "blockquote" | "ul" | "ol" | "table" | "hr" | "empty";
11
+ level?: number;
12
+ content?: string | string[];
13
+ language?: string;
14
+ }
15
+
16
+ export default function MarkdownPreview({ content }: MarkdownPreviewProps) {
17
+ const blocks = useMemo(() => {
18
+ if (!content) return [];
19
+
20
+ const lines = content.split("\n");
21
+ const parsedBlocks: Block[] = [];
22
+ let currentBlock: Block | null = null;
23
+
24
+ for (let i = 0; i < lines.length; i++) {
25
+ const line = lines[i];
26
+
27
+ // Code block handling
28
+ if (currentBlock && currentBlock.type === "code") {
29
+ if (line.trim().startsWith("```")) {
30
+ parsedBlocks.push(currentBlock);
31
+ currentBlock = null;
32
+ } else {
33
+ (currentBlock.content as string[]).push(line);
34
+ }
35
+ continue;
36
+ }
37
+
38
+ // Table block handling
39
+ if (currentBlock && currentBlock.type === "table") {
40
+ if (line.trim().startsWith("|")) {
41
+ (currentBlock.content as string[]).push(line);
42
+ continue;
43
+ } else {
44
+ parsedBlocks.push(currentBlock);
45
+ currentBlock = null;
46
+ }
47
+ }
48
+
49
+ const trimmed = line.trim();
50
+
51
+ // Code block start
52
+ if (trimmed.startsWith("```")) {
53
+ if (currentBlock) parsedBlocks.push(currentBlock);
54
+ const lang = trimmed.substring(3).trim();
55
+ currentBlock = { type: "code", language: lang, content: [] };
56
+ continue;
57
+ }
58
+
59
+ // Horizontal rule
60
+ if (/^(\s*[-*_]\s*){3,}$/.test(trimmed)) {
61
+ if (currentBlock) parsedBlocks.push(currentBlock);
62
+ parsedBlocks.push({ type: "hr" });
63
+ currentBlock = null;
64
+ continue;
65
+ }
66
+
67
+ // Heading
68
+ const headingMatch = line.match(/^(#{1,6})\s+(.*)$/);
69
+ if (headingMatch) {
70
+ if (currentBlock) parsedBlocks.push(currentBlock);
71
+ parsedBlocks.push({ type: "h", level: headingMatch[1].length, content: headingMatch[2] });
72
+ currentBlock = null;
73
+ continue;
74
+ }
75
+
76
+ // Blockquote
77
+ const blockquoteMatch = line.match(/^>\s*(.*)$/);
78
+ if (blockquoteMatch) {
79
+ if (currentBlock) {
80
+ if (currentBlock.type === "blockquote") {
81
+ (currentBlock.content as string[]).push(blockquoteMatch[1]);
82
+ continue;
83
+ } else {
84
+ parsedBlocks.push(currentBlock);
85
+ }
86
+ }
87
+ currentBlock = { type: "blockquote", content: [blockquoteMatch[1]] };
88
+ continue;
89
+ }
90
+
91
+ // Unordered list
92
+ const ulMatch = line.match(/^([-*+])\s+(.*)$/);
93
+ if (ulMatch) {
94
+ if (currentBlock) {
95
+ if (currentBlock.type === "ul") {
96
+ (currentBlock.content as string[]).push(ulMatch[2]);
97
+ continue;
98
+ } else {
99
+ parsedBlocks.push(currentBlock);
100
+ }
101
+ }
102
+ currentBlock = { type: "ul", content: [ulMatch[2]] };
103
+ continue;
104
+ }
105
+
106
+ // Ordered list
107
+ const olMatch = line.match(/^(\d+)\.\s+(.*)$/);
108
+ if (olMatch) {
109
+ if (currentBlock) {
110
+ if (currentBlock.type === "ol") {
111
+ (currentBlock.content as string[]).push(olMatch[2]);
112
+ continue;
113
+ } else {
114
+ parsedBlocks.push(currentBlock);
115
+ }
116
+ }
117
+ currentBlock = { type: "ol", content: [olMatch[2]] };
118
+ continue;
119
+ }
120
+
121
+ // Table start
122
+ if (trimmed.startsWith("|")) {
123
+ if (currentBlock) parsedBlocks.push(currentBlock);
124
+ currentBlock = { type: "table", content: [line] };
125
+ continue;
126
+ }
127
+
128
+ // Empty line
129
+ if (trimmed === "") {
130
+ if (currentBlock) {
131
+ parsedBlocks.push(currentBlock);
132
+ currentBlock = null;
133
+ }
134
+ continue;
135
+ }
136
+
137
+ // Paragraph
138
+ if (currentBlock) {
139
+ if (currentBlock.type === "p") {
140
+ currentBlock.content = (currentBlock.content as string) + " " + trimmed;
141
+ } else {
142
+ parsedBlocks.push(currentBlock);
143
+ currentBlock = { type: "p", content: trimmed };
144
+ }
145
+ } else {
146
+ currentBlock = { type: "p", content: trimmed };
147
+ }
148
+ }
149
+
150
+ if (currentBlock) {
151
+ parsedBlocks.push(currentBlock);
152
+ }
153
+
154
+ return parsedBlocks;
155
+ }, [content]);
156
+
157
+ let keyCounter = 0;
158
+
159
+ // Safe inline regex-based React parser
160
+ function parseInline(text: string): React.ReactNode[] {
161
+ function parseSegment(str: string): React.ReactNode[] {
162
+ if (!str) return [];
163
+
164
+ const codeMatch = str.match(/`(.*?)`/);
165
+ const boldMatch = str.match(/\*\*(.*?)\*\*/);
166
+ const italicMatch = str.match(/\*(.*?)\*/);
167
+ const linkMatch = str.match(/\[(.*?)\]\((.*?)\)/);
168
+
169
+ const matches = [
170
+ codeMatch ? { index: codeMatch.index!, type: "code", match: codeMatch } : null,
171
+ boldMatch ? { index: boldMatch.index!, type: "bold", match: boldMatch } : null,
172
+ italicMatch ? { index: italicMatch.index!, type: "italic", match: italicMatch } : null,
173
+ linkMatch ? { index: linkMatch.index!, type: "link", match: linkMatch } : null,
174
+ ].filter(Boolean) as { index: number; type: string; match: RegExpMatchArray }[];
175
+
176
+ if (matches.length === 0) {
177
+ return [str];
178
+ }
179
+
180
+ matches.sort((a, b) => a.index - b.index);
181
+ const first = matches[0];
182
+
183
+ const prefix = str.substring(0, first.index);
184
+ const matchedText = first.match[0];
185
+ const suffix = str.substring(first.index + matchedText.length);
186
+
187
+ const nodes: React.ReactNode[] = [];
188
+ if (prefix) {
189
+ nodes.push(prefix);
190
+ }
191
+
192
+ const key = `inline-${first.type}-${keyCounter++}`;
193
+ if (first.type === "code") {
194
+ nodes.push(<code key={key} style={inlineCodeStyle}>{first.match[1]}</code>);
195
+ } else if (first.type === "bold") {
196
+ nodes.push(<strong key={key} style={{ fontWeight: 700, color: "var(--foreground)" }}>{parseSegment(first.match[1])}</strong>);
197
+ } else if (first.type === "italic") {
198
+ nodes.push(<em key={key} style={{ fontStyle: "italic" }}>{parseSegment(first.match[1])}</em>);
199
+ } else if (first.type === "link") {
200
+ nodes.push(
201
+ <a key={key} href={first.match[2]} target="_blank" rel="noopener noreferrer" style={linkStyle}>
202
+ {parseSegment(first.match[1])}
203
+ </a>
204
+ );
205
+ }
206
+
207
+ return [...nodes, ...parseSegment(suffix)];
208
+ }
209
+
210
+ return parseSegment(text);
211
+ }
212
+
213
+ function renderTable(rows: string[], key: string) {
214
+ const parsedRows = rows.map((row) =>
215
+ row
216
+ .split("|")
217
+ .map((c) => c.trim())
218
+ .filter((_, idx, arr) => idx > 0 && idx < arr.length - 1)
219
+ );
220
+
221
+ if (parsedRows.length === 0) return null;
222
+
223
+ const headers = parsedRows[0];
224
+ const dataRows = parsedRows.slice(1).filter((r) => !r.every((cell) => cell.startsWith("-") || cell === ""));
225
+
226
+ return (
227
+ <div key={key} style={tableContainerStyle}>
228
+ <table style={tableStyle}>
229
+ <thead>
230
+ <tr>
231
+ {headers.map((h, i) => (
232
+ <th key={i} style={tableHeaderStyle}>{parseInline(h)}</th>
233
+ ))}
234
+ </tr>
235
+ </thead>
236
+ <tbody>
237
+ {dataRows.map((row, rIdx) => (
238
+ <tr key={rIdx} style={rIdx % 2 === 0 ? tableRowStyleEven : tableRowStyleOdd}>
239
+ {row.map((cell, cIdx) => (
240
+ <td key={cIdx} style={tableCellStyle}>{parseInline(cell)}</td>
241
+ ))}
242
+ </tr>
243
+ ))}
244
+ </tbody>
245
+ </table>
246
+ </div>
247
+ );
248
+ }
249
+
250
+ return (
251
+ <div style={containerStyle}>
252
+ {blocks.map((block, idx) => {
253
+ const key = `block-${block.type}-${idx}`;
254
+
255
+ switch (block.type) {
256
+ case "h": {
257
+ const headingContent = parseInline(block.content as string);
258
+ switch (block.level) {
259
+ case 1:
260
+ return <h1 key={key} style={h1Style}>{headingContent}</h1>;
261
+ case 2:
262
+ return <h2 key={key} style={h2Style}>{headingContent}</h2>;
263
+ case 3:
264
+ return <h3 key={key} style={h3Style}>{headingContent}</h3>;
265
+ default:
266
+ return <h4 key={key} style={h4Style}>{headingContent}</h4>;
267
+ }
268
+ }
269
+ case "code": {
270
+ const rawCode = (block.content as string[]).join("\n");
271
+ return <CodeBlock key={key} code={rawCode} language={block.language || ""} />;
272
+ }
273
+ case "blockquote": {
274
+ return (
275
+ <blockquote key={key} style={blockquoteStyle}>
276
+ {block.content && (block.content as string[]).map((line, lIdx) => (
277
+ <p key={lIdx} style={{ margin: "0.25rem 0" }}>{parseInline(line)}</p>
278
+ ))}
279
+ </blockquote>
280
+ );
281
+ }
282
+ case "ul": {
283
+ return (
284
+ <ul key={key} style={ulStyle}>
285
+ {block.content && (block.content as string[]).map((line, lIdx) => (
286
+ <li key={lIdx} style={liStyle}>
287
+ <span style={{ marginRight: "0.5rem", color: "var(--accent)" }}>•</span>
288
+ <div style={{ flex: 1 }}>{parseInline(line)}</div>
289
+ </li>
290
+ ))}
291
+ </ul>
292
+ );
293
+ }
294
+ case "ol": {
295
+ return (
296
+ <ol key={key} style={olStyle}>
297
+ {block.content && (block.content as string[]).map((line, lIdx) => (
298
+ <li key={lIdx} style={liStyle}>
299
+ <span style={{ marginRight: "0.5rem", color: "var(--accent)", fontWeight: 600 }}>{lIdx + 1}.</span>
300
+ <div style={{ flex: 1 }}>{parseInline(line)}</div>
301
+ </li>
302
+ ))}
303
+ </ol>
304
+ );
305
+ }
306
+ case "table": {
307
+ return renderTable(block.content as string[], key);
308
+ }
309
+ case "hr": {
310
+ return <hr key={key} style={hrStyle} />;
311
+ }
312
+ case "p": {
313
+ return <p key={key} style={pStyle}>{parseInline(block.content as string)}</p>;
314
+ }
315
+ default:
316
+ return null;
317
+ }
318
+ })}
319
+ </div>
320
+ );
321
+ }
322
+
323
+ function CodeBlock({ code, language }: { code: string; language: string }) {
324
+ const [copied, setCopied] = useState(false);
325
+ const handleCopy = () => {
326
+ navigator.clipboard.writeText(code);
327
+ setCopied(true);
328
+ setTimeout(() => setCopied(false), 2000);
329
+ };
330
+ return (
331
+ <div style={codeBlockContainerStyle}>
332
+ <div style={codeBlockHeaderStyle}>
333
+ <span>{language || "code"}</span>
334
+ <button onClick={handleCopy} style={copyBtnStyle}>
335
+ {copied ? "Copied! ✓" : "Copy"}
336
+ </button>
337
+ </div>
338
+ <pre style={preStyle}><code>{code}</code></pre>
339
+ </div>
340
+ );
341
+ }
342
+
343
+ // Styling Constants for Preview Document (Vanilla dark elements matching NeuralLoom layout)
344
+ const containerStyle: React.CSSProperties = {
345
+ fontFamily: "var(--font-sans), sans-serif",
346
+ color: "var(--foreground)",
347
+ lineHeight: 1.6,
348
+ padding: "1.5rem",
349
+ overflowY: "auto",
350
+ height: "100%",
351
+ backgroundColor: "#080c14",
352
+ borderLeft: "1px solid var(--border)",
353
+ };
354
+
355
+ const pStyle: React.CSSProperties = {
356
+ fontSize: "0.875rem",
357
+ marginBottom: "1rem",
358
+ color: "var(--foreground-muted, #94a3b8)",
359
+ };
360
+
361
+ const h1Style: React.CSSProperties = {
362
+ fontSize: "1.5rem",
363
+ fontWeight: 700,
364
+ margin: "1.5rem 0 1rem 0",
365
+ paddingBottom: "0.3rem",
366
+ borderBottom: "1px solid var(--border)",
367
+ color: "var(--foreground)",
368
+ background: "linear-gradient(135deg, #fff 0%, #a855f7 100%)",
369
+ WebkitBackgroundClip: "text",
370
+ WebkitTextFillColor: "transparent",
371
+ };
372
+
373
+ const h2Style: React.CSSProperties = {
374
+ fontSize: "1.25rem",
375
+ fontWeight: 650,
376
+ margin: "1.25rem 0 0.85rem 0",
377
+ paddingBottom: "0.25rem",
378
+ borderBottom: "1px solid var(--border)",
379
+ color: "var(--foreground)",
380
+ };
381
+
382
+ const h3Style: React.CSSProperties = {
383
+ fontSize: "1.05rem",
384
+ fontWeight: 600,
385
+ margin: "1rem 0 0.75rem 0",
386
+ color: "var(--foreground)",
387
+ };
388
+
389
+ const h4Style: React.CSSProperties = {
390
+ fontSize: "0.925rem",
391
+ fontWeight: 600,
392
+ margin: "0.85rem 0 0.5rem 0",
393
+ color: "var(--foreground)",
394
+ };
395
+
396
+ const ulStyle: React.CSSProperties = {
397
+ listStyleType: "none",
398
+ padding: 0,
399
+ margin: "0 0 1rem 0",
400
+ };
401
+
402
+ const olStyle: React.CSSProperties = {
403
+ listStyleType: "none",
404
+ padding: 0,
405
+ margin: "0 0 1rem 0",
406
+ };
407
+
408
+ const liStyle: React.CSSProperties = {
409
+ display: "flex",
410
+ alignItems: "flex-start",
411
+ fontSize: "0.875rem",
412
+ marginBottom: "0.375rem",
413
+ color: "var(--foreground-muted, #94a3b8)",
414
+ };
415
+
416
+ const hrStyle: React.CSSProperties = {
417
+ border: "none",
418
+ height: "1px",
419
+ background: "linear-gradient(90deg, var(--border) 0%, rgba(255,255,255,0.05) 100%)",
420
+ margin: "1.5rem 0",
421
+ };
422
+
423
+ // Reuse code block styles
424
+ const inlineCodeStyle: React.CSSProperties = {
425
+ fontFamily: "var(--font-mono), monospace",
426
+ fontSize: "0.85em",
427
+ backgroundColor: "rgba(255, 255, 255, 0.06)",
428
+ border: "1px solid rgba(255, 255, 255, 0.08)",
429
+ borderRadius: "4px",
430
+ padding: "0.1rem 0.3rem",
431
+ color: "#f87171",
432
+ };
433
+
434
+ const linkStyle: React.CSSProperties = {
435
+ color: "#60a5fa",
436
+ textDecoration: "underline",
437
+ fontWeight: 500,
438
+ };
439
+
440
+ const tableContainerStyle: React.CSSProperties = {
441
+ width: "100%",
442
+ overflowX: "auto",
443
+ margin: "1rem 0",
444
+ borderRadius: "8px",
445
+ border: "1px solid var(--border)",
446
+ backgroundColor: "rgba(255, 255, 255, 0.01)",
447
+ };
448
+
449
+ const tableStyle: React.CSSProperties = {
450
+ width: "100%",
451
+ borderCollapse: "collapse",
452
+ fontSize: "0.85rem",
453
+ };
454
+
455
+ const tableHeaderStyle: React.CSSProperties = {
456
+ backgroundColor: "rgba(255, 255, 255, 0.03)",
457
+ borderBottom: "2px solid var(--border)",
458
+ padding: "0.5rem 0.75rem",
459
+ fontWeight: 700,
460
+ textAlign: "left",
461
+ color: "var(--foreground)",
462
+ };
463
+
464
+ const tableCellStyle: React.CSSProperties = {
465
+ borderBottom: "1px solid var(--border)",
466
+ padding: "0.5rem 0.75rem",
467
+ color: "var(--foreground-muted, #94a3b8)",
468
+ };
469
+
470
+ const tableRowStyleEven: React.CSSProperties = {
471
+ backgroundColor: "rgba(255, 255, 255, 0.01)",
472
+ };
473
+
474
+ const tableRowStyleOdd: React.CSSProperties = {
475
+ backgroundColor: "transparent",
476
+ };
477
+
478
+ const blockquoteStyle: React.CSSProperties = {
479
+ borderLeft: "4px solid #a855f7",
480
+ backgroundColor: "rgba(168, 85, 247, 0.03)",
481
+ padding: "0.5rem 1rem",
482
+ margin: "1rem 0",
483
+ borderRadius: "4px",
484
+ fontStyle: "italic",
485
+ color: "var(--muted)",
486
+ };
487
+
488
+ const codeBlockContainerStyle: React.CSSProperties = {
489
+ margin: "1rem 0",
490
+ borderRadius: "8px",
491
+ border: "1px solid var(--border)",
492
+ backgroundColor: "#05070a",
493
+ overflow: "hidden",
494
+ };
495
+
496
+ const codeBlockHeaderStyle: React.CSSProperties = {
497
+ display: "flex",
498
+ justifyContent: "space-between",
499
+ alignItems: "center",
500
+ padding: "0.35rem 0.75rem",
501
+ backgroundColor: "rgba(255, 255, 255, 0.02)",
502
+ borderBottom: "1px solid var(--border)",
503
+ fontSize: "0.7rem",
504
+ color: "var(--muted)",
505
+ textTransform: "uppercase",
506
+ fontFamily: "var(--font-mono), monospace",
507
+ };
508
+
509
+ const preStyle: React.CSSProperties = {
510
+ margin: 0,
511
+ padding: "1rem",
512
+ overflowX: "auto",
513
+ fontSize: "0.8rem",
514
+ fontFamily: "var(--font-mono), monospace",
515
+ lineHeight: 1.5,
516
+ color: "#e2e8f0",
517
+ };
518
+
519
+ const copyBtnStyle: React.CSSProperties = {
520
+ background: "none",
521
+ border: "1px solid var(--border)",
522
+ borderRadius: "4px",
523
+ padding: "2px 6px",
524
+ color: "var(--muted)",
525
+ cursor: "pointer",
526
+ fontSize: "0.65rem",
527
+ transition: "all 0.1s ease",
528
+ };
@@ -15,6 +15,12 @@ const geistMono = Geist_Mono({
15
15
  export const metadata: Metadata = {
16
16
  title: "NeuralLoom - Unified AI Agent Orchestrator & Context Bridge",
17
17
  description: "Advanced console dashboard and context staging manager for Claude Code and simulated AI agents.",
18
+ icons: {
19
+ icon: "/logo.png",
20
+ shortcut: "/logo.png",
21
+ apple: "/logo.png",
22
+ },
23
+ manifest: "/manifest.json",
18
24
  };
19
25
 
20
26
  export default function RootLayout({
@@ -335,5 +335,7 @@
335
335
  padding: 1rem 1.5rem;
336
336
  gap: 1rem;
337
337
  overflow: hidden;
338
+ max-width: none;
339
+ width: 100%;
338
340
  }
339
341
 
package/src/app/page.tsx CHANGED
@@ -89,6 +89,7 @@ export default function Home() {
89
89
  const [isClaudeDockerLaunch, setIsClaudeDockerLaunch] = useState<boolean>(false);
90
90
  const [serverCwd, setServerCwd] = useState<string>("");
91
91
  const [wsPort, setWsPort] = useState<number>(3001);
92
+ const [appVersion, setAppVersion] = useState<string>("0.2.19");
92
93
  const [lastSessionConfig, setLastSessionConfig] = useState<{
93
94
  type: 'mock' | 'claude' | 'claude-docker' | 'claude-ssh' | 'aider' | 'aider-docker';
94
95
  name?: string;
@@ -115,6 +116,9 @@ export default function Home() {
115
116
  if (data.originalCwd) {
116
117
  setServerCwd(data.originalCwd);
117
118
  }
119
+ if (data.version) {
120
+ setAppVersion(data.version);
121
+ }
118
122
  } catch (err) {
119
123
  console.error("Failed to fetch sessions:", err);
120
124
  }
@@ -140,6 +144,14 @@ export default function Home() {
140
144
  await fetchRecents();
141
145
  };
142
146
  initFetch();
147
+
148
+ // Register PWA Service Worker for standalone taskbar icon installation
149
+ if ('serviceWorker' in navigator) {
150
+ navigator.serviceWorker.register('/sw.js')
151
+ .then((reg) => console.log('Service Worker registered:', reg.scope))
152
+ .catch((err) => console.error('Service Worker registration failed:', err));
153
+ }
154
+
143
155
  const interval = setInterval(fetchSessions, 4000);
144
156
  return () => clearInterval(interval);
145
157
  }, []);
@@ -232,9 +244,12 @@ export default function Home() {
232
244
  <div className={`${styles.container} ${activeSession ? styles.containerActive : ""}`}>
233
245
  {/* Header */}
234
246
  <header className={styles.header}>
235
- <div className={styles.logoArea}>
236
- <h1 className={styles.title}>NeuralLoom</h1>
237
- <span className={styles.subtitle}>Unified AI Orchestrator & Context Bridge</span>
247
+ <div style={{ display: "flex", alignItems: "center", gap: "1.5rem" }}>
248
+ <img src="/logo.png" alt="NeuralLoom Logo" style={{ width: "160px", height: "160px", borderRadius: "16px", objectFit: "contain" }} />
249
+ <div className={styles.logoArea}>
250
+ <h1 className={styles.title} style={{ margin: 0, lineHeight: 1.1 }}>NeuralLoom</h1>
251
+ <span className={styles.subtitle}>Unified AI Orchestrator & Context Bridge</span>
252
+ </div>
238
253
  </div>
239
254
  <div className={styles.statusIndicator}>
240
255
  <span className={styles.pulseDot}></span>
@@ -470,8 +485,22 @@ export default function Home() {
470
485
  </section>
471
486
  )}
472
487
 
473
- {/* Context Hub Staging section */}
488
+ {/* Workspace Shell Terminal */}
474
489
  <section>
490
+ <h2 className={styles.sectionTitle}>Workspace Shell Terminal</h2>
491
+ <div className="card" style={{ display: "flex", flexDirection: "column", border: "1px solid var(--border)", padding: 0 }}>
492
+ <div className={styles.agentHeader} style={{ justifyContent: "space-between", background: "rgba(255, 255, 255, 0.02)" }}>
493
+ <span style={{ fontWeight: 600, display: "flex", alignItems: "center", gap: "0.5rem", fontSize: "0.85rem" }}>
494
+ 💻 Local Workspace Shell (CWD: {serverCwd || "root"})
495
+ </span>
496
+ <span style={{ fontSize: "0.7rem", color: "var(--muted)" }}>Pre-configured environment</span>
497
+ </div>
498
+ <TerminalConsole sessionId="workspace-terminal" height="300px" wsPort={wsPort} />
499
+ </div>
500
+ </section>
501
+
502
+ {/* Context Hub Staging section */}
503
+ <section style={{ marginTop: "2rem" }}>
475
504
  <h2 className={styles.sectionTitle}>Shared Context Hub & Slash Commands</h2>
476
505
  <div className={styles.contextList}>
477
506
  <div className={`${styles.contextItem} card`}>
@@ -538,20 +567,6 @@ export default function Home() {
538
567
  </div>
539
568
  <ContextEditor />
540
569
  </section>
541
-
542
- {/* Workspace Shell Terminal */}
543
- <section style={{ marginTop: "2rem" }}>
544
- <h2 className={styles.sectionTitle}>Workspace Shell Terminal</h2>
545
- <div className="card" style={{ display: "flex", flexDirection: "column", border: "1px solid var(--border)", padding: 0 }}>
546
- <div className={styles.agentHeader} style={{ justifyContent: "space-between", background: "rgba(255, 255, 255, 0.02)" }}>
547
- <span style={{ fontWeight: 600, display: "flex", alignItems: "center", gap: "0.5rem", fontSize: "0.85rem" }}>
548
- 💻 Local Workspace Shell (CWD: {serverCwd || "root"})
549
- </span>
550
- <span style={{ fontSize: "0.7rem", color: "var(--muted)" }}>Pre-configured environment</span>
551
- </div>
552
- <TerminalConsole sessionId="workspace-terminal" height="300px" wsPort={wsPort} />
553
- </div>
554
- </section>
555
570
  </main>
556
571
 
557
572
  {/* Right Panel: Environments & Actions */}
@@ -686,7 +701,7 @@ export default function Home() {
686
701
 
687
702
  {/* Footer */}
688
703
  <footer className={styles.footer}>
689
- <span>NeuralLoom v0.2.13 — Experimental AI Orchestrator Bridge</span>
704
+ <span>NeuralLoom v{appVersion} — Experimental AI Orchestrator Bridge</span>
690
705
  <span>Directory: {serverCwd || "Loading..."}</span>
691
706
  </footer>
692
707