@bahulam/code 0.1.13 → 0.1.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/package.json +1 -1
- package/src/commands/install.mjs +87 -0
- package/src/commands/plugin-manage.mjs +215 -29
- package/src/config/model-catalog-default.json +0 -4
- package/src/core/resume-mode.mjs +0 -1
- package/src/core/stream-client.mjs +18 -0
- package/src/daemon/session-core.mjs +3 -0
- package/src/local-service/agent-relay.mjs +6 -1
- package/src/local-service/file-access.mjs +116 -2
- package/src/local-service/server.mjs +209 -20
- package/src/plugins/npm-install.mjs +138 -0
- package/src/plugins/pi-compat/requirements.mjs +465 -0
- package/src/plugins/pi-compat/scaffold.mjs +86 -10
- package/src/plugins/pi-compat/shim.mjs +29 -1
- package/src/plugins/preflight.mjs +2 -0
- package/src/terminal/main.mjs +2 -1
- package/src/terminal/repl.mjs +52 -23
- package/src/ui/input-dock.mjs +48 -10
- package/src/ui/text-layout.mjs +4 -3
|
@@ -6,6 +6,7 @@ import * as fs from 'node:fs';
|
|
|
6
6
|
import * as path from 'node:path';
|
|
7
7
|
|
|
8
8
|
const DEFAULT_MAX_ENTRIES = 300;
|
|
9
|
+
const DEFAULT_MAX_SEARCH_RESULTS = 200;
|
|
9
10
|
const DEFAULT_MAX_TEXT_BYTES = 256 * 1024;
|
|
10
11
|
export const DEFAULT_MAX_RAW_BYTES = 100 * 1024 * 1024;
|
|
11
12
|
|
|
@@ -42,8 +43,8 @@ const EXTENSION_FILE_TYPES = new Map([
|
|
|
42
43
|
['env', { kind: 'config', language: 'plaintext', label: 'Environment', textLike: true }],
|
|
43
44
|
['properties', { kind: 'config', language: 'plaintext', label: 'Properties', textLike: true }],
|
|
44
45
|
['xml', { kind: 'code', language: 'xml', label: 'XML', textLike: true }],
|
|
45
|
-
['html', { kind: '
|
|
46
|
-
['htm', { kind: '
|
|
46
|
+
['html', { kind: 'web', language: 'html', label: 'HTML', textLike: true }],
|
|
47
|
+
['htm', { kind: 'web', language: 'html', label: 'HTML', textLike: true }],
|
|
47
48
|
['css', { kind: 'code', language: 'css', label: 'CSS', textLike: true }],
|
|
48
49
|
['scss', { kind: 'code', language: 'scss', label: 'SCSS', textLike: true }],
|
|
49
50
|
['sass', { kind: 'code', language: 'scss', label: 'Sass', textLike: true }],
|
|
@@ -110,6 +111,18 @@ const EXTENSION_FILE_TYPES = new Map([
|
|
|
110
111
|
['svg', { kind: 'image', language: 'xml', label: 'SVG Image', textLike: false }],
|
|
111
112
|
['bmp', { kind: 'image', language: null, label: 'Bitmap Image', textLike: false }],
|
|
112
113
|
['ico', { kind: 'image', language: null, label: 'Icon', textLike: false }],
|
|
114
|
+
['avif', { kind: 'image', language: null, label: 'AVIF Image', textLike: false }],
|
|
115
|
+
['mp4', { kind: 'video', language: null, label: 'MP4 Video', textLike: false }],
|
|
116
|
+
['webm', { kind: 'video', language: null, label: 'WebM Video', textLike: false }],
|
|
117
|
+
['mov', { kind: 'video', language: null, label: 'QuickTime Video', textLike: false }],
|
|
118
|
+
['m4v', { kind: 'video', language: null, label: 'M4V Video', textLike: false }],
|
|
119
|
+
['ogv', { kind: 'video', language: null, label: 'Ogg Video', textLike: false }],
|
|
120
|
+
['mp3', { kind: 'audio', language: null, label: 'MP3 Audio', textLike: false }],
|
|
121
|
+
['m4a', { kind: 'audio', language: null, label: 'M4A Audio', textLike: false }],
|
|
122
|
+
['wav', { kind: 'audio', language: null, label: 'WAV Audio', textLike: false }],
|
|
123
|
+
['ogg', { kind: 'audio', language: null, label: 'Ogg Audio', textLike: false }],
|
|
124
|
+
['flac', { kind: 'audio', language: null, label: 'FLAC Audio', textLike: false }],
|
|
125
|
+
['aac', { kind: 'audio', language: null, label: 'AAC Audio', textLike: false }],
|
|
113
126
|
['pdf', { kind: 'pdf', language: null, label: 'PDF', textLike: false }],
|
|
114
127
|
['xlsx', { kind: 'spreadsheet', language: null, label: 'Excel Workbook', textLike: false }],
|
|
115
128
|
['xls', { kind: 'spreadsheet', language: null, label: 'Excel Workbook', textLike: false }],
|
|
@@ -165,12 +178,16 @@ export function listWorkspacePath(session, requestedPath = '.', { maxEntries = D
|
|
|
165
178
|
try {
|
|
166
179
|
childStat = fs.statSync(fullPath);
|
|
167
180
|
} catch {}
|
|
181
|
+
const file = childStat?.isFile() ? describeFile(root, fullPath, childStat) : null;
|
|
168
182
|
return {
|
|
169
183
|
name: entry.name,
|
|
170
184
|
path: normalizeRelative(root, fullPath),
|
|
171
185
|
type: entry.isDirectory() ? 'directory' : entry.isFile() ? 'file' : 'other',
|
|
172
186
|
size: childStat?.size ?? null,
|
|
173
187
|
updated_at: childStat?.mtime ? childStat.mtime.toISOString() : null,
|
|
188
|
+
kind: file?.kind ?? (entry.isDirectory() ? 'directory' : null),
|
|
189
|
+
viewer: file?.viewer ?? (entry.isDirectory() ? 'directory' : null),
|
|
190
|
+
label: file?.label ?? null,
|
|
174
191
|
};
|
|
175
192
|
});
|
|
176
193
|
|
|
@@ -201,6 +218,88 @@ export function listWorkspacePath(session, requestedPath = '.', { maxEntries = D
|
|
|
201
218
|
};
|
|
202
219
|
}
|
|
203
220
|
|
|
221
|
+
export function searchWorkspaceFiles(session, {
|
|
222
|
+
query = '',
|
|
223
|
+
kinds = [],
|
|
224
|
+
maxResults = DEFAULT_MAX_SEARCH_RESULTS,
|
|
225
|
+
} = {}) {
|
|
226
|
+
const root = fs.realpathSync(session.root_path);
|
|
227
|
+
const wanted = new Set((Array.isArray(kinds) ? kinds : String(kinds || '').split(','))
|
|
228
|
+
.map((kind) => String(kind || '').trim().toLowerCase())
|
|
229
|
+
.filter(Boolean)
|
|
230
|
+
.filter((kind) => kind !== 'all'));
|
|
231
|
+
const term = String(query || '').trim().toLowerCase();
|
|
232
|
+
const limit = Math.max(1, Math.min(1000, Number(maxResults) || DEFAULT_MAX_SEARCH_RESULTS));
|
|
233
|
+
const results = [];
|
|
234
|
+
|
|
235
|
+
function visit(dir) {
|
|
236
|
+
if (results.length >= limit) return;
|
|
237
|
+
let entries = [];
|
|
238
|
+
try {
|
|
239
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
240
|
+
} catch {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
entries.sort((a, b) => {
|
|
244
|
+
if (a.isDirectory() !== b.isDirectory()) return a.isDirectory() ? -1 : 1;
|
|
245
|
+
return a.name.localeCompare(b.name);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
for (const entry of entries) {
|
|
249
|
+
if (results.length >= limit) break;
|
|
250
|
+
if (shouldHideEntry(entry.name)) continue;
|
|
251
|
+
const fullPath = path.join(dir, entry.name);
|
|
252
|
+
let stat = null;
|
|
253
|
+
try {
|
|
254
|
+
stat = fs.statSync(fullPath);
|
|
255
|
+
} catch {
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
const rel = normalizeRelative(root, fullPath);
|
|
259
|
+
if (entry.isDirectory()) {
|
|
260
|
+
if ((!term || entry.name.toLowerCase().includes(term) || rel.toLowerCase().includes(term))
|
|
261
|
+
&& (!wanted.size || wanted.has('directory'))) {
|
|
262
|
+
results.push({
|
|
263
|
+
name: entry.name,
|
|
264
|
+
path: rel,
|
|
265
|
+
type: 'directory',
|
|
266
|
+
size: null,
|
|
267
|
+
updated_at: stat.mtime.toISOString(),
|
|
268
|
+
kind: 'directory',
|
|
269
|
+
viewer: 'directory',
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
visit(fullPath);
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
if (!entry.isFile()) continue;
|
|
276
|
+
const file = describeFile(root, fullPath, stat);
|
|
277
|
+
if (wanted.size && !wanted.has(file.kind) && !wanted.has(file.viewer)) continue;
|
|
278
|
+
if (term && !entry.name.toLowerCase().includes(term) && !rel.toLowerCase().includes(term)) continue;
|
|
279
|
+
results.push({
|
|
280
|
+
name: entry.name,
|
|
281
|
+
path: rel,
|
|
282
|
+
type: 'file',
|
|
283
|
+
size: stat.size,
|
|
284
|
+
updated_at: stat.mtime.toISOString(),
|
|
285
|
+
kind: file.kind,
|
|
286
|
+
viewer: file.viewer,
|
|
287
|
+
label: file.label,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
visit(root);
|
|
293
|
+
return {
|
|
294
|
+
ok: true,
|
|
295
|
+
type: 'search',
|
|
296
|
+
query: term,
|
|
297
|
+
kinds: [...wanted],
|
|
298
|
+
results,
|
|
299
|
+
truncated: results.length >= limit,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
204
303
|
export function readWorkspaceFile(session, requestedPath, { maxBytes = DEFAULT_MAX_TEXT_BYTES } = {}) {
|
|
205
304
|
const target = resolveWorkspacePath(session, requestedPath);
|
|
206
305
|
const stat = fs.statSync(target);
|
|
@@ -252,6 +351,18 @@ export function contentTypeForPath(filePath) {
|
|
|
252
351
|
case 'svg': return 'image/svg+xml';
|
|
253
352
|
case 'bmp': return 'image/bmp';
|
|
254
353
|
case 'ico': return 'image/x-icon';
|
|
354
|
+
case 'avif': return 'image/avif';
|
|
355
|
+
case 'mp4': return 'video/mp4';
|
|
356
|
+
case 'webm': return 'video/webm';
|
|
357
|
+
case 'mov': return 'video/quicktime';
|
|
358
|
+
case 'm4v': return 'video/x-m4v';
|
|
359
|
+
case 'ogv': return 'video/ogg';
|
|
360
|
+
case 'mp3': return 'audio/mpeg';
|
|
361
|
+
case 'm4a': return 'audio/mp4';
|
|
362
|
+
case 'wav': return 'audio/wav';
|
|
363
|
+
case 'ogg': return 'audio/ogg';
|
|
364
|
+
case 'flac': return 'audio/flac';
|
|
365
|
+
case 'aac': return 'audio/aac';
|
|
255
366
|
case 'pdf': return 'application/pdf';
|
|
256
367
|
case 'txt':
|
|
257
368
|
case 'log':
|
|
@@ -351,7 +462,10 @@ function viewerForKind(kind) {
|
|
|
351
462
|
case 'mermaid': return 'mermaid';
|
|
352
463
|
case 'drawio': return 'drawio';
|
|
353
464
|
case 'image': return 'image';
|
|
465
|
+
case 'video': return 'video';
|
|
466
|
+
case 'audio': return 'audio';
|
|
354
467
|
case 'pdf': return 'pdf';
|
|
468
|
+
case 'web': return 'web';
|
|
355
469
|
case 'spreadsheet': return 'spreadsheet';
|
|
356
470
|
case 'document': return 'document';
|
|
357
471
|
case 'presentation': return 'presentation';
|
|
@@ -19,8 +19,8 @@ import {
|
|
|
19
19
|
DEFAULT_MAX_RAW_BYTES,
|
|
20
20
|
contentTypeForPath,
|
|
21
21
|
listWorkspacePath,
|
|
22
|
-
readWorkspaceFile,
|
|
23
22
|
resolveWorkspacePath,
|
|
23
|
+
searchWorkspaceFiles,
|
|
24
24
|
} from './file-access.mjs';
|
|
25
25
|
import {
|
|
26
26
|
createOfficePdfPreview,
|
|
@@ -45,6 +45,7 @@ const DEFAULT_MAX_UPLOAD_FILES = 20;
|
|
|
45
45
|
const DEFAULT_MAX_UPLOAD_FILE_BYTES = DEFAULT_MAX_RAW_BYTES;
|
|
46
46
|
const DEFAULT_MAX_UPLOAD_BODY_BYTES = 140 * 1024 * 1024;
|
|
47
47
|
const DEFAULT_MAX_SAVE_BYTES = 2 * 1024 * 1024;
|
|
48
|
+
const DEFAULT_MAX_MEDIA_BYTES = 1024 * 1024 * 1024;
|
|
48
49
|
|
|
49
50
|
export async function startLocalWorkspaceService({
|
|
50
51
|
session,
|
|
@@ -364,6 +365,19 @@ async function routeRequest({ req, res, sessionId, token, events, sseClients, em
|
|
|
364
365
|
return;
|
|
365
366
|
}
|
|
366
367
|
|
|
368
|
+
if (req.method === 'GET' && url.pathname === '/api/workspace/search') {
|
|
369
|
+
const query = url.searchParams.get('q') || '';
|
|
370
|
+
const kinds = (url.searchParams.get('kind') || url.searchParams.get('kinds') || '')
|
|
371
|
+
.split(',')
|
|
372
|
+
.map((item) => item.trim())
|
|
373
|
+
.filter(Boolean);
|
|
374
|
+
const maxResults = envInt('BAHULAM_LOCAL_SEARCH_MAX_RESULTS', 200);
|
|
375
|
+
const result = searchWorkspaceFiles(session, { query, kinds, maxResults });
|
|
376
|
+
emit('workspace_searched', { query: result.query, kinds: result.kinds, count: result.results.length });
|
|
377
|
+
sendJson(res, 200, result);
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
|
|
367
381
|
if (req.method === 'POST' && url.pathname === '/api/files/upload') {
|
|
368
382
|
const body = await readJsonBody(req, envInt('BAHULAM_LOCAL_UPLOAD_MAX_BODY_BYTES', DEFAULT_MAX_UPLOAD_BODY_BYTES));
|
|
369
383
|
const result = saveUploadedFiles(session, body);
|
|
@@ -402,15 +416,8 @@ async function routeRequest({ req, res, sessionId, token, events, sseClients, em
|
|
|
402
416
|
err.code = 'BAD_REQUEST';
|
|
403
417
|
throw err;
|
|
404
418
|
}
|
|
405
|
-
|
|
406
|
-
emit('file_read', { path: requestedPath,
|
|
407
|
-
res.writeHead(200, {
|
|
408
|
-
'Content-Type': contentTypeForPath(requestedPath),
|
|
409
|
-
'Cache-Control': 'no-store',
|
|
410
|
-
'Content-Security-Policy': "default-src 'none'; style-src 'unsafe-inline'; img-src data: blob:",
|
|
411
|
-
'X-Content-Type-Options': 'nosniff',
|
|
412
|
-
});
|
|
413
|
-
res.end(bytes);
|
|
419
|
+
sendWorkspaceRawFile({ req, res, session, requestedPath });
|
|
420
|
+
emit('file_read', { path: requestedPath, streamed: true });
|
|
414
421
|
return;
|
|
415
422
|
}
|
|
416
423
|
|
|
@@ -691,7 +698,9 @@ const PLUGIN_VIEW_MIME = {
|
|
|
691
698
|
js: 'text/javascript; charset=utf-8', mjs: 'text/javascript; charset=utf-8',
|
|
692
699
|
json: 'application/json', map: 'application/json',
|
|
693
700
|
png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg', gif: 'image/gif',
|
|
694
|
-
webp: 'image/webp', svg: 'image/svg+xml', ico: 'image/x-icon',
|
|
701
|
+
webp: 'image/webp', svg: 'image/svg+xml', ico: 'image/x-icon', avif: 'image/avif',
|
|
702
|
+
mp4: 'video/mp4', webm: 'video/webm', mov: 'video/quicktime', m4v: 'video/x-m4v', ogv: 'video/ogg',
|
|
703
|
+
mp3: 'audio/mpeg', m4a: 'audio/mp4', wav: 'audio/wav', ogg: 'audio/ogg', flac: 'audio/flac', aac: 'audio/aac',
|
|
695
704
|
woff: 'font/woff', woff2: 'font/woff2', ttf: 'font/ttf',
|
|
696
705
|
wasm: 'application/wasm',
|
|
697
706
|
};
|
|
@@ -801,8 +810,7 @@ function saveUploadedFiles(session, body = {}) {
|
|
|
801
810
|
}
|
|
802
811
|
|
|
803
812
|
const root = fs.realpathSync(session.root_path);
|
|
804
|
-
const
|
|
805
|
-
const directory = path.posix.join(LOCAL_UPLOAD_DIR, safePathSegment(session.id), group);
|
|
813
|
+
const directory = LOCAL_UPLOAD_DIR;
|
|
806
814
|
const uploadDir = path.join(root, ...directory.split('/'));
|
|
807
815
|
fs.mkdirSync(uploadDir, { recursive: true });
|
|
808
816
|
|
|
@@ -880,6 +888,72 @@ function uniqueUploadTarget(uploadDir, fileName) {
|
|
|
880
888
|
return path.join(uploadDir, `${parsed.name}-${crypto.randomBytes(4).toString('hex')}${parsed.ext}`);
|
|
881
889
|
}
|
|
882
890
|
|
|
891
|
+
function sendWorkspaceRawFile({ req, res, session, requestedPath }) {
|
|
892
|
+
const target = resolveWorkspacePath(session, requestedPath);
|
|
893
|
+
const stat = fs.statSync(target);
|
|
894
|
+
if (!stat.isFile()) {
|
|
895
|
+
const err = new Error('Requested path is not a file');
|
|
896
|
+
err.code = 'NOT_FILE';
|
|
897
|
+
throw err;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
const contentType = contentTypeForPath(target);
|
|
901
|
+
const mediaLike = /^(audio|video)\//.test(contentType);
|
|
902
|
+
const maxBytes = mediaLike
|
|
903
|
+
? envInt('BAHULAM_LOCAL_MEDIA_MAX_BYTES', DEFAULT_MAX_MEDIA_BYTES)
|
|
904
|
+
: DEFAULT_MAX_RAW_BYTES;
|
|
905
|
+
if (stat.size > maxBytes) {
|
|
906
|
+
const err = new Error(`File is larger than ${maxBytes} bytes`);
|
|
907
|
+
err.code = 'FILE_TOO_LARGE';
|
|
908
|
+
throw err;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
const commonHeaders = {
|
|
912
|
+
'Content-Type': contentType,
|
|
913
|
+
'Cache-Control': 'no-store',
|
|
914
|
+
'Content-Security-Policy': "default-src 'none'; style-src 'unsafe-inline'; img-src data: blob:; media-src 'self' blob:",
|
|
915
|
+
'X-Content-Type-Options': 'nosniff',
|
|
916
|
+
};
|
|
917
|
+
const range = parseRangeHeader(req.headers.range, stat.size);
|
|
918
|
+
if (range) {
|
|
919
|
+
res.writeHead(206, {
|
|
920
|
+
...commonHeaders,
|
|
921
|
+
'Accept-Ranges': 'bytes',
|
|
922
|
+
'Content-Range': `bytes ${range.start}-${range.end}/${stat.size}`,
|
|
923
|
+
'Content-Length': range.end - range.start + 1,
|
|
924
|
+
});
|
|
925
|
+
fs.createReadStream(target, { start: range.start, end: range.end }).pipe(res);
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
res.writeHead(200, {
|
|
930
|
+
...commonHeaders,
|
|
931
|
+
'Accept-Ranges': mediaLike ? 'bytes' : 'none',
|
|
932
|
+
'Content-Length': stat.size,
|
|
933
|
+
});
|
|
934
|
+
fs.createReadStream(target).pipe(res);
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
function parseRangeHeader(header, size) {
|
|
938
|
+
const value = String(header || '').trim();
|
|
939
|
+
if (!value || !value.startsWith('bytes=')) return null;
|
|
940
|
+
const first = value.slice(6).split(',')[0]?.trim() || '';
|
|
941
|
+
const match = first.match(/^(\d*)-(\d*)$/);
|
|
942
|
+
if (!match) return null;
|
|
943
|
+
let start = match[1] ? Number(match[1]) : null;
|
|
944
|
+
let end = match[2] ? Number(match[2]) : null;
|
|
945
|
+
if (start == null && end == null) return null;
|
|
946
|
+
if (start == null) {
|
|
947
|
+
const suffix = Math.max(0, Math.min(size, end || 0));
|
|
948
|
+
start = Math.max(0, size - suffix);
|
|
949
|
+
end = size - 1;
|
|
950
|
+
} else {
|
|
951
|
+
end = end == null ? size - 1 : Math.min(end, size - 1);
|
|
952
|
+
}
|
|
953
|
+
if (!Number.isFinite(start) || !Number.isFinite(end) || start < 0 || end < start || start >= size) return null;
|
|
954
|
+
return { start, end };
|
|
955
|
+
}
|
|
956
|
+
|
|
883
957
|
function sendJson(res, status, body) {
|
|
884
958
|
res.writeHead(status, {
|
|
885
959
|
'Content-Type': 'application/json; charset=utf-8',
|
|
@@ -981,6 +1055,18 @@ function staticContentType(filePath) {
|
|
|
981
1055
|
case '.jpeg': return 'image/jpeg';
|
|
982
1056
|
case '.gif': return 'image/gif';
|
|
983
1057
|
case '.webp': return 'image/webp';
|
|
1058
|
+
case '.avif': return 'image/avif';
|
|
1059
|
+
case '.mp4': return 'video/mp4';
|
|
1060
|
+
case '.webm': return 'video/webm';
|
|
1061
|
+
case '.mov': return 'video/quicktime';
|
|
1062
|
+
case '.m4v': return 'video/x-m4v';
|
|
1063
|
+
case '.ogv': return 'video/ogg';
|
|
1064
|
+
case '.mp3': return 'audio/mpeg';
|
|
1065
|
+
case '.m4a': return 'audio/mp4';
|
|
1066
|
+
case '.wav': return 'audio/wav';
|
|
1067
|
+
case '.ogg': return 'audio/ogg';
|
|
1068
|
+
case '.flac': return 'audio/flac';
|
|
1069
|
+
case '.aac': return 'audio/aac';
|
|
984
1070
|
case '.ttf': return 'font/ttf';
|
|
985
1071
|
case '.woff': return 'font/woff';
|
|
986
1072
|
case '.woff2': return 'font/woff2';
|
|
@@ -1070,11 +1156,11 @@ button,textarea,input{font:inherit}button{color:inherit}.shell{display:flex;flex
|
|
|
1070
1156
|
.menubar{height:28px;display:flex;align-items:center;gap:2px;border-bottom:1px solid rgba(27,27,27,.06);background:#F7F5EF;padding:0 12px;flex:0 0 auto;user-select:none;position:relative;z-index:20}.menu-item{height:22px;border:0;background:transparent;border-radius:var(--ws-radius-sm);padding:0 8px;color:rgba(27,27,27,.58);font-size:12px;font-weight:500;cursor:pointer}.menu-item:hover{background:var(--ws-hover);color:rgba(27,27,27,.86)}.menubar-spacer{flex:1}.session-menu-wrap{display:flex;align-items:center}.session-menu-button{max-width:240px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.session-modal-backdrop,.approval-modal-backdrop{position:fixed;inset:0;z-index:80;display:flex;align-items:flex-start;justify-content:center;background:rgba(27,27,27,.28);padding:92px 16px 24px}.approval-modal-backdrop{z-index:90;background:rgba(27,27,27,.36)}.session-modal-backdrop[hidden],.approval-modal-backdrop[hidden]{display:none}.session-dialog,.approval-dialog{width:min(620px,100%);max-height:min(620px,calc(100vh - 128px));display:flex;flex-direction:column;overflow:hidden;border:1px solid rgba(27,27,27,.12);border-radius:var(--ws-radius-md);background:#FFFDF7;box-shadow:0 24px 70px rgba(27,27,27,.22)}.approval-dialog{width:min(680px,100%)}.session-dialog-head,.approval-dialog-head{height:48px;display:flex;align-items:center;justify-content:space-between;gap:12px;border-bottom:1px solid var(--ws-border-subtle);padding:0 12px}.session-dialog-title,.approval-dialog-title{font-size:13px;font-weight:600;color:rgba(27,27,27,.84)}.session-dialog-subtitle,.approval-dialog-subtitle{margin-top:1px;font:12px/1.45 var(--sans);color:rgba(27,27,27,.46);max-width:560px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.session-menu{display:block;overflow:auto;padding:6px}.session-menu-empty{padding:10px;color:rgba(27,27,27,.42);font-size:12px}.approval-body{padding:12px;overflow:auto}.approval-subject{border:1px solid var(--ws-border);border-radius:var(--ws-radius-md);background:#fff;padding:10px;font:12px/1.45 var(--mono);color:rgba(27,27,27,.72);white-space:pre-wrap;overflow-wrap:anywhere}.approval-reason{margin-top:10px;color:rgba(27,27,27,.58);font-size:12px;line-height:1.5}.approval-actions{display:flex;align-items:center;justify-content:flex-end;gap:8px;border-top:1px solid var(--ws-border-subtle);padding:10px 12px;background:#F7F5EF}.approval-actions .danger{border-color:rgba(185,28,28,.24);color:#B91C1C}.approval-actions .primary-action{background:#1B1B1B;color:#FFFDF7;border-color:#1B1B1B}.approval-inline{width:100%;max-width:960px;border:1px solid rgba(217,119,6,.22);border-radius:var(--ws-radius-md);background:#FFFBEB;overflow:hidden;box-shadow:0 8px 24px rgba(146,64,14,.08)}.approval-inline.done{border-color:rgba(27,27,27,.08);background:#F7F5EF;box-shadow:none}.approval-inline-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:9px 11px;border-bottom:1px solid rgba(217,119,6,.14)}.approval-inline-title{font-size:13px;font-weight:600;color:#92400E}.approval-inline-meta{font:11px var(--sans);color:rgba(146,64,14,.62);white-space:nowrap}.approval-inline-subject{margin:10px 11px 0;border:1px solid rgba(217,119,6,.18);border-radius:var(--ws-radius-md);background:#fff;padding:9px;font:11px/1.45 var(--mono);color:rgba(27,27,27,.74);white-space:pre-wrap;overflow-wrap:anywhere;max-height:180px;overflow:auto}.approval-inline-reason{padding:8px 11px 10px;color:rgba(27,27,27,.58);font-size:12px;line-height:1.45}.approval-inline-actions{display:flex;justify-content:flex-end;gap:8px;flex-wrap:wrap;padding:9px 11px;border-top:1px solid rgba(217,119,6,.12);background:rgba(255,255,255,.58)}
|
|
1071
1157
|
main{--left-w:256px;--right-w:480px;display:grid;grid-template-columns:var(--left-w) 6px minmax(360px,1fr) 6px var(--right-w);flex:1;min-height:0}.panel{min-width:0;background:var(--ws-panel);overflow:hidden}.files{grid-column:1;background:rgba(255,255,255,.52)}.left-resizer{grid-column:2}.work{grid-column:3;display:flex;flex-direction:column;background:#fff}.right-resizer{grid-column:4}.agent{grid-column:5;background:rgba(255,255,255,.58);display:flex;flex-direction:column}.resizer{background:transparent;border-left:1px solid var(--ws-border-subtle);border-right:1px solid transparent;cursor:col-resize;position:relative}.resizer:hover,.resizer.dragging{background:rgba(8,145,178,.08);border-left-color:rgba(8,145,178,.25)}
|
|
1072
1158
|
main.hide-files{grid-template-columns:0 0 minmax(360px,1fr) 6px var(--right-w)}main.hide-files .files,main.hide-files .left-resizer{display:none}main.hide-agent{grid-template-columns:var(--left-w) 6px minmax(360px,1fr) 0 0}main.hide-agent .agent,main.hide-agent .right-resizer{display:none}
|
|
1073
|
-
.section-head{height:36px;border-bottom:1px solid var(--ws-border-subtle);display:flex;align-items:center;justify-content:space-between;padding:0 12px;color:var(--ws-faint);font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.08em;background:rgba(255,255,255,.45)}.section-actions{display:flex;align-items:center;gap:4px}.section-button{height:20px;border:0;background:transparent;border-radius:var(--ws-radius-sm);color:rgba(27,27,27,.35);cursor:pointer;padding:0 4px}.section-button:hover{background:var(--ws-hover);color:rgba(27,27,27,.70)}
|
|
1074
|
-
.file-list{padding:6px;overflow:auto;height:calc(100% -
|
|
1159
|
+
.section-head{height:36px;border-bottom:1px solid var(--ws-border-subtle);display:flex;align-items:center;justify-content:space-between;padding:0 12px;color:var(--ws-faint);font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.08em;background:rgba(255,255,255,.45)}.section-actions{display:flex;align-items:center;gap:4px}.section-button{height:20px;border:0;background:transparent;border-radius:var(--ws-radius-sm);color:rgba(27,27,27,.35);cursor:pointer;padding:0 4px}.section-button:hover{background:var(--ws-hover);color:rgba(27,27,27,.70)}.workspace-tools{height:68px;border-bottom:1px solid var(--ws-border-subtle);padding:7px 8px;background:#FFFDF7;display:flex;flex-direction:column;gap:7px}.file-search{width:100%;height:26px;border:1px solid rgba(27,27,27,.10);border-radius:6px;background:#fff;color:var(--ws-foreground);outline:none;padding:0 8px;font-size:12px}.file-search:focus{border-color:rgba(8,145,178,.35);box-shadow:0 0 0 2px rgba(8,145,178,.10)}.file-filters{display:flex;gap:5px;overflow-x:auto;scrollbar-width:none}.file-filters::-webkit-scrollbar{display:none}.filter-chip{height:22px;border:1px solid rgba(27,27,27,.08);border-radius:999px;background:#fff;color:rgba(27,27,27,.52);padding:0 8px;font-size:11px;cursor:pointer;white-space:nowrap}.filter-chip:hover{background:#F7F5EF;color:rgba(27,27,27,.78)}.filter-chip.active{background:#ECFEFF;border-color:rgba(8,145,178,.22);color:#0E7490}.search-results{padding:4px 8px;color:rgba(27,27,27,.38);font:11px var(--sans)}
|
|
1160
|
+
.file-list{padding:6px;overflow:auto;height:calc(100% - 104px)}.row{display:flex;align-items:center;gap:5px;width:100%;height:27px;border:0;background:transparent;text-align:left;border-radius:var(--ws-radius-sm);padding:0 8px;color:rgba(27,27,27,.62);cursor:pointer;font-size:13px;line-height:1}.row:hover{background:var(--ws-hover);color:rgba(27,27,27,.84)}.row.selected{background:var(--ws-active);color:var(--ws-foreground)}.row:focus-visible{outline:2px solid rgba(8,145,178,.35);outline-offset:1px}.chev{width:12px;text-align:center;color:rgba(27,27,27,.32);font:11px var(--mono)}.icon{width:16px;display:inline-flex;align-items:center;justify-content:center;color:var(--ws-faint);font-size:11px;font-family:var(--mono)}.name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sub{color:rgba(27,27,27,.34);font:11px var(--sans);margin-left:auto}.loading-row{height:24px;padding-left:32px;color:rgba(27,27,27,.38);font:12px var(--sans)}
|
|
1075
1161
|
.tabbar{height:36px;display:flex;align-items:center;border-bottom:1px solid var(--ws-border-subtle);background:var(--ws-tab);flex:0 0 auto;overflow-x:auto}.tab{height:100%;display:flex;align-items:center;gap:7px;border:0;border-right:1px solid var(--ws-border-subtle);padding:0 9px;background:transparent;color:rgba(27,27,27,.48);font-size:13px;font-weight:500;cursor:pointer;max-width:220px;min-width:90px}.tab.active{background:#fff;color:var(--ws-foreground);font-weight:600;box-shadow:inset 0 -1.5px 0 var(--ws-primary)}.tab:hover{background:rgba(27,27,27,.03);color:rgba(27,27,27,.75)}.tab-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tab-close{border:0;background:transparent;border-radius:var(--ws-radius-sm);color:rgba(27,27,27,.28);cursor:pointer;padding:0 2px}.tab-close:hover{background:rgba(27,27,27,.07);color:rgba(27,27,27,.70)}.tab-muted{flex:1;height:100%;border-left:1px solid var(--ws-border-subtle);min-width:24px}
|
|
1076
1162
|
.viewer{flex:1;min-height:0;overflow:hidden;background:#fff;display:flex;flex-direction:column}.file-header{min-height:34px;flex:0 0 auto;border-bottom:1px solid var(--ws-border-subtle);display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:5px 12px;background:rgba(27,27,27,.015);font:12px var(--mono);color:rgba(27,27,27,.50)}.path{min-width:120px;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-chip{display:inline-flex;align-items:center;gap:5px;border:1px solid rgba(27,27,27,.08);border-radius:999px;background:#fff;padding:1px 7px;font:10px var(--sans);color:rgba(27,27,27,.48);white-space:nowrap}.file-chip.warn{border-color:#FDE68A;background:#FFFBEB;color:#92400E}.file-actions{margin-left:auto;display:flex;align-items:center;gap:6px;min-width:0;flex-wrap:wrap}.file-action{font:11px var(--sans);color:rgba(27,27,27,.50);text-decoration:none;border:1px solid var(--ws-border);border-radius:6px;padding:2px 7px;background:#fff;cursor:pointer}.file-action:hover{color:var(--ws-foreground);background:var(--ws-surface)}.file-icon-action{width:24px;height:24px;min-width:24px;padding:0;display:inline-flex;align-items:center;justify-content:center}.file-icon-action svg{width:13px;height:13px;display:block}select.file-action{height:23px;max-width:190px;padding:1px 24px 1px 7px}.empty{color:var(--ws-faint);padding:24px;font-size:12px}.error{color:var(--ws-error)}
|
|
1077
|
-
.monaco-host{flex:1;min-height:0}.code-fallback{flex:1;min-height:0;overflow:auto}.code-wrap{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:start;min-height:100%;font:12px/1.55 var(--mono)}.line-nums{user-select:none;text-align:right;padding:14px 10px 14px 14px;color:rgba(27,27,27,.25);background:#FAF9F5;border-right:1px solid var(--ws-border-subtle);white-space:pre}.code-pre{margin:0;padding:14px;white-space:pre;overflow:auto;color:#1F2937;background:#fff;min-height:100%}.markdown-preview{flex:1;min-height:0;overflow:auto;max-width:920px;padding:24px 28px;color:rgba(27,27,27,.86);font-size:14px;line-height:1.65}.markdown-preview h1,.markdown-preview h2,.markdown-preview h3{line-height:1.2;margin:18px 0 8px}.markdown-preview p{margin:0 0 12px}.markdown-preview code,.message-content code{font-family:var(--mono);font-size:.92em;background:rgba(27,27,27,.06);border-radius:4px;padding:1px 4px}.markdown-preview pre,.message-content pre{overflow:auto;background:#0D1117;color:#E5E7EB;border-radius:7px;padding:12px}.image-stage{flex:1;min-height:0;display:flex;flex-direction:column;background:#F8F7F2}.image-toolbar{height:34px;flex:0 0 auto;display:flex;align-items:center;justify-content:flex-end;gap:6px;padding:0 10px;border-bottom:1px solid var(--ws-border-subtle);background:#fff}.image-preview{flex:1;min-height:0;display:flex;align-items:center;justify-content:center;padding:18px;overflow:auto}.image-preview img{max-width:100%;max-height:100%;object-fit:contain;border:1px solid var(--ws-border);background:#fff;box-shadow:0 10px 30px rgba(27,27,27,.10);transform-origin:center center}.frame-preview{flex:1;min-height:0;background:#F8F7F2}.frame-preview iframe{width:100%;height:100%;border:0;background:#fff}.table-preview{flex:1;min-height:0;padding:18px;overflow:auto}.table-preview .table-meta{margin:0 0 10px;color:rgba(27,27,27,.42);font:11px var(--mono)}.table-preview table{border-collapse:collapse;font-size:12px;background:#fff}.table-preview th,.table-preview td{border:1px solid var(--ws-border);padding:5px 7px;max-width:320px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.table-preview th{background:#F7F5EF;text-align:left;color:rgba(27,27,27,.65);position:sticky;top:0}.table-preview td.formula-cell{background:#F0F9FF;color:#075985}.diagram-preview{flex:1;min-height:0;padding:18px;display:grid;gap:14px;max-width:none;overflow:auto}.mermaid-card{border:1px solid var(--ws-border);border-radius:8px;background:#fff;overflow:hidden;display:flex;flex-direction:column}.mermaid-output{padding:18px;overflow:auto;min-height:220px;display:flex;align-items:center;justify-content:center}.mermaid-output svg{width:100%;max-width:100%;height:auto;display:block}.mermaid-source{margin:0;border-top:1px solid var(--ws-border-subtle);border-radius:0;background:#FAF9F5;color:rgba(27,27,27,.68);font:11px/1.45 var(--mono);max-height:220px;overflow:auto;padding:10px 12px;white-space:pre}.viewer-note{flex:1;min-height:0;overflow:auto;display:flex;align-items:center;justify-content:center;padding:24px;background:#FAF9F5}.viewer-note-card{width:min(520px,100%);max-height:100%;overflow:auto;border:1px solid var(--ws-border);border-radius:8px;background:#fff;padding:18px;box-shadow:0 10px 34px rgba(27,27,27,.05)}.viewer-note-title{font-size:14px;font-weight:750;color:rgba(27,27,27,.84)}.viewer-note-body{margin-top:8px;color:rgba(27,27,27,.56);font-size:12px;line-height:1.55}.viewer-note-actions{margin-top:14px;display:flex;gap:8px;flex-wrap:wrap}.binary-preview{flex:1;min-height:0;display:flex;align-items:center;justify-content:center;padding:24px;color:rgba(27,27,27,.50);text-align:center}
|
|
1163
|
+
.monaco-host{flex:1;min-height:0}.code-fallback{flex:1;min-height:0;overflow:auto}.code-wrap{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:start;min-height:100%;font:12px/1.55 var(--mono)}.line-nums{user-select:none;text-align:right;padding:14px 10px 14px 14px;color:rgba(27,27,27,.25);background:#FAF9F5;border-right:1px solid var(--ws-border-subtle);white-space:pre}.code-pre{margin:0;padding:14px;white-space:pre;overflow:auto;color:#1F2937;background:#fff;min-height:100%}.markdown-preview{flex:1;min-height:0;overflow:auto;max-width:920px;padding:24px 28px;color:rgba(27,27,27,.86);font-size:14px;line-height:1.65}.markdown-preview h1,.markdown-preview h2,.markdown-preview h3{line-height:1.2;margin:18px 0 8px}.markdown-preview p{margin:0 0 12px}.markdown-preview code,.message-content code{font-family:var(--mono);font-size:.92em;background:rgba(27,27,27,.06);border-radius:4px;padding:1px 4px}.markdown-preview pre,.message-content pre{overflow:auto;background:#0D1117;color:#E5E7EB;border-radius:7px;padding:12px}.image-stage,.media-stage{flex:1;min-height:0;display:flex;flex-direction:column;background:#F8F7F2}.image-toolbar,.media-toolbar{height:34px;flex:0 0 auto;display:flex;align-items:center;justify-content:flex-end;gap:6px;padding:0 10px;border-bottom:1px solid var(--ws-border-subtle);background:#fff}.image-preview,.media-preview{flex:1;min-height:0;display:flex;align-items:center;justify-content:center;padding:18px;overflow:auto}.image-preview img{max-width:100%;max-height:100%;object-fit:contain;border:1px solid var(--ws-border);background:#fff;box-shadow:0 10px 30px rgba(27,27,27,.10);transform-origin:center center}.media-preview video{width:min(100%,1120px);max-height:100%;background:#0B0B0B;border-radius:8px;box-shadow:0 14px 42px rgba(27,27,27,.16)}.media-preview audio{width:min(100%,720px)}.frame-preview{flex:1;min-height:0;background:#F8F7F2}.frame-preview iframe{width:100%;height:100%;border:0;background:#fff}.table-preview{flex:1;min-height:0;padding:18px;overflow:auto}.table-preview .table-meta{margin:0 0 10px;color:rgba(27,27,27,.42);font:11px var(--mono)}.table-preview table{border-collapse:collapse;font-size:12px;background:#fff}.table-preview th,.table-preview td{border:1px solid var(--ws-border);padding:5px 7px;max-width:320px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.table-preview th{background:#F7F5EF;text-align:left;color:rgba(27,27,27,.65);position:sticky;top:0}.table-preview td.formula-cell{background:#F0F9FF;color:#075985}.diagram-preview{flex:1;min-height:0;padding:18px;display:grid;gap:14px;max-width:none;overflow:auto}.mermaid-card{border:1px solid var(--ws-border);border-radius:8px;background:#fff;overflow:hidden;display:flex;flex-direction:column}.mermaid-output{padding:18px;overflow:auto;min-height:220px;display:flex;align-items:center;justify-content:center}.mermaid-output svg{width:100%;max-width:100%;height:auto;display:block}.mermaid-source{margin:0;border-top:1px solid var(--ws-border-subtle);border-radius:0;background:#FAF9F5;color:rgba(27,27,27,.68);font:11px/1.45 var(--mono);max-height:220px;overflow:auto;padding:10px 12px;white-space:pre}.viewer-note{flex:1;min-height:0;overflow:auto;display:flex;align-items:center;justify-content:center;padding:24px;background:#FAF9F5}.viewer-note-card{width:min(520px,100%);max-height:100%;overflow:auto;border:1px solid var(--ws-border);border-radius:8px;background:#fff;padding:18px;box-shadow:0 10px 34px rgba(27,27,27,.05)}.viewer-note-title{font-size:14px;font-weight:750;color:rgba(27,27,27,.84)}.viewer-note-body{margin-top:8px;color:rgba(27,27,27,.56);font-size:12px;line-height:1.55}.viewer-note-actions{margin-top:14px;display:flex;gap:8px;flex-wrap:wrap}.binary-preview{flex:1;min-height:0;display:flex;align-items:center;justify-content:center;padding:24px;color:rgba(27,27,27,.50);text-align:center}
|
|
1078
1164
|
.chat-head{height:36px;border-bottom:1px solid var(--ws-border-subtle);display:flex;align-items:center;gap:8px;padding:0 12px;background:rgba(255,255,255,.55)}.chat-title{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.08em;color:rgba(27,27,27,.42)}.chat-subtitle{min-width:0;flex:1;font-size:12px;color:rgba(27,27,27,.42);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.agent-tabs{height:34px;display:flex;align-items:center;border-bottom:1px solid var(--ws-border-subtle);background:#F7F5EF;padding:0 8px;gap:3px}.agent-tab{height:26px;border:0;border-radius:var(--ws-radius-md);background:transparent;color:rgba(27,27,27,.48);font-size:13px;font-weight:500;padding:0 9px;cursor:pointer}.agent-tab:hover{background:var(--ws-hover);color:rgba(27,27,27,.76)}.agent-tab.active{background:#fff;color:var(--ws-foreground);font-weight:600;box-shadow:0 0 0 1px rgba(27,27,27,.06)}.chat-body{display:flex;flex-direction:column;flex:1;min-height:0}.chat-pane{display:none;flex-direction:column;flex:1;min-height:0}.chat-pane.active{display:flex}.plugins-menu-wrap{position:relative}.plugins-menu-wrap[hidden]{display:none}.plugins-dropdown{position:absolute;top:26px;left:0;z-index:60;min-width:210px;background:#fff;border:1px solid var(--ws-border);border-radius:var(--ws-radius-md);box-shadow:0 12px 34px rgba(27,27,27,.14);padding:4px;display:flex;flex-direction:column}.plugins-dropdown[hidden]{display:none}.plugins-dropdown button{border:0;background:transparent;text-align:left;font:12px var(--sans);color:rgba(27,27,27,.78);padding:6px 9px;border-radius:var(--ws-radius-sm);cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:10px}.plugins-dropdown button:hover{background:var(--ws-hover)}.plugins-dropdown .plugin-origin{color:var(--ws-faint);font:11px var(--sans)}.thread{flex:1;min-height:0;overflow:auto;padding:16px 14px 10px;background:rgba(255,255,255,.40)}.thread-inner{display:flex;flex-direction:column;gap:12px}.empty-chat{display:flex;height:100%;align-items:center;justify-content:center;text-align:center;color:rgba(27,27,27,.42);font-size:12px}.session-list{display:flex;flex-direction:column;gap:2px}.session-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:10px;align-items:center;width:100%;border:0;background:transparent;text-align:left;border-radius:var(--ws-radius-md);padding:8px;color:inherit;cursor:pointer}.session-row:hover{background:rgba(27,27,27,.035)}.session-row.selected{background:var(--ws-active);box-shadow:inset 2px 0 0 var(--ws-primary)}.session-row:focus-visible{outline:2px solid rgba(8,145,178,.35);outline-offset:1px}.session-main{min-width:0}.session-prompt{display:block;font-size:13px;font-weight:500;color:rgba(27,27,27,.84);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.session-meta{display:block;margin-top:3px;font:12px/1.4 var(--sans);color:rgba(27,27,27,.46);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.session-tools{margin-top:5px;display:flex;gap:4px;flex-wrap:wrap}.session-chip{border-radius:999px;border:1px solid rgba(27,27,27,.07);background:#F7F5EF;padding:1px 6px;font:11px var(--sans);color:rgba(27,27,27,.52)}.session-action{height:24px;display:inline-flex;align-items:center;justify-content:center;border:1px solid rgba(27,27,27,.10);border-radius:var(--ws-radius-md);background:#fff;color:rgba(27,27,27,.62);padding:0 8px;font-size:12px;font-weight:500}.session-row:hover .session-action{background:#F7F5EF;color:var(--ws-foreground)}.msg{display:flex}.msg.user{justify-content:flex-end}.msg.assistant{justify-content:flex-start}.bubble{max-width:86%;border-radius:16px;padding:10px 12px;font-size:13px;line-height:1.55;word-break:break-word}.user .bubble{background:#1B1B1B;color:#FFFDF7}.message-attachments{display:flex;flex-wrap:wrap;gap:5px;margin-top:8px}.message-attachment{max-width:100%;display:inline-flex;align-items:center;gap:5px;border:1px solid rgba(255,255,255,.20);border-radius:999px;background:rgba(255,255,255,.10);color:#FFFDF7;padding:2px 7px;cursor:pointer}.message-attachment span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:180px}.message-attachment small{font:11px var(--sans);opacity:.68}.message-attachment:hover{background:rgba(255,255,255,.17)}.assistant-stack{width:100%;max-width:960px;display:flex;flex-direction:column;gap:8px}.assistant-bubble{display:none;max-width:94%;border-radius:16px;background:#F7F5EF;padding:11px 13px;color:rgba(27,27,27,.86);font-size:13px;line-height:1.6}.assistant-bubble:not(:empty){display:block}.message-content p{margin:0 0 10px}.message-content p:last-child{margin-bottom:0}.message-content ul{margin:0 0 10px 18px;padding:0}.message-content li{margin:2px 0}
|
|
1079
1165
|
.activity-card{display:none;overflow:hidden;border:1px solid var(--ws-border);border-radius:8px;background:#FFFDF7;font-size:12px}.activity-card.active{display:block}.activity-head{height:28px;width:100%;border:0;background:transparent;display:flex;align-items:center;gap:8px;padding:0 9px;cursor:pointer;color:rgba(27,27,27,.68)}.activity-head:hover{background:#F7F5EF}.activity-label{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left;font-size:11px;font-weight:650}.activity-rollup{font-size:10px;color:rgba(27,27,27,.38)}.activity-rows{border-top:1px solid rgba(27,27,27,.05);padding:7px 9px;max-height:96px;overflow:auto;display:flex;flex-direction:column;gap:5px}.activity-card.expanded .activity-rows{max-height:360px}.activity-row{display:flex;align-items:flex-start;gap:7px;color:rgba(27,27,27,.65);font-size:11px;line-height:1.35}.activity-row .status-dot{width:8px;height:8px;border-radius:999px;background:rgba(27,27,27,.18);margin-top:4px;flex:0 0 auto}.activity-row.running .status-dot{background:#0891B2}.activity-row.done .status-dot{background:#059669}.activity-row.error .status-dot{background:#DC2626}.activity-row.approval .status-dot{background:#D97706}.activity-row.thinking{font-style:italic;color:rgba(27,27,27,.48)}.activity-main{display:block;min-width:0;flex:1}.activity-message{display:block}.activity-row pre{display:none;margin:4px 0 0;max-height:120px;overflow:auto;border-radius:6px;background:rgba(27,27,27,.04);padding:6px;font:10px/1.4 var(--mono);color:rgba(27,27,27,.62);white-space:pre-wrap}.activity-card.expanded .activity-row pre{display:block}.activity-approval{margin-top:7px;border:1px solid rgba(217,119,6,.20);border-radius:7px;background:#FFFBEB;overflow:hidden;transition:opacity .85s ease,transform .85s ease,max-height .85s ease,margin .85s ease}.activity-approval.fading{opacity:0;transform:translateY(-4px);max-height:0;margin:0;pointer-events:none}.activity-approval-head{display:flex;align-items:center;justify-content:space-between;gap:8px;border-bottom:1px solid rgba(217,119,6,.12);padding:6px 8px}.activity-approval-title{font-size:11px;font-weight:800;color:#92400E}.activity-approval-meta{font:10px var(--mono);color:rgba(146,64,14,.58);white-space:nowrap}.activity-approval-subject{margin:7px 8px 0;border:1px solid rgba(217,119,6,.14);border-radius:5px;background:#fff;padding:7px;font:10px/1.45 var(--mono);color:rgba(27,27,27,.72);white-space:pre-wrap;overflow-wrap:anywhere;max-height:130px;overflow:auto}.activity-approval-reason{padding:6px 8px 8px;color:rgba(27,27,27,.56);font-size:11px;line-height:1.45}.activity-approval-actions{display:flex;justify-content:flex-end;gap:6px;flex-wrap:wrap;border-top:1px solid rgba(217,119,6,.12);background:rgba(255,255,255,.58);padding:7px 8px}.activity-result{margin-top:6px}.trace{display:block;flex:1;min-height:0;overflow:auto;background:#fff;padding:8px}.trace-row{font:11px/1.45 var(--mono);border-bottom:1px solid rgba(27,27,27,.05);padding:7px 4px;color:rgba(27,27,27,.52);white-space:pre-wrap;overflow-wrap:anywhere}.trace-row b{color:var(--ws-primary)}
|
|
1080
1166
|
.notebook-preview{flex:1;min-height:0;overflow:auto;background:#F7F5EF;padding:14px 14px 40px;display:flex;flex-direction:column;gap:10px}.notebook-meta{font:11px var(--mono);color:rgba(27,27,27,.42);padding:0 6px}.notebook-cell{border:1px solid var(--ws-border-subtle);border-radius:8px;background:#fff;overflow:hidden;box-shadow:0 1px 0 rgba(27,27,27,.02)}.notebook-cell.code{display:grid;grid-template-columns:64px minmax(0,1fr);padding:0;align-items:stretch}.notebook-cell.markdown{padding:16px 20px}.notebook-cell.raw{background:#F7F5EF;padding:12px 16px}.notebook-cell.raw .notebook-cell-body{padding:0}.notebook-cell.raw pre{margin:0;white-space:pre-wrap;font:12px/1.5 var(--mono);color:rgba(27,27,27,.72)}.notebook-cell-body{padding:0}.notebook-markdown{font-size:14px;line-height:1.65;color:rgba(27,27,27,.86)}.notebook-markdown h1,.notebook-markdown h2,.notebook-markdown h3{line-height:1.2;margin:14px 0 8px;color:rgba(27,27,27,.92)}.notebook-markdown h1{font-size:22px;border-bottom:1px solid var(--ws-border-subtle);padding-bottom:4px}.notebook-markdown p{margin:0 0 10px}.notebook-markdown code{font-family:var(--mono);font-size:.92em;background:rgba(27,27,27,.06);border-radius:4px;padding:1px 4px}.notebook-markdown pre{overflow:auto;background:#0D1117;color:#E5E7EB;border-radius:6px;padding:10px}.notebook-prompt{padding:12px 10px 12px 10px;font:11px/1.4 var(--mono);text-align:right;user-select:none;color:#4B6BFB;background:transparent;border-right:1px solid var(--ws-border-subtle);white-space:nowrap;display:flex;align-items:flex-start;justify-content:flex-end}.notebook-prompt.out{color:#A21818}.notebook-prompt.empty{color:transparent;pointer-events:none}.notebook-prompt.in::before{content:"In "}.notebook-prompt.out::before{content:"Out "}.notebook-cell-monaco{background:#FAFBFC;min-height:52px;position:relative;overflow:hidden;padding:6px 0}.notebook-cell-monaco .monaco-editor,.notebook-cell-monaco .monaco-editor .overflow-guard,.notebook-cell-monaco .monaco-editor-background,.notebook-cell-monaco .margin{background:#FAFBFC!important}.notebook-code-fallback{margin:0;padding:8px 12px;background:transparent;color:#1F2937;font:12px/1.5 var(--mono);white-space:pre;overflow:auto}.notebook-cell-outputs{grid-column:1 / -1;display:grid;grid-template-columns:64px minmax(0,1fr);background:#fff;border-top:1px solid var(--ws-border-subtle)}.notebook-output-item{display:contents}.notebook-output-item+.notebook-output-item>.notebook-prompt,.notebook-output-item+.notebook-output-item>.notebook-output-body{border-top:1px solid var(--ws-border-subtle)}.notebook-output-body{padding:8px 12px;overflow:auto;min-width:0;background:#fff}.notebook-stream{margin:0;font:12px/1.5 var(--mono);color:#1F2937;white-space:pre-wrap;word-break:break-word;background:transparent;padding:0}.notebook-stream.stderr{color:#7F1D1D;background:#FEF2F2;padding:6px 8px;border-radius:5px}.notebook-error{margin:0;font:12px/1.5 var(--mono);color:#7F1D1D;background:#FEF2F2;padding:8px 10px;border-radius:5px;white-space:pre-wrap;word-break:break-word;overflow:auto}.notebook-plain{margin:0;font:12px/1.5 var(--mono);color:#1F2937;white-space:pre-wrap;word-break:break-word;background:transparent;padding:0}.notebook-json{margin:0;font:12px/1.5 var(--mono);color:#0F172A;background:#F8FAFC;padding:8px 10px;border-radius:5px;white-space:pre;overflow:auto}.notebook-output-body img{max-width:100%;height:auto;display:block;background:#fff;border-radius:4px}.notebook-output-body iframe{width:100%;min-height:220px;border:1px solid var(--ws-border-subtle);border-radius:5px;background:#fff}.notebook-latex{font-size:14px;color:rgba(27,27,27,.90);padding:6px 0;overflow:auto}.katex-display{margin:6px 0!important}.viewer.maximized{position:fixed;inset:12px;z-index:70;border:1px solid rgba(27,27,27,.12);border-radius:8px;box-shadow:0 24px 80px rgba(27,27,27,.28);background:#fff}.viewer.maximized .diagram-preview,.viewer.maximized .markdown-preview{max-width:none}.viewer.maximized .mermaid-output{min-height:calc(100vh - 220px)}.composer{border-top:1px solid var(--ws-border-subtle);background:#FFFDF7;padding:10px 12px}.composer-box{border:1px solid var(--ws-border);border-radius:10px;background:#fff;overflow:hidden}.upload-tray{display:flex;gap:6px;flex-wrap:wrap;padding:8px 9px 0}.upload-tray[hidden]{display:none}.upload-chip{height:24px;display:inline-flex;align-items:center;gap:6px;max-width:100%;border:1px solid rgba(8,145,178,.18);border-radius:999px;background:#F0F9FF;color:#075985;padding:0 4px 0 8px;font-size:11px}.upload-chip-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:210px}.upload-chip-meta{font:10px var(--mono);color:rgba(7,89,133,.58)}.upload-chip button{width:18px;height:18px;border:0;border-radius:999px;background:transparent;color:rgba(7,89,133,.52);cursor:pointer;padding:0}.upload-chip button:hover{background:rgba(8,145,178,.12);color:#075985}textarea{display:block;width:100%;min-height:84px;max-height:240px;resize:vertical;border:0;padding:10px 11px;background:#fff;color:var(--ws-foreground);outline:none}.composer-actions{height:34px;border-top:1px solid var(--ws-border-subtle);display:flex;align-items:center;justify-content:space-between;padding:0 8px}.composer-left,.composer-right{display:flex;align-items:center;gap:6px;min-width:0}.composer-right{margin-left:auto}.status{font-size:11px;color:var(--ws-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding-right:8px}.stop-button{height:24px;border:1px solid rgba(185,28,28,.20);border-radius:6px;background:#FEF2F2;color:#B91C1C;font-size:11px;font-weight:750;padding:0 8px;display:inline-flex;align-items:center;gap:5px;cursor:pointer}.stop-button svg{width:12px;height:12px}.stop-button:hover{background:#FEE2E2;border-color:rgba(185,28,28,.30)}.stop-button:disabled{opacity:.55;cursor:not-allowed}.stop-button[hidden]{display:none}button.primary{height:24px;border:0;border-radius:6px;background:var(--ws-foreground);color:#fff;font-size:11px;font-weight:750;padding:0 10px;cursor:pointer}button.primary:hover{background:#2B2B2B}button.primary:disabled{opacity:.45;cursor:not-allowed}
|
|
@@ -1137,6 +1223,17 @@ main.hide-files{grid-template-columns:0 0 minmax(360px,1fr) 6px var(--right-w)}m
|
|
|
1137
1223
|
<main id="layout">
|
|
1138
1224
|
<section class="panel files" id="filesPanel">
|
|
1139
1225
|
<div class="section-head"><span>Files</span><span class="section-actions"><button class="section-button" id="refreshFiles" type="button" title="Refresh">↻</button><span id="fileCount"></span></span></div>
|
|
1226
|
+
<div class="workspace-tools">
|
|
1227
|
+
<input class="file-search" id="fileSearch" type="search" placeholder="Search workspace" autocomplete="off">
|
|
1228
|
+
<div class="file-filters" id="fileFilters" aria-label="File type filters">
|
|
1229
|
+
<button class="filter-chip active" type="button" data-file-filter="all">All</button>
|
|
1230
|
+
<button class="filter-chip" type="button" data-file-filter="code">Code</button>
|
|
1231
|
+
<button class="filter-chip" type="button" data-file-filter="docs">Docs</button>
|
|
1232
|
+
<button class="filter-chip" type="button" data-file-filter="data">Data</button>
|
|
1233
|
+
<button class="filter-chip" type="button" data-file-filter="media">Media</button>
|
|
1234
|
+
<button class="filter-chip" type="button" data-file-filter="web">Web</button>
|
|
1235
|
+
</div>
|
|
1236
|
+
</div>
|
|
1140
1237
|
<div class="file-list" id="fileList"></div>
|
|
1141
1238
|
</section>
|
|
1142
1239
|
<div class="resizer left-resizer" data-resize="left"></div>
|
|
@@ -1217,6 +1314,10 @@ const headers = { 'X-Bahulam-Local-Token': token };
|
|
|
1217
1314
|
const dirCache = new Map();
|
|
1218
1315
|
const expandedDirs = new Set(['.']);
|
|
1219
1316
|
const loadingDirs = new Set();
|
|
1317
|
+
let workspaceQuery = '';
|
|
1318
|
+
let workspaceFilter = 'all';
|
|
1319
|
+
let workspaceSearchTimer = null;
|
|
1320
|
+
let workspaceSearchSeq = 0;
|
|
1220
1321
|
const openTabs = [];
|
|
1221
1322
|
const fileCache = new Map();
|
|
1222
1323
|
let activePath = null;
|
|
@@ -1282,7 +1383,10 @@ function attachmentHint(file){
|
|
|
1282
1383
|
const mime=String(file?.mime_type||'').toLowerCase();
|
|
1283
1384
|
const ext=extname(file?.path||file?.name||'');
|
|
1284
1385
|
if(kind==='image'||mime.startsWith('image/'))return 'vision';
|
|
1386
|
+
if(kind==='video'||mime.startsWith('video/'))return 'video';
|
|
1387
|
+
if(kind==='audio'||mime.startsWith('audio/'))return 'audio';
|
|
1285
1388
|
if(kind==='spreadsheet'||kind==='table'||['csv','tsv','xlsx','xls','ods'].includes(ext))return 'table';
|
|
1389
|
+
if(kind==='web')return 'web';
|
|
1286
1390
|
if(['pdf','markdown','text','code','config','notebook'].includes(kind)||['txt','md','mdx','pdf','json','yaml','yml','toml','html','xml','ipynb','log','rst','sql','sh'].includes(ext))return 'read';
|
|
1287
1391
|
return 'file';
|
|
1288
1392
|
}
|
|
@@ -1368,8 +1472,11 @@ function fileKind(data){
|
|
|
1368
1472
|
const file=data.file||{};
|
|
1369
1473
|
if(file.viewer)return file.viewer;
|
|
1370
1474
|
const ext=extname(data.path);
|
|
1371
|
-
if(['png','jpg','jpeg','gif','webp','svg','bmp','ico'].includes(ext))return 'image';
|
|
1475
|
+
if(['png','jpg','jpeg','gif','webp','svg','bmp','ico','avif'].includes(ext))return 'image';
|
|
1476
|
+
if(['mp4','webm','mov','m4v','ogv'].includes(ext))return 'video';
|
|
1477
|
+
if(['mp3','m4a','wav','ogg','flac','aac'].includes(ext))return 'audio';
|
|
1372
1478
|
if(ext==='pdf')return 'pdf';
|
|
1479
|
+
if(['html','htm'].includes(ext))return 'web';
|
|
1373
1480
|
if(['md','mdx'].includes(ext))return 'markdown';
|
|
1374
1481
|
if(['mmd','mermaid'].includes(ext))return 'mermaid';
|
|
1375
1482
|
if(['drawio','dio'].includes(ext))return 'drawio';
|
|
@@ -1502,7 +1609,7 @@ function bindHeaderActions(path){
|
|
|
1502
1609
|
}
|
|
1503
1610
|
function askAgentForFile(path,kind){
|
|
1504
1611
|
const prompt=document.getElementById('prompt');
|
|
1505
|
-
const label=kind==='image'?'Analyze this image':kind==='pdf'?'Summarize this PDF':kind==='spreadsheet'?'Inspect this spreadsheet':kind==='document'?'Inspect this document':kind==='presentation'?'Inspect this presentation':'Inspect this file';
|
|
1612
|
+
const label=kind==='image'?'Analyze this image':kind==='video'?'Inspect this video':kind==='audio'?'Inspect this audio':kind==='web'?'Review this web page':kind==='pdf'?'Summarize this PDF':kind==='spreadsheet'?'Inspect this spreadsheet':kind==='document'?'Inspect this document':kind==='presentation'?'Inspect this presentation':'Inspect this file';
|
|
1506
1613
|
prompt.value=label+' at '+path+'. Explain what it contains and call the right local tools if needed.';
|
|
1507
1614
|
prompt.focus();
|
|
1508
1615
|
}
|
|
@@ -1695,11 +1802,75 @@ function renderTabs(){
|
|
|
1695
1802
|
function renderExplorer(){
|
|
1696
1803
|
const root=dirCache.get('.');
|
|
1697
1804
|
const list=document.getElementById('fileList');
|
|
1805
|
+
if(workspaceSearchActive()){scheduleWorkspaceSearch(0);return;}
|
|
1698
1806
|
if(!root){list.innerHTML='<div class="loading-row">Loading...</div>';return;}
|
|
1699
1807
|
list.innerHTML=renderEntries(root.entries||[],0);
|
|
1700
1808
|
list.querySelectorAll('[data-dir]').forEach(btn=>btn.addEventListener('click',async()=>{const p=btn.dataset.dir;if(expandedDirs.has(p)&&p!=='.')expandedDirs.delete(p);else{expandedDirs.add(p);if(!dirCache.has(p))await loadDir(p);}renderExplorer();}));
|
|
1701
1809
|
list.querySelectorAll('[data-file]').forEach(btn=>btn.addEventListener('click',()=>openFile(btn.dataset.file)));
|
|
1702
1810
|
}
|
|
1811
|
+
function workspaceSearchActive(){
|
|
1812
|
+
return Boolean(workspaceQuery.trim() || workspaceFilter !== 'all');
|
|
1813
|
+
}
|
|
1814
|
+
function filterKinds(filter){
|
|
1815
|
+
switch(filter){
|
|
1816
|
+
case 'code': return ['code','config'];
|
|
1817
|
+
case 'docs': return ['markdown','pdf','document','presentation','notebook'];
|
|
1818
|
+
case 'data': return ['table','spreadsheet'];
|
|
1819
|
+
case 'media': return ['image','video','audio'];
|
|
1820
|
+
case 'web': return ['web','mermaid','drawio'];
|
|
1821
|
+
default: return [];
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
function setWorkspaceFilter(filter){
|
|
1825
|
+
workspaceFilter=filter||'all';
|
|
1826
|
+
document.querySelectorAll('[data-file-filter]').forEach(btn=>btn.classList.toggle('active',btn.dataset.fileFilter===workspaceFilter));
|
|
1827
|
+
renderExplorer();
|
|
1828
|
+
}
|
|
1829
|
+
function scheduleWorkspaceSearch(delay=160){
|
|
1830
|
+
if(workspaceSearchTimer)clearTimeout(workspaceSearchTimer);
|
|
1831
|
+
workspaceSearchTimer=setTimeout(loadWorkspaceSearch,delay);
|
|
1832
|
+
}
|
|
1833
|
+
async function loadWorkspaceSearch(){
|
|
1834
|
+
if(!workspaceSearchActive())return;
|
|
1835
|
+
const list=document.getElementById('fileList');
|
|
1836
|
+
const seq=++workspaceSearchSeq;
|
|
1837
|
+
const kinds=filterKinds(workspaceFilter);
|
|
1838
|
+
list.innerHTML='<div class="loading-row">Searching...</div>';
|
|
1839
|
+
try{
|
|
1840
|
+
const url='/api/workspace/search?q='+encodeURIComponent(workspaceQuery.trim())+(kinds.length?'&kind='+encodeURIComponent(kinds.join(',')):'');
|
|
1841
|
+
const result=await api(url);
|
|
1842
|
+
if(seq!==workspaceSearchSeq)return;
|
|
1843
|
+
document.getElementById('fileCount').textContent=String((result.results||[]).length);
|
|
1844
|
+
renderSearchResults(result);
|
|
1845
|
+
}catch(err){
|
|
1846
|
+
if(seq!==workspaceSearchSeq)return;
|
|
1847
|
+
list.innerHTML='<div class="search-results error">'+esc(err.message||'Search failed')+'</div>';
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
function renderSearchResults(result){
|
|
1851
|
+
const list=document.getElementById('fileList');
|
|
1852
|
+
const rows=Array.isArray(result.results)?result.results:[];
|
|
1853
|
+
const note='<div class="search-results">'+esc(rows.length)+' result'+(rows.length===1?'':'s')+(result.truncated?' · truncated':'')+'</div>';
|
|
1854
|
+
if(!rows.length){list.innerHTML=note+'<div class="empty">No matching files.</div>';return;}
|
|
1855
|
+
list.innerHTML=note+rows.map(entry=>{
|
|
1856
|
+
const attrs=entry.type==='directory'?'data-dir="'+esc(entry.path)+'"':'data-file="'+esc(entry.path)+'"';
|
|
1857
|
+
return '<button class="row '+(entry.path===activePath?'selected':'')+'" '+attrs+' title="'+esc(entry.path)+'"><span class="chev"></span><span class="icon">'+entryIcon(entry)+'</span><span class="name">'+esc(entry.path)+'</span><span class="sub">'+esc(entry.label||entry.kind||'')+'</span></button>';
|
|
1858
|
+
}).join('');
|
|
1859
|
+
list.querySelectorAll('[data-dir]').forEach(btn=>btn.addEventListener('click',async()=>{const dir=btn.dataset.dir;expandedDirs.add(dir);workspaceQuery='';document.getElementById('fileSearch').value='';setWorkspaceFilter('all');if(!dirCache.has(dir))await loadDir(dir);else renderExplorer();}));
|
|
1860
|
+
list.querySelectorAll('[data-file]').forEach(btn=>btn.addEventListener('click',()=>openFile(btn.dataset.file)));
|
|
1861
|
+
}
|
|
1862
|
+
function entryIcon(entry){
|
|
1863
|
+
const kind=String(entry.kind||entry.viewer||'').toLowerCase();
|
|
1864
|
+
if(entry.type==='directory'||kind==='directory')return '▦';
|
|
1865
|
+
if(kind==='image')return '◉';
|
|
1866
|
+
if(kind==='video')return '▶';
|
|
1867
|
+
if(kind==='audio')return '♪';
|
|
1868
|
+
if(kind==='web')return '⌘';
|
|
1869
|
+
if(['spreadsheet','table'].includes(kind))return '▤';
|
|
1870
|
+
if(['markdown','pdf','document','presentation','notebook'].includes(kind))return '▣';
|
|
1871
|
+
if(['code','config','mermaid','drawio'].includes(kind))return '◇';
|
|
1872
|
+
return '·';
|
|
1873
|
+
}
|
|
1703
1874
|
function renderEntries(entries,depth){
|
|
1704
1875
|
return entries.map(entry=>{
|
|
1705
1876
|
const pad=8+depth*13;
|
|
@@ -1709,7 +1880,7 @@ function renderEntries(entries,depth){
|
|
|
1709
1880
|
const rows=open?(child?renderEntries(child.entries||[],depth+1):'<div class="loading-row" style="padding-left:'+(pad+24)+'px">Loading...</div>'):'';
|
|
1710
1881
|
return '<button class="row" style="padding-left:'+pad+'px" data-dir="'+esc(entry.path)+'"><span class="chev">'+(open?'⌄':'›')+'</span><span class="icon">▦</span><span class="name">'+esc(entry.name)+'</span></button>'+rows;
|
|
1711
1882
|
}
|
|
1712
|
-
return '<button class="row '+(entry.path===activePath?'selected':'')+'" style="padding-left:'+pad+'px" data-file="'+esc(entry.path)+'"><span class="chev"></span><span class="icon"
|
|
1883
|
+
return '<button class="row '+(entry.path===activePath?'selected':'')+'" style="padding-left:'+pad+'px" data-file="'+esc(entry.path)+'"><span class="chev"></span><span class="icon">'+entryIcon(entry)+'</span><span class="name">'+esc(entry.name)+'</span><span class="sub">'+(entry.size!=null?formatBytes(entry.size):'')+'</span></button>';
|
|
1713
1884
|
}).join('');
|
|
1714
1885
|
}
|
|
1715
1886
|
function renderEmptyViewer(){
|
|
@@ -1720,6 +1891,8 @@ function renderFile(data){
|
|
|
1720
1891
|
const text=data.preview&&data.preview.content!=null?sourceTextForRender(data):null;
|
|
1721
1892
|
const kind=fileKind(data);
|
|
1722
1893
|
if(kind==='image'){renderImage(data);return;}
|
|
1894
|
+
if(kind==='video'||kind==='audio'){renderMedia(data,kind);return;}
|
|
1895
|
+
if(kind==='web'&&text!=null){renderWebFile(data,text);return;}
|
|
1723
1896
|
if(kind==='pdf'){renderPdf(data);return;}
|
|
1724
1897
|
if(kind==='markdown'&&text!=null){renderMarkdownFile(data,text);return;}
|
|
1725
1898
|
if(kind==='mermaid'&&text!=null){renderMermaidFile(data,text);return;}
|
|
@@ -1929,11 +2102,25 @@ function renderImage(data){
|
|
|
1929
2102
|
if(scale)scale.textContent=Math.round(activeImageScale*100)+'%';
|
|
1930
2103
|
}));
|
|
1931
2104
|
}
|
|
2105
|
+
function renderMedia(data,kind){
|
|
2106
|
+
const header=fileHeader(data,{extraActions:'<span class="file-chip">'+esc(kind)+'</span>'});
|
|
2107
|
+
const source=rawUrl(data.path);
|
|
2108
|
+
const body=kind==='video'
|
|
2109
|
+
? '<video controls playsinline preload="metadata" src="'+source+'"></video>'
|
|
2110
|
+
: '<audio controls preload="metadata" src="'+source+'"></audio>';
|
|
2111
|
+
renderViewer(header+'<div class="media-stage" data-preview-content><div class="media-toolbar"><span class="file-chip">'+esc(formatBytes(data.file?.size))+'</span></div><div class="media-preview">'+body+'</div></div>');
|
|
2112
|
+
bindHeaderActions(data.path);
|
|
2113
|
+
}
|
|
1932
2114
|
function renderPdf(data){
|
|
1933
2115
|
const header=fileHeader(data);
|
|
1934
2116
|
renderViewer(header+'<div class="frame-preview" data-preview-content><iframe src="'+rawUrl(data.path)+'" title="'+esc(data.path)+'"></iframe></div>');
|
|
1935
2117
|
bindHeaderActions(data.path);
|
|
1936
2118
|
}
|
|
2119
|
+
function renderWebFile(data,text){
|
|
2120
|
+
const header=fileHeader(data,{language:'html',truncated:Boolean(data.preview&&data.preview.truncated),save:canEditFile(data),editSource:canEditFile(data),extraActions:'<span class="file-chip">web preview</span>'});
|
|
2121
|
+
renderViewer(header+'<div class="frame-preview" data-preview-content><iframe sandbox="allow-scripts allow-forms allow-modals" srcdoc="'+esc(text)+'" title="'+esc(data.path)+'"></iframe></div>');
|
|
2122
|
+
bindHeaderActions(data.path);
|
|
2123
|
+
}
|
|
1937
2124
|
function renderMarkdownFile(data,text){
|
|
1938
2125
|
const header=fileHeader(data,{language:'markdown',truncated:Boolean(data.preview&&data.preview.truncated),save:canEditFile(data),editSource:canEditFile(data)});
|
|
1939
2126
|
renderViewer(header+'<div class="markdown-preview" data-preview-content>'+markdown(text)+'</div>');
|
|
@@ -2942,7 +3129,9 @@ document.getElementById('sessionModal').addEventListener('click',(e)=>{if(e.targ
|
|
|
2942
3129
|
document.getElementById('approvalDenyTop').addEventListener('click',()=>submitApproval('reject'));
|
|
2943
3130
|
document.getElementById('approvalAuto').addEventListener('change',e=>setApprovalAutoMode(e.target.checked));
|
|
2944
3131
|
document.addEventListener('keydown',(e)=>{if(e.key==='Escape'&&pendingApproval){submitApproval('reject');return;}if(e.key==='Escape'&&sessionMenuOpen){setSessionMenuOpen(false);return;}if(e.key==='Escape'&&previewMaximized)setPreviewMaximized(false);});
|
|
2945
|
-
document.getElementById('
|
|
3132
|
+
document.getElementById('fileSearch').addEventListener('input',e=>{workspaceQuery=e.target.value||'';renderExplorer();});
|
|
3133
|
+
document.querySelectorAll('[data-file-filter]').forEach(btn=>btn.addEventListener('click',()=>setWorkspaceFilter(btn.dataset.fileFilter)));
|
|
3134
|
+
document.getElementById('refreshFiles').addEventListener('click',()=>{dirCache.clear();if(workspaceSearchActive())scheduleWorkspaceSearch(0);else loadDir('.');});
|
|
2946
3135
|
document.getElementById('toggleExplorer').addEventListener('click',()=>{let prefs={explorerVisible:true};try{prefs={...prefs,...JSON.parse(localStorage.getItem(layoutKey)||'{}')};}catch{}saveLayoutPatch({explorerVisible:!prefs.explorerVisible});});
|
|
2947
3136
|
document.getElementById('toggleAgent').addEventListener('click',()=>{let prefs={agentVisible:true};try{prefs={...prefs,...JSON.parse(localStorage.getItem(layoutKey)||'{}')};}catch{}saveLayoutPatch({agentVisible:!prefs.agentVisible});});
|
|
2948
3137
|
applyLayout();
|