zdashboard 2.8.3 → 2.8.5

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.
Files changed (37) hide show
  1. package/dist/cli.js +80 -304
  2. package/dist/cli.js.map +1 -1
  3. package/dist/web/assets/CodeViewer-BrquqtDE.js +307 -0
  4. package/dist/web/assets/{FileIcon-a612-H-j.js → FileIcon-FyROY2Qe.js} +1 -1
  5. package/dist/web/assets/{FilterPills-BVAToHeu.js → FilterPills-DwCH0Z96.js} +1 -1
  6. package/dist/web/assets/{Sidebar-CmJ0RfM6.js → Sidebar-BUi2jDuu.js} +1 -1
  7. package/dist/web/assets/{Sidebar-CYYR-the.js → Sidebar-Cz3W5MP6.js} +1 -1
  8. package/dist/web/assets/Workspace-CafALYiK.js +1 -0
  9. package/dist/web/assets/Workspace-D-n83gau.js +1 -0
  10. package/dist/web/assets/{Workspace-DT0JWcsX.js → Workspace-Db4r4oQO.js} +1 -1
  11. package/dist/web/assets/Workspace-ICT0FTaI.js +1 -0
  12. package/dist/web/assets/index--t_ijYil.css +1 -0
  13. package/dist/web/assets/{index-C_16tmIU.js → index-BAFFLjYP.js} +12 -12
  14. package/dist/web/assets/{usePluginData-pzvMTyoN.js → usePluginData-DEpAv1Yl.js} +1 -1
  15. package/dist/web/assets/web-BP-QGcd3.js +2 -0
  16. package/dist/web/assets/web-CE86ahqk.js +2 -0
  17. package/dist/web/assets/{web-DwYp5Vde.js → web-D0z_1kb8.js} +2 -2
  18. package/dist/web/assets/web-S85uEYzf.js +2 -0
  19. package/dist/web/index.html +2 -2
  20. package/package.json +1 -1
  21. package/dist/web/assets/BatchView-D9TMypRX.js +0 -2
  22. package/dist/web/assets/CheckpointViewer-DJ9yKpMh.js +0 -1
  23. package/dist/web/assets/CodeViewer-C_3Ms2Ri.js +0 -279
  24. package/dist/web/assets/DependencyGraph-hsA8ZmBD.js +0 -1
  25. package/dist/web/assets/ProgressBar-YEvCsTOC.js +0 -1
  26. package/dist/web/assets/SingleChangeView-CCpmUD7z.js +0 -1
  27. package/dist/web/assets/ViewHeader-C_euf5UJ.js +0 -1
  28. package/dist/web/assets/Workspace-BLaqqsJU.js +0 -1
  29. package/dist/web/assets/Workspace-C70CR7yx.js +0 -1
  30. package/dist/web/assets/Workspace-Coooyssr.js +0 -1
  31. package/dist/web/assets/Workspace-NqbDbmhC.js +0 -2
  32. package/dist/web/assets/index-CwS-KyOV.css +0 -1
  33. package/dist/web/assets/index-DvE_prho.js +0 -29
  34. package/dist/web/assets/web-BXIb25pa.js +0 -2
  35. package/dist/web/assets/web-CF8JCQ-n.js +0 -2
  36. package/dist/web/assets/web-D-wmMJ1D.js +0 -2
  37. package/dist/web/assets/web-qAmlbo_B.js +0 -2
package/dist/cli.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import path11 from "path";
5
- import fs11 from "fs";
4
+ import path9 from "path";
5
+ import fs9 from "fs";
6
6
  import { fileURLToPath as fileURLToPath2 } from "url";
7
7
  import { access, readdir } from "fs/promises";
8
8
  import { parseArgs as utilParseArgs } from "util";
@@ -43,7 +43,7 @@ import { fileURLToPath } from "url";
43
43
  // package.json
44
44
  var package_default = {
45
45
  name: "zdashboard",
46
- version: "2.8.3",
46
+ version: "2.8.5",
47
47
  description: "ZCode skill dashboard platform \u2014 pluggable viewers for zdesign/zview/zreview/zgoal",
48
48
  type: "module",
49
49
  bin: {
@@ -452,13 +452,13 @@ var ServerService = class extends Service {
452
452
  });
453
453
  this.start(config.port);
454
454
  }
455
- route(path12, handler) {
456
- this.routes.set(path12, handler);
457
- this.ctx.effect(() => () => this.routes.delete(path12));
455
+ route(path10, handler) {
456
+ this.routes.set(path10, handler);
457
+ this.ctx.effect(() => () => this.routes.delete(path10));
458
458
  }
459
- sse(path12, onConnect) {
460
- this.sses.set(path12, onConnect);
461
- this.ctx.effect(() => () => this.sses.delete(path12));
459
+ sse(path10, onConnect) {
460
+ this.sses.set(path10, onConnect);
461
+ this.ctx.effect(() => () => this.sses.delete(path10));
462
462
  }
463
463
  static(prefix, dir) {
464
464
  this.prefixStatic.set(prefix, dir);
@@ -757,7 +757,7 @@ import path5 from "path";
757
757
  import fs5 from "fs";
758
758
  import path4 from "path";
759
759
  function walkDir(root, opts = {}) {
760
- const { skip = /* @__PURE__ */ new Set(), maxDepth, onFile, onDir } = opts;
760
+ const { skip = /* @__PURE__ */ new Set(), maxDepth, allowDotDirs = false, onFile, onDir } = opts;
761
761
  function walk(dir, rel, depth) {
762
762
  if (typeof maxDepth === "number" && depth > maxDepth) return;
763
763
  let ents;
@@ -767,7 +767,7 @@ function walkDir(root, opts = {}) {
767
767
  return;
768
768
  }
769
769
  for (const ent of ents) {
770
- if (ent.name.startsWith(".")) continue;
770
+ if (ent.name.startsWith(".") && !(allowDotDirs && ent.isDirectory())) continue;
771
771
  if (skip.has(ent.name)) continue;
772
772
  const abs = path4.join(dir, ent.name);
773
773
  const r = rel ? `${rel}/${ent.name}` : ent.name;
@@ -835,12 +835,14 @@ function prefixPaths(nodes, prefix) {
835
835
  function scanTree(root, scanDirs, opts) {
836
836
  const tree = [];
837
837
  const defaultExpandDepth = typeof opts?.defaultExpandDepth === "number" ? opts.defaultExpandDepth : 2;
838
+ const dotDeclared = new Set(Array.isArray(opts?.dotDirs) ? opts.dotDirs : []);
838
839
  const dirs = Array.isArray(scanDirs) ? scanDirs.filter((d) => typeof d === "string" && d) : [];
839
840
  for (const dir of dirs) {
841
+ if (dir.startsWith(".") && !dotDeclared.has(dir)) continue;
840
842
  const dirPath = path5.join(root, dir);
841
843
  if (!fs6.existsSync(dirPath)) continue;
842
844
  const paths = [];
843
- walkDir(dirPath, { maxDepth: 4, onFile: (_, rel) => paths.push(rel) });
845
+ walkDir(dirPath, { maxDepth: 4, allowDotDirs: dotDeclared.has(dir), onFile: (_, rel) => paths.push(rel) });
844
846
  const prefix = dir;
845
847
  const children = prefixPaths(buildTree(paths, defaultExpandDepth), prefix);
846
848
  if (children.length) {
@@ -851,7 +853,8 @@ function scanTree(root, scanDirs, opts) {
851
853
  }
852
854
 
853
855
  // src/core/tree.ts
854
- var CONVENTION_SCAN_DIRS = ["openspec", "docs"];
856
+ var CONVENTION_SCAN_DIRS = ["openspec", "docs", ".zdev/apply"];
857
+ var CONVENTION_DOT_DIRS = CONVENTION_SCAN_DIRS.filter((d) => d.startsWith("."));
855
858
  var apply = {
856
859
  inject: ["server"],
857
860
  apply(ctx, config) {
@@ -862,7 +865,7 @@ var apply = {
862
865
  const url = new URL(req.url || "/", "http://localhost");
863
866
  const wt = url.searchParams.get("wt");
864
867
  const scanRoot = wt ? decodeURIComponent(wt) : config.root;
865
- const tree = scanTree(scanRoot, [...CONVENTION_SCAN_DIRS]);
868
+ const tree = scanTree(scanRoot, [...CONVENTION_SCAN_DIRS], { dotDirs: [...CONVENTION_DOT_DIRS] });
866
869
  res.writeHead(200, { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-cache" });
867
870
  res.end(JSON.stringify({ tree }));
868
871
  } catch {
@@ -1028,9 +1031,9 @@ var DashboardService = class extends Service3 {
1028
1031
  res.end('{"error":"method not allowed"}');
1029
1032
  });
1030
1033
  }
1031
- register(manifest6) {
1032
- this.plugins.set(manifest6.mode, manifest6);
1033
- this.ctx.effect(() => () => this.plugins.delete(manifest6.mode));
1034
+ register(manifest5) {
1035
+ this.plugins.set(manifest5.mode, manifest5);
1036
+ this.ctx.effect(() => () => this.plugins.delete(manifest5.mode));
1034
1037
  }
1035
1038
  list() {
1036
1039
  return Array.from(this.plugins.values());
@@ -1193,7 +1196,7 @@ var JustRunner = class {
1193
1196
 
1194
1197
  // src/sdk/server.ts
1195
1198
  function definePlugin(def) {
1196
- const { manifest: manifest6, setup } = def;
1199
+ const { manifest: manifest5, setup } = def;
1197
1200
  return {
1198
1201
  inject: ["server", "dashboard", "reload"],
1199
1202
  apply(ctx) {
@@ -1203,49 +1206,49 @@ function definePlugin(def) {
1203
1206
  try {
1204
1207
  fn();
1205
1208
  } catch (e) {
1206
- console.error(`[zdashboard] plugin ${manifest6.mode} dispose error:`, e);
1209
+ console.error(`[zdashboard] plugin ${manifest5.mode} dispose error:`, e);
1207
1210
  }
1208
1211
  }
1209
1212
  });
1210
- ctx.dashboard.register(manifest6);
1213
+ ctx.dashboard.register(manifest5);
1211
1214
  const respondWith = (handler) => async (req, res) => {
1212
1215
  if (res.headersSent) return;
1213
1216
  try {
1214
1217
  const data = await handler(req, res);
1215
1218
  if (data !== void 0 && !res.writableEnded) json(res, data);
1216
1219
  } catch (e) {
1217
- console.error(`[zdashboard] plugin ${manifest6.mode} route error:`, e);
1220
+ console.error(`[zdashboard] plugin ${manifest5.mode} route error:`, e);
1218
1221
  if (!res.headersSent) json(res, { error: "internal" }, 500);
1219
1222
  }
1220
1223
  };
1221
1224
  const pctx = {
1222
- mode: manifest6.mode,
1225
+ mode: manifest5.mode,
1223
1226
  config() {
1224
- const schema = manifest6.config ?? {};
1225
- const stored = ctx.server.getPluginConfig(manifest6.mode) ?? {};
1227
+ const schema = manifest5.config ?? {};
1228
+ const stored = ctx.server.getPluginConfig(manifest5.mode) ?? {};
1226
1229
  const defaults = Object.fromEntries(
1227
1230
  Object.entries(schema).map(([key, field]) => [key, field.default])
1228
1231
  );
1229
1232
  return { ...defaults, ...stored };
1230
1233
  },
1231
- route(path12, handler) {
1232
- ctx.server.route(path12, respondWith(handler));
1234
+ route(path10, handler) {
1235
+ ctx.server.route(path10, respondWith(handler));
1233
1236
  },
1234
- guardedRoute(path12, handler) {
1237
+ guardedRoute(path10, handler) {
1235
1238
  const token = () => ctx.server.stopToken;
1236
- ctx.server.route(path12, (req, res) => {
1239
+ ctx.server.route(path10, (req, res) => {
1237
1240
  if (!guarded(req, res, token())) return;
1238
1241
  void respondWith(handler)(req, res);
1239
1242
  });
1240
1243
  },
1241
- sse(path12, handler) {
1242
- ctx.server.sse(path12, handler);
1244
+ sse(path10, handler) {
1245
+ ctx.server.sse(path10, handler);
1243
1246
  },
1244
1247
  static(prefix, dir) {
1245
1248
  ctx.server.static(prefix, dir);
1246
1249
  },
1247
1250
  broadcast(event, data) {
1248
- ctx.reload?.broadcast(`plugin:${manifest6.mode}:${event}`, data ?? "");
1251
+ ctx.reload?.broadcast(`plugin:${manifest5.mode}:${event}`, data ?? "");
1249
1252
  },
1250
1253
  onDispose(fn) {
1251
1254
  disposers.push(fn);
@@ -1350,239 +1353,12 @@ var apply3 = defineBuiltin({
1350
1353
  }
1351
1354
  });
1352
1355
 
1353
- // src/plugins/apply/scan.ts
1354
- import fs7 from "fs";
1355
- import path6 from "path";
1356
-
1357
- // src/plugins/apply/parse-tasks.ts
1358
- var TASK_RE = /^\s*-\s*\[([ xX])\]\s*(.*)$/;
1359
- var MANUAL_PREFIX = "\u{1F527}[\u4EBA\u5DE5]";
1360
- function parseTasks(md) {
1361
- return md.split(/\r?\n/).filter((l) => TASK_RE.test(l)).map((l) => {
1362
- const m = l.match(TASK_RE);
1363
- const text = (m?.[2] ?? l).trim();
1364
- return { text, checked: m?.[1] !== " ", manual: text.startsWith(MANUAL_PREFIX) };
1365
- });
1366
- }
1367
- function countTasks(md) {
1368
- const tasks = parseTasks(md);
1369
- const normal = tasks.filter((t) => !t.manual);
1370
- return {
1371
- total: normal.length,
1372
- done: normal.filter((t) => t.checked).length,
1373
- manual: tasks.length - normal.length
1374
- };
1375
- }
1376
-
1377
- // src/plugins/apply/scan.ts
1378
- function readText(p) {
1379
- try {
1380
- return fs7.readFileSync(p, "utf8");
1381
- } catch {
1382
- return "";
1383
- }
1384
- }
1385
- function worktreeDir(root, name) {
1386
- return path6.join(root, ".zworktree", name);
1387
- }
1388
- function changeDir(root, name) {
1389
- return path6.join(root, "openspec", "changes", name);
1390
- }
1391
- function parseDependsOn(proposal) {
1392
- const deps = [];
1393
- const m = proposal.match(/^##\s+依赖\s*\n([\s\S]*?)(?:\n#{1,6}\s|\n---\s*\n|$)/i);
1394
- if (!m) return deps;
1395
- for (const line of m[1].split("\n")) {
1396
- if (!/^-\s+/.test(line)) continue;
1397
- const name = line.replace(/^-\s+/, "").trim();
1398
- if (name) deps.push(name);
1399
- }
1400
- return deps;
1401
- }
1402
- function scanApplyChanges(root) {
1403
- const changesDir = path6.join(root, "openspec", "changes");
1404
- if (!fs7.existsSync(changesDir)) return [];
1405
- const out = [];
1406
- for (const ent of fs7.readdirSync(changesDir, { withFileTypes: true })) {
1407
- if (!ent.isDirectory() || ent.name.startsWith(".") || ent.name === "archive") continue;
1408
- const wt = worktreeDir(root, ent.name);
1409
- const tasks = readText(path6.join(wt, "openspec", "changes", ent.name, "tasks.md"));
1410
- if (!tasks) {
1411
- const fallback = readText(path6.join(changesDir, ent.name, "tasks.md"));
1412
- if (fallback) {
1413
- const { total, done } = countTasks(fallback);
1414
- const wtChange = path6.join(wt, "openspec", "changes", ent.name);
1415
- const mainChange = path6.join(changesDir, ent.name);
1416
- out.push({
1417
- name: ent.name,
1418
- path: `openspec/changes/${ent.name}`,
1419
- total,
1420
- done,
1421
- hasProposal: fs7.existsSync(path6.join(wtChange, "proposal.md")) || fs7.existsSync(path6.join(mainChange, "proposal.md")),
1422
- hasDesign: fs7.existsSync(path6.join(wtChange, "design.md")) || fs7.existsSync(path6.join(mainChange, "design.md")),
1423
- // worktree 目录存在即算执行中(tasks.md 可能尚未落盘)
1424
- inWorktree: fs7.existsSync(wtChange)
1425
- });
1426
- }
1427
- } else {
1428
- const { total, done } = countTasks(tasks);
1429
- const wtChange = path6.join(wt, "openspec", "changes", ent.name);
1430
- const mainChange = path6.join(changesDir, ent.name);
1431
- out.push({
1432
- name: ent.name,
1433
- path: `openspec/changes/${ent.name}`,
1434
- total,
1435
- done,
1436
- // 任一侧存在即算(详情读取是 worktree 优先、主目录兜底,列表标记保持一致)
1437
- hasProposal: fs7.existsSync(path6.join(wtChange, "proposal.md")) || fs7.existsSync(path6.join(mainChange, "proposal.md")),
1438
- hasDesign: fs7.existsSync(path6.join(wtChange, "design.md")) || fs7.existsSync(path6.join(mainChange, "design.md")),
1439
- inWorktree: true
1440
- });
1441
- }
1442
- }
1443
- out.sort((a, b) => a.name.localeCompare(b.name));
1444
- return out;
1445
- }
1446
- function readApplyChange(root, name) {
1447
- const wt = worktreeDir(root, name);
1448
- const mainChangeDir = changeDir(root, name);
1449
- const proposalFrom = fs7.existsSync(path6.join(wt, "openspec", "changes", name, "proposal.md")) ? path6.join(wt, "openspec", "changes", name, "proposal.md") : path6.join(mainChangeDir, "proposal.md");
1450
- const designFrom = fs7.existsSync(path6.join(wt, "openspec", "changes", name, "design.md")) ? path6.join(wt, "openspec", "changes", name, "design.md") : path6.join(mainChangeDir, "design.md");
1451
- const tasksFrom = fs7.existsSync(path6.join(wt, "openspec", "changes", name, "tasks.md")) ? path6.join(wt, "openspec", "changes", name, "tasks.md") : path6.join(mainChangeDir, "tasks.md");
1452
- const proposal = readText(proposalFrom);
1453
- const design = readText(designFrom);
1454
- const tasks = readText(tasksFrom);
1455
- const { total, done } = countTasks(tasks);
1456
- const inWorktree = fs7.existsSync(path6.join(wt, "openspec", "changes", name));
1457
- const dependsOn = parseDependsOn(proposal);
1458
- const hasTestStrategy = /^##\s+测试策略\s*$/m.test(design);
1459
- return {
1460
- name,
1461
- path: `openspec/changes/${name}`,
1462
- total,
1463
- done,
1464
- hasProposal: !!proposal,
1465
- hasDesign: !!design,
1466
- inWorktree,
1467
- proposal,
1468
- design,
1469
- tasks,
1470
- dependsOn,
1471
- hasTestStrategy
1472
- };
1473
- }
1474
-
1475
- // src/plugins/apply/batch.ts
1476
- import fs8 from "fs";
1477
- import path7 from "path";
1478
- var RUN_ID_PATTERN = /^[A-Za-z0-9-]+$/;
1479
- function isPlainObject(v) {
1480
- return typeof v === "object" && v !== null && !Array.isArray(v);
1481
- }
1482
- function readText2(p) {
1483
- try {
1484
- return fs8.readFileSync(p, "utf8");
1485
- } catch {
1486
- return null;
1487
- }
1488
- }
1489
- function readBatchState(root, explicitRun) {
1490
- const applyDir = path7.join(root, ".zdev", "apply");
1491
- const requested = explicitRun?.trim() ?? "";
1492
- const runId = requested && RUN_ID_PATTERN.test(requested) ? requested : readText2(path7.join(applyDir, "CURRENT"))?.trim() ?? "";
1493
- if (!runId || !RUN_ID_PATTERN.test(runId)) {
1494
- return { run: null, state: null };
1495
- }
1496
- const parsed = (() => {
1497
- const text = readText2(path7.join(applyDir, "runs", runId, "state.json"));
1498
- if (text == null) return null;
1499
- try {
1500
- return JSON.parse(text);
1501
- } catch {
1502
- return null;
1503
- }
1504
- })();
1505
- if (!isPlainObject(parsed)) {
1506
- return { run: { id: runId }, state: null };
1507
- }
1508
- return { run: { id: runId }, state: parsed };
1509
- }
1510
- function projectGraph(state) {
1511
- if (!state) {
1512
- return { changes: [], batches: [], conflicts: [] };
1513
- }
1514
- const rawChanges = state.changes;
1515
- const rawBatches = state.batches;
1516
- const rawConflicts = state.conflicts;
1517
- return {
1518
- changes: (Array.isArray(rawChanges) ? rawChanges : []).map((c) => ({
1519
- name: c.name,
1520
- status: c.status,
1521
- dependencies: Array.isArray(c?.dependencies) ? c.dependencies : [],
1522
- batchIndex: c.batchIndex
1523
- })),
1524
- batches: Array.isArray(rawBatches) ? rawBatches : [],
1525
- conflicts: Array.isArray(rawConflicts) ? rawConflicts : []
1526
- };
1527
- }
1528
- var BATCH_LOGS_TAIL = 100;
1529
- function tailLogs(state) {
1530
- return (state?.logs ?? []).slice(-BATCH_LOGS_TAIL);
1531
- }
1532
- function readBatchPlan(root, runId) {
1533
- return readText2(path7.join(root, ".zdev", "apply", "runs", runId, "plan.md"));
1534
- }
1535
-
1536
- // src/plugins/apply/manifest.ts
1537
- var manifest2 = {
1538
- mode: "apply",
1539
- label: "\u6267\u884C\u8FDB\u5EA6",
1540
- icon: "\u2699\uFE0F",
1541
- description: "OpenSpec \u6267\u884C\u8FDB\u5EA6 \xB7 zapply \u5355 change \u4E0E\u6279\u91CF",
1542
- order: 40
1543
- };
1544
-
1545
- // src/plugins/apply/index.ts
1546
- function errorResponse(res, status, msg) {
1547
- res.writeHead(status, { "Content-Type": "application/json; charset=utf-8" });
1548
- res.end(JSON.stringify({ error: msg }));
1549
- return void 0;
1550
- }
1551
- var apply4 = defineBuiltin({
1552
- manifest: manifest2,
1553
- setup(ctx, root) {
1554
- ctx.route("/__apply", async () => scanApplyChanges(root));
1555
- ctx.route("/__apply/change", async (req, res) => {
1556
- const url = new URL(req.url || "", "http://x");
1557
- const name = url.searchParams.get("name");
1558
- const bad = (msg) => errorResponse(res, 400, msg);
1559
- if (!name) return bad("missing name");
1560
- if (name.includes("..") || name.includes("/") || name.includes("\\")) return bad("invalid name");
1561
- try {
1562
- return readApplyChange(root, name);
1563
- } catch (e) {
1564
- return bad(e instanceof Error ? e.message : "unknown error");
1565
- }
1566
- });
1567
- const queryRun = (req) => new URL(req.url || "", "http://x").searchParams.get("run") ?? void 0;
1568
- ctx.route("/__apply/batch", async (req) => readBatchState(root, queryRun(req)));
1569
- ctx.route("/__apply/batch/graph", async (req) => projectGraph(readBatchState(root, queryRun(req)).state));
1570
- ctx.route("/__apply/batch/logs", async (req) => tailLogs(readBatchState(root, queryRun(req)).state));
1571
- ctx.route("/__apply/batch/plan", async (req, res) => {
1572
- const snap = readBatchState(root, queryRun(req));
1573
- const plan = snap.run ? readBatchPlan(root, snap.run.id) : null;
1574
- if (plan == null) return errorResponse(res, 404, "plan not found");
1575
- return { plan };
1576
- });
1577
- }
1578
- });
1579
-
1580
1356
  // src/plugins/design/index.ts
1581
- import path9 from "path";
1582
- import fs9 from "fs";
1357
+ import path7 from "path";
1358
+ import fs7 from "fs";
1583
1359
 
1584
1360
  // src/server/design-assets.ts
1585
- import path8 from "path";
1361
+ import path6 from "path";
1586
1362
  var PAGE_EXTS = [".html", ".htm"];
1587
1363
  var ICON_EXTS = [".svg", ".png", ".ico", ".jpg", ".jpeg", ".gif", ".webp"];
1588
1364
  var VIDEO_EXTS = [".mp4", ".webm", ".mov", ".ogg", ".ogv"];
@@ -1610,17 +1386,17 @@ function scanAssets(root, subDir = "") {
1610
1386
  const keys = ["page", "component", "icon", "token", "md", "video", "audio", "pdf", "font"];
1611
1387
  for (const k of keys) out[k] = [];
1612
1388
  const SKIP = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", "coverage", ".next", ".cache"]);
1613
- const scanRoot = subDir ? path8.join(root, subDir) : root;
1389
+ const scanRoot = subDir ? path6.join(root, subDir) : root;
1614
1390
  walkDir(scanRoot, { skip: SKIP, onFile: (abs, rel) => {
1615
- const ext = path8.extname(abs).toLowerCase();
1391
+ const ext = path6.extname(abs).toLowerCase();
1616
1392
  const t = categorize(rel, ext);
1617
- if (t) out[t].push({ path: rel, name: path8.basename(abs), ext, type: t });
1393
+ if (t) out[t].push({ path: rel, name: path6.basename(abs), ext, type: t });
1618
1394
  } });
1619
1395
  return out;
1620
1396
  }
1621
1397
 
1622
1398
  // src/plugins/design/manifest.ts
1623
- var manifest3 = {
1399
+ var manifest2 = {
1624
1400
  mode: "design",
1625
1401
  label: "\u8BBE\u8BA1\u8D44\u4EA7",
1626
1402
  icon: "\u{1F3A8}",
@@ -1635,35 +1411,35 @@ function emptyScan() {
1635
1411
  for (const k of ASSET_KEYS) out[k] = [];
1636
1412
  return out;
1637
1413
  }
1638
- var apply5 = defineBuiltin({
1639
- manifest: manifest3,
1414
+ var apply4 = defineBuiltin({
1415
+ manifest: manifest2,
1640
1416
  setup(ctx, root) {
1641
1417
  ctx.route("/__design/assets", async () => {
1642
- const designRoot = path9.join(root, ".zdev", "design");
1643
- return fs9.existsSync(designRoot) ? scanAssets(designRoot) : emptyScan();
1418
+ const designRoot = path7.join(root, ".zdev", "design");
1419
+ return fs7.existsSync(designRoot) ? scanAssets(designRoot) : emptyScan();
1644
1420
  });
1645
1421
  ctx.route("/__design/asset", async (req, res) => {
1646
1422
  const rel = new URL(req.url || "/", "http://localhost").searchParams.get("path") ?? "";
1647
- if (!rel || rel.includes("..") || rel.includes("\\") || path9.isAbsolute(rel)) {
1423
+ if (!rel || rel.includes("..") || rel.includes("\\") || path7.isAbsolute(rel)) {
1648
1424
  res.writeHead(400);
1649
1425
  res.end("bad path");
1650
1426
  return;
1651
1427
  }
1652
- const designRoot = path9.join(root, ".zdev", "design");
1653
- const filePath = path9.join(designRoot, rel);
1654
- if (!filePath.startsWith(designRoot + path9.sep)) {
1428
+ const designRoot = path7.join(root, ".zdev", "design");
1429
+ const filePath = path7.join(designRoot, rel);
1430
+ if (!filePath.startsWith(designRoot + path7.sep)) {
1655
1431
  res.writeHead(400);
1656
1432
  res.end("bad path");
1657
1433
  return;
1658
1434
  }
1659
- fs9.stat(filePath, (err) => {
1435
+ fs7.stat(filePath, (err) => {
1660
1436
  if (err) {
1661
1437
  res.writeHead(404);
1662
1438
  return res.end("Not found");
1663
1439
  }
1664
- const ct = MIME[path9.extname(filePath).toLowerCase()] ?? "application/octet-stream";
1440
+ const ct = MIME[path7.extname(filePath).toLowerCase()] ?? "application/octet-stream";
1665
1441
  res.writeHead(200, { "Content-Type": ct, "Cache-Control": "no-cache" });
1666
- const stream = fs9.createReadStream(filePath);
1442
+ const stream = fs7.createReadStream(filePath);
1667
1443
  stream.on("error", () => {
1668
1444
  try {
1669
1445
  res.destroy();
@@ -1677,7 +1453,7 @@ var apply5 = defineBuiltin({
1677
1453
  });
1678
1454
 
1679
1455
  // src/plugins/view/manifest.ts
1680
- var manifest4 = {
1456
+ var manifest3 = {
1681
1457
  mode: "view",
1682
1458
  label: "\u9879\u76EE\u6D4F\u89C8",
1683
1459
  icon: "\u{1F441}\uFE0F",
@@ -1686,19 +1462,19 @@ var manifest4 = {
1686
1462
  };
1687
1463
 
1688
1464
  // src/plugins/view/index.ts
1689
- var apply6 = defineBuiltin({
1690
- manifest: manifest4,
1465
+ var apply5 = defineBuiltin({
1466
+ manifest: manifest3,
1691
1467
  setup() {
1692
1468
  }
1693
1469
  });
1694
1470
 
1695
1471
  // src/plugins/stats/index.ts
1696
- import fs10 from "fs";
1697
- import path10 from "path";
1472
+ import fs8 from "fs";
1473
+ import path8 from "path";
1698
1474
  import { execFile as execFile6 } from "child_process";
1699
1475
 
1700
1476
  // src/plugins/stats/manifest.ts
1701
- var manifest5 = {
1477
+ var manifest4 = {
1702
1478
  mode: "stats",
1703
1479
  label: "\u9879\u76EE\u7EDF\u8BA1",
1704
1480
  icon: "\u{1F4CA}",
@@ -1715,14 +1491,14 @@ function execFilePromise(file, args, opts) {
1715
1491
  }
1716
1492
  function scan(root) {
1717
1493
  const stats = {
1718
- root: path10.basename(root),
1494
+ root: path8.basename(root),
1719
1495
  files: 0,
1720
1496
  dirs: 0,
1721
1497
  totalSize: 0,
1722
1498
  byExt: [],
1723
1499
  markdown: 0,
1724
1500
  openspec: { active: 0, archived: 0 },
1725
- hasJust: fs10.existsSync(path10.join(root, "justfile")),
1501
+ hasJust: fs8.existsSync(path8.join(root, "justfile")),
1726
1502
  worktrees: 0
1727
1503
  };
1728
1504
  const extMap = /* @__PURE__ */ new Map();
@@ -1732,22 +1508,22 @@ function scan(root) {
1732
1508
  }, onFile: (abs) => {
1733
1509
  stats.files++;
1734
1510
  try {
1735
- stats.totalSize += fs10.statSync(abs).size;
1511
+ stats.totalSize += fs8.statSync(abs).size;
1736
1512
  } catch {
1737
1513
  }
1738
- const ext = path10.extname(abs).toLowerCase() || "(\u65E0\u6269\u5C55\u540D)";
1514
+ const ext = path8.extname(abs).toLowerCase() || "(\u65E0\u6269\u5C55\u540D)";
1739
1515
  extMap.set(ext, (extMap.get(ext) ?? 0) + 1);
1740
1516
  if (ext === ".md" || ext === ".markdown") stats.markdown++;
1741
1517
  } });
1742
1518
  };
1743
1519
  walk(root);
1744
- const changesDir = path10.join(root, "openspec", "changes");
1745
- if (fs10.existsSync(changesDir)) {
1746
- for (const ent of fs10.readdirSync(changesDir, { withFileTypes: true })) {
1520
+ const changesDir = path8.join(root, "openspec", "changes");
1521
+ if (fs8.existsSync(changesDir)) {
1522
+ for (const ent of fs8.readdirSync(changesDir, { withFileTypes: true })) {
1747
1523
  if (!ent.isDirectory() || ent.name.startsWith(".")) continue;
1748
1524
  if (ent.name === "archive") {
1749
1525
  try {
1750
- stats.openspec.archived = fs10.readdirSync(path10.join(changesDir, "archive"), { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith(".")).length;
1526
+ stats.openspec.archived = fs8.readdirSync(path8.join(changesDir, "archive"), { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith(".")).length;
1751
1527
  } catch {
1752
1528
  }
1753
1529
  } else stats.openspec.active++;
@@ -1756,8 +1532,8 @@ function scan(root) {
1756
1532
  stats.byExt = Array.from(extMap.entries()).map(([ext, count]) => ({ ext, count })).sort((a, b) => b.count - a.count).slice(0, 10);
1757
1533
  return stats;
1758
1534
  }
1759
- var apply7 = defineBuiltin({
1760
- manifest: manifest5,
1535
+ var apply6 = defineBuiltin({
1536
+ manifest: manifest4,
1761
1537
  setup(ctx, root) {
1762
1538
  ctx.route("/__stats/data", async () => {
1763
1539
  const stats = scan(root);
@@ -1783,7 +1559,7 @@ var apply7 = defineBuiltin({
1783
1559
  });
1784
1560
 
1785
1561
  // src/cli.ts
1786
- var __dirname2 = path11.dirname(fileURLToPath2(import.meta.url));
1562
+ var __dirname2 = path9.dirname(fileURLToPath2(import.meta.url));
1787
1563
  var DEFAULT_PORT = 4190;
1788
1564
  function parseArgs() {
1789
1565
  const args = process.argv.slice(2);
@@ -1833,7 +1609,7 @@ async function loadExternal(ctx, dir, root) {
1833
1609
  if (!ent.isDirectory()) continue;
1834
1610
  const candidates = tsxLoaded ? ["index.ts", "index.js", "index.mjs"] : ["index.js", "index.mjs"];
1835
1611
  for (const name of candidates) {
1836
- const p = path11.join(dir, ent.name, name);
1612
+ const p = path9.join(dir, ent.name, name);
1837
1613
  if (await pathExists(p)) {
1838
1614
  try {
1839
1615
  const mod = await import(p);
@@ -1848,8 +1624,8 @@ async function loadExternal(ctx, dir, root) {
1848
1624
  const m = ctx.dashboard.get(ent.name);
1849
1625
  if (m && m.mode === ent.name) {
1850
1626
  const patch = { external: true };
1851
- const webDir = path11.join(dir, ent.name, "web");
1852
- if (await pathExists(path11.join(webDir, "index.html"))) {
1627
+ const webDir = path9.join(dir, ent.name, "web");
1628
+ if (await pathExists(path9.join(webDir, "index.html"))) {
1853
1629
  ctx.server.static(`${PLUGIN_STATIC_PREFIX}${ent.name}/`, webDir);
1854
1630
  if (!m.viewerUrl) patch.viewerUrl = `${PLUGIN_STATIC_PREFIX}${ent.name}/`;
1855
1631
  }
@@ -1868,7 +1644,7 @@ async function loadExternal(ctx, dir, root) {
1868
1644
  }
1869
1645
  async function main() {
1870
1646
  const args = parseArgs();
1871
- const root = path11.resolve(args.dir);
1647
+ const root = path9.resolve(args.dir);
1872
1648
  const existing = await findReusable(root);
1873
1649
  if (existing && !args.restart) {
1874
1650
  const u = `http://localhost:${existing.port}` + (args.page ? `#${args.page}` : "");
@@ -1882,14 +1658,14 @@ async function main() {
1882
1658
  console.log(`[zdashboard] --restart\uFF1A\u505C\u6B62\u65E7\u5B9E\u4F8B pid=${oldRecord.pid}`);
1883
1659
  await stopInstance(oldRecord);
1884
1660
  }
1885
- const appDir = path11.resolve(__dirname2, "web");
1886
- const BUILTIN_PLUGINS = [apply7, apply3, apply4, apply5, apply6];
1661
+ const appDir = path9.resolve(__dirname2, "web");
1662
+ const BUILTIN_PLUGINS = [apply6, apply3, apply4, apply5];
1887
1663
  if (stripDeadPluginConfig(root, BUILTIN_PLUGINS.map((p) => p.manifest))) {
1888
1664
  console.log("[zdashboard] \u5DF2\u6E05\u7406 dashboard.json \u4E2D\u5185\u7F6E\u63D2\u4EF6\u7684\u8FC7\u65F6\u914D\u7F6E\u952E");
1889
1665
  }
1890
1666
  const startPort = oldRecord && !args.portExplicit ? oldRecord.port : args.port;
1891
- const zdevDir = path11.join(root, ".zdev");
1892
- const dataDir = fs11.existsSync(zdevDir) ? ".zdev/" : "";
1667
+ const zdevDir = path9.join(root, ".zdev");
1668
+ const dataDir = fs9.existsSync(zdevDir) ? ".zdev/" : "";
1893
1669
  const det = await detect(root);
1894
1670
  const ctx = new Context();
1895
1671
  ctx.plugin(ServerService, {
@@ -1906,15 +1682,15 @@ async function main() {
1906
1682
  ctx.plugin(apply, { root });
1907
1683
  ctx.plugin(apply2, { root });
1908
1684
  ctx.plugin(DashboardService);
1909
- for (const apply8 of BUILTIN_PLUGINS) {
1685
+ for (const apply7 of BUILTIN_PLUGINS) {
1910
1686
  try {
1911
- ctx.plugin(apply8, { root });
1687
+ ctx.plugin(apply7, { root });
1912
1688
  } catch (e) {
1913
1689
  console.error("[zdashboard] builtin plugin failed:", e);
1914
1690
  }
1915
1691
  }
1916
1692
  if (args.plugins) {
1917
- await loadExternal(ctx, path11.resolve(args.plugins), root);
1693
+ await loadExternal(ctx, path9.resolve(args.plugins), root);
1918
1694
  }
1919
1695
  const shutdown = () => {
1920
1696
  try {