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.
- package/.next/BUILD_ID +1 -1
- package/.next/app-path-routes-manifest.json +0 -1
- package/.next/build-manifest.json +3 -3
- package/.next/cache/.previewinfo +1 -1
- package/.next/cache/.rscinfo +1 -1
- package/.next/cache/.tsbuildinfo +1 -1
- package/.next/diagnostics/route-bundle-stats.json +2 -2
- package/.next/fallback-build-manifest.json +3 -3
- package/.next/prerender-manifest.json +3 -32
- package/.next/routes-manifest.json +0 -6
- package/.next/server/app/_global-error/page.js +6 -7
- package/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +2 -3
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +2 -3
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -2
- package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page.js +6 -7
- package/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +2 -2
- package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/api/context/aider/route.js +2 -2
- package/.next/server/app/api/context/aider/route.js.nft.json +1 -1
- package/.next/server/app/api/context/claude/route.js +2 -2
- package/.next/server/app/api/context/claude/route.js.nft.json +1 -1
- package/.next/server/app/api/context/route.js +2 -2
- package/.next/server/app/api/context/route.js.nft.json +1 -1
- package/.next/server/app/api/context/ssh/route.js +2 -2
- package/.next/server/app/api/context/ssh/route.js.nft.json +1 -1
- package/.next/server/app/api/files/route.js +2 -2
- package/.next/server/app/api/files/route.js.nft.json +1 -1
- package/.next/server/app/api/git/route.js +2 -2
- package/.next/server/app/api/git/route.js.nft.json +1 -1
- package/.next/server/app/api/recents/route.js +2 -2
- package/.next/server/app/api/recents/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/inject/route.js +2 -2
- package/.next/server/app/api/sessions/inject/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/input/route.js +2 -2
- package/.next/server/app/api/sessions/input/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/launch/route.js +2 -2
- package/.next/server/app/api/sessions/launch/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/route.js +2 -2
- package/.next/server/app/api/sessions/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/scope/route.js +2 -2
- package/.next/server/app/api/sessions/scope/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/start/route.js +2 -2
- package/.next/server/app/api/sessions/start/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/stats/route.js +2 -2
- package/.next/server/app/api/sessions/stats/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/stop/route.js +2 -2
- package/.next/server/app/api/sessions/stop/route.js.nft.json +1 -1
- package/.next/server/app/index.html +1 -1
- package/.next/server/app/index.rsc +4 -4
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +3 -3
- package/.next/server/app/index.segments/_full.segment.rsc +4 -4
- package/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/page/react-loadable-manifest.json +2 -2
- package/.next/server/app/page.js +6 -7
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +0 -1
- package/.next/server/chunks/{[externals]_next_dist_0arv.vj._.js → [externals]__048y_op._.js} +2 -2
- package/.next/server/chunks/{[root-of-the-server]__0-lisav._.js → [root-of-the-server]__0-vx6-s._.js} +3 -3
- package/.next/server/chunks/{[root-of-the-server]__0-lisav._.js.map → [root-of-the-server]__0-vx6-s._.js.map} +1 -1
- package/.next/server/chunks/{[root-of-the-server]__0k6w___._.js → [root-of-the-server]__0656ruo._.js} +3 -3
- package/.next/server/chunks/{[root-of-the-server]__0k6w___._.js.map → [root-of-the-server]__0656ruo._.js.map} +1 -1
- package/.next/server/chunks/[root-of-the-server]__0969ozy._.js +3 -0
- package/.next/server/chunks/{[root-of-the-server]__0l7c-gn._.js.map → [root-of-the-server]__0969ozy._.js.map} +1 -1
- package/.next/server/chunks/[root-of-the-server]__0d0pykb._.js +4 -4
- package/.next/server/chunks/[root-of-the-server]__0d0pykb._.js.map +1 -1
- package/.next/server/chunks/{[root-of-the-server]__0iqaxhx._.js → [root-of-the-server]__0d9_-7g._.js} +3 -3
- package/.next/server/chunks/{[root-of-the-server]__0iqaxhx._.js.map → [root-of-the-server]__0d9_-7g._.js.map} +1 -1
- package/.next/server/chunks/{[root-of-the-server]__0qz~w0~._.js → [root-of-the-server]__0fhv7.1._.js} +3 -3
- package/.next/server/chunks/{[root-of-the-server]__0qz~w0~._.js.map → [root-of-the-server]__0fhv7.1._.js.map} +1 -1
- package/.next/server/chunks/{[root-of-the-server]__0j8-xkl._.js → [root-of-the-server]__0i83~95._.js} +2 -2
- package/.next/server/chunks/{[root-of-the-server]__0j8-xkl._.js.map → [root-of-the-server]__0i83~95._.js.map} +1 -1
- package/.next/server/chunks/[root-of-the-server]__0kn5tap._.js +4 -0
- package/.next/server/chunks/{[root-of-the-server]__0ntt3om._.js.map → [root-of-the-server]__0kn5tap._.js.map} +1 -1
- package/.next/server/chunks/[root-of-the-server]__0n-zban._.js +3 -0
- package/.next/server/chunks/{[root-of-the-server]__0p~u94k._.js.map → [root-of-the-server]__0n-zban._.js.map} +1 -1
- package/.next/server/chunks/[root-of-the-server]__0qqnqov._.js +15 -0
- package/.next/server/chunks/{[root-of-the-server]__0m91xif._.js.map → [root-of-the-server]__0qqnqov._.js.map} +1 -1
- package/.next/server/chunks/[root-of-the-server]__0sa_gpm._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0sa_gpm._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0t_~on0._.js +15 -0
- package/.next/server/chunks/[root-of-the-server]__0t_~on0._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0vp8-ka._.js +3 -0
- package/.next/server/chunks/{[root-of-the-server]__0qyrt6_._.js.map → [root-of-the-server]__0vp8-ka._.js.map} +1 -1
- package/.next/server/chunks/{[root-of-the-server]__0__9rdk._.js → [root-of-the-server]__0xr~y1f._.js} +3 -3
- package/.next/server/chunks/{[root-of-the-server]__0__9rdk._.js.map → [root-of-the-server]__0xr~y1f._.js.map} +1 -1
- package/.next/server/chunks/{[root-of-the-server]__0_2_i_q._.js → [root-of-the-server]__0zkcq9q._.js} +3 -3
- package/.next/server/chunks/{[root-of-the-server]__0_2_i_q._.js.map → [root-of-the-server]__0zkcq9q._.js.map} +1 -1
- package/.next/server/chunks/{[root-of-the-server]__0bi3d5z._.js → [root-of-the-server]__0~zauvq._.js} +3 -3
- package/.next/server/chunks/{[root-of-the-server]__0bi3d5z._.js.map → [root-of-the-server]__0~zauvq._.js.map} +1 -1
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0ev3h.z.js +1 -1
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0ev3h.z.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0cbmrds._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0cbmrds._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0ni-l5l._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0ni-l5l._.js.map +1 -0
- package/.next/server/chunks/ssr/{[root-of-the-server]__089dc4i._.js → [root-of-the-server]__0tcyn68._.js} +2 -2
- package/.next/server/chunks/ssr/[root-of-the-server]__0tcyn68._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0v73tbn._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0v73tbn._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0yj_dfr._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0yj_dfr._.js.map +1 -0
- package/.next/server/chunks/ssr/_0t7oqy6._.js +1 -1
- package/.next/server/chunks/ssr/_0t7oqy6._.js.map +1 -1
- package/.next/server/chunks/ssr/{node_modules_next_dist_0ppctuh._.js → node_modules_next_dist_0-g.jog._.js} +2 -2
- package/.next/server/chunks/ssr/node_modules_next_dist_0-g.jog._.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0bj8dkg.js +4 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0bj8dkg.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0cvrgh7.js +4 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0cvrgh7.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0rc3ul_.js +4 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0rc3ul_.js.map +1 -0
- package/.next/server/middleware-build-manifest.js +3 -3
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/07-tub5vqy.fk.js +1 -0
- package/.next/static/chunks/0kkoif8x_kxrq.js +1 -0
- package/.next/static/chunks/{0pp.lp89pntpv.css → 0m-_sw1425nkp.css} +1 -1
- package/.next/static/chunks/0wq3_34inbzj6.js +1 -0
- package/.next/trace +1 -1
- package/.next/trace-build +1 -1
- package/package.json +1 -1
- package/public/logo.png +0 -0
- package/public/manifest.json +22 -0
- package/public/sw.js +12 -0
- package/src/app/api/context/aider/route.ts +6 -1
- package/src/app/api/files/route.ts +20 -8
- package/src/app/api/git/route.ts +117 -1
- package/src/app/api/sessions/route.ts +4 -1
- package/src/app/components/AiderWizard.tsx +19 -1
- package/src/app/components/IdeLayout.tsx +715 -87
- package/src/app/components/MarkdownPreview.tsx +528 -0
- package/src/app/layout.tsx +6 -0
- package/src/app/page.module.css +2 -0
- package/src/app/page.tsx +34 -19
- package/src/lib/agents/AiderRunner.ts +75 -36
- package/src/lib/agents/SessionManager.ts +18 -9
- package/src/lib/agents/SessionPersister.ts +10 -0
- package/.next/server/app/favicon.ico/route/app-paths-manifest.json +0 -3
- package/.next/server/app/favicon.ico/route/build-manifest.json +0 -9
- package/.next/server/app/favicon.ico/route.js +0 -7
- package/.next/server/app/favicon.ico/route.js.map +0 -5
- package/.next/server/app/favicon.ico/route.js.nft.json +0 -1
- package/.next/server/app/favicon.ico.body +0 -0
- package/.next/server/app/favicon.ico.meta +0 -1
- package/.next/server/chunks/[externals]__1334_78._.js +0 -3
- package/.next/server/chunks/[externals]_next_dist_0arv.vj._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__0l7c-gn._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0m91xif._.js +0 -15
- package/.next/server/chunks/[root-of-the-server]__0ntt3om._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0p~u94k._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0qyrt6_._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0ty8hwz._.js +0 -15
- package/.next/server/chunks/[root-of-the-server]__0ty8hwz._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__0ylcu31._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0ylcu31._.js.map +0 -1
- package/.next/server/chunks/_next-internal_server_app_favicon_ico_route_actions_095lj93.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_favicon_ico_route_actions_095lj93.js.map +0 -1
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0m.429v.js +0 -3
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0m.429v.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__089dc4i._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0_7i5h0._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0_7i5h0._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0hw~y-4._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0hw~y-4._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0~y8ue.._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0~y8ue.._.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_05l396c._.js +0 -3
- package/.next/server/chunks/ssr/node_modules_05l396c._.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_0ppctuh._.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_03-z2qq.js +0 -4
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_03-z2qq.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_07vh7rm.js +0 -4
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_07vh7rm.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0qp4u6g.js +0 -4
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0qp4u6g.js.map +0 -1
- package/.next/static/chunks/01.1lqu6kmllv.js +0 -1
- package/.next/static/chunks/0ek0280331wie.js +0 -1
- package/.next/static/chunks/0jxar8nsw_py3.js +0 -1
- package/.next/static/media/favicon.0x3dzn~oxb6tn.ico +0 -0
- package/src/app/favicon.ico +0 -0
- /package/.next/server/chunks/{[externals]__1334_78._.js.map → [externals]__048y_op._.js.map} +0 -0
- /package/.next/static/{W3UxhE_D02EcHxTzdXKHX → 5uGIuH8oXybqivkeHIrqb}/_buildManifest.js +0 -0
- /package/.next/static/{W3UxhE_D02EcHxTzdXKHX → 5uGIuH8oXybqivkeHIrqb}/_clientMiddlewareManifest.js +0 -0
- /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
|
+
};
|
package/src/app/layout.tsx
CHANGED
|
@@ -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({
|
package/src/app/page.module.css
CHANGED
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
|
|
236
|
-
<
|
|
237
|
-
<
|
|
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
|
-
{/*
|
|
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
|
|
704
|
+
<span>NeuralLoom v{appVersion} — Experimental AI Orchestrator Bridge</span>
|
|
690
705
|
<span>Directory: {serverCwd || "Loading..."}</span>
|
|
691
706
|
</footer>
|
|
692
707
|
|