brainctl 0.1.25 → 0.1.26
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/dist/ui/routes.js +57 -13
- package/dist/web/assets/index-DA6dMqS1.js +63 -0
- package/dist/web/assets/index-DWHJW1mo.css +2 -0
- package/dist/web/assets/index-Dfl6zkjD.js +63 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/assets/index-CQbRl-ip.css +0 -2
- package/dist/web/assets/index-Dpa_8Gkh.js +0 -63
- package/dist/web/assets/index-DpcVh6Yo.js +0 -63
package/dist/ui/routes.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
|
-
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { readFile, readdir, stat } from 'node:fs/promises';
|
|
3
3
|
import { BrainctlError, ProfileError, ProfileNotFoundError, ValidationError } from '../errors.js';
|
|
4
4
|
import { createAgentConfigService } from '../services/agent/agent-config-service.js';
|
|
5
5
|
import { createMcpPreflightService } from '../services/platform/mcp-preflight-service.js';
|
|
@@ -16,6 +16,17 @@ import path from 'node:path';
|
|
|
16
16
|
import os from 'node:os';
|
|
17
17
|
import { fileURLToPath } from 'node:url';
|
|
18
18
|
import { spawn } from 'node:child_process';
|
|
19
|
+
function revealInFileManager(targetPath) {
|
|
20
|
+
if (process.platform === 'darwin') {
|
|
21
|
+
spawn('open', ['-R', targetPath], { detached: true, stdio: 'ignore' }).unref();
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (process.platform === 'win32') {
|
|
25
|
+
spawn('explorer', [`/select,${targetPath}`], { detached: true, stdio: 'ignore' }).unref();
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
spawn('xdg-open', [path.dirname(targetPath)], { detached: true, stdio: 'ignore' }).unref();
|
|
29
|
+
}
|
|
19
30
|
function resolveCwd(req, fallback) {
|
|
20
31
|
const url = new URL(req.url ?? '/', 'http://localhost');
|
|
21
32
|
const raw = url.searchParams.get('cwd');
|
|
@@ -89,13 +100,8 @@ export function createUiRouteHandler(dependencies) {
|
|
|
89
100
|
if (!existsSync(folderPath)) {
|
|
90
101
|
return sendJson(response, 404, { error: `Path not found: ${folderPath}` });
|
|
91
102
|
}
|
|
92
|
-
const opener = process.platform === 'darwin'
|
|
93
|
-
? 'open'
|
|
94
|
-
: process.platform === 'win32'
|
|
95
|
-
? 'explorer'
|
|
96
|
-
: 'xdg-open';
|
|
97
103
|
try {
|
|
98
|
-
|
|
104
|
+
revealInFileManager(folderPath);
|
|
99
105
|
return sendJson(response, 200, { ok: true, path: folderPath });
|
|
100
106
|
}
|
|
101
107
|
catch (error) {
|
|
@@ -221,6 +227,49 @@ export function createUiRouteHandler(dependencies) {
|
|
|
221
227
|
const recents = await recentProjectsService.addRecent(cwd);
|
|
222
228
|
return sendJson(response, 200, { recents });
|
|
223
229
|
}
|
|
230
|
+
case '/api/fs/browse': {
|
|
231
|
+
if (request.method !== 'GET') {
|
|
232
|
+
return sendJson(response, 405, { error: 'Method not allowed' });
|
|
233
|
+
}
|
|
234
|
+
const raw = url.searchParams.get('path');
|
|
235
|
+
const mode = url.searchParams.get('mode') === 'file' ? 'file' : 'dir';
|
|
236
|
+
const startPath = raw && path.isAbsolute(raw) ? raw : os.homedir();
|
|
237
|
+
try {
|
|
238
|
+
const stats = await stat(startPath);
|
|
239
|
+
if (!stats.isDirectory()) {
|
|
240
|
+
return sendJson(response, 400, { error: 'Path is not a directory' });
|
|
241
|
+
}
|
|
242
|
+
const entries = await readdir(startPath, { withFileTypes: true });
|
|
243
|
+
const items = entries
|
|
244
|
+
.filter((entry) => !entry.name.startsWith('.'))
|
|
245
|
+
.filter((entry) => {
|
|
246
|
+
if (mode === 'file')
|
|
247
|
+
return entry.isDirectory() || entry.isFile();
|
|
248
|
+
return entry.isDirectory();
|
|
249
|
+
})
|
|
250
|
+
.map((entry) => ({
|
|
251
|
+
name: entry.name,
|
|
252
|
+
isDir: entry.isDirectory(),
|
|
253
|
+
}))
|
|
254
|
+
.sort((a, b) => {
|
|
255
|
+
if (a.isDir !== b.isDir)
|
|
256
|
+
return a.isDir ? -1 : 1;
|
|
257
|
+
return a.name.localeCompare(b.name);
|
|
258
|
+
});
|
|
259
|
+
const parent = path.dirname(startPath);
|
|
260
|
+
return sendJson(response, 200, {
|
|
261
|
+
path: startPath,
|
|
262
|
+
parent: parent === startPath ? null : parent,
|
|
263
|
+
home: os.homedir(),
|
|
264
|
+
entries: items,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
return sendJson(response, 404, {
|
|
269
|
+
error: error instanceof Error ? error.message : 'Cannot read path',
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
}
|
|
224
273
|
case '/api/profiles/snapshot': {
|
|
225
274
|
if (request.method !== 'POST') {
|
|
226
275
|
return sendJson(response, 405, { error: 'Method not allowed' });
|
|
@@ -258,13 +307,8 @@ export function createUiRouteHandler(dependencies) {
|
|
|
258
307
|
if (!existsSync(folderPath)) {
|
|
259
308
|
return sendJson(response, 404, { error: `Profile folder not found: ${folderPath}` });
|
|
260
309
|
}
|
|
261
|
-
const opener = process.platform === 'darwin'
|
|
262
|
-
? 'open'
|
|
263
|
-
: process.platform === 'win32'
|
|
264
|
-
? 'explorer'
|
|
265
|
-
: 'xdg-open';
|
|
266
310
|
try {
|
|
267
|
-
|
|
311
|
+
revealInFileManager(folderPath);
|
|
268
312
|
return sendJson(response, 200, { ok: true, path: folderPath });
|
|
269
313
|
}
|
|
270
314
|
catch (error) {
|