neural-loom 0.2.13 → 0.2.14
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 +2 -0
- 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 -3
- package/.next/routes-manifest.json +12 -0
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- 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.html +1 -1
- package/.next/server/app/_not-found.rsc +1 -1
- package/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- 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 +1 -1
- package/.next/server/app/api/context/aider/route.js.nft.json +1 -1
- package/.next/server/app/api/context/claude/route.js +1 -1
- package/.next/server/app/api/context/claude/route.js.nft.json +1 -1
- package/.next/server/app/api/recents/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/recents/route/build-manifest.json +9 -0
- package/.next/server/app/api/recents/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/recents/route.js +6 -0
- package/.next/server/app/api/recents/route.js.map +5 -0
- package/.next/server/app/api/recents/route.js.nft.json +1 -0
- package/.next/server/app/api/recents/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/sessions/inject/route.js +1 -1
- package/.next/server/app/api/sessions/inject/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/input/route.js +1 -1
- package/.next/server/app/api/sessions/input/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/launch/route.js +1 -1
- package/.next/server/app/api/sessions/launch/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/route.js +1 -1
- package/.next/server/app/api/sessions/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/scope/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/sessions/scope/route/build-manifest.json +9 -0
- package/.next/server/app/api/sessions/scope/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/sessions/scope/route.js +7 -0
- package/.next/server/app/api/sessions/scope/route.js.map +5 -0
- package/.next/server/app/api/sessions/scope/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/scope/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/sessions/stats/route.js +1 -1
- package/.next/server/app/api/sessions/stats/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/stop/route.js +1 -1
- 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 +2 -2
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/index.segments/_full.segment.rsc +2 -2
- 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 +1 -1
- package/.next/server/app/page/react-loadable-manifest.json +4 -3
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +2 -0
- package/.next/server/chunks/[root-of-the-server]__0_2_i_q._.js +15 -0
- package/.next/server/chunks/{[root-of-the-server]__0rd5ojc._.js.map → [root-of-the-server]__0_2_i_q._.js.map} +1 -1
- package/.next/server/chunks/[root-of-the-server]__0__9rdk._.js +15 -0
- package/.next/server/chunks/{[root-of-the-server]__0m7xwu2._.js.map → [root-of-the-server]__0__9rdk._.js.map} +1 -1
- package/.next/server/chunks/[root-of-the-server]__0bi3d5z._.js +15 -0
- package/.next/server/chunks/{[root-of-the-server]__0ezygp7._.js.map → [root-of-the-server]__0bi3d5z._.js.map} +1 -1
- package/.next/server/chunks/[root-of-the-server]__0d0pykb._.js +3 -3
- package/.next/server/chunks/[root-of-the-server]__0d0pykb._.js.map +1 -1
- package/.next/server/chunks/[root-of-the-server]__0iqaxhx._.js +15 -0
- package/.next/server/chunks/[root-of-the-server]__0iqaxhx._.js.map +1 -0
- package/.next/server/chunks/{[root-of-the-server]__12-x1lx._.js → [root-of-the-server]__0m91xif._.js} +3 -3
- package/.next/server/chunks/{[root-of-the-server]__12-x1lx._.js.map → [root-of-the-server]__0m91xif._.js.map} +1 -1
- package/.next/server/chunks/[root-of-the-server]__0p~u94k._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0p~u94k._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0qyrt6_._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0qyrt6_._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0qz~w0~._.js +15 -0
- package/.next/server/chunks/[root-of-the-server]__0qz~w0~._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0ty8hwz._.js +15 -0
- package/.next/server/chunks/{[root-of-the-server]__0tl2n51._.js.map → [root-of-the-server]__0ty8hwz._.js.map} +1 -1
- package/.next/server/chunks/[root-of-the-server]__0ylcu31._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0ylcu31._.js.map +1 -0
- package/.next/server/chunks/_next-internal_server_app_api_recents_route_actions_0wmi3sl.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_recents_route_actions_0wmi3sl.js.map +1 -0
- package/.next/server/chunks/_next-internal_server_app_api_sessions_scope_route_actions_0g112ee.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_sessions_scope_route_actions_0g112ee.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/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/0b89ti7ob.09t.js +1 -0
- package/.next/static/chunks/0eidfx-s54367.js +1 -0
- package/.next/static/chunks/0ew-ei_k3d-qg.js +1 -0
- package/.next/static/chunks/0g45rn_9mbzt6.js +1 -0
- package/.next/static/chunks/0jxar8nsw_py3.js +1 -0
- package/.next/trace +1 -1
- package/.next/trace-build +1 -1
- package/.next/types/routes.d.ts +3 -1
- package/.next/types/validator.ts +18 -0
- package/package.json +1 -1
- package/src/app/api/context/aider/route.ts +37 -22
- package/src/app/api/context/claude/route.ts +28 -16
- package/src/app/api/recents/route.ts +34 -0
- package/src/app/api/sessions/launch/route.ts +12 -0
- package/src/app/api/sessions/scope/route.ts +139 -0
- package/src/app/components/AiderWizard.tsx +70 -4
- package/src/app/components/ClaudeWizard.tsx +70 -4
- package/src/app/components/IdeLayout.tsx +86 -12
- package/src/app/page.tsx +1 -0
- package/src/lib/agents/AgentRunner.ts +2 -0
- package/src/lib/agents/SessionManager.ts +60 -2
- package/src/lib/agents/SessionPersister.ts +4 -2
- package/src/lib/recents.ts +57 -0
- package/src/lib/workspaceParser.ts +40 -0
- package/.next/server/chunks/[root-of-the-server]__0e5cwnx._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0e5cwnx._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__0efi5cr._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0efi5cr._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__0ezygp7._.js +0 -15
- package/.next/server/chunks/[root-of-the-server]__0m7xwu2._.js +0 -15
- package/.next/server/chunks/[root-of-the-server]__0rd5ojc._.js +0 -15
- package/.next/server/chunks/[root-of-the-server]__0tl2n51._.js +0 -15
- package/.next/server/chunks/[root-of-the-server]__0y-63z8._.js +0 -15
- package/.next/server/chunks/[root-of-the-server]__0y-63z8._.js.map +0 -1
- package/.next/static/chunks/095uz52in_39t.js +0 -1
- package/.next/static/chunks/0ayrw9yot-bjb.js +0 -1
- package/.next/static/chunks/0wdcf.26dj03~.js +0 -1
- package/.next/static/chunks/178yphwi3n~oc.js +0 -1
- /package/.next/static/{w0G47Es9qpUItx3l4uJ_v → g7S_nNTPWKtmCY0Va4YcB}/_buildManifest.js +0 -0
- /package/.next/static/{w0G47Es9qpUItx3l4uJ_v → g7S_nNTPWKtmCY0Va4YcB}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{w0G47Es9qpUItx3l4uJ_v → g7S_nNTPWKtmCY0Va4YcB}/_ssgManifest.js +0 -0
package/package.json
CHANGED
|
@@ -17,36 +17,51 @@ function maskKey(key: string): string {
|
|
|
17
17
|
return `${key.slice(0, 6)}...${key.slice(-4)}`;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
import { getWorkspaceFileFolders } from "@/lib/workspaceParser";
|
|
21
|
+
|
|
20
22
|
export async function GET() {
|
|
21
23
|
try {
|
|
24
|
+
let openaiApiKey = "";
|
|
25
|
+
let anthropicApiKey = "";
|
|
26
|
+
let geminiApiKey = "";
|
|
27
|
+
let model = "claude-3-5-sonnet";
|
|
28
|
+
let extraFlags = "";
|
|
29
|
+
let workspaceRoot = "";
|
|
30
|
+
let scopedDirs: string[] = [];
|
|
31
|
+
|
|
22
32
|
if (fs.existsSync(configPath)) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
config:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
},
|
|
37
|
-
});
|
|
33
|
+
try {
|
|
34
|
+
const rawData = fs.readFileSync(configPath, "utf8");
|
|
35
|
+
const config = JSON.parse(rawData);
|
|
36
|
+
openaiApiKey = config.openaiApiKey ? maskKey(config.openaiApiKey) : "";
|
|
37
|
+
anthropicApiKey = config.anthropicApiKey ? maskKey(config.anthropicApiKey) : "";
|
|
38
|
+
geminiApiKey = config.geminiApiKey ? maskKey(config.geminiApiKey) : "";
|
|
39
|
+
model = config.model || "claude-3-5-sonnet";
|
|
40
|
+
extraFlags = config.extraFlags || "";
|
|
41
|
+
workspaceRoot = config.workspaceRoot || "";
|
|
42
|
+
scopedDirs = config.scopedDirs || [];
|
|
43
|
+
} catch (e) {
|
|
44
|
+
console.error("Failed to parse aider.json:", e);
|
|
45
|
+
}
|
|
38
46
|
}
|
|
39
47
|
|
|
48
|
+
// Resolve workspace folders from the code-workspace file if it exists
|
|
49
|
+
const rootToScan = workspaceRoot || process.env.ORIGINAL_CWD || process.cwd();
|
|
50
|
+
const wsFolders = getWorkspaceFileFolders(rootToScan);
|
|
51
|
+
|
|
52
|
+
// Merge scopedDirs, filtering out duplicates
|
|
53
|
+
const mergedScopes = Array.from(new Set([...scopedDirs, ...wsFolders]));
|
|
54
|
+
|
|
40
55
|
return NextResponse.json({
|
|
41
56
|
success: true,
|
|
42
57
|
config: {
|
|
43
|
-
openaiApiKey
|
|
44
|
-
anthropicApiKey
|
|
45
|
-
geminiApiKey
|
|
46
|
-
model
|
|
47
|
-
extraFlags
|
|
48
|
-
workspaceRoot
|
|
49
|
-
scopedDirs:
|
|
58
|
+
openaiApiKey,
|
|
59
|
+
anthropicApiKey,
|
|
60
|
+
geminiApiKey,
|
|
61
|
+
model,
|
|
62
|
+
extraFlags,
|
|
63
|
+
workspaceRoot,
|
|
64
|
+
scopedDirs: mergedScopes,
|
|
50
65
|
},
|
|
51
66
|
});
|
|
52
67
|
} catch (error) {
|
|
@@ -11,30 +11,42 @@ function ensureDir() {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
import { getWorkspaceFileFolders } from "@/lib/workspaceParser";
|
|
15
|
+
|
|
14
16
|
export async function GET() {
|
|
15
17
|
try {
|
|
18
|
+
let name = "Claude Local";
|
|
19
|
+
let workspaceRoot = "";
|
|
20
|
+
let scopedDirs: string[] = [];
|
|
21
|
+
let extraFlags = "";
|
|
22
|
+
|
|
16
23
|
if (fs.existsSync(configPath)) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
config
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
},
|
|
28
|
-
});
|
|
24
|
+
try {
|
|
25
|
+
const rawData = fs.readFileSync(configPath, "utf8");
|
|
26
|
+
const config = JSON.parse(rawData);
|
|
27
|
+
name = config.name || "Claude Local";
|
|
28
|
+
workspaceRoot = config.workspaceRoot || "";
|
|
29
|
+
scopedDirs = config.scopedDirs || [];
|
|
30
|
+
extraFlags = config.extraFlags || "";
|
|
31
|
+
} catch (e) {
|
|
32
|
+
console.error("Failed to parse claude.json:", e);
|
|
33
|
+
}
|
|
29
34
|
}
|
|
30
35
|
|
|
36
|
+
// Resolve workspace folders from the code-workspace file if it exists
|
|
37
|
+
const rootToScan = workspaceRoot || process.env.ORIGINAL_CWD || process.cwd();
|
|
38
|
+
const wsFolders = getWorkspaceFileFolders(rootToScan);
|
|
39
|
+
|
|
40
|
+
// Merge scopedDirs, filtering out duplicates
|
|
41
|
+
const mergedScopes = Array.from(new Set([...scopedDirs, ...wsFolders]));
|
|
42
|
+
|
|
31
43
|
return NextResponse.json({
|
|
32
44
|
success: true,
|
|
33
45
|
config: {
|
|
34
|
-
name
|
|
35
|
-
workspaceRoot
|
|
36
|
-
scopedDirs:
|
|
37
|
-
extraFlags
|
|
46
|
+
name,
|
|
47
|
+
workspaceRoot,
|
|
48
|
+
scopedDirs: mergedScopes,
|
|
49
|
+
extraFlags,
|
|
38
50
|
},
|
|
39
51
|
});
|
|
40
52
|
} catch (error) {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { loadRecents, addRecent } from "@/lib/recents";
|
|
3
|
+
|
|
4
|
+
export async function GET() {
|
|
5
|
+
try {
|
|
6
|
+
const recents = loadRecents();
|
|
7
|
+
return NextResponse.json({ success: true, recents });
|
|
8
|
+
} catch (error) {
|
|
9
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
10
|
+
return NextResponse.json({ success: false, error: errorMessage }, { status: 500 });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function POST(request: Request) {
|
|
15
|
+
try {
|
|
16
|
+
const body = await request.json();
|
|
17
|
+
const { type, path } = body;
|
|
18
|
+
|
|
19
|
+
if (!type || !path) {
|
|
20
|
+
return NextResponse.json({ success: false, error: "Missing type or path" }, { status: 400 });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (type !== "workspace" && type !== "scope") {
|
|
24
|
+
return NextResponse.json({ success: false, error: "Invalid type. Must be 'workspace' or 'scope'" }, { status: 400 });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
addRecent(type, path);
|
|
28
|
+
const recents = loadRecents();
|
|
29
|
+
return NextResponse.json({ success: true, recents });
|
|
30
|
+
} catch (error) {
|
|
31
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
32
|
+
return NextResponse.json({ success: false, error: errorMessage }, { status: 500 });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { NextResponse } from "next/server";
|
|
2
2
|
import { SessionManager } from "@/lib/agents/SessionManager";
|
|
3
|
+
import { addRecent } from "@/lib/recents";
|
|
3
4
|
|
|
4
5
|
export async function POST(request: Request) {
|
|
5
6
|
try {
|
|
@@ -14,6 +15,17 @@ export async function POST(request: Request) {
|
|
|
14
15
|
const manager = SessionManager.getInstance();
|
|
15
16
|
const session = await manager.createSession(type, name, workspaceRoot, scopedDirs);
|
|
16
17
|
|
|
18
|
+
// Save workspace root to recents list
|
|
19
|
+
if (workspaceRoot) {
|
|
20
|
+
addRecent("workspace", workspaceRoot);
|
|
21
|
+
}
|
|
22
|
+
// Save scoped directories to recents list
|
|
23
|
+
if (scopedDirs && Array.isArray(scopedDirs)) {
|
|
24
|
+
for (const dir of scopedDirs) {
|
|
25
|
+
addRecent("scope", dir);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
17
29
|
return NextResponse.json({
|
|
18
30
|
success: true,
|
|
19
31
|
session: session.getStatus()
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { SessionManager } from "@/lib/agents/SessionManager";
|
|
3
|
+
import { SessionPersister } from "@/lib/agents/SessionPersister";
|
|
4
|
+
import { ContextManager } from "@/lib/agents/ContextManager";
|
|
5
|
+
import { addRecent } from "@/lib/recents";
|
|
6
|
+
import fs from "fs";
|
|
7
|
+
import path from "path";
|
|
8
|
+
|
|
9
|
+
export async function POST(request: Request) {
|
|
10
|
+
try {
|
|
11
|
+
const body = await request.json();
|
|
12
|
+
const { sessionId, path: newPath, action = "add" } = body;
|
|
13
|
+
|
|
14
|
+
if (!sessionId || !newPath) {
|
|
15
|
+
return NextResponse.json({ error: "Missing sessionId or path" }, { status: 400 });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const manager = SessionManager.getInstance();
|
|
19
|
+
const session = manager.getSession(sessionId);
|
|
20
|
+
|
|
21
|
+
if (!session) {
|
|
22
|
+
return NextResponse.json({ error: "Session not found" }, { status: 404 });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Normalize path
|
|
26
|
+
const resolvedPath = path.resolve(newPath).replace(/\\/g, "/");
|
|
27
|
+
|
|
28
|
+
if (action === "add") {
|
|
29
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
30
|
+
return NextResponse.json({ error: "Path does not exist on the server" }, { status: 400 });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 1. Add to active session runner
|
|
34
|
+
if (!session.scopedDirs) {
|
|
35
|
+
session.scopedDirs = [];
|
|
36
|
+
}
|
|
37
|
+
if (!session.scopedDirs.includes(resolvedPath)) {
|
|
38
|
+
session.scopedDirs.push(resolvedPath);
|
|
39
|
+
SessionPersister.saveSession(session, true);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 2. Carry over to global configurations for next Launch
|
|
43
|
+
const configDir = path.join(process.env.ORIGINAL_CWD || process.cwd(), ".ai", "neural-loom");
|
|
44
|
+
|
|
45
|
+
if (session.type === "claude" || session.type === "claude-docker") {
|
|
46
|
+
const claudeConfigPath = path.join(configDir, "claude.json");
|
|
47
|
+
if (fs.existsSync(claudeConfigPath)) {
|
|
48
|
+
try {
|
|
49
|
+
const config = JSON.parse(fs.readFileSync(claudeConfigPath, "utf8"));
|
|
50
|
+
if (!config.scopedDirs) config.scopedDirs = [];
|
|
51
|
+
if (!config.scopedDirs.includes(resolvedPath)) {
|
|
52
|
+
config.scopedDirs.push(resolvedPath);
|
|
53
|
+
fs.writeFileSync(claudeConfigPath, JSON.stringify(config, null, 2), "utf8");
|
|
54
|
+
}
|
|
55
|
+
} catch (err) {
|
|
56
|
+
console.error("Failed to update claude.json with new scoped folder:", err);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
} else if (session.type === "aider" || session.type === "aider-docker") {
|
|
60
|
+
const aiderConfigPath = path.join(configDir, "aider.json");
|
|
61
|
+
if (fs.existsSync(aiderConfigPath)) {
|
|
62
|
+
try {
|
|
63
|
+
const config = JSON.parse(fs.readFileSync(aiderConfigPath, "utf8"));
|
|
64
|
+
if (!config.scopedDirs) config.scopedDirs = [];
|
|
65
|
+
if (!config.scopedDirs.includes(resolvedPath)) {
|
|
66
|
+
config.scopedDirs.push(resolvedPath);
|
|
67
|
+
fs.writeFileSync(aiderConfigPath, JSON.stringify(config, null, 2), "utf8");
|
|
68
|
+
}
|
|
69
|
+
} catch (err) {
|
|
70
|
+
console.error("Failed to update aider.json with new scoped folder:", err);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Add to recents
|
|
76
|
+
addRecent("scope", resolvedPath);
|
|
77
|
+
|
|
78
|
+
// Re-compile context & hot-reload in runner
|
|
79
|
+
const root = session.workspaceRoot || process.env.ORIGINAL_CWD || process.cwd();
|
|
80
|
+
ContextManager.compileSessionContext(root, session.scopedDirs);
|
|
81
|
+
if (session.status === "running") {
|
|
82
|
+
await manager.injectCommand(sessionId, "/ccc");
|
|
83
|
+
}
|
|
84
|
+
} else if (action === "remove") {
|
|
85
|
+
// 1. Remove from active session runner
|
|
86
|
+
if (session.scopedDirs) {
|
|
87
|
+
session.scopedDirs = session.scopedDirs.filter(p => p !== resolvedPath);
|
|
88
|
+
SessionPersister.saveSession(session, true);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 2. Remove from global configuration so it doesn't carry over
|
|
92
|
+
const configDir = path.join(process.env.ORIGINAL_CWD || process.cwd(), ".ai", "neural-loom");
|
|
93
|
+
|
|
94
|
+
if (session.type === "claude" || session.type === "claude-docker") {
|
|
95
|
+
const claudeConfigPath = path.join(configDir, "claude.json");
|
|
96
|
+
if (fs.existsSync(claudeConfigPath)) {
|
|
97
|
+
try {
|
|
98
|
+
const config = JSON.parse(fs.readFileSync(claudeConfigPath, "utf8"));
|
|
99
|
+
if (config.scopedDirs) {
|
|
100
|
+
config.scopedDirs = config.scopedDirs.filter((p: string) => p !== resolvedPath);
|
|
101
|
+
fs.writeFileSync(claudeConfigPath, JSON.stringify(config, null, 2), "utf8");
|
|
102
|
+
}
|
|
103
|
+
} catch (err) {
|
|
104
|
+
console.error("Failed to remove scoped folder from claude.json:", err);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
} else if (session.type === "aider" || session.type === "aider-docker") {
|
|
108
|
+
const aiderConfigPath = path.join(configDir, "aider.json");
|
|
109
|
+
if (fs.existsSync(aiderConfigPath)) {
|
|
110
|
+
try {
|
|
111
|
+
const config = JSON.parse(fs.readFileSync(aiderConfigPath, "utf8"));
|
|
112
|
+
if (config.scopedDirs) {
|
|
113
|
+
config.scopedDirs = config.scopedDirs.filter((p: string) => p !== resolvedPath);
|
|
114
|
+
fs.writeFileSync(aiderConfigPath, JSON.stringify(config, null, 2), "utf8");
|
|
115
|
+
}
|
|
116
|
+
} catch (err) {
|
|
117
|
+
console.error("Failed to remove scoped folder from aider.json:", err);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Re-compile context & hot-reload in runner
|
|
123
|
+
const root = session.workspaceRoot || process.env.ORIGINAL_CWD || process.cwd();
|
|
124
|
+
ContextManager.compileSessionContext(root, session.scopedDirs);
|
|
125
|
+
if (session.status === "running") {
|
|
126
|
+
await manager.injectCommand(sessionId, "/ccc");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return NextResponse.json({
|
|
131
|
+
success: true,
|
|
132
|
+
scopedDirs: session.scopedDirs || []
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
} catch (error) {
|
|
136
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
137
|
+
return NextResponse.json({ error: errorMessage }, { status: 500 });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
@@ -36,10 +36,11 @@ export default function AiderWizard({ onClose, onConfirmLaunch, isDocker }: Aide
|
|
|
36
36
|
const [errorMessage, setErrorMessage] = useState("");
|
|
37
37
|
const [isBrowsingWorkspace, setIsBrowsingWorkspace] = useState(false);
|
|
38
38
|
const [isBrowsingScope, setIsBrowsingScope] = useState(false);
|
|
39
|
+
const [recents, setRecents] = useState<{ workspaces: string[]; scopes: string[] }>({ workspaces: [], scopes: [] });
|
|
39
40
|
|
|
40
|
-
// Load config on mount
|
|
41
|
+
// Load config and recents on mount
|
|
41
42
|
useEffect(() => {
|
|
42
|
-
const
|
|
43
|
+
const loadConfigAndRecents = async () => {
|
|
43
44
|
try {
|
|
44
45
|
const res = await fetch("/api/context/aider");
|
|
45
46
|
if (res.ok) {
|
|
@@ -56,14 +57,22 @@ export default function AiderWizard({ onClose, onConfirmLaunch, isDocker }: Aide
|
|
|
56
57
|
});
|
|
57
58
|
}
|
|
58
59
|
}
|
|
60
|
+
|
|
61
|
+
const recentsRes = await fetch("/api/recents");
|
|
62
|
+
if (recentsRes.ok) {
|
|
63
|
+
const rData = await recentsRes.json();
|
|
64
|
+
if (rData.success && rData.recents) {
|
|
65
|
+
setRecents(rData.recents);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
59
68
|
} catch (err) {
|
|
60
|
-
console.error("Failed to load Aider configuration:", err);
|
|
69
|
+
console.error("Failed to load Aider configuration / recents:", err);
|
|
61
70
|
} finally {
|
|
62
71
|
setIsLoading(false);
|
|
63
72
|
}
|
|
64
73
|
};
|
|
65
74
|
|
|
66
|
-
|
|
75
|
+
loadConfigAndRecents();
|
|
67
76
|
}, []);
|
|
68
77
|
|
|
69
78
|
const handleSaveAndLaunch = async () => {
|
|
@@ -172,6 +181,31 @@ export default function AiderWizard({ onClose, onConfirmLaunch, isDocker }: Aide
|
|
|
172
181
|
Browse...
|
|
173
182
|
</button>
|
|
174
183
|
</div>
|
|
184
|
+
{recents.workspaces.length > 0 && (
|
|
185
|
+
<div style={{ marginTop: "0.35rem", display: "flex", gap: "0.35rem", flexWrap: "wrap", alignItems: "center" }}>
|
|
186
|
+
<span style={{ fontSize: "0.65rem", color: "var(--muted)" }}>Recent:</span>
|
|
187
|
+
{recents.workspaces.map((wsPath) => (
|
|
188
|
+
<button
|
|
189
|
+
key={wsPath}
|
|
190
|
+
type="button"
|
|
191
|
+
onClick={() => setConfig({ ...config, workspaceRoot: wsPath })}
|
|
192
|
+
style={{
|
|
193
|
+
background: "rgba(255,255,255,0.03)",
|
|
194
|
+
border: "1px solid var(--border)",
|
|
195
|
+
borderRadius: "3px",
|
|
196
|
+
color: "var(--muted)",
|
|
197
|
+
fontSize: "0.65rem",
|
|
198
|
+
padding: "1px 6px",
|
|
199
|
+
cursor: "pointer",
|
|
200
|
+
fontFamily: "var(--font-mono)"
|
|
201
|
+
}}
|
|
202
|
+
title={wsPath}
|
|
203
|
+
>
|
|
204
|
+
{wsPath.split(/[/\\]/).pop() || wsPath}
|
|
205
|
+
</button>
|
|
206
|
+
))}
|
|
207
|
+
</div>
|
|
208
|
+
)}
|
|
175
209
|
<span style={{ fontSize: "0.7rem", color: "var(--muted)", marginTop: "0.25rem" }}>
|
|
176
210
|
Leave blank to default to the current orchestrator directory.
|
|
177
211
|
</span>
|
|
@@ -238,6 +272,38 @@ export default function AiderWizard({ onClose, onConfirmLaunch, isDocker }: Aide
|
|
|
238
272
|
Add
|
|
239
273
|
</button>
|
|
240
274
|
</div>
|
|
275
|
+
{recents.scopes.length > 0 && (
|
|
276
|
+
<div style={{ marginTop: "0.35rem", display: "flex", gap: "0.35rem", flexWrap: "wrap", alignItems: "center" }}>
|
|
277
|
+
<span style={{ fontSize: "0.65rem", color: "var(--muted)" }}>Recent:</span>
|
|
278
|
+
{recents.scopes
|
|
279
|
+
.filter(scopePath => !config.scopedDirs.includes(scopePath))
|
|
280
|
+
.map((scopePath) => (
|
|
281
|
+
<button
|
|
282
|
+
key={scopePath}
|
|
283
|
+
type="button"
|
|
284
|
+
onClick={() => {
|
|
285
|
+
if (!config.scopedDirs.includes(scopePath)) {
|
|
286
|
+
setConfig({ ...config, scopedDirs: [...config.scopedDirs, scopePath] });
|
|
287
|
+
}
|
|
288
|
+
}}
|
|
289
|
+
style={{
|
|
290
|
+
background: "rgba(168, 85, 247, 0.05)",
|
|
291
|
+
border: "1px solid rgba(168, 85, 247, 0.2)",
|
|
292
|
+
borderRadius: "3px",
|
|
293
|
+
color: "#c084fc",
|
|
294
|
+
fontSize: "0.65rem",
|
|
295
|
+
padding: "1px 6px",
|
|
296
|
+
cursor: "pointer",
|
|
297
|
+
fontFamily: "var(--font-mono)"
|
|
298
|
+
}}
|
|
299
|
+
title={scopePath}
|
|
300
|
+
>
|
|
301
|
+
+{scopePath.split(/[/\\]/).pop() || scopePath}
|
|
302
|
+
</button>
|
|
303
|
+
))
|
|
304
|
+
}
|
|
305
|
+
</div>
|
|
306
|
+
)}
|
|
241
307
|
</div>
|
|
242
308
|
|
|
243
309
|
<div style={formGroupStyle}>
|
|
@@ -30,10 +30,11 @@ export default function ClaudeWizard({ onClose, onConfirmLaunch, isDocker }: Cla
|
|
|
30
30
|
const [errorMessage, setErrorMessage] = useState("");
|
|
31
31
|
const [isBrowsingWorkspace, setIsBrowsingWorkspace] = useState(false);
|
|
32
32
|
const [isBrowsingScope, setIsBrowsingScope] = useState(false);
|
|
33
|
+
const [recents, setRecents] = useState<{ workspaces: string[]; scopes: string[] }>({ workspaces: [], scopes: [] });
|
|
33
34
|
|
|
34
|
-
// Load config on mount
|
|
35
|
+
// Load config and recents on mount
|
|
35
36
|
useEffect(() => {
|
|
36
|
-
const
|
|
37
|
+
const loadConfigAndRecents = async () => {
|
|
37
38
|
try {
|
|
38
39
|
const res = await fetch("/api/context/claude");
|
|
39
40
|
if (res.ok) {
|
|
@@ -47,14 +48,22 @@ export default function ClaudeWizard({ onClose, onConfirmLaunch, isDocker }: Cla
|
|
|
47
48
|
});
|
|
48
49
|
}
|
|
49
50
|
}
|
|
51
|
+
|
|
52
|
+
const recentsRes = await fetch("/api/recents");
|
|
53
|
+
if (recentsRes.ok) {
|
|
54
|
+
const rData = await recentsRes.json();
|
|
55
|
+
if (rData.success && rData.recents) {
|
|
56
|
+
setRecents(rData.recents);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
50
59
|
} catch (err) {
|
|
51
|
-
console.error("Failed to load Claude configuration:", err);
|
|
60
|
+
console.error("Failed to load Claude configuration / recents:", err);
|
|
52
61
|
} finally {
|
|
53
62
|
setIsLoading(false);
|
|
54
63
|
}
|
|
55
64
|
};
|
|
56
65
|
|
|
57
|
-
|
|
66
|
+
loadConfigAndRecents();
|
|
58
67
|
}, [isDocker]);
|
|
59
68
|
|
|
60
69
|
const handleSaveAndLaunch = async () => {
|
|
@@ -141,6 +150,31 @@ export default function ClaudeWizard({ onClose, onConfirmLaunch, isDocker }: Cla
|
|
|
141
150
|
Browse...
|
|
142
151
|
</button>
|
|
143
152
|
</div>
|
|
153
|
+
{recents.workspaces.length > 0 && (
|
|
154
|
+
<div style={{ marginTop: "0.35rem", display: "flex", gap: "0.35rem", flexWrap: "wrap", alignItems: "center" }}>
|
|
155
|
+
<span style={{ fontSize: "0.65rem", color: "var(--muted)" }}>Recent:</span>
|
|
156
|
+
{recents.workspaces.map((wsPath) => (
|
|
157
|
+
<button
|
|
158
|
+
key={wsPath}
|
|
159
|
+
type="button"
|
|
160
|
+
onClick={() => setConfig({ ...config, workspaceRoot: wsPath })}
|
|
161
|
+
style={{
|
|
162
|
+
background: "rgba(255,255,255,0.03)",
|
|
163
|
+
border: "1px solid var(--border)",
|
|
164
|
+
borderRadius: "3px",
|
|
165
|
+
color: "var(--muted)",
|
|
166
|
+
fontSize: "0.65rem",
|
|
167
|
+
padding: "1px 6px",
|
|
168
|
+
cursor: "pointer",
|
|
169
|
+
fontFamily: "var(--font-mono)"
|
|
170
|
+
}}
|
|
171
|
+
title={wsPath}
|
|
172
|
+
>
|
|
173
|
+
{wsPath.split(/[/\\]/).pop() || wsPath}
|
|
174
|
+
</button>
|
|
175
|
+
))}
|
|
176
|
+
</div>
|
|
177
|
+
)}
|
|
144
178
|
<span style={{ fontSize: "0.7rem", color: "var(--muted)", marginTop: "0.25rem" }}>
|
|
145
179
|
The active folder Claude Code will run in. Leave blank to run in the current orchestrator directory.
|
|
146
180
|
</span>
|
|
@@ -221,6 +255,38 @@ export default function ClaudeWizard({ onClose, onConfirmLaunch, isDocker }: Cla
|
|
|
221
255
|
Add
|
|
222
256
|
</button>
|
|
223
257
|
</div>
|
|
258
|
+
{recents.scopes.length > 0 && (
|
|
259
|
+
<div style={{ marginTop: "0.35rem", display: "flex", gap: "0.35rem", flexWrap: "wrap", alignItems: "center" }}>
|
|
260
|
+
<span style={{ fontSize: "0.65rem", color: "var(--muted)" }}>Recent:</span>
|
|
261
|
+
{recents.scopes
|
|
262
|
+
.filter(scopePath => !config.scopedDirs.includes(scopePath))
|
|
263
|
+
.map((scopePath) => (
|
|
264
|
+
<button
|
|
265
|
+
key={scopePath}
|
|
266
|
+
type="button"
|
|
267
|
+
onClick={() => {
|
|
268
|
+
if (!config.scopedDirs.includes(scopePath)) {
|
|
269
|
+
setConfig({ ...config, scopedDirs: [...config.scopedDirs, scopePath] });
|
|
270
|
+
}
|
|
271
|
+
}}
|
|
272
|
+
style={{
|
|
273
|
+
background: "rgba(168, 85, 247, 0.05)",
|
|
274
|
+
border: "1px solid rgba(168, 85, 247, 0.2)",
|
|
275
|
+
borderRadius: "3px",
|
|
276
|
+
color: "#c084fc",
|
|
277
|
+
fontSize: "0.65rem",
|
|
278
|
+
padding: "1px 6px",
|
|
279
|
+
cursor: "pointer",
|
|
280
|
+
fontFamily: "var(--font-mono)"
|
|
281
|
+
}}
|
|
282
|
+
title={scopePath}
|
|
283
|
+
>
|
|
284
|
+
+{scopePath.split(/[/\\]/).pop() || scopePath}
|
|
285
|
+
</button>
|
|
286
|
+
))
|
|
287
|
+
}
|
|
288
|
+
</div>
|
|
289
|
+
)}
|
|
224
290
|
</div>
|
|
225
291
|
|
|
226
292
|
{errorMessage && (
|