zdashboard 2.13.0 → 2.15.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.
Files changed (28) hide show
  1. package/dist/cli.js +45 -118
  2. package/dist/cli.js.map +1 -1
  3. package/dist/web/assets/{FileIcon-KX0Rfn5x.js → FileIcon-qMWiXCuh.js} +1 -1
  4. package/dist/web/assets/{FilterPills-D2zZaent.js → FilterPills-D4oEoDdf.js} +1 -1
  5. package/dist/web/assets/Sidebar-K85f6s_v.js +1 -0
  6. package/dist/web/assets/{Sidebar-B6Pvc7pb.js → Sidebar-UhpDd_r6.js} +1 -1
  7. package/dist/web/assets/{DiagramViewer-CQYfB79k.js → UnsupportedViewer-DW7gYl0e.js} +49 -50
  8. package/dist/web/assets/Workspace-CDIORqDn.js +2 -0
  9. package/dist/web/assets/{Workspace-5hZEbEDw.js → Workspace-CEGk753f.js} +1 -1
  10. package/dist/web/assets/{Workspace-CpV2wf10.js → Workspace-D1535fIs.js} +2 -2
  11. package/dist/web/assets/Workspace-FYtBxShi.js +1 -0
  12. package/dist/web/assets/{cynefin-OW5HDTMX-BLthHq8j.js → cynefin-OW5HDTMX-CafNfxMw.js} +2 -2
  13. package/dist/web/assets/{excalidraw-Duf4g83v.js → excalidraw-B6QTBxnj.js} +6 -6
  14. package/dist/web/assets/index-B7bsV2ku.css +1 -0
  15. package/dist/web/assets/{index-BxPRo4R9.js → index-Ipssembb.js} +9 -9
  16. package/dist/web/assets/{usePluginData-BaCM6nnK.js → usePluginData-B8y55C_P.js} +1 -1
  17. package/dist/web/assets/{web-oi27dtPg.js → web-BT48JLMA.js} +2 -2
  18. package/dist/web/assets/web-CeRdVt5Q.js +2 -0
  19. package/dist/web/assets/{web-C7ddFKgL.js → web-DKDQ9hoO.js} +2 -2
  20. package/dist/web/assets/{web-CmZk5ox_.js → web-QjEj88xq.js} +2 -2
  21. package/dist/web/index.html +2 -2
  22. package/package.json +1 -1
  23. package/dist/web/assets/Sidebar-Cg5Nabqa.js +0 -1
  24. package/dist/web/assets/Workspace-BzLI5G5q.js +0 -1
  25. package/dist/web/assets/Workspace-DbRd77b0.js +0 -1
  26. package/dist/web/assets/index-DJ7iFi2B.css +0 -1
  27. package/dist/web/assets/web-CBXj6xFf.js +0 -2
  28. /package/dist/web/assets/{DiagramViewer-BTcE7LSd.css → UnsupportedViewer-BTcE7LSd.css} +0 -0
package/dist/cli.js CHANGED
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import path9 from "path";
5
- import fs9 from "fs";
4
+ import path7 from "path";
5
+ import fs8 from "fs";
6
6
  import { fileURLToPath as fileURLToPath2 } from "url";
7
7
  import { access, readdir } from "fs/promises";
8
8
 
9
9
  // package.json
