@dotobokuri/fleet-console 1.28.0 → 1.30.0
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/cli.mjs +209 -387
- package/dist/client/assets/{_baseUniq-0TpVlb56.js → _baseUniq-Dvbxpxj-.js} +1 -1
- package/dist/client/assets/{arc-BIRhKPNZ.js → arc-Cqerxs8I.js} +1 -1
- package/dist/client/assets/{architectureDiagram-Q4EWVU46-CJzkivmk.js → architectureDiagram-Q4EWVU46-gNhmCKnU.js} +1 -1
- package/dist/client/assets/{blockDiagram-DXYQGD6D-PkVBy6UB.js → blockDiagram-DXYQGD6D-CM5HRpKC.js} +1 -1
- package/dist/client/assets/{c4Diagram-AHTNJAMY-TOO0Zc07.js → c4Diagram-AHTNJAMY-DxLhQuvg.js} +1 -1
- package/dist/client/assets/channel-DKkQpLWI.js +1 -0
- package/dist/client/assets/{chunk-4BX2VUAB-Ugm2Ht26.js → chunk-4BX2VUAB-HX6C_GAC.js} +1 -1
- package/dist/client/assets/{chunk-4TB4RGXK-Byfwafb_.js → chunk-4TB4RGXK-CoBQUhS4.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-2I_nwtuS.js → chunk-55IACEB6-DWsWxGBm.js} +1 -1
- package/dist/client/assets/{chunk-EDXVE4YY-JYP41aJo.js → chunk-EDXVE4YY-BXNRu1M4.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-Duh-U1jY.js → chunk-FMBD7UC4-DzKgP1_A.js} +1 -1
- package/dist/client/assets/{chunk-OYMX7WX6-64cqkTOO.js → chunk-OYMX7WX6-aqXdvKUD.js} +1 -1
- package/dist/client/assets/{chunk-QZHKN3VN-engflZJB.js → chunk-QZHKN3VN-BbMqaUb0.js} +1 -1
- package/dist/client/assets/{chunk-YZCP3GAM-BwnK_1vX.js → chunk-YZCP3GAM-D8Mo0nv8.js} +1 -1
- package/dist/client/assets/classDiagram-6PBFFD2Q-CQurO5ix.js +1 -0
- package/dist/client/assets/classDiagram-v2-HSJHXN6E-CQurO5ix.js +1 -0
- package/dist/client/assets/clone-IodjsAGU.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-D43_BnnE.js → cose-bilkent-S5V4N54A-BOuVjjXz.js} +1 -1
- package/dist/client/assets/{dagre-KV5264BT-Wh_p74YO.js → dagre-KV5264BT-BdUFzAj_.js} +1 -1
- package/dist/client/assets/{diagram-5BDNPKRD-BNcxA6wC.js → diagram-5BDNPKRD-C0iFrsGo.js} +1 -1
- package/dist/client/assets/{diagram-G4DWMVQ6-HQdA06kX.js → diagram-G4DWMVQ6-CGxGeQZt.js} +1 -1
- package/dist/client/assets/{diagram-MMDJMWI5-DlMdX_ng.js → diagram-MMDJMWI5-Dex5uqlA.js} +1 -1
- package/dist/client/assets/{diagram-TYMM5635-C1hKAjZD.js → diagram-TYMM5635-O48PEpaS.js} +1 -1
- package/dist/client/assets/{erDiagram-SMLLAGMA-CsSiuv9G.js → erDiagram-SMLLAGMA-B7PGw3YA.js} +1 -1
- package/dist/client/assets/{flowDiagram-DWJPFMVM-DfjQ3Ug9.js → flowDiagram-DWJPFMVM-CCXWJIMw.js} +1 -1
- package/dist/client/assets/{ganttDiagram-T4ZO3ILL-B0QHKePg.js → ganttDiagram-T4ZO3ILL-B26RghpR.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-UUTBAWPF-_zejoqTH.js → gitGraphDiagram-UUTBAWPF-BJsjMn6A.js} +1 -1
- package/dist/client/assets/{graph-Dr6IPcji.js → graph-DuEL0RWH.js} +1 -1
- package/dist/client/assets/index-Dj775lUe.css +1 -0
- package/dist/client/assets/index-r6rDZQCs.js +451 -0
- package/dist/client/assets/{infoDiagram-42DDH7IO-dhruAwPt.js → infoDiagram-42DDH7IO-D32dz1SM.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-UXIWVN3A-DPoZZiH0.js → ishikawaDiagram-UXIWVN3A-4YPQjln0.js} +1 -1
- package/dist/client/assets/{journeyDiagram-VCZTEJTY-DQk8gmrd.js → journeyDiagram-VCZTEJTY-BSvi22HM.js} +1 -1
- package/dist/client/assets/{kanban-definition-6JOO6SKY-B9rOgVFq.js → kanban-definition-6JOO6SKY-SozOXS7m.js} +1 -1
- package/dist/client/assets/{layout-D54BXsv2.js → layout-CNXntIRV.js} +1 -1
- package/dist/client/assets/{linear-DJxG7kFF.js → linear-9RZPFtO4.js} +1 -1
- package/dist/client/assets/{mermaid.core-BBFWA-zA.js → mermaid.core-kwH-UxKY.js} +4 -4
- package/dist/client/assets/{min-Dv_aLAYb.js → min-BdN2p8Q_.js} +1 -1
- package/dist/client/assets/{mindmap-definition-QFDTVHPH-Dv5woCon.js → mindmap-definition-QFDTVHPH-H-3dJmH9.js} +1 -1
- package/dist/client/assets/{pieDiagram-DEJITSTG-B_V_vCG8.js → pieDiagram-DEJITSTG-CspzYvcs.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-34T5L4WZ-QHqq3tFD.js → quadrantDiagram-34T5L4WZ-D1C7e3-s.js} +1 -1
- package/dist/client/assets/{requirementDiagram-MS252O5E-BhPhfMzK.js → requirementDiagram-MS252O5E-BJwKRtMi.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-XADWPNL6-D2-ZsaS_.js → sankeyDiagram-XADWPNL6-7oc42Z3P.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-FGHM5R23-Di0qgM3v.js → sequenceDiagram-FGHM5R23-TP5H_DnF.js} +1 -1
- package/dist/client/assets/{stateDiagram-FHFEXIEX-BAuqrwY8.js → stateDiagram-FHFEXIEX-BWnrNgJY.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-Cmp8tobq.js +1 -0
- package/dist/client/assets/{timeline-definition-GMOUNBTQ-BcMGkC6T.js → timeline-definition-GMOUNBTQ-xXFvCsrr.js} +1 -1
- package/dist/client/assets/{vennDiagram-DHZGUBPP-C9dkwyKX.js → vennDiagram-DHZGUBPP-D5unm_iH.js} +1 -1
- package/dist/client/assets/{wardley-RL74JXVD-BLLCncPa.js → wardley-RL74JXVD-B-eT02rs.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-NUSXRM2D-Yb9mlL0_.js → wardleyDiagram-NUSXRM2D-BTQ1Yqmb.js} +1 -1
- package/dist/client/assets/{xychartDiagram-5P7HB3ND-BAHLdje7.js → xychartDiagram-5P7HB3ND-Bialvg0l.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/fleet-plugins/file-explorer/routes.mjs +199 -38
- package/dist/fleet-plugins/repository/routes.mjs +407 -108
- package/dist/fleet-plugins/skills/routes.mjs +60 -79
- package/dist/fleet-plugins/terminal/routes.mjs +577 -102
- package/package.json +1 -1
- package/dist/client/assets/channel-CqmujVSi.js +0 -1
- package/dist/client/assets/classDiagram-6PBFFD2Q-DLXkYur6.js +0 -1
- package/dist/client/assets/classDiagram-v2-HSJHXN6E-DLXkYur6.js +0 -1
- package/dist/client/assets/clone-KonJWRw9.js +0 -1
- package/dist/client/assets/index-CsmxZ8UQ.js +0 -453
- package/dist/client/assets/index-DC8tBAf_.css +0 -1
- package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-DhNebJyd.js +0 -1
|
@@ -6,12 +6,12 @@ import path2 from 'path';
|
|
|
6
6
|
function definePlugin(definition) {
|
|
7
7
|
return definition;
|
|
8
8
|
}
|
|
9
|
-
function registerRouter(ctx,
|
|
10
|
-
ctx.registerRouter(normalizePath(
|
|
9
|
+
function registerRouter(ctx, path5, handler) {
|
|
10
|
+
ctx.registerRouter(normalizePath(path5), handler);
|
|
11
11
|
}
|
|
12
|
-
function normalizePath(
|
|
13
|
-
if (
|
|
14
|
-
return
|
|
12
|
+
function normalizePath(path5) {
|
|
13
|
+
if (path5.length === 0 || path5 === "/") return "/";
|
|
14
|
+
return path5;
|
|
15
15
|
}
|
|
16
16
|
var FileReadError = class extends Error {
|
|
17
17
|
code;
|
|
@@ -301,9 +301,142 @@ function isWithinRoot2(resolved, root) {
|
|
|
301
301
|
return resolved === root || resolved.startsWith(normalizedRoot);
|
|
302
302
|
}
|
|
303
303
|
var DEBOUNCE_MS = 200;
|
|
304
|
+
var LINUX_DIRECTORY_WATCH_CAP = 1024;
|
|
304
305
|
var watcherRegistry = createWatcherRegistry();
|
|
305
|
-
function createWatcherRegistry(watcherFactory = (p, opts, cb) => fs.watch(p, opts, (ev, fn) => cb(ev, typeof fn === "string" ? fn : null)), debounceMs = DEBOUNCE_MS) {
|
|
306
|
+
function createWatcherRegistry(watcherFactory = (p, opts, cb) => fs.watch(p, opts, (ev, fn) => cb(ev, typeof fn === "string" ? fn : null)), debounceMs = DEBOUNCE_MS, platform = process.platform) {
|
|
306
307
|
const entries = /* @__PURE__ */ new Map();
|
|
308
|
+
function scheduleChange(entry, relDir) {
|
|
309
|
+
const pending = entry.debounceTimers.get(relDir);
|
|
310
|
+
if (pending) clearTimeout(pending);
|
|
311
|
+
entry.debounceTimers.set(
|
|
312
|
+
relDir,
|
|
313
|
+
setTimeout(() => {
|
|
314
|
+
entry.debounceTimers.delete(relDir);
|
|
315
|
+
for (const sub of entry.subscribers) sub(relDir);
|
|
316
|
+
}, debounceMs)
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
function closeEntry(entry) {
|
|
320
|
+
for (const timer of entry.debounceTimers.values()) clearTimeout(timer);
|
|
321
|
+
entry.debounceTimers.clear();
|
|
322
|
+
for (const watcher of entry.watchers.values()) {
|
|
323
|
+
try {
|
|
324
|
+
watcher.close();
|
|
325
|
+
} catch {
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
entry.watchers.clear();
|
|
329
|
+
entry.identityChecks.clear();
|
|
330
|
+
entry.pendingDirectories.clear();
|
|
331
|
+
}
|
|
332
|
+
async function rearmPendingDirectories(theaterId, entry) {
|
|
333
|
+
entry.rearmRequested = true;
|
|
334
|
+
if (entry.rearmRunning) return;
|
|
335
|
+
entry.rearmRunning = true;
|
|
336
|
+
try {
|
|
337
|
+
while (entry.rearmRequested) {
|
|
338
|
+
entry.rearmRequested = false;
|
|
339
|
+
for (const relativePath of entry.pendingDirectories) {
|
|
340
|
+
const target = await resolveTrackedDirectory(entry.theaterPath, relativePath);
|
|
341
|
+
if (!target) continue;
|
|
342
|
+
if (entries.get(theaterId) !== entry || !entry.pendingDirectories.has(relativePath) || entry.watchers.has(relativePath) || entry.watchers.size >= LINUX_DIRECTORY_WATCH_CAP) continue;
|
|
343
|
+
try {
|
|
344
|
+
startWatcher(theaterId, entry, relativePath, target.path, target.identity);
|
|
345
|
+
entry.pendingDirectories.delete(relativePath);
|
|
346
|
+
scheduleChange(entry, relativePath);
|
|
347
|
+
} catch {
|
|
348
|
+
for (const notify of entry.stateSubscribers) notify("degraded");
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
} finally {
|
|
353
|
+
entry.rearmRunning = false;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
function invalidateWatcherTree(entry, watchKey) {
|
|
357
|
+
const descendantPrefix = watchKey + path2.sep;
|
|
358
|
+
for (const [candidateKey, candidateWatcher] of entry.watchers) {
|
|
359
|
+
if (candidateKey !== watchKey && !candidateKey.startsWith(descendantPrefix)) continue;
|
|
360
|
+
entry.watchers.delete(candidateKey);
|
|
361
|
+
entry.identityChecks.delete(candidateKey);
|
|
362
|
+
entry.pendingDirectories.add(candidateKey);
|
|
363
|
+
try {
|
|
364
|
+
candidateWatcher.close();
|
|
365
|
+
} catch {
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
function startWatcher(theaterId, entry, watchKey, watchPath, watchIdentity) {
|
|
370
|
+
let identityCheckRunning = false;
|
|
371
|
+
let identityCheckRequested = false;
|
|
372
|
+
let activeWatcher = null;
|
|
373
|
+
const lexicalWatchPath = path2.resolve(entry.theaterPath, watchKey);
|
|
374
|
+
const checkDirectoryIdentity = async (expectedWatcher) => {
|
|
375
|
+
identityCheckRequested = true;
|
|
376
|
+
if (identityCheckRunning || !watchIdentity) return;
|
|
377
|
+
identityCheckRunning = true;
|
|
378
|
+
try {
|
|
379
|
+
while (identityCheckRequested) {
|
|
380
|
+
identityCheckRequested = false;
|
|
381
|
+
let replaced = false;
|
|
382
|
+
try {
|
|
383
|
+
const stats = await fs.promises.stat(lexicalWatchPath);
|
|
384
|
+
replaced = stats.dev !== watchIdentity.device || stats.ino !== watchIdentity.inode;
|
|
385
|
+
} catch (error) {
|
|
386
|
+
replaced = error.code === "ENOENT";
|
|
387
|
+
}
|
|
388
|
+
if (entry.watchers.get(watchKey) !== expectedWatcher) return;
|
|
389
|
+
if (!replaced) continue;
|
|
390
|
+
invalidateWatcherTree(entry, watchKey);
|
|
391
|
+
await rearmPendingDirectories(theaterId, entry);
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
} finally {
|
|
395
|
+
identityCheckRunning = false;
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
const watcher = watcherFactory(watchPath, { recursive: entry.recursive }, (event, filename) => {
|
|
399
|
+
const currentWatcher = activeWatcher;
|
|
400
|
+
if (!currentWatcher || entry.watchers.get(watchKey) !== currentWatcher) return;
|
|
401
|
+
scheduleChange(entry, entry.recursive ? computeRelDir(filename) : watchKey);
|
|
402
|
+
if (!entry.recursive && event === "rename") {
|
|
403
|
+
if (watchKey !== "" && watchIdentity) void checkDirectoryIdentity(currentWatcher);
|
|
404
|
+
if (filename) {
|
|
405
|
+
const changedChildKey = path2.join(watchKey, filename);
|
|
406
|
+
entry.identityChecks.get(changedChildKey)?.();
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
if (!entry.recursive && entry.pendingDirectories.size > 0) {
|
|
410
|
+
void rearmPendingDirectories(theaterId, entry);
|
|
411
|
+
}
|
|
412
|
+
});
|
|
413
|
+
activeWatcher = watcher;
|
|
414
|
+
entry.watchers.set(watchKey, watcher);
|
|
415
|
+
if (watchIdentity) {
|
|
416
|
+
entry.identityChecks.set(watchKey, () => {
|
|
417
|
+
const currentWatcher = activeWatcher;
|
|
418
|
+
if (currentWatcher) void checkDirectoryIdentity(currentWatcher);
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
watcher.on("error", () => {
|
|
422
|
+
if (entry.watchers.get(watchKey) !== watcher) return;
|
|
423
|
+
try {
|
|
424
|
+
watcher.close();
|
|
425
|
+
} catch {
|
|
426
|
+
}
|
|
427
|
+
entry.watchers.delete(watchKey);
|
|
428
|
+
entry.identityChecks.delete(watchKey);
|
|
429
|
+
if (watchKey === "") {
|
|
430
|
+
closeEntry(entry);
|
|
431
|
+
if (entries.get(theaterId) === entry) entries.delete(theaterId);
|
|
432
|
+
} else {
|
|
433
|
+
const pending = entry.debounceTimers.get(watchKey);
|
|
434
|
+
if (pending) clearTimeout(pending);
|
|
435
|
+
entry.debounceTimers.delete(watchKey);
|
|
436
|
+
}
|
|
437
|
+
for (const notify of entry.stateSubscribers) notify("degraded");
|
|
438
|
+
});
|
|
439
|
+
}
|
|
307
440
|
function makeUnsubscribe(theaterId, onChange, onState, entry) {
|
|
308
441
|
let called = false;
|
|
309
442
|
return () => {
|
|
@@ -313,8 +446,7 @@ function createWatcherRegistry(watcherFactory = (p, opts, cb) => fs.watch(p, opt
|
|
|
313
446
|
entry.stateSubscribers.delete(onState);
|
|
314
447
|
entry.subscriberCount--;
|
|
315
448
|
if (entry.subscriberCount <= 0) {
|
|
316
|
-
|
|
317
|
-
entry.watcher.close();
|
|
449
|
+
closeEntry(entry);
|
|
318
450
|
if (entries.get(theaterId) === entry) entries.delete(theaterId);
|
|
319
451
|
}
|
|
320
452
|
};
|
|
@@ -328,46 +460,74 @@ function createWatcherRegistry(watcherFactory = (p, opts, cb) => fs.watch(p, opt
|
|
|
328
460
|
onState("watching");
|
|
329
461
|
return makeUnsubscribe(theaterId, onChange, onState, existing);
|
|
330
462
|
}
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
463
|
+
const entry = {
|
|
464
|
+
// Linux의 recursive fs.watch fallback은 구독 시 전체 트리를 동기 순회한다.
|
|
465
|
+
// 대신 root와 실제로 조회된 디렉터리만 개별 비재귀 watcher로 추적한다.
|
|
466
|
+
theaterPath,
|
|
467
|
+
recursive: platform !== "linux",
|
|
468
|
+
watchers: /* @__PURE__ */ new Map(),
|
|
469
|
+
identityChecks: /* @__PURE__ */ new Map(),
|
|
470
|
+
pendingDirectories: /* @__PURE__ */ new Set(),
|
|
471
|
+
subscribers: /* @__PURE__ */ new Set([onChange]),
|
|
472
|
+
stateSubscribers: /* @__PURE__ */ new Set([onState]),
|
|
473
|
+
subscriberCount: 1,
|
|
474
|
+
debounceTimers: /* @__PURE__ */ new Map(),
|
|
475
|
+
rearmRunning: false,
|
|
476
|
+
rearmRequested: false
|
|
477
|
+
};
|
|
335
478
|
try {
|
|
336
|
-
|
|
337
|
-
const relDir = computeRelDir(filename);
|
|
338
|
-
const pending = debounceTimers.get(relDir);
|
|
339
|
-
if (pending) clearTimeout(pending);
|
|
340
|
-
debounceTimers.set(
|
|
341
|
-
relDir,
|
|
342
|
-
setTimeout(() => {
|
|
343
|
-
debounceTimers.delete(relDir);
|
|
344
|
-
for (const sub of subscribers) sub(relDir);
|
|
345
|
-
}, debounceMs)
|
|
346
|
-
);
|
|
347
|
-
});
|
|
479
|
+
startWatcher(theaterId, entry, "", theaterPath);
|
|
348
480
|
} catch {
|
|
349
481
|
onState("degraded");
|
|
350
482
|
return () => {
|
|
351
483
|
};
|
|
352
484
|
}
|
|
353
|
-
const entry = { watcher, subscribers, stateSubscribers, subscriberCount: 1, debounceTimers };
|
|
354
|
-
watcher.on("error", () => {
|
|
355
|
-
for (const t of debounceTimers.values()) clearTimeout(t);
|
|
356
|
-
debounceTimers.clear();
|
|
357
|
-
try {
|
|
358
|
-
watcher.close();
|
|
359
|
-
} catch {
|
|
360
|
-
}
|
|
361
|
-
if (entries.get(theaterId) === entry) entries.delete(theaterId);
|
|
362
|
-
for (const notify of stateSubscribers) notify("degraded");
|
|
363
|
-
});
|
|
364
485
|
entries.set(theaterId, entry);
|
|
365
|
-
subscribers.add(onChange);
|
|
366
|
-
stateSubscribers.add(onState);
|
|
367
486
|
onState("watching");
|
|
368
487
|
return makeUnsubscribe(theaterId, onChange, onState, entry);
|
|
369
488
|
}
|
|
370
|
-
|
|
489
|
+
async function trackDirectory(theaterId, theaterPath, relativePath) {
|
|
490
|
+
const entry = entries.get(theaterId);
|
|
491
|
+
if (!entry || entry.recursive || relativePath === "" || entry.watchers.has(relativePath)) return;
|
|
492
|
+
if (entry.watchers.size >= LINUX_DIRECTORY_WATCH_CAP) {
|
|
493
|
+
for (const notify of entry.stateSubscribers) notify("degraded");
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
const target = await resolveTrackedDirectory(theaterPath, relativePath);
|
|
497
|
+
if (!target) return;
|
|
498
|
+
if (entries.get(theaterId) !== entry || entry.watchers.has(relativePath) || entry.watchers.size >= LINUX_DIRECTORY_WATCH_CAP) return;
|
|
499
|
+
try {
|
|
500
|
+
startWatcher(theaterId, entry, relativePath, target.path, target.identity);
|
|
501
|
+
entry.pendingDirectories.delete(relativePath);
|
|
502
|
+
} catch {
|
|
503
|
+
for (const notify of entry.stateSubscribers) notify("degraded");
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
return { subscribe, trackDirectory };
|
|
507
|
+
}
|
|
508
|
+
async function resolveTrackedDirectory(theaterPath, relativePath) {
|
|
509
|
+
const resolvedRoot = path2.resolve(theaterPath);
|
|
510
|
+
const targetPath = path2.resolve(resolvedRoot, relativePath);
|
|
511
|
+
if (!isWithinRoot3(targetPath, resolvedRoot)) return null;
|
|
512
|
+
try {
|
|
513
|
+
const [realRoot, realTarget] = await Promise.all([
|
|
514
|
+
fs.promises.realpath(theaterPath),
|
|
515
|
+
fs.promises.realpath(targetPath)
|
|
516
|
+
]);
|
|
517
|
+
if (!isWithinRoot3(realTarget, realRoot)) return null;
|
|
518
|
+
const stats = await fs.promises.stat(realTarget);
|
|
519
|
+
if (!stats.isDirectory()) return null;
|
|
520
|
+
return {
|
|
521
|
+
path: realTarget,
|
|
522
|
+
identity: { device: stats.dev, inode: stats.ino }
|
|
523
|
+
};
|
|
524
|
+
} catch {
|
|
525
|
+
return null;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
function isWithinRoot3(candidate, root) {
|
|
529
|
+
const normalizedRoot = root.endsWith(path2.sep) ? root : root + path2.sep;
|
|
530
|
+
return candidate === root || candidate.startsWith(normalizedRoot);
|
|
371
531
|
}
|
|
372
532
|
function computeRelDir(filename) {
|
|
373
533
|
if (!filename) return "";
|
|
@@ -415,6 +575,7 @@ async function handleFilesList(req, res, ctx) {
|
|
|
415
575
|
}
|
|
416
576
|
try {
|
|
417
577
|
const result = await listTheaterContents(theaterPath, relPath);
|
|
578
|
+
await watcherRegistry.trackDirectory(rawTheaterId, theaterPath, relPath);
|
|
418
579
|
ctx.host.http.writeJson(res, 200, result);
|
|
419
580
|
} catch (error) {
|
|
420
581
|
if (error instanceof FolderBrowserError) {
|