zdashboard 2.1.1 → 2.2.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.js CHANGED
@@ -162,7 +162,7 @@ import { fileURLToPath } from "url";
162
162
  // package.json
163
163
  var package_default = {
164
164
  name: "zdashboard",
165
- version: "2.1.1",
165
+ version: "2.2.0",
166
166
  description: "ZCode skill dashboard platform \u2014 pluggable viewers for zdesign/zview/zreview/zgoal",
167
167
  type: "module",
168
168
  bin: {
@@ -754,6 +754,84 @@ var apply = {
754
754
  }
755
755
  };
756
756
 
757
+ // src/core/worktrees.ts
758
+ import { execFile as execFile2 } from "child_process";
759
+ var GIT_TIMEOUT_MS = 5e3;
760
+ var ZWORKTREE_SEGMENT = ".zworktree/";
761
+ function runGit(args, cwd) {
762
+ return new Promise((resolve) => {
763
+ execFile2("git", args, { cwd, timeout: GIT_TIMEOUT_MS }, (err, stdout) => {
764
+ if (err) return resolve("");
765
+ resolve(stdout);
766
+ });
767
+ });
768
+ }
769
+ async function listWorktrees(root) {
770
+ const raw = await runGit(["worktree", "list", "--porcelain"], root);
771
+ if (!raw) return [];
772
+ const entries = [];
773
+ const lines = raw.split("\n");
774
+ let current = {};
775
+ for (const line of lines) {
776
+ const m = line.match(/^(worktree|HEAD|branch|detached)\s+(.+)$/);
777
+ if (!m) continue;
778
+ const [, key, val] = m;
779
+ if (key === "worktree") {
780
+ if (current.path && current.path.includes(ZWORKTREE_SEGMENT)) {
781
+ entries.push({
782
+ path: current.path,
783
+ name: current.path.split(ZWORKTREE_SEGMENT).pop() ?? "",
784
+ branch: current.branch ?? "",
785
+ head: current.head ?? "",
786
+ dirty: false
787
+ });
788
+ }
789
+ current = { path: val, head: "", branch: "" };
790
+ } else if (key === "HEAD") {
791
+ current.head = val;
792
+ } else if (key === "branch") {
793
+ current.branch = val.replace(/^refs\/heads\//, "");
794
+ }
795
+ }
796
+ if (current.path && current.path.includes(ZWORKTREE_SEGMENT)) {
797
+ entries.push({
798
+ path: current.path,
799
+ name: current.path.split(ZWORKTREE_SEGMENT).pop() ?? "",
800
+ branch: current.branch ?? "",
801
+ head: current.head ?? "",
802
+ dirty: false
803
+ });
804
+ }
805
+ await Promise.all(
806
+ entries.map(async (entry) => {
807
+ try {
808
+ const statusOut = await runGit(["status", "--porcelain"], entry.path);
809
+ entry.dirty = statusOut.trim().length > 0;
810
+ } catch {
811
+ entry.dirty = false;
812
+ }
813
+ })
814
+ );
815
+ return entries;
816
+ }
817
+ var apply2 = {
818
+ inject: ["server"],
819
+ apply(ctx, config) {
820
+ const server = ctx.server;
821
+ if (!server?.route) return;
822
+ server.route("/__worktrees", async (_req, res) => {
823
+ try {
824
+ const entries = await listWorktrees(config.root);
825
+ res.writeHead(200, { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-cache" });
826
+ res.end(JSON.stringify(entries));
827
+ } catch {
828
+ res.writeHead(200, { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-cache" });
829
+ res.end(JSON.stringify([]));
830
+ }
831
+ });
832
+ }
833
+ };
834
+
757
835
  // src/core/manifest.ts
758
836
  import { Service as Service3 } from "cordis";
759
837
  var DashboardService = class extends Service3 {
@@ -780,7 +858,7 @@ var DashboardService = class extends Service3 {
780
858
  };
781
859
 
782
860
  // src/server/just-runner.ts
783
- import { spawn, execFile as execFile2 } from "child_process";
861
+ import { spawn, execFile as execFile3 } from "child_process";
784
862
  var MAX_BUFFER = 1e3;
785
863
  var JustRunner = class {
786
864
  cwd;
@@ -793,7 +871,7 @@ var JustRunner = class {
793
871
  recipes() {
794
872
  if (this.recipesCache) return Promise.resolve(this.recipesCache);
795
873
  return new Promise((resolve) => {
796
- execFile2("just", ["--list", "--unsorted"], { cwd: this.cwd, maxBuffer: 1 << 20, timeout: 8e3 }, (err, stdout) => {
874
+ execFile3("just", ["--list", "--unsorted"], { cwd: this.cwd, maxBuffer: 1 << 20, timeout: 8e3 }, (err, stdout) => {
797
875
  if (err) {
798
876
  resolve([]);
799
877
  return;
@@ -919,7 +997,7 @@ var JustRunner = class {
919
997
  };
920
998
 
921
999
  // src/plugins/just/index.ts
922
- var apply2 = {
1000
+ var apply3 = {
923
1001
  inject: ["server", "dashboard"],
924
1002
  apply(ctx, config) {
925
1003
  const root = config.root;
@@ -1011,7 +1089,7 @@ async function readBody(req) {
1011
1089
  }
1012
1090
 
1013
1091
  // src/plugins/bugs/index.ts
1014
- var apply3 = {
1092
+ var apply4 = {
1015
1093
  inject: ["server", "dashboard"],
1016
1094
  apply(ctx, config) {
1017
1095
  const root = config.root;
@@ -1094,7 +1172,7 @@ var ReviewStore = class {
1094
1172
  };
1095
1173
 
1096
1174
  // src/plugins/review/index.ts
1097
- var apply4 = {
1175
+ var apply5 = {
1098
1176
  inject: ["server", "dashboard", "reload"],
1099
1177
  apply(ctx, config) {
1100
1178
  const root = config.root;
@@ -1263,54 +1341,7 @@ function readApplyChange(root, name) {
1263
1341
  }
1264
1342
 
1265
1343
  // src/plugins/apply/index.ts
1266
- import { execFile as execFile3 } from "child_process";
1267
- var GIT_TIMEOUT_MS = 5e3;
1268
- function gitWorktrees(root) {
1269
- return new Promise((resolve) => {
1270
- execFile3(
1271
- "git",
1272
- ["worktree", "list", "--porcelain"],
1273
- { cwd: root, timeout: GIT_TIMEOUT_MS },
1274
- (err, stdout) => {
1275
- if (err) return resolve([]);
1276
- const entries = [];
1277
- const lines = stdout.split("\n");
1278
- let current = {};
1279
- for (const line of lines) {
1280
- const m = line.match(/^(worktree|HEAD|branch|detached)\s+(.+)$/);
1281
- if (m) {
1282
- const [, key, val] = m;
1283
- if (key === "worktree") {
1284
- if (current.path && current.path.includes(".zworktree/")) {
1285
- entries.push({
1286
- path: current.path,
1287
- name: current.path.split("/.zworktree/").pop() ?? "",
1288
- branch: current.branch ?? "",
1289
- head: current.head ?? ""
1290
- });
1291
- }
1292
- current = { path: val, head: "", branch: "" };
1293
- } else if (key === "HEAD") {
1294
- current.head = val;
1295
- } else if (key === "branch") {
1296
- current.branch = val.replace(/^refs\/heads\//, "");
1297
- }
1298
- }
1299
- }
1300
- if (current.path && current.path.includes(".zworktree/")) {
1301
- entries.push({
1302
- path: current.path,
1303
- name: current.path.split("/.zworktree/").pop() ?? "",
1304
- branch: current.branch ?? "",
1305
- head: current.head ?? ""
1306
- });
1307
- }
1308
- resolve(entries);
1309
- }
1310
- );
1311
- });
1312
- }
1313
- var apply5 = {
1344
+ var apply6 = {
1314
1345
  inject: ["server", "dashboard"],
1315
1346
  apply(ctx, config) {
1316
1347
  const root = config.root;
@@ -1343,16 +1374,6 @@ var apply5 = {
1343
1374
  res.end(JSON.stringify({ error: e instanceof Error ? e.message : "unknown error" }));
1344
1375
  }
1345
1376
  });
1346
- ctx.server.route("/__worktrees", async (_req, res) => {
1347
- try {
1348
- const entries = await gitWorktrees(root);
1349
- res.writeHead(200, { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-cache" });
1350
- res.end(JSON.stringify(entries));
1351
- } catch {
1352
- res.writeHead(200, { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-cache" });
1353
- res.end(JSON.stringify([]));
1354
- }
1355
- });
1356
1377
  });
1357
1378
  }
1358
1379
  };
@@ -1411,7 +1432,7 @@ function scanAssets(root) {
1411
1432
  }
1412
1433
 
1413
1434
  // src/plugins/design/index.ts
1414
- var apply6 = {
1435
+ var apply7 = {
1415
1436
  inject: ["server", "dashboard"],
1416
1437
  apply(ctx, config) {
1417
1438
  const root = config.root;
@@ -1427,7 +1448,7 @@ var apply6 = {
1427
1448
  };
1428
1449
 
1429
1450
  // src/plugins/view/index.ts
1430
- var apply7 = {
1451
+ var apply8 = {
1431
1452
  inject: ["dashboard"],
1432
1453
  apply(ctx) {
1433
1454
  ctx.dashboard.register({ mode: "view", label: "\u9879\u76EE\u6D4F\u89C8", icon: "\u{1F441}\uFE0F", description: "openspec / docs / \u6587\u6863\u9884\u89C8" });
@@ -1491,7 +1512,7 @@ function scan(root) {
1491
1512
  stats.byExt = Array.from(extMap.entries()).map(([ext, count]) => ({ ext, count })).sort((a, b) => b.count - a.count).slice(0, 10);
1492
1513
  return stats;
1493
1514
  }
1494
- var apply8 = {
1515
+ var apply9 = {
1495
1516
  inject: ["server", "dashboard"],
1496
1517
  apply(ctx, config) {
1497
1518
  ctx.inject(["server", "dashboard"], () => {
@@ -1633,15 +1654,16 @@ async function main() {
1633
1654
  });
1634
1655
  ctx.plugin(ReloadService, { root });
1635
1656
  ctx.plugin(apply, { root });
1657
+ ctx.plugin(apply2, { root });
1636
1658
  ctx.plugin(DashboardService);
1637
1659
  const plugins = [
1638
- { name: "stats", apply: apply8 },
1639
- { name: "just", apply: apply2 },
1640
- { name: "bugs", apply: apply3 },
1641
- { name: "review", apply: apply4 },
1642
- { name: "apply", apply: apply5 },
1643
- { name: "design", apply: apply6 },
1644
- { name: "view", apply: apply7 }
1660
+ { name: "stats", apply: apply9 },
1661
+ { name: "just", apply: apply3 },
1662
+ { name: "bugs", apply: apply4 },
1663
+ { name: "review", apply: apply5 },
1664
+ { name: "apply", apply: apply6 },
1665
+ { name: "design", apply: apply7 },
1666
+ { name: "view", apply: apply8 }
1645
1667
  ];
1646
1668
  for (const p of plugins) {
1647
1669
  try {