@davidbalzan/groundwork-console 0.1.0 → 0.1.3

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 (97) hide show
  1. package/README.md +44 -0
  2. package/bin/groundwork-console.mjs +12 -3
  3. package/dist/kitresolve.js +17 -0
  4. package/dist/server.js +31 -3
  5. package/dist/skills.js +13 -5
  6. package/package.json +1 -1
  7. package/public/assets/{abnfDiagram-N423BO3Z-DPhyKd1N.js → abnfDiagram-N423BO3Z-B9qt2Lrn.js} +1 -1
  8. package/public/assets/{arc-DmkLmHHi.js → arc-Bu5e98OE.js} +1 -1
  9. package/public/assets/architecture-TIHT7OUA-Bga-lAng.js +1 -0
  10. package/public/assets/{architectureDiagram-T3A2C74G-BXFkjpze.js → architectureDiagram-T3A2C74G-C9YgdNEk.js} +1 -1
  11. package/public/assets/{blockDiagram-VBNYF7ZC-Ddhca5b4.js → blockDiagram-VBNYF7ZC-KV2ZfVrI.js} +1 -1
  12. package/public/assets/{c4Diagram-5PPSVZJV-D4M2Oz2j.js → c4Diagram-5PPSVZJV-BOIhWD29.js} +1 -1
  13. package/public/assets/channel-BdIShFYL.js +1 -0
  14. package/public/assets/{chunk-2GRJ4B5K-B2cLnEJA.js → chunk-2GRJ4B5K-BOYqDFv-.js} +1 -1
  15. package/public/assets/{chunk-4I5QYGJK-CVuqmZe1.js → chunk-4I5QYGJK-aPXqNUlF.js} +1 -1
  16. package/public/assets/{chunk-5RXB4S5H-CAj33Qry.js → chunk-5RXB4S5H-BESU8h4l.js} +1 -1
  17. package/public/assets/{chunk-6Q2QTUOP-B6kTvnZS.js → chunk-6Q2QTUOP-Dy_tviVm.js} +1 -1
  18. package/public/assets/{chunk-7Z6QIM7H-BCYMaGkK.js → chunk-7Z6QIM7H-CViytsd0.js} +1 -1
  19. package/public/assets/{chunk-GF5L2VYU-eAfQwP-A.js → chunk-GF5L2VYU-Bw_WxctK.js} +1 -1
  20. package/public/assets/{chunk-I66GZJ75-DyWmv43M.js → chunk-I66GZJ75-CyLcz-VG.js} +1 -1
  21. package/public/assets/{chunk-JQJVKLGR-xpwVLHiM.js → chunk-JQJVKLGR-BehQOyT2.js} +1 -1
  22. package/public/assets/{chunk-KBJHAD2P-BsIw_3BM.js → chunk-KBJHAD2P-Cv0WMvkU.js} +1 -1
  23. package/public/assets/{chunk-NSK5VX7P-Dy4p7ORp.js → chunk-NSK5VX7P-Duq5i1Q8.js} +1 -1
  24. package/public/assets/{chunk-QR6OTTB3-D8k2NFkq.js → chunk-QR6OTTB3-Xi-RqgB3.js} +1 -1
  25. package/public/assets/{chunk-RYQCIY6F-TbGMiTbW.js → chunk-RYQCIY6F-pkCoj5q-.js} +1 -1
  26. package/public/assets/{chunk-UBXNYLIW-By3VqDlw.js → chunk-UBXNYLIW-BRvAYX25.js} +1 -1
  27. package/public/assets/{chunk-W5SLKNZC-B6TSWP8U.js → chunk-W5SLKNZC-Bjt98ztx.js} +1 -1
  28. package/public/assets/{chunk-WRU74C26-CqCOF3fo.js → chunk-WRU74C26-a9B5o7qU.js} +1 -1
  29. package/public/assets/{chunk-XXDRQBXY-B6BeKGFV.js → chunk-XXDRQBXY-KvoTdu-7.js} +1 -1
  30. package/public/assets/classDiagram-JCYQIIEL-D2R4WmWG.js +1 -0
  31. package/public/assets/classDiagram-v2-OCEON4UE-D2R4WmWG.js +1 -0
  32. package/public/assets/{cose-bilkent-JH36ORCC-2ieLCSa1.js → cose-bilkent-JH36ORCC-N6ziZwxK.js} +1 -1
  33. package/public/assets/{cynefin-VYW2F7L2-BfajhBFb.js → cynefin-VYW2F7L2-CIULy749.js} +1 -1
  34. package/public/assets/{cynefinDiagram-MW4NZA55-DZFY7WjS.js → cynefinDiagram-MW4NZA55-Du-pmosA.js} +1 -1
  35. package/public/assets/{dagre-VZM6K2ZE-DECeuEL2.js → dagre-VZM6K2ZE-HGby89Zn.js} +1 -1
  36. package/public/assets/{diagram-7IWD3JNH-DA6fCDep.js → diagram-7IWD3JNH-B7q3-bCI.js} +1 -1
  37. package/public/assets/{diagram-B4RE2ZJO-Dj8QoIQR.js → diagram-B4RE2ZJO-YWiWiMdK.js} +1 -1
  38. package/public/assets/{diagram-LBJQPF4R-9JYAugOO.js → diagram-LBJQPF4R-BPCYGRvd.js} +1 -1
  39. package/public/assets/{diagram-Q27KOJAE-ecTfssa6.js → diagram-Q27KOJAE-B2LXUwVb.js} +1 -1
  40. package/public/assets/{diagram-UB23O5K3-DOGgwSDm.js → diagram-UB23O5K3-BNVtmpPQ.js} +1 -1
  41. package/public/assets/{dist-DTWyzWtG.js → dist-BVRuovsg.js} +1 -1
  42. package/public/assets/{ebnfDiagram-BXEA7PRR-BGmWK80p.js → ebnfDiagram-BXEA7PRR-BWXGcOBy.js} +1 -1
  43. package/public/assets/{erDiagram-JOGREHBK-CNl1QvhN.js → erDiagram-JOGREHBK-Bs7Rt9fE.js} +1 -1
  44. package/public/assets/eventmodeling-45OFAUF4-DNrXe8VH.js +1 -0
  45. package/public/assets/flowDiagram-UKHOOZJN-Bx68YkAo.js +1 -0
  46. package/public/assets/{ganttDiagram-PKOTCBZU-C01y-MjT.js → ganttDiagram-PKOTCBZU-76WOMwTJ.js} +1 -1
  47. package/public/assets/{gitGraph-TEB2WS4Q-BW4zQmf5.js → gitGraph-TEB2WS4Q-ChX3jwy9.js} +1 -1
  48. package/public/assets/{gitGraphDiagram-DS77QQ5N-CnlU6XMJ.js → gitGraphDiagram-DS77QQ5N-Df90jw60.js} +1 -1
  49. package/public/assets/{index-DrqxoBmk.js → index-Duxs51eO.js} +3 -3
  50. package/public/assets/{info-DKCQHKI2--A5cJC9V.js → info-DKCQHKI2-B4sk1tEu.js} +1 -1
  51. package/public/assets/{infoDiagram-6WML65LV-Cz2UOAMW.js → infoDiagram-6WML65LV-CwHXQy_Y.js} +1 -1
  52. package/public/assets/{ishikawaDiagram-WSZJBQD7-B4Iqm47_.js → ishikawaDiagram-WSZJBQD7-9Wx7fEa-.js} +1 -1
  53. package/public/assets/{journeyDiagram-NVQOT4AX-BU0js6EE.js → journeyDiagram-NVQOT4AX-YjyFj4j3.js} +1 -1
  54. package/public/assets/{kanban-definition-27J2QSJJ-DmeEPzz0.js → kanban-definition-27J2QSJJ-CCSVpJmG.js} +1 -1
  55. package/public/assets/{line-Dxi6NubD.js → line-BNlogVke.js} +1 -1
  56. package/public/assets/{linear-tama2Fqh.js → linear-DtHynSNJ.js} +1 -1
  57. package/public/assets/{mermaid-parser.core-bGhrBY9T.js → mermaid-parser.core-Tzw7YIHZ.js} +3 -3
  58. package/public/assets/{mermaid.core-_OoTZaAK.js → mermaid.core-BYlHVIMn.js} +4 -4
  59. package/public/assets/{mindmap-definition-FAOFIHXS-BRJt4F9_.js → mindmap-definition-FAOFIHXS-D3RdOamQ.js} +1 -1
  60. package/public/assets/{packet-7NZHBO7P-DAZsca60.js → packet-7NZHBO7P-Gg9ynt_Q.js} +1 -1
  61. package/public/assets/{pegDiagram-VL7TDLO6-2k0rcz9N.js → pegDiagram-VL7TDLO6-CF8QpCrl.js} +1 -1
  62. package/public/assets/{pie-RZYD4A2V-ojW1YX_G.js → pie-RZYD4A2V-tZaCjWV1.js} +1 -1
  63. package/public/assets/{pieDiagram-7S7Q4E2Y-CrrciDrS.js → pieDiagram-7S7Q4E2Y-q9v-b_KS.js} +1 -1
  64. package/public/assets/{quadrantDiagram-CIZ2JOQS-Dj5lMd95.js → quadrantDiagram-CIZ2JOQS-C1jEdjlT.js} +1 -1
  65. package/public/assets/{radar-I7S5WNFK-flsKqrK_.js → radar-I7S5WNFK-Dq9mh9W6.js} +1 -1
  66. package/public/assets/{railroad-3IZDKUUU-BX9H_OcC.js → railroad-3IZDKUUU-Di1R2Dd0.js} +1 -1
  67. package/public/assets/railroad-abnf-AHOZXSZD-CUlgmRQa.js +1 -0
  68. package/public/assets/railroad-ebnf-EBAXGLYW-sFLjr1iD.js +1 -0
  69. package/public/assets/railroad-peg-LSFZ7HO6-BjRYu4TF.js +1 -0
  70. package/public/assets/{railroadDiagram-AXF67PYL-BRNOv6Sh.js → railroadDiagram-AXF67PYL-LvRdE_s1.js} +1 -1
  71. package/public/assets/{requirementDiagram-LRYGKXZP-BqJbwH3b.js → requirementDiagram-LRYGKXZP-BnZ07FeK.js} +1 -1
  72. package/public/assets/{sankeyDiagram-W5VNT64P-BE7fRCAN.js → sankeyDiagram-W5VNT64P-E8-ON6IS.js} +1 -1
  73. package/public/assets/{sequenceDiagram-SI44F4Z6-Cwt-L1ko.js → sequenceDiagram-SI44F4Z6-DlVaUXz0.js} +1 -1
  74. package/public/assets/{src-Bc2f8joo.js → src-qdf2s-T4.js} +1 -1
  75. package/public/assets/{stateDiagram-OKZ733FA-etLHG0qi.js → stateDiagram-OKZ733FA-B9ThZGE5.js} +1 -1
  76. package/public/assets/stateDiagram-v2-UEYNNEHI-Bt0yXMXs.js +1 -0
  77. package/public/assets/{swimlanes-SLNWSIFB-B06NxeYI.js → swimlanes-SLNWSIFB-DtPuEFdj.js} +1 -1
  78. package/public/assets/swimlanesDiagram-ULZ7WXOC-MLUjmCjx.js +8 -0
  79. package/public/assets/{timeline-definition-Z64GVDOM-BihNR1uq.js → timeline-definition-Z64GVDOM-BR4Z5jFy.js} +1 -1
  80. package/public/assets/{treeView-QDETBFTQ-CImTfOYf.js → treeView-QDETBFTQ-BgvlYe1u.js} +1 -1
  81. package/public/assets/{treemap-6X3UGDF4-DBRjbghn.js → treemap-6X3UGDF4-BIP2RMFS.js} +1 -1
  82. package/public/assets/{vennDiagram-T6HMQDX7-HcbmXJRd.js → vennDiagram-T6HMQDX7-DA80iXM-.js} +1 -1
  83. package/public/assets/{wardley-OPB4EBWU-xY5d-6YU.js → wardley-OPB4EBWU-Dcxb0gTX.js} +1 -1
  84. package/public/assets/{wardleyDiagram-T6FBY63Y-B6KN3TYi.js → wardleyDiagram-T6FBY63Y-i2RYxGIr.js} +1 -1
  85. package/public/assets/{xychartDiagram-ELKLHX3M-AAW8Pwrl.js → xychartDiagram-ELKLHX3M-BWEBGjsc.js} +1 -1
  86. package/public/index.html +1 -1
  87. package/public/assets/architecture-TIHT7OUA-MgcjoiPc.js +0 -1
  88. package/public/assets/channel-BAs2g7Wn.js +0 -1
  89. package/public/assets/classDiagram-JCYQIIEL-D8vKmZUF.js +0 -1
  90. package/public/assets/classDiagram-v2-OCEON4UE-D8vKmZUF.js +0 -1
  91. package/public/assets/eventmodeling-45OFAUF4-GcvHanur.js +0 -1
  92. package/public/assets/flowDiagram-UKHOOZJN-DdgmWP6g.js +0 -1
  93. package/public/assets/railroad-abnf-AHOZXSZD-DD8mz__c.js +0 -1
  94. package/public/assets/railroad-ebnf-EBAXGLYW-CWer5P7V.js +0 -1
  95. package/public/assets/railroad-peg-LSFZ7HO6-DDrRJYYw.js +0 -1
  96. package/public/assets/stateDiagram-v2-UEYNNEHI-Crgtg4pC.js +0 -1
  97. package/public/assets/swimlanesDiagram-ULZ7WXOC-C8S-XAyy.js +0 -8
package/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # Groundwork Console
2
+
3
+ The cockpit for [Groundwork Kit](https://github.com/davidbalzan/groundwork-kit) fleets — the board (WORKSTREAMS/QUEUE/DONE/FACTS), the agent bus, live tmux panes, docs with change marks, roadmap actions, and ops — in one local web app. Single user, token auth, loopback by default.
4
+
5
+ ## Install & run
6
+
7
+ ```sh
8
+ npm i -g agent-coord-mcp @davidbalzan/groundwork agent-coordination # the kit (once)
9
+ npx @davidbalzan/groundwork-console # or: npm i -g … && groundwork-console (alias: gwc)
10
+ ```
11
+
12
+ First run creates `~/.groundwork-console/config.json` (add projects from Home → **Add project**) and `~/.groundwork-console/token`, prints the URL and a sign-in link, and opens the browser already signed in. Everything runs on one port (`:8790`).
13
+
14
+ ```
15
+ groundwork-console [start] [--port 8790] [--host 127.0.0.1 | --tailscale] [--no-open] [--no-auth] [--config <file>]
16
+ groundwork-console doctor # kit requires + which bins/paths were resolved
17
+ groundwork-console token # print the token
18
+ groundwork-console config # print the config path
19
+ ```
20
+
21
+ Requires on the host: Node ≥ 22, tmux (pane monitor / spawn), and either the three kit bins above on PATH or a kit checkout at `kitPath` in the config. `doctor` tells you which it found. Console requires: seam `^0.1.0` · agent-coord-mcp `^0.23.0` · groundwork `^0.3.0` · agent-coordination `^0.5.0`.
22
+
23
+ ## From another machine
24
+
25
+ `groundwork-console --tailscale` binds this machine's Tailscale IP (found via `tailscale ip -4`) instead of loopback and prints a sign-in link you can open from any device on your tailnet; the token cookie does the rest (plain http — keep it on the tailnet, or put TLS in front). Without Tailscale: `ssh -N -L 8790:127.0.0.1:8790 <host>` and open `http://localhost:8790`.
26
+
27
+ ## What it does
28
+
29
+ - **Home** — what needs you (DAVID_DECISION packets with age), fleet presence per project, roadmap strips.
30
+ - **Board** — active streams, queue, done, facts, phases with Plan / Kick off / Audit (DMs to the aide/coordinator), project doctor with Fix → agent.
31
+ - **Bus** — rooms, inbox, status stream, prefix chips, decision packets; replies mark packets answered.
32
+ - **Monitor** — live read-only tmux panes per agent, role colours, the "Now" widget (phase · streams → owners), pop-out with the phase task list.
33
+ - **Docs** — project docs and the global knowledge repo (ADRs, notes) with git change marks; edit non-seam docs in place.
34
+ - **Summon** — bottom-right avatar: DM any agent from any page with the page/doc as context, paste images.
35
+ - **Ops** — fleets (spawn / unregister / prune / decommission), skills, release, runs, events.
36
+
37
+ Writes are behind two one-click header switches (bus writes · seam & docs writes); with both off the console cannot change disk or bus. Seam files are only ever written through the seam (byte-identical round-trip); the console never types into panes — messages go through the bus and each agent's own pusher.
38
+
39
+ ## Config & env
40
+
41
+ `~/.groundwork-console/config.json`: `{ "kitPath": "~/workspace/groundwork-kit", "coordDir": "~/agent-coord", "projects": [{ "name", "path", "room" }] }`.
42
+ Env: `GROUNDWORK_CONSOLE_HOST` (bind; default `127.0.0.1` — put the token auth in front before exposing), `GROUNDWORK_CONSOLE_TOKEN`, `GROUNDWORK_CONSOLE_AUTH=off`, `GROUNDWORK_CONSOLE_CONFIG`, `GROUNDWORK_CONSOLE_RULES`, `AGENT_COORD_DIR`, `PORT`. (`KIT_CONSOLE_*` from the pre-rename days is still honoured.)
43
+
44
+ Source, issues, design notes: <https://github.com/davidbalzan/groundwork-console>. MIT.
@@ -1,8 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  /* groundwork-console — one command: starts the API + serves the built UI on one port, prints the sign-in link, opens the browser.
3
- Flags: --port 8790 · --host 127.0.0.1 · --no-open · --no-auth · --config <file>
3
+ Flags: --port 8790 · --host 127.0.0.1 · --tailscale (bind the tailnet IP, print the remote sign-in link) · --no-open · --no-auth · --config <file>
4
4
  Subcommands: token (print the token) · doctor (kit requires + paths) · config (print config path) */
5
5
  import { readFileSync, existsSync } from "node:fs";
6
+ import { execFileSync } from "node:child_process";
7
+ import os from "node:os";
6
8
  import { homedir } from "node:os";
7
9
  import path from "node:path";
8
10
  import { fileURLToPath } from "node:url";
@@ -15,7 +17,14 @@ const has = (k) => args.includes(k);
15
17
  const sub = args.find((a) => !a.startsWith("--") && !["true", "false"].includes(a) && !/^\d+$/.test(a) && !args[args.indexOf(a) - 1]?.startsWith("--"));
16
18
 
17
19
  const port = String(flag("--port", process.env.PORT ?? "8790"));
18
- const host = String(flag("--host", process.env.GROUNDWORK_CONSOLE_HOST ?? "127.0.0.1"));
20
+ /** Tailnet IPv4 of this machine: `tailscale ip -4` (CLI or the macOS app), else the first 100.64/10 interface address. */
21
+ function tailscaleIp() {
22
+ for (const bin of ["tailscale", "/Applications/Tailscale.app/Contents/MacOS/Tailscale"]) { try { const ip = execFileSync(bin, ["ip", "-4"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim().split("\n")[0]; if (/^100\./.test(ip)) return ip; } catch { /* next */ } }
23
+ for (const addrs of Object.values(os.networkInterfaces())) for (const a of addrs ?? []) if (a.family === "IPv4" && /^100\.(6[4-9]|[7-9]\d|1[01]\d|12[0-7])\./.test(a.address)) return a.address;
24
+ return null;
25
+ }
26
+ let host = String(flag("--host", process.env.GROUNDWORK_CONSOLE_HOST ?? "127.0.0.1"));
27
+ if (has("--tailscale")) { const ip = tailscaleIp(); if (!ip) { console.error("--tailscale: no tailnet address found (is Tailscale running? try `tailscale ip -4`)"); process.exit(1); } host = ip; if (!process.env.GROUNDWORK_CONSOLE_PUBLIC_API) process.env.GROUNDWORK_CONSOLE_PUBLIC_API = `http://${ip}:${port}/api`; }
19
28
  if (flag("--config")) process.env.GROUNDWORK_CONSOLE_CONFIG = String(flag("--config"));
20
29
  process.env.PORT = port; process.env.GROUNDWORK_CONSOLE_HOST = host;
21
30
  if (has("--no-auth")) process.env.GROUNDWORK_CONSOLE_AUTH = "off";
@@ -43,5 +52,5 @@ const { CONFIG_FILE } = await import("../dist/config.js");
43
52
  const base = `http://${host === "0.0.0.0" ? "localhost" : host}:${port}`;
44
53
  const token = authEnabled ? loadToken() : null;
45
54
  const url = token ? `${base}/api/auth/login?token=${encodeURIComponent(token)}&next=/` : `${base}/`;
46
- console.log(`\n groundwork-console ${pkg.version}\n UI ${base}/\n config ${CONFIG_FILE}\n token ${authEnabled ? tokenFile : "auth off"}\n sign in ${url}\n`);
55
+ console.log(`\n groundwork-console ${pkg.version}\n UI ${base}/\n config ${CONFIG_FILE}\n token ${authEnabled ? tokenFile : "auth off"}\n sign in ${url}${has("--tailscale") ? `\n remote open the sign-in link above from any device on your tailnet (token cookie, 30 d). Plain http — keep it on the tailnet.` : ""}\n`);
47
56
  if (!has("--no-open") && host !== "0.0.0.0") { try { const { default: open } = await import("open"); await open(url); } catch { /* headless: link is printed */ } }
@@ -77,3 +77,20 @@ export function requiresReport(kitPath) {
77
77
  const r = { seam: check("seam"), mcp: check("mcp"), groundwork: check("groundwork"), playbook: check("playbook") };
78
78
  return { ...r, paths: inst.paths, ok: Object.values(r).every((x) => x.ok !== false) };
79
79
  }
80
+ /** Package root dir for a kit package: the checkout's packages/<dir> if present, else the installed npm package (found from its bin). Null when neither exists. */
81
+ export function packageRoot(kitPath, which) {
82
+ const dir = { groundwork: "packages/groundwork", playbook: "packages/coord-playbook", mcp: "packages/coord-mcp" }[which];
83
+ const local = path.join(kitPath, dir);
84
+ if (existsSync(path.join(local, "package.json")))
85
+ return local;
86
+ const bin = which === "groundwork" ? groundworkCli(kitPath) : which === "playbook" ? playbookCli(kitPath) : mcpServer(kitPath);
87
+ if (!bin)
88
+ return null;
89
+ let d = path.dirname(bin);
90
+ for (let i = 0; i < 6; i++) {
91
+ if (existsSync(path.join(d, "package.json")))
92
+ return d;
93
+ d = path.dirname(d);
94
+ }
95
+ return null;
96
+ }
package/dist/server.js CHANGED
@@ -29,7 +29,7 @@ import { saveUpload, uploadPath, UPLOAD_DIR } from "./uploads.js";
29
29
  import { answered, markAnswered, isAnswered } from "./answered.js";
30
30
  import { requireAuth, login, logout, isAuthed, authEnabled, tokenFile } from "./auth.js";
31
31
  import { knowledgeIndex, knowledgeDoc, knowledgePath } from "./knowledge.js";
32
- import { requiresReport, groundworkCli, REQUIRES } from "./kitresolve.js";
32
+ import { requiresReport, groundworkCli, playbookCli, packageRoot, REQUIRES } from "./kitresolve.js";
33
33
  let cfg = loadConfig();
34
34
  const port = Number(process.env.PORT ?? 8790);
35
35
  const HERE = path.dirname(fileURLToPath(import.meta.url));
@@ -46,6 +46,7 @@ const root = new Hono();
46
46
  const app = new Hono().basePath("/api");
47
47
  app.use("*", cors({ origin: (o) => o ?? "*", credentials: true }));
48
48
  app.use("*", requireAuth());
49
+ app.onError((err, c) => { console.error(`[api] ${c.req.method} ${c.req.path}: ${err.message}`); return c.json({ error: err.message }, 500); });
49
50
  app.get("/auth/status", (c) => c.json({ enabled: authEnabled, authed: isAuthed(c) }));
50
51
  app.post("/auth/login", async (c) => { const b = (await c.req.json().catch(() => ({}))); if (!b.token || !login(c, b.token))
51
52
  return c.json({ error: "wrong token — it's in ~/.groundwork-console/token (or GROUNDWORK_CONSOLE_TOKEN)" }, 401); return c.json({ ok: true }); });
@@ -182,7 +183,8 @@ app.get("/kit", (c) => {
182
183
  app.get("/projects", (c) => {
183
184
  const sc = scopes(cfg.coordDir);
184
185
  const kitGw = (() => { try {
185
- return JSON.parse(readFileSync(path.join(cfg.kitPath, "packages/groundwork/package.json"), "utf8")).version;
186
+ const r = packageRoot(cfg.kitPath, "groundwork");
187
+ return r ? JSON.parse(readFileSync(path.join(r, "package.json"), "utf8")).version : null;
186
188
  }
187
189
  catch {
188
190
  return null;
@@ -505,6 +507,32 @@ app.get("/bus/unread", async (c) => {
505
507
  }
506
508
  });
507
509
  /* ---- CLI updates (repo / global writes) as shell Runs; playbook has native --dry-run; groundwork update reports git status after ---- */
510
+ /* groundwork init — only for repos that are NOT inited (no docs/.groundwork/VERSION); the console never re-inits. Shell Run, typed confirm. */
511
+ app.post("/actions/groundwork-init/:name", async (c) => {
512
+ const p = project(c.req.param("name"));
513
+ if (!p)
514
+ return c.json({ error: "unknown project" }, 404);
515
+ const b = (await c.req.json().catch(() => ({})));
516
+ if (b.confirm !== p.name)
517
+ return c.json({ error: "confirm must equal the project name" }, 400);
518
+ if (existsSync(path.join(p.path, "docs/.groundwork/VERSION")))
519
+ return c.json({ error: "already inited (docs/.groundwork/VERSION exists) — use update" }, 409);
520
+ const cli = groundworkCli(cfg.kitPath);
521
+ if (!cli)
522
+ return c.json({ error: "groundwork CLI not found — npm i -g @davidbalzan/groundwork" }, 500);
523
+ const argv = [cli, "init", p.path, ...(b.minimal ? ["--minimal"] : [])];
524
+ const r = await runs.exec({ kind: "shell", label: `groundwork init · ${p.name}${b.minimal ? " --minimal" : ""}`, project: p.name, sideEffects: true, args: { argv: argv.slice(1) } }, async (log) => {
525
+ log(`$ node ${argv.map((a) => a.replace(cfg.kitPath, "<kit>").replace(p.path, "<repo>")).join(" ")}`);
526
+ const out = await execP("node", argv, { timeout: 120_000, maxBuffer: 8 << 20 }).catch((e) => { log(`exit: ${e.message}`); return { stdout: e.stdout ?? "", stderr: e.stderr ?? "" }; });
527
+ for (const l of (out.stdout + out.stderr).replace(/\x1b\[[0-9;]*m/g, "").split("\n").filter(Boolean).slice(0, 120))
528
+ log(l);
529
+ const st = await execP("git", ["status", "--porcelain"], { cwd: p.path }).then((x) => x.stdout).catch(() => "");
530
+ const changed = st.split("\n").filter(Boolean);
531
+ log(`git status: ${changed.length} path(s) changed — review, then commit (the console does not commit)`);
532
+ return { changed, cli: "groundwork init", inited: existsSync(path.join(p.path, "docs/.groundwork/VERSION")) };
533
+ });
534
+ return c.json(r, r.status === "ok" ? 200 : 500);
535
+ });
508
536
  app.post("/actions/groundwork-update/:name", async (c) => {
509
537
  const p = project(c.req.param("name"));
510
538
  if (!p)
@@ -531,7 +559,7 @@ app.post("/actions/playbook-update", async (c) => {
531
559
  const dry = b.dryRun !== false;
532
560
  if (!dry && b.confirm !== "UPDATE")
533
561
  return c.json({ error: "confirm must be UPDATE to apply" }, 400);
534
- const cli = path.join(cfg.kitPath, "packages/coord-playbook/bin/install.mjs");
562
+ const cli = playbookCli(cfg.kitPath) ?? path.join(cfg.kitPath, "packages/coord-playbook/bin/install.mjs");
535
563
  const argv = [cli, "update", ...(dry ? ["--dry-run"] : [])];
536
564
  const r = await runs.exec({ kind: "shell", label: `agent-coordination update${dry ? " (dry-run)" : ""}`, sideEffects: !dry, args: { argv: argv.slice(1) } }, async (log) => {
537
565
  log(`$ node ${argv.map((a) => a.replace(cfg.kitPath, "<kit>")).join(" ")}`);
package/dist/skills.js CHANGED
@@ -3,17 +3,22 @@ import { existsSync, readFileSync, readdirSync } from "node:fs";
3
3
  import { createHash } from "node:crypto";
4
4
  import { homedir } from "node:os";
5
5
  import path from "node:path";
6
+ import { packageRoot } from "./kitresolve.js";
6
7
  const sha = (p) => (existsSync(p) ? createHash("sha1").update(readFileSync(p)).digest("hex").slice(0, 10) : null);
7
8
  const dirs = (p) => (existsSync(p) ? readdirSync(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name) : []);
8
9
  const front = (p) => { if (!existsSync(p))
9
10
  return {}; const m = readFileSync(p, "utf8").match(/^---\n([\s\S]*?)\n---/); const o = {}; m?.[1].split("\n").forEach((l) => { const i = l.indexOf(":"); if (i > 0)
10
11
  o[l.slice(0, i).trim()] = l.slice(i + 1).trim(); }); return o; };
11
12
  export function groundworkSkills(kitPath, projectPath) {
12
- const payload = path.join(kitPath, "packages/groundwork/payload/skills");
13
- const pathsMjs = path.join(kitPath, "packages/groundwork/src/lib/paths.mjs");
13
+ const root = packageRoot(kitPath, "groundwork");
14
+ const versionMarker0 = existsSync(path.join(projectPath, "docs/.groundwork/VERSION")) ? readFileSync(path.join(projectPath, "docs/.groundwork/VERSION"), "utf8").trim() : null;
15
+ if (!root)
16
+ return { versionMarker: versionMarker0, kitVersion: null, driftedVersion: false, skills: [], error: "groundwork not found — npm i -g @davidbalzan/groundwork (or set kitPath to a kit checkout)" };
17
+ const payload = path.join(root, "payload/skills");
18
+ const pathsMjs = path.join(root, "src/lib/paths.mjs");
14
19
  const minimal = existsSync(pathsMjs) ? [...(readFileSync(pathsMjs, "utf8").match(/MINIMAL_SKILLS = \[([\s\S]*?)\]/)?.[1] ?? "").matchAll(/"([^"]+)"/g)].map((m) => m[1]) : [];
15
20
  const versionMarker = existsSync(path.join(projectPath, "docs/.groundwork/VERSION")) ? readFileSync(path.join(projectPath, "docs/.groundwork/VERSION"), "utf8").trim() : null;
16
- const kitVersion = JSON.parse(readFileSync(path.join(kitPath, "packages/groundwork/package.json"), "utf8")).version;
21
+ const kitVersion = JSON.parse(readFileSync(path.join(root, "package.json"), "utf8")).version;
17
22
  return {
18
23
  versionMarker, kitVersion, driftedVersion: !!versionMarker && versionMarker !== kitVersion,
19
24
  skills: dirs(payload).map((name) => {
@@ -32,8 +37,11 @@ export function groundworkSkills(kitPath, projectPath) {
32
37
  /* Global playbook cards live in more than one harness home: Claude → ~/.claude/skills, Grok → ~/.grok/skills (+ ~/.grok/groundwork-playbook). Measure each. */
33
38
  const HARNESS_HOMES = [["claude", path.join(homedir(), ".claude/skills")], ["grok", path.join(homedir(), ".grok/skills")]];
34
39
  export function playbookCards(kitPath) {
35
- const srcRoot = path.join(kitPath, "packages/coord-playbook/skills");
36
- const kitVersion = JSON.parse(readFileSync(path.join(kitPath, "packages/coord-playbook/package.json"), "utf8")).version;
40
+ const root = packageRoot(kitPath, "playbook");
41
+ if (!root)
42
+ return { kitVersion: null, globalDir: HARNESS_HOMES[0][1], homes: [], cards: [], error: "agent-coordination not found — npm i -g agent-coordination (or set kitPath to a kit checkout)" };
43
+ const srcRoot = path.join(root, "skills");
44
+ const kitVersion = JSON.parse(readFileSync(path.join(root, "package.json"), "utf8")).version;
37
45
  const homes = HARNESS_HOMES.filter(([, d]) => existsSync(d));
38
46
  return {
39
47
  kitVersion, globalDir: HARNESS_HOMES[0][1], homes: homes.map(([h, d]) => ({ harness: h, dir: d })),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@davidbalzan/groundwork-console",
3
3
  "private": false,
4
- "version": "0.1.0",
4
+ "version": "0.1.3",
5
5
  "type": "module",
6
6
  "dependencies": {
7
7
  "@davidbalzan/groundwork-seam": "^0.1.0",
@@ -1 +1 @@
1
- import{m as e,t}from"./mermaid-parser.core-bGhrBY9T.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-Bc2f8joo.js";import"./chunk-I66GZJ75-DyWmv43M.js";import{n as i,r as a,t as o}from"./chunk-6Q2QTUOP-B6kTvnZS.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-_OoTZaAK.js";var c=e().RailroadAbnf.parser.LangiumParser,l=n(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=n(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=n(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=n(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=n(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=n(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=n(e=>{s(e,o),e.title&&o.setTitle(e.title),e.rules.map(e=>o.addRule(m(e)))},`populateDb`),g={parser:{parse:n(e=>{o.clear(),r.debug(`[ABNF Parser] Starting Langium parse`);let n=c.parse(e);if(n.lexerErrors.length>0||n.parserErrors.length>0)throw new t(n);let i=n.value;r.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),r.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:o}},db:o,renderer:a,styles:i};export{g as diagram};
1
+ import{m as e,t}from"./mermaid-parser.core-Tzw7YIHZ.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-qdf2s-T4.js";import"./chunk-I66GZJ75-CyLcz-VG.js";import{n as i,r as a,t as o}from"./chunk-6Q2QTUOP-Dy_tviVm.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-BYlHVIMn.js";var c=e().RailroadAbnf.parser.LangiumParser,l=n(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=n(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=n(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=n(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=n(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=n(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=n(e=>{s(e,o),e.title&&o.setTitle(e.title),e.rules.map(e=>o.addRule(m(e)))},`populateDb`),g={parser:{parse:n(e=>{o.clear(),r.debug(`[ABNF Parser] Starting Langium parse`);let n=c.parse(e);if(n.lexerErrors.length>0||n.parserErrors.length>0)throw new t(n);let i=n.value;r.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),r.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:o}},db:o,renderer:a,styles:i};export{g as diagram};
@@ -1 +1 @@
1
- import{n as e,t}from"./path-fybaL0A-.js";import{a as n,c as r,d as i,f as a,i as o,l as s,m as c,n as l,o as u,p as d,r as f,u as p}from"./dist-DTWyzWtG.js";function m(e){return e.innerRadius}function h(e){return e.outerRadius}function g(e){return e.startAngle}function _(e){return e.endAngle}function v(e){return e&&e.padAngle}function y(e,t,n,r,i,a,o,s){var c=n-e,l=r-t,u=o-i,d=s-a,f=d*c-u*l;if(!(f*f<1e-12))return f=(u*(t-a)-d*(e-i))/f,[e+f*c,t+f*l]}function b(e,t,n,r,i,a,o){var c=e-n,l=t-r,u=(o?a:-a)/d(c*c+l*l),f=u*l,p=-u*c,m=e+f,h=t+p,g=n+f,_=r+p,v=(m+g)/2,y=(h+_)/2,b=g-m,x=_-h,S=b*b+x*x,C=i-a,w=m*_-g*h,T=(x<0?-1:1)*d(s(0,C*C*S-w*w)),E=(w*x-b*T)/S,D=(-w*b-x*T)/S,O=(w*x+b*T)/S,k=(-w*b+x*T)/S,A=E-v,j=D-y,M=O-v,N=k-y;return A*A+j*j>M*M+N*N&&(E=O,D=k),{cx:E,cy:D,x01:-f,y01:-p,x11:E*(i/C-1),y11:D*(i/C-1)}}function x(){var s=m,x=h,S=e(0),C=null,w=g,T=_,E=v,D=null,O=t(k);function k(){var e,t,m=+s.apply(this,arguments),h=+x.apply(this,arguments),g=w.apply(this,arguments)-r,_=T.apply(this,arguments)-r,v=l(_-g),k=_>g;if(D||=e=O(),h<m&&(t=h,h=m,m=t),!(h>1e-12))D.moveTo(0,0);else if(v>c-1e-12)D.moveTo(h*u(g),h*a(g)),D.arc(0,0,h,g,_,!k),m>1e-12&&(D.moveTo(m*u(_),m*a(_)),D.arc(0,0,m,_,g,k));else{var A=g,j=_,M=g,N=_,P=v,F=v,I=E.apply(this,arguments)/2,L=I>1e-12&&(C?+C.apply(this,arguments):d(m*m+h*h)),R=p(l(h-m)/2,+S.apply(this,arguments)),z=R,B=R,V,H;if(L>1e-12){var U=o(L/m*a(I)),W=o(L/h*a(I));(P-=U*2)>1e-12?(U*=k?1:-1,M+=U,N-=U):(P=0,M=N=(g+_)/2),(F-=W*2)>1e-12?(W*=k?1:-1,A+=W,j-=W):(F=0,A=j=(g+_)/2)}var G=h*u(A),K=h*a(A),q=m*u(N),J=m*a(N);if(R>1e-12){var Y=h*u(j),X=h*a(j),Z=m*u(M),Q=m*a(M),$;if(v<i){if($=y(G,K,Z,Q,Y,X,q,J)){var ee=G-$[0],te=K-$[1],ne=Y-$[0],re=X-$[1],ie=1/a(f((ee*ne+te*re)/(d(ee*ee+te*te)*d(ne*ne+re*re)))/2),ae=d($[0]*$[0]+$[1]*$[1]);z=p(R,(m-ae)/(ie-1)),B=p(R,(h-ae)/(ie+1))}else z=B=0}}F>1e-12?B>1e-12?(V=b(Z,Q,G,K,h,B,k),H=b(Y,X,q,J,h,B,k),D.moveTo(V.cx+V.x01,V.cy+V.y01),B<R?D.arc(V.cx,V.cy,B,n(V.y01,V.x01),n(H.y01,H.x01),!k):(D.arc(V.cx,V.cy,B,n(V.y01,V.x01),n(V.y11,V.x11),!k),D.arc(0,0,h,n(V.cy+V.y11,V.cx+V.x11),n(H.cy+H.y11,H.cx+H.x11),!k),D.arc(H.cx,H.cy,B,n(H.y11,H.x11),n(H.y01,H.x01),!k))):(D.moveTo(G,K),D.arc(0,0,h,A,j,!k)):D.moveTo(G,K),!(m>1e-12)||!(P>1e-12)?D.lineTo(q,J):z>1e-12?(V=b(q,J,Y,X,m,-z,k),H=b(G,K,Z,Q,m,-z,k),D.lineTo(V.cx+V.x01,V.cy+V.y01),z<R?D.arc(V.cx,V.cy,z,n(V.y01,V.x01),n(H.y01,H.x01),!k):(D.arc(V.cx,V.cy,z,n(V.y01,V.x01),n(V.y11,V.x11),!k),D.arc(0,0,m,n(V.cy+V.y11,V.cx+V.x11),n(H.cy+H.y11,H.cx+H.x11),k),D.arc(H.cx,H.cy,z,n(H.y11,H.x11),n(H.y01,H.x01),!k))):D.arc(0,0,m,N,M,k)}if(D.closePath(),e)return D=null,e+``||null}return k.centroid=function(){var e=(+s.apply(this,arguments)+ +x.apply(this,arguments))/2,t=(+w.apply(this,arguments)+ +T.apply(this,arguments))/2-i/2;return[u(t)*e,a(t)*e]},k.innerRadius=function(t){return arguments.length?(s=typeof t==`function`?t:e(+t),k):s},k.outerRadius=function(t){return arguments.length?(x=typeof t==`function`?t:e(+t),k):x},k.cornerRadius=function(t){return arguments.length?(S=typeof t==`function`?t:e(+t),k):S},k.padRadius=function(t){return arguments.length?(C=t==null?null:typeof t==`function`?t:e(+t),k):C},k.startAngle=function(t){return arguments.length?(w=typeof t==`function`?t:e(+t),k):w},k.endAngle=function(t){return arguments.length?(T=typeof t==`function`?t:e(+t),k):T},k.padAngle=function(t){return arguments.length?(E=typeof t==`function`?t:e(+t),k):E},k.context=function(e){return arguments.length?(D=e??null,k):D},k}export{x as t};
1
+ import{n as e,t}from"./path-fybaL0A-.js";import{a as n,c as r,d as i,f as a,i as o,l as s,m as c,n as l,o as u,p as d,r as f,u as p}from"./dist-BVRuovsg.js";function m(e){return e.innerRadius}function h(e){return e.outerRadius}function g(e){return e.startAngle}function _(e){return e.endAngle}function v(e){return e&&e.padAngle}function y(e,t,n,r,i,a,o,s){var c=n-e,l=r-t,u=o-i,d=s-a,f=d*c-u*l;if(!(f*f<1e-12))return f=(u*(t-a)-d*(e-i))/f,[e+f*c,t+f*l]}function b(e,t,n,r,i,a,o){var c=e-n,l=t-r,u=(o?a:-a)/d(c*c+l*l),f=u*l,p=-u*c,m=e+f,h=t+p,g=n+f,_=r+p,v=(m+g)/2,y=(h+_)/2,b=g-m,x=_-h,S=b*b+x*x,C=i-a,w=m*_-g*h,T=(x<0?-1:1)*d(s(0,C*C*S-w*w)),E=(w*x-b*T)/S,D=(-w*b-x*T)/S,O=(w*x+b*T)/S,k=(-w*b+x*T)/S,A=E-v,j=D-y,M=O-v,N=k-y;return A*A+j*j>M*M+N*N&&(E=O,D=k),{cx:E,cy:D,x01:-f,y01:-p,x11:E*(i/C-1),y11:D*(i/C-1)}}function x(){var s=m,x=h,S=e(0),C=null,w=g,T=_,E=v,D=null,O=t(k);function k(){var e,t,m=+s.apply(this,arguments),h=+x.apply(this,arguments),g=w.apply(this,arguments)-r,_=T.apply(this,arguments)-r,v=l(_-g),k=_>g;if(D||=e=O(),h<m&&(t=h,h=m,m=t),!(h>1e-12))D.moveTo(0,0);else if(v>c-1e-12)D.moveTo(h*u(g),h*a(g)),D.arc(0,0,h,g,_,!k),m>1e-12&&(D.moveTo(m*u(_),m*a(_)),D.arc(0,0,m,_,g,k));else{var A=g,j=_,M=g,N=_,P=v,F=v,I=E.apply(this,arguments)/2,L=I>1e-12&&(C?+C.apply(this,arguments):d(m*m+h*h)),R=p(l(h-m)/2,+S.apply(this,arguments)),z=R,B=R,V,H;if(L>1e-12){var U=o(L/m*a(I)),W=o(L/h*a(I));(P-=U*2)>1e-12?(U*=k?1:-1,M+=U,N-=U):(P=0,M=N=(g+_)/2),(F-=W*2)>1e-12?(W*=k?1:-1,A+=W,j-=W):(F=0,A=j=(g+_)/2)}var G=h*u(A),K=h*a(A),q=m*u(N),J=m*a(N);if(R>1e-12){var Y=h*u(j),X=h*a(j),Z=m*u(M),Q=m*a(M),$;if(v<i){if($=y(G,K,Z,Q,Y,X,q,J)){var ee=G-$[0],te=K-$[1],ne=Y-$[0],re=X-$[1],ie=1/a(f((ee*ne+te*re)/(d(ee*ee+te*te)*d(ne*ne+re*re)))/2),ae=d($[0]*$[0]+$[1]*$[1]);z=p(R,(m-ae)/(ie-1)),B=p(R,(h-ae)/(ie+1))}else z=B=0}}F>1e-12?B>1e-12?(V=b(Z,Q,G,K,h,B,k),H=b(Y,X,q,J,h,B,k),D.moveTo(V.cx+V.x01,V.cy+V.y01),B<R?D.arc(V.cx,V.cy,B,n(V.y01,V.x01),n(H.y01,H.x01),!k):(D.arc(V.cx,V.cy,B,n(V.y01,V.x01),n(V.y11,V.x11),!k),D.arc(0,0,h,n(V.cy+V.y11,V.cx+V.x11),n(H.cy+H.y11,H.cx+H.x11),!k),D.arc(H.cx,H.cy,B,n(H.y11,H.x11),n(H.y01,H.x01),!k))):(D.moveTo(G,K),D.arc(0,0,h,A,j,!k)):D.moveTo(G,K),!(m>1e-12)||!(P>1e-12)?D.lineTo(q,J):z>1e-12?(V=b(q,J,Y,X,m,-z,k),H=b(G,K,Z,Q,m,-z,k),D.lineTo(V.cx+V.x01,V.cy+V.y01),z<R?D.arc(V.cx,V.cy,z,n(V.y01,V.x01),n(H.y01,H.x01),!k):(D.arc(V.cx,V.cy,z,n(V.y01,V.x01),n(V.y11,V.x11),!k),D.arc(0,0,m,n(V.cy+V.y11,V.cx+V.x11),n(H.cy+H.y11,H.cx+H.x11),k),D.arc(H.cx,H.cy,z,n(H.y11,H.x11),n(H.y01,H.x01),!k))):D.arc(0,0,m,N,M,k)}if(D.closePath(),e)return D=null,e+``||null}return k.centroid=function(){var e=(+s.apply(this,arguments)+ +x.apply(this,arguments))/2,t=(+w.apply(this,arguments)+ +T.apply(this,arguments))/2-i/2;return[u(t)*e,a(t)*e]},k.innerRadius=function(t){return arguments.length?(s=typeof t==`function`?t:e(+t),k):s},k.outerRadius=function(t){return arguments.length?(x=typeof t==`function`?t:e(+t),k):x},k.cornerRadius=function(t){return arguments.length?(S=typeof t==`function`?t:e(+t),k):S},k.padRadius=function(t){return arguments.length?(C=t==null?null:typeof t==`function`?t:e(+t),k):C},k.startAngle=function(t){return arguments.length?(w=typeof t==`function`?t:e(+t),k):w},k.endAngle=function(t){return arguments.length?(T=typeof t==`function`?t:e(+t),k):T},k.padAngle=function(t){return arguments.length?(E=typeof t==`function`?t:e(+t),k):E},k.context=function(e){return arguments.length?(D=e??null,k):D},k}export{x as t};
@@ -0,0 +1 @@
1
+ import"./chunk-KEIR6QF5-BICK3FdT.js";import{M as e}from"./mermaid-parser.core-Tzw7YIHZ.js";export{e as createArchitectureServices};