10
10
  var package_default = {
11
11
  name: "zdashboard",
12
- version: "2.13.0",
12
+ version: "2.15.0",
13
13
  description: "ZCode skill dashboard platform \u2014 pluggable viewers for zdesign/zview/zreview/zgoal",
14
14
  type: "module",
15
15
  bin: {
@@ -423,6 +423,7 @@ var ServerService = class extends Service {
423
423
  page;
424
424
  det;
425
425
  dataDir;
426
+ host;
426
427
  routes = /* @__PURE__ */ new Map();
427
428
  sses = /* @__PURE__ */ new Map();
428
429
  prefixStatic = /* @__PURE__ */ new Map();
@@ -437,6 +438,7 @@ var ServerService = class extends Service {
437
438
  this.page = config.page;
438
439
  this.det = config.detect;
439
440
  this.dataDir = config.dataDir;
441
+ this.host = config.host ?? "127.0.0.1";
440
442
  this.onListen = config.onListen;
441
443
  ctx.effect(() => () => this.dispose());
442
444
  this.refreshGitInfo();
@@ -482,13 +484,13 @@ var ServerService = class extends Service {
482
484
  });
483
485
  this.start(config.port);
484
486
  }
485
- route(path10, handler) {
486
- this.routes.set(path10, handler);
487
- this.ctx.effect(() => () => this.routes.delete(path10));
487
+ route(path8, handler) {
488
+ this.routes.set(path8, handler);
489
+ this.ctx.effect(() => () => this.routes.delete(path8));
488
490
  }
489
- sse(path10, onConnect) {
490
- this.sses.set(path10, onConnect);
491
- this.ctx.effect(() => () => this.sses.delete(path10));
491
+ sse(path8, onConnect) {
492
+ this.sses.set(path8, onConnect);
493
+ this.ctx.effect(() => () => this.sses.delete(path8));
492
494
  }
493
495
  static(prefix, dir) {
494
496
  this.prefixStatic.set(prefix, dir);
@@ -657,15 +659,17 @@ var ServerService = class extends Service {
657
659
  this.start(port + 1);
658
660
  } else throw err;
659
661
  });
660
- this.server.listen(port, "127.0.0.1", () => {
662
+ this.server.listen(port, this.host, () => {
661
663
  const addr = this.server?.address();
662
664
  const bound = typeof addr === "object" && addr ? addr.port : port;
665
+ const loopback = this.host === "127.0.0.1" || this.host === "localhost" || this.host === "::1";
663
666
  const u = `http://localhost:${bound}`;
664
667
  const target = this.page ? `${u}#${this.page}` : u;
665
668
  console.log(`[zdashboard] v${VERSION} dashboard -> ${u}`);
666
669
  console.log(`[zdashboard] project -> ${this.root}`);
667
670
  console.log(`[zdashboard] detect -> openspec:${this.det.hasOpenspec} docs:${this.det.hasDocs} just:${this.det.hasJust}`);
668
671
  if (this.dataDir) console.log(`[zdashboard] data -> ${this.dataDir}`);
672
+ if (!loopback) console.log(`[zdashboard] host -> ${this.host}(\u975E\u56DE\u73AF\u76D1\u542C:\u5C40\u57DF\u7F51/Tailscale \u53EF\u8BBF\u95EE;\u65E0\u9274\u6743,\u6CE8\u610F\u7F51\u7EDC\u8FB9\u754C)`);
669
673
  if (this.open) openUrl(target);
670
674
  this.onListen?.(bound);
671
675
  });
@@ -1361,18 +1365,18 @@ function definePlugin(def) {
1361
1365
  );
1362
1366
  return { ...defaults, ...stored };
1363
1367
  },
1364
- route(path10, handler) {
1365
- ctx.server.route(path10, respondWith(handler));
1368
+ route(path8, handler) {
1369
+ ctx.server.route(path8, respondWith(handler));
1366
1370
  },
1367
- guardedRoute(path10, handler) {
1371
+ guardedRoute(path8, handler) {
1368
1372
  const token = () => ctx.server.stopToken;
1369
- ctx.server.route(path10, (req, res) => {
1373
+ ctx.server.route(path8, (req, res) => {
1370
1374
  if (!guarded(req, res, token())) return;
1371
1375
  void respondWith(handler)(req, res);
1372
1376
  });
1373
1377
  },
1374
- sse(path10, handler) {
1375
- ctx.server.sse(path10, handler);
1378
+ sse(path8, handler) {
1379
+ ctx.server.sse(path8, handler);
1376
1380
  },
1377
1381
  static(prefix, dir) {
1378
1382
  ctx.server.static(prefix, dir);
@@ -1495,102 +1499,22 @@ var apply3 = defineBuiltin({
1495
1499
  }
1496
1500
  });
1497
1501
 
1498
- // src/plugins/design/index.ts
1499
- import path7 from "path";
1500
- import fs7 from "fs";
1501
-
1502
- // src/server/design-assets.ts
1503
- import path6 from "path";
1504
- var PAGE_EXTS = [".html", ".htm"];
1505
- var ICON_EXTS = [".svg", ".png", ".ico", ".jpg", ".jpeg", ".gif", ".webp"];
1506
- var VIDEO_EXTS = [".mp4", ".webm", ".mov", ".ogg", ".ogv"];
1507
- var AUDIO_EXTS = [".mp3", ".wav", ".flac", ".aac", ".m4a"];
1508
- var CODE_EXTS = [".js", ".mjs", ".cjs", ".mts", ".cts", ".ts", ".tsx", ".jsx", ".css", ".json", ".txt", ".xml", ".yml", ".yaml", ".sh", ".md"];
1509
- var FONT_EXTS = [".woff", ".woff2", ".ttf", ".otf"];
1510
- var TOKEN_RE = /token|theme|design|color|palette|typograph/i;
1511
- function categorize(rel, ext) {
1512
- if (rel.indexOf("components/") === 0) return "component";
1513
- if (VIDEO_EXTS.includes(ext)) return "video";
1514
- if (AUDIO_EXTS.includes(ext)) return "audio";
1515
- if (ext === ".pdf") return "pdf";
1516
- if (ext === ".md") return "md";
1517
- if (ext === ".excalidraw" || ext === ".drawio") return "diagram";
1518
- if (FONT_EXTS.includes(ext)) return "font";
1519
- if (ICON_EXTS.includes(ext)) return "icon";
1520
- if (PAGE_EXTS.includes(ext)) return "page";
1521
- if (CODE_EXTS.includes(ext)) {
1522
- if (TOKEN_RE.test(rel) && (ext === ".css" || ext === ".json")) return "token";
1523
- return null;
1524
- }
1525
- return null;
1526
- }
1527
- function scanAssets(root, subDir = "") {
1528
- const out = {};
1529
- const keys = ["page", "component", "icon", "token", "md", "video", "audio", "pdf", "font", "diagram"];
1530
- for (const k of keys) out[k] = [];
1531
- const SKIP = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", "coverage", ".next", ".cache"]);
1532
- const scanRoot = subDir ? path6.join(root, subDir) : root;
1533
- walkDir(scanRoot, { skip: SKIP, onFile: (abs, rel) => {
1534
- const ext = path6.extname(abs).toLowerCase();
1535
- const t = categorize(rel, ext);
1536
- if (t) out[t].push({ path: rel, name: path6.basename(abs), ext, type: t });
1537
- } });
1538
- return out;
1539
- }
1540
-
1541
1502
  // src/plugins/design/manifest.ts
1542
1503
  var manifest2 = {
1543
1504
  mode: "design",
1544
1505
  label: "\u8BBE\u8BA1\u8D44\u4EA7",
1545
1506
  icon: "\u{1F3A8}",
1546
- description: "\u8BBE\u8BA1\u8D44\u4EA7\u5206\u7C7B\u6D4F\u89C8 \xB7 zdesign",
1507
+ description: "\u8BBE\u8BA1\u76EE\u5F55\u6D4F\u89C8 \xB7 prototypes/design",
1547
1508
  order: 30
1548
1509
  };
1549
1510
 
1550
1511
  // src/plugins/design/index.ts
1551
- var ASSET_KEYS = ["page", "component", "icon", "token", "md", "video", "audio", "pdf", "font", "diagram"];
1552
- function emptyScan() {
1553
- const out = {};
1554
- for (const k of ASSET_KEYS) out[k] = [];
1555
- return out;
1556
- }
1512
+ var SCAN_DIRS = ["prototypes", "design"];
1557
1513
  var apply4 = defineBuiltin({
1558
1514
  manifest: manifest2,
1559
1515
  setup(ctx, root) {
1560
1516
  ctx.route("/__design/assets", async () => {
1561
- const designRoot = path7.join(root, ".zdev", "design");
1562
- return fs7.existsSync(designRoot) ? scanAssets(designRoot) : emptyScan();
1563
- });
1564
- ctx.route("/__design/asset", async (req, res) => {
1565
- const rel = new URL(req.url || "/", "http://localhost").searchParams.get("path") ?? "";
1566
- if (!rel || rel.includes("..") || rel.includes("\\") || path7.isAbsolute(rel)) {
1567
- res.writeHead(400);
1568
- res.end("bad path");
1569
- return;
1570
- }
1571
- const designRoot = path7.join(root, ".zdev", "design");
1572
- const filePath = path7.join(designRoot, rel);
1573
- if (!filePath.startsWith(designRoot + path7.sep)) {
1574
- res.writeHead(400);
1575
- res.end("bad path");
1576
- return;
1577
- }
1578
- fs7.stat(filePath, (err) => {
1579
- if (err) {
1580
- res.writeHead(404);
1581
- return res.end("Not found");
1582
- }
1583
- const ct = MIME[path7.extname(filePath).toLowerCase()] ?? "application/octet-stream";
1584
- res.writeHead(200, { "Content-Type": ct, "Cache-Control": "no-cache" });
1585
- const stream = fs7.createReadStream(filePath);
1586
- stream.on("error", () => {
1587
- try {
1588
- res.destroy();
1589
- } catch {
1590
- }
1591
- });
1592
- stream.pipe(res);
1593
- });
1517
+ return { tree: scanTree(root, [...SCAN_DIRS], { defaultExpandDepth: 2 }) };
1594
1518
  });
1595
1519
  }
1596
1520
  });
@@ -1612,8 +1536,8 @@ var apply5 = defineBuiltin({
1612
1536
  });
1613
1537
 
1614
1538
  // src/plugins/stats/index.ts
1615
- import fs8 from "fs";
1616
- import path8 from "path";
1539
+ import fs7 from "fs";
1540
+ import path6 from "path";
1617
1541
  import { execFile as execFile7 } from "child_process";
1618
1542
 
1619
1543
  // src/plugins/stats/manifest.ts
@@ -1634,14 +1558,14 @@ function execFilePromise(file, args, opts) {
1634
1558
  }
1635
1559
  function scan(root) {
1636
1560
  const stats = {
1637
- root: path8.basename(root),
1561
+ root: path6.basename(root),
1638
1562
  files: 0,
1639
1563
  dirs: 0,
1640
1564
  totalSize: 0,
1641
1565
  byExt: [],
1642
1566
  markdown: 0,
1643
1567
  openspec: { active: 0, archived: 0 },
1644
- hasJust: fs8.existsSync(path8.join(root, "justfile")),
1568
+ hasJust: fs7.existsSync(path6.join(root, "justfile")),
1645
1569
  worktrees: 0
1646
1570
  };
1647
1571
  const extMap = /* @__PURE__ */ new Map();
@@ -1651,22 +1575,22 @@ function scan(root) {
1651
1575
  }, onFile: (abs) => {
1652
1576
  stats.files++;
1653
1577
  try {
1654
- stats.totalSize += fs8.statSync(abs).size;
1578
+ stats.totalSize += fs7.statSync(abs).size;
1655
1579
  } catch {
1656
1580
  }
1657
- const ext = path8.extname(abs).toLowerCase() || "(\u65E0\u6269\u5C55\u540D)";
1581
+ const ext = path6.extname(abs).toLowerCase() || "(\u65E0\u6269\u5C55\u540D)";
1658
1582
  extMap.set(ext, (extMap.get(ext) ?? 0) + 1);
1659
1583
  if (ext === ".md" || ext === ".markdown") stats.markdown++;
1660
1584
  } });
1661
1585
  };
1662
1586
  walk(root);
1663
- const changesDir = path8.join(root, "openspec", "changes");
1664
- if (fs8.existsSync(changesDir)) {
1665
- for (const ent of fs8.readdirSync(changesDir, { withFileTypes: true })) {
1587
+ const changesDir = path6.join(root, "openspec", "changes");
1588
+ if (fs7.existsSync(changesDir)) {
1589
+ for (const ent of fs7.readdirSync(changesDir, { withFileTypes: true })) {
1666
1590
  if (!ent.isDirectory() || ent.name.startsWith(".")) continue;
1667
1591
  if (ent.name === "archive") {
1668
1592
  try {
1669
- stats.openspec.archived = fs8.readdirSync(path8.join(changesDir, "archive"), { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith(".")).length;
1593
+ stats.openspec.archived = fs7.readdirSync(path6.join(changesDir, "archive"), { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith(".")).length;
1670
1594
  } catch {
1671
1595
  }
1672
1596
  } else stats.openspec.active++;
@@ -1702,7 +1626,7 @@ var apply6 = defineBuiltin({
1702
1626
  });
1703
1627
 
1704
1628
  // src/cli.ts
1705
- var __dirname2 = path9.dirname(fileURLToPath2(import.meta.url));
1629
+ var __dirname2 = path7.dirname(fileURLToPath2(import.meta.url));
1706
1630
  var DEFAULT_PORT = 4190;
1707
1631
  function parseArgs() {
1708
1632
  const args = process.argv.slice(2);
@@ -1710,6 +1634,7 @@ function parseArgs() {
1710
1634
  options: {
1711
1635
  dir: { type: "string" },
1712
1636
  port: { type: "string" },
1637
+ host: { type: "string" },
1713
1638
  open: { type: "boolean", default: false },
1714
1639
  page: { type: "string" },
1715
1640
  restart: { type: "boolean", default: false },
@@ -1723,6 +1648,7 @@ function parseArgs() {
1723
1648
  dir: typeof values.dir === "string" ? values.dir : process.cwd(),
1724
1649
  port: typeof values.port === "string" ? Number(values.port) : DEFAULT_PORT,
1725
1650
  portExplicit: args.some((a) => a === "--port" || a.startsWith("--port=")),
1651
+ host: typeof values.host === "string" && values.host.trim() ? values.host.trim() : "127.0.0.1",
1726
1652
  open: !!values.open,
1727
1653
  page: typeof values.page === "string" ? values.page : null,
1728
1654
  restart: !!values.restart,
@@ -1752,7 +1678,7 @@ async function loadExternal(ctx, dir, root) {
1752
1678
  if (!ent.isDirectory()) continue;
1753
1679
  const candidates = tsxLoaded ? ["index.ts", "index.js", "index.mjs"] : ["index.js", "index.mjs"];
1754
1680
  for (const name of candidates) {
1755
- const p = path9.join(dir, ent.name, name);
1681
+ const p = path7.join(dir, ent.name, name);
1756
1682
  if (await pathExists(p)) {
1757
1683
  try {
1758
1684
  const mod = await import(p);
@@ -1767,8 +1693,8 @@ async function loadExternal(ctx, dir, root) {
1767
1693
  const m = ctx.dashboard.get(ent.name);
1768
1694
  if (m && m.mode === ent.name) {
1769
1695
  const patch = { external: true };
1770
- const webDir = path9.join(dir, ent.name, "web");
1771
- if (await pathExists(path9.join(webDir, "index.html"))) {
1696
+ const webDir = path7.join(dir, ent.name, "web");
1697
+ if (await pathExists(path7.join(webDir, "index.html"))) {
1772
1698
  ctx.server.static(`${PLUGIN_STATIC_PREFIX}${ent.name}/`, webDir);
1773
1699
  if (!m.viewerUrl) patch.viewerUrl = `${PLUGIN_STATIC_PREFIX}${ent.name}/`;
1774
1700
  }
@@ -1787,7 +1713,7 @@ async function loadExternal(ctx, dir, root) {
1787
1713
  }
1788
1714
  async function main() {
1789
1715
  const args = parseArgs();
1790
- const root = path9.resolve(args.dir);
1716
+ const root = path7.resolve(args.dir);
1791
1717
  const found = await findReusable(root, package_default.version);
1792
1718
  const existing = found?.record ?? null;
1793
1719
  const autoUpgrade = found?.status === "stale-version";
@@ -1809,20 +1735,21 @@ async function main() {
1809
1735
  }
1810
1736
  await stopInstance(oldRecord);
1811
1737
  }
1812
- const appDir = path9.resolve(__dirname2, "web");
1738
+ const appDir = path7.resolve(__dirname2, "web");
1813
1739
  const BUILTIN_PLUGINS = [apply6, apply3, apply4, apply5];
1814
1740
  if (stripDeadPluginConfig(root, BUILTIN_PLUGINS.map((p) => p.manifest))) {
1815
1741
  console.log("[zdashboard] \u5DF2\u6E05\u7406 dashboard.json \u4E2D\u5185\u7F6E\u63D2\u4EF6\u7684\u8FC7\u65F6\u914D\u7F6E\u952E");
1816
1742
  }
1817
1743
  const startPort = oldRecord && !args.portExplicit ? oldRecord.port : args.port;
1818
- const zdevDir = path9.join(root, ".zdev");
1819
- const dataDir = fs9.existsSync(zdevDir) ? ".zdev/" : "";
1744
+ const zdevDir = path7.join(root, ".zdev");
1745
+ const dataDir = fs8.existsSync(zdevDir) ? ".zdev/" : "";
1820
1746
  const det = await detect(root);
1821
1747
  const ctx = new Context();
1822
1748
  ctx.plugin(ServerService, {
1823
1749
  root,
1824
1750
  appDir,
1825
1751
  port: startPort,
1752
+ host: args.host,
1826
1753
  open: args.open,
1827
1754
  detect: det,
1828
1755
  page: args.page,
@@ -1841,7 +1768,7 @@ async function main() {
1841
1768
  }
1842
1769
  }
1843
1770
  if (args.plugins) {
1844
- await loadExternal(ctx, path9.resolve(args.plugins), root);
1771
+ await loadExternal(ctx, path7.resolve(args.plugins), root);
1845
1772
  }
1846
1773
  const shutdown = () => {
1847
1774
  try {