neural-loom 0.2.18 → 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 +10 -5
- 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 +40 -10
- package/src/lib/agents/AgentRunner.ts +2 -2
- package/src/lib/agents/AiderRunner.ts +75 -36
- package/src/lib/agents/SessionManager.ts +25 -10
- package/src/lib/agents/SessionPersister.ts +10 -0
- package/src/lib/agents/ShellRunner.ts +159 -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/0ek0280331wie.js +0 -1
- package/.next/static/chunks/0jxar8nsw_py3.js +0 -1
- package/.next/static/chunks/0whfmx9l_25d4.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/{OOK46QJncZAPJTv2oCT-X → 5uGIuH8oXybqivkeHIrqb}/_buildManifest.js +0 -0
- /package/.next/static/{OOK46QJncZAPJTv2oCT-X → 5uGIuH8oXybqivkeHIrqb}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{OOK46QJncZAPJTv2oCT-X → 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;
|
|
@@ -96,9 +97,10 @@ export default function Home() {
|
|
|
96
97
|
scopedDirs?: string[];
|
|
97
98
|
} | null>(null);
|
|
98
99
|
|
|
100
|
+
const activeAgents = sessions.filter(s => s.id !== "workspace-terminal");
|
|
99
101
|
const activeSession = sessions.find(s => s.id === activeSessionId);
|
|
100
|
-
const isDockerActive =
|
|
101
|
-
const isSshActive =
|
|
102
|
+
const isDockerActive = activeAgents.some(s => (s.type === 'claude-docker' || s.type === 'aider-docker') && s.status === 'running');
|
|
103
|
+
const isSshActive = activeAgents.some(s => s.type === 'claude-ssh' && s.status === 'running');
|
|
102
104
|
|
|
103
105
|
// Fetch all sessions on mount & periodically
|
|
104
106
|
const fetchSessions = async () => {
|
|
@@ -114,6 +116,9 @@ export default function Home() {
|
|
|
114
116
|
if (data.originalCwd) {
|
|
115
117
|
setServerCwd(data.originalCwd);
|
|
116
118
|
}
|
|
119
|
+
if (data.version) {
|
|
120
|
+
setAppVersion(data.version);
|
|
121
|
+
}
|
|
117
122
|
} catch (err) {
|
|
118
123
|
console.error("Failed to fetch sessions:", err);
|
|
119
124
|
}
|
|
@@ -139,6 +144,14 @@ export default function Home() {
|
|
|
139
144
|
await fetchRecents();
|
|
140
145
|
};
|
|
141
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
|
+
|
|
142
155
|
const interval = setInterval(fetchSessions, 4000);
|
|
143
156
|
return () => clearInterval(interval);
|
|
144
157
|
}, []);
|
|
@@ -231,9 +244,12 @@ export default function Home() {
|
|
|
231
244
|
<div className={`${styles.container} ${activeSession ? styles.containerActive : ""}`}>
|
|
232
245
|
{/* Header */}
|
|
233
246
|
<header className={styles.header}>
|
|
234
|
-
<div
|
|
235
|
-
<
|
|
236
|
-
<
|
|
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>
|
|
237
253
|
</div>
|
|
238
254
|
<div className={styles.statusIndicator}>
|
|
239
255
|
<span className={styles.pulseDot}></span>
|
|
@@ -263,7 +279,7 @@ export default function Home() {
|
|
|
263
279
|
<section>
|
|
264
280
|
<h2 className={styles.sectionTitle}>Active AI Agents</h2>
|
|
265
281
|
|
|
266
|
-
{
|
|
282
|
+
{activeAgents.length === 0 ? (
|
|
267
283
|
<div className="card" style={{ padding: "3rem 1.5rem", textAlign: "center" }}>
|
|
268
284
|
<p style={{ color: "var(--muted)", marginBottom: "1.5rem" }}>
|
|
269
285
|
No active agent sessions in this workspace. Launch a Claude or Aider agent session to begin.
|
|
@@ -334,7 +350,7 @@ export default function Home() {
|
|
|
334
350
|
</div>
|
|
335
351
|
) : (
|
|
336
352
|
<div className={styles.agentGrid}>
|
|
337
|
-
{
|
|
353
|
+
{activeAgents.map(session => (
|
|
338
354
|
<div key={session.id} className={`${styles.agentCard} card ${activeSessionId === session.id ? styles.activeBorder : ""}`}>
|
|
339
355
|
<div className={styles.agentHeader}>
|
|
340
356
|
<span className={styles.agentName}>{session.name}</span>
|
|
@@ -410,7 +426,7 @@ export default function Home() {
|
|
|
410
426
|
</section>
|
|
411
427
|
|
|
412
428
|
{/* Interactive Session Terminal Display */}
|
|
413
|
-
{activeSessionId && (
|
|
429
|
+
{activeSessionId && activeSessionId !== "workspace-terminal" && (
|
|
414
430
|
<section className="card" style={{ display: "flex", flexDirection: "column", border: "1px solid var(--border-focus)" }}>
|
|
415
431
|
<div className={styles.agentHeader} style={{ justifyContent: "space-between", background: "rgba(109, 40, 217, 0.08)" }}>
|
|
416
432
|
<span style={{ fontWeight: 600, display: "flex", alignItems: "center", gap: "0.5rem" }}>
|
|
@@ -469,8 +485,22 @@ export default function Home() {
|
|
|
469
485
|
</section>
|
|
470
486
|
)}
|
|
471
487
|
|
|
472
|
-
{/*
|
|
488
|
+
{/* Workspace Shell Terminal */}
|
|
473
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" }}>
|
|
474
504
|
<h2 className={styles.sectionTitle}>Shared Context Hub & Slash Commands</h2>
|
|
475
505
|
<div className={styles.contextList}>
|
|
476
506
|
<div className={`${styles.contextItem} card`}>
|
|
@@ -671,7 +701,7 @@ export default function Home() {
|
|
|
671
701
|
|
|
672
702
|
{/* Footer */}
|
|
673
703
|
<footer className={styles.footer}>
|
|
674
|
-
<span>NeuralLoom
|
|
704
|
+
<span>NeuralLoom v{appVersion} — Experimental AI Orchestrator Bridge</span>
|
|
675
705
|
<span>Directory: {serverCwd || "Loading..."}</span>
|
|
676
706
|
</footer>
|
|
677
707
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export interface RunnerStatus {
|
|
2
2
|
id: string;
|
|
3
3
|
name: string;
|
|
4
|
-
type: 'mock' | 'claude' | 'claude-docker' | 'claude-ssh' | 'aider' | 'aider-docker';
|
|
4
|
+
type: 'mock' | 'claude' | 'claude-docker' | 'claude-ssh' | 'aider' | 'aider-docker' | 'shell';
|
|
5
5
|
status: 'idle' | 'running' | 'stopped';
|
|
6
6
|
createdAt: string;
|
|
7
7
|
logsCount: number;
|
|
@@ -14,7 +14,7 @@ export interface RunnerStatus {
|
|
|
14
14
|
export abstract class AgentRunner {
|
|
15
15
|
abstract id: string;
|
|
16
16
|
abstract name: string;
|
|
17
|
-
abstract type: 'mock' | 'claude' | 'claude-docker' | 'claude-ssh' | 'aider' | 'aider-docker';
|
|
17
|
+
abstract type: 'mock' | 'claude' | 'claude-docker' | 'claude-ssh' | 'aider' | 'aider-docker' | 'shell';
|
|
18
18
|
abstract status: 'idle' | 'running' | 'stopped';
|
|
19
19
|
abstract createdAt: string;
|
|
20
20
|
abstract logs: string[];
|