@davidbalzan/groundwork-console 0.1.3 → 0.1.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 (100) hide show
  1. package/dist/answered.js +35 -2
  2. package/dist/groundwork.js +8 -3
  3. package/dist/mcp.js +12 -1
  4. package/dist/provision.js +23 -2
  5. package/dist/seam.js +4 -0
  6. package/dist/server.js +39 -7
  7. package/package.json +1 -1
  8. package/public/assets/{abnfDiagram-N423BO3Z-B9qt2Lrn.js → abnfDiagram-N423BO3Z-eACBdXEp.js} +1 -1
  9. package/public/assets/{arc-Bu5e98OE.js → arc-C8zPWxct.js} +1 -1
  10. package/public/assets/architecture-TIHT7OUA-CtVIKkxG.js +1 -0
  11. package/public/assets/{architectureDiagram-T3A2C74G-C9YgdNEk.js → architectureDiagram-T3A2C74G-BZqtGnsC.js} +1 -1
  12. package/public/assets/{blockDiagram-VBNYF7ZC-KV2ZfVrI.js → blockDiagram-VBNYF7ZC-D265Ytun.js} +1 -1
  13. package/public/assets/{c4Diagram-5PPSVZJV-BOIhWD29.js → c4Diagram-5PPSVZJV-CodzUBEt.js} +1 -1
  14. package/public/assets/channel-CpTfWcC2.js +1 -0
  15. package/public/assets/{chunk-2GRJ4B5K-BOYqDFv-.js → chunk-2GRJ4B5K-D59ECeXb.js} +1 -1
  16. package/public/assets/{chunk-4I5QYGJK-aPXqNUlF.js → chunk-4I5QYGJK-DlE6ad0r.js} +1 -1
  17. package/public/assets/{chunk-5RXB4S5H-BESU8h4l.js → chunk-5RXB4S5H-Bw4SBOdN.js} +1 -1
  18. package/public/assets/{chunk-6Q2QTUOP-Dy_tviVm.js → chunk-6Q2QTUOP-BD4S6iuB.js} +1 -1
  19. package/public/assets/{chunk-7Z6QIM7H-CViytsd0.js → chunk-7Z6QIM7H-DvwJZM4T.js} +1 -1
  20. package/public/assets/{chunk-GF5L2VYU-Bw_WxctK.js → chunk-GF5L2VYU-BlzSHpI6.js} +1 -1
  21. package/public/assets/{chunk-I66GZJ75-CyLcz-VG.js → chunk-I66GZJ75-DJurmtZ9.js} +1 -1
  22. package/public/assets/{chunk-JQJVKLGR-BehQOyT2.js → chunk-JQJVKLGR-t20LaGIq.js} +1 -1
  23. package/public/assets/{chunk-KBJHAD2P-Cv0WMvkU.js → chunk-KBJHAD2P-Dgjyd4B5.js} +1 -1
  24. package/public/assets/{chunk-NSK5VX7P-Duq5i1Q8.js → chunk-NSK5VX7P-Chchkdi8.js} +1 -1
  25. package/public/assets/{chunk-QR6OTTB3-Xi-RqgB3.js → chunk-QR6OTTB3-CJK67frw.js} +1 -1
  26. package/public/assets/{chunk-RYQCIY6F-pkCoj5q-.js → chunk-RYQCIY6F-sGSUyT6_.js} +1 -1
  27. package/public/assets/{chunk-UBXNYLIW-BRvAYX25.js → chunk-UBXNYLIW-CEzUmAZt.js} +1 -1
  28. package/public/assets/{chunk-W5SLKNZC-Bjt98ztx.js → chunk-W5SLKNZC-Spmh0y1r.js} +1 -1
  29. package/public/assets/{chunk-WRU74C26-a9B5o7qU.js → chunk-WRU74C26-DEsyhzZw.js} +1 -1
  30. package/public/assets/{chunk-XXDRQBXY-KvoTdu-7.js → chunk-XXDRQBXY-Bo1s3Uh5.js} +1 -1
  31. package/public/assets/classDiagram-JCYQIIEL-BSB0boKu.js +1 -0
  32. package/public/assets/classDiagram-v2-OCEON4UE-BSB0boKu.js +1 -0
  33. package/public/assets/{cose-bilkent-JH36ORCC-N6ziZwxK.js → cose-bilkent-JH36ORCC-15pcvj-n.js} +1 -1
  34. package/public/assets/{cynefin-VYW2F7L2-CIULy749.js → cynefin-VYW2F7L2-BZxWqC-g.js} +1 -1
  35. package/public/assets/{cynefinDiagram-MW4NZA55-Du-pmosA.js → cynefinDiagram-MW4NZA55-B_czkRTa.js} +1 -1
  36. package/public/assets/{dagre-VZM6K2ZE-HGby89Zn.js → dagre-VZM6K2ZE-D8bvaK5F.js} +1 -1
  37. package/public/assets/{diagram-7IWD3JNH-B7q3-bCI.js → diagram-7IWD3JNH-_vpWqUu0.js} +1 -1
  38. package/public/assets/{diagram-B4RE2ZJO-YWiWiMdK.js → diagram-B4RE2ZJO-DPfWeSE2.js} +1 -1
  39. package/public/assets/{diagram-LBJQPF4R-BPCYGRvd.js → diagram-LBJQPF4R-Cb7ustRg.js} +1 -1
  40. package/public/assets/{diagram-Q27KOJAE-B2LXUwVb.js → diagram-Q27KOJAE-CRIHo9aN.js} +1 -1
  41. package/public/assets/{diagram-UB23O5K3-BNVtmpPQ.js → diagram-UB23O5K3-CMyiQouk.js} +1 -1
  42. package/public/assets/{dist-BVRuovsg.js → dist-DVdstvf6.js} +1 -1
  43. package/public/assets/{ebnfDiagram-BXEA7PRR-BWXGcOBy.js → ebnfDiagram-BXEA7PRR-UURYMfYm.js} +1 -1
  44. package/public/assets/{erDiagram-JOGREHBK-Bs7Rt9fE.js → erDiagram-JOGREHBK-Dio32huH.js} +1 -1
  45. package/public/assets/eventmodeling-45OFAUF4-DP5rNNNm.js +1 -0
  46. package/public/assets/flowDiagram-UKHOOZJN-DjrqEV81.js +1 -0
  47. package/public/assets/{ganttDiagram-PKOTCBZU-76WOMwTJ.js → ganttDiagram-PKOTCBZU-62etRb4w.js} +1 -1
  48. package/public/assets/{gitGraph-TEB2WS4Q-ChX3jwy9.js → gitGraph-TEB2WS4Q-CfIUb3Fs.js} +1 -1
  49. package/public/assets/{gitGraphDiagram-DS77QQ5N-Df90jw60.js → gitGraphDiagram-DS77QQ5N-DuwZInBC.js} +1 -1
  50. package/public/assets/index-ZvSJKDLe.css +2 -0
  51. package/public/assets/{index-Duxs51eO.js → index-iKIFRUDL.js} +12 -12
  52. package/public/assets/{info-DKCQHKI2-B4sk1tEu.js → info-DKCQHKI2-BfXJHEd1.js} +1 -1
  53. package/public/assets/{infoDiagram-6WML65LV-CwHXQy_Y.js → infoDiagram-6WML65LV-Bmh_7gih.js} +1 -1
  54. package/public/assets/{ishikawaDiagram-WSZJBQD7-9Wx7fEa-.js → ishikawaDiagram-WSZJBQD7-i8-L2rAe.js} +1 -1
  55. package/public/assets/{journeyDiagram-NVQOT4AX-YjyFj4j3.js → journeyDiagram-NVQOT4AX-BtfEqljI.js} +1 -1
  56. package/public/assets/{kanban-definition-27J2QSJJ-CCSVpJmG.js → kanban-definition-27J2QSJJ-pH6QumbR.js} +1 -1
  57. package/public/assets/{line-BNlogVke.js → line-DsGf4Aam.js} +1 -1
  58. package/public/assets/{linear-DtHynSNJ.js → linear-BNSu_43k.js} +1 -1
  59. package/public/assets/{mermaid-parser.core-Tzw7YIHZ.js → mermaid-parser.core-679COn57.js} +3 -3
  60. package/public/assets/{mermaid.core-BYlHVIMn.js → mermaid.core-D_f4AlrR.js} +4 -4
  61. package/public/assets/{mindmap-definition-FAOFIHXS-D3RdOamQ.js → mindmap-definition-FAOFIHXS-D1tM4SRn.js} +1 -1
  62. package/public/assets/{packet-7NZHBO7P-Gg9ynt_Q.js → packet-7NZHBO7P-olELdMgx.js} +1 -1
  63. package/public/assets/{pegDiagram-VL7TDLO6-CF8QpCrl.js → pegDiagram-VL7TDLO6-DgAndH0A.js} +1 -1
  64. package/public/assets/{pie-RZYD4A2V-tZaCjWV1.js → pie-RZYD4A2V-DWj8tY38.js} +1 -1
  65. package/public/assets/{pieDiagram-7S7Q4E2Y-q9v-b_KS.js → pieDiagram-7S7Q4E2Y-DK7c2EvE.js} +1 -1
  66. package/public/assets/{quadrantDiagram-CIZ2JOQS-C1jEdjlT.js → quadrantDiagram-CIZ2JOQS-DI-ZbPxK.js} +1 -1
  67. package/public/assets/{radar-I7S5WNFK-Dq9mh9W6.js → radar-I7S5WNFK-DLsdeAbl.js} +1 -1
  68. package/public/assets/{railroad-3IZDKUUU-Di1R2Dd0.js → railroad-3IZDKUUU-BFUnqJxV.js} +1 -1
  69. package/public/assets/railroad-abnf-AHOZXSZD-B00TU1b8.js +1 -0
  70. package/public/assets/railroad-ebnf-EBAXGLYW-RrXgWJqj.js +1 -0
  71. package/public/assets/railroad-peg-LSFZ7HO6-CsiNSgst.js +1 -0
  72. package/public/assets/{railroadDiagram-AXF67PYL-LvRdE_s1.js → railroadDiagram-AXF67PYL-BcCf-qnq.js} +1 -1
  73. package/public/assets/{requirementDiagram-LRYGKXZP-BnZ07FeK.js → requirementDiagram-LRYGKXZP-CSERzrsB.js} +1 -1
  74. package/public/assets/{sankeyDiagram-W5VNT64P-E8-ON6IS.js → sankeyDiagram-W5VNT64P-BTHdyTAB.js} +1 -1
  75. package/public/assets/{sequenceDiagram-SI44F4Z6-DlVaUXz0.js → sequenceDiagram-SI44F4Z6-DCMbcZQ-.js} +1 -1
  76. package/public/assets/{src-qdf2s-T4.js → src-CWXJqyrc.js} +1 -1
  77. package/public/assets/{stateDiagram-OKZ733FA-B9ThZGE5.js → stateDiagram-OKZ733FA-BhzI_RZ_.js} +1 -1
  78. package/public/assets/stateDiagram-v2-UEYNNEHI-DKG0b0eo.js +1 -0
  79. package/public/assets/{swimlanes-SLNWSIFB-DtPuEFdj.js → swimlanes-SLNWSIFB-DPKSeErn.js} +1 -1
  80. package/public/assets/swimlanesDiagram-ULZ7WXOC-D6CPDB9k.js +8 -0
  81. package/public/assets/{timeline-definition-Z64GVDOM-BR4Z5jFy.js → timeline-definition-Z64GVDOM-BnLvIO3-.js} +1 -1
  82. package/public/assets/{treeView-QDETBFTQ-BgvlYe1u.js → treeView-QDETBFTQ-BgFXBEUi.js} +1 -1
  83. package/public/assets/{treemap-6X3UGDF4-BIP2RMFS.js → treemap-6X3UGDF4-KzlTv1ih.js} +1 -1
  84. package/public/assets/{vennDiagram-T6HMQDX7-DA80iXM-.js → vennDiagram-T6HMQDX7-gsHmzjh9.js} +1 -1
  85. package/public/assets/{wardley-OPB4EBWU-Dcxb0gTX.js → wardley-OPB4EBWU-DyQkbq8g.js} +1 -1
  86. package/public/assets/{wardleyDiagram-T6FBY63Y-i2RYxGIr.js → wardleyDiagram-T6FBY63Y-DqwaVwnv.js} +1 -1
  87. package/public/assets/{xychartDiagram-ELKLHX3M-BWEBGjsc.js → xychartDiagram-ELKLHX3M-DGZxfApD.js} +1 -1
  88. package/public/index.html +2 -2
  89. package/public/assets/architecture-TIHT7OUA-Bga-lAng.js +0 -1
  90. package/public/assets/channel-BdIShFYL.js +0 -1
  91. package/public/assets/classDiagram-JCYQIIEL-D2R4WmWG.js +0 -1
  92. package/public/assets/classDiagram-v2-OCEON4UE-D2R4WmWG.js +0 -1
  93. package/public/assets/eventmodeling-45OFAUF4-DNrXe8VH.js +0 -1
  94. package/public/assets/flowDiagram-UKHOOZJN-Bx68YkAo.js +0 -1
  95. package/public/assets/index-C3zhnM_H.css +0 -2
  96. package/public/assets/railroad-abnf-AHOZXSZD-CUlgmRQa.js +0 -1
  97. package/public/assets/railroad-ebnf-EBAXGLYW-sFLjr1iD.js +0 -1
  98. package/public/assets/railroad-peg-LSFZ7HO6-BjRYu4TF.js +0 -1
  99. package/public/assets/stateDiagram-v2-UEYNNEHI-Bt0yXMXs.js +0 -1
  100. package/public/assets/swimlanesDiagram-ULZ7WXOC-MLUjmCjx.js +0 -8
package/dist/answered.js CHANGED
@@ -1,4 +1,4 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
1
+ import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
2
2
  import { homedir } from "node:os";
3
3
  import path from "node:path";
4
4
  /* Console-owned "answered" set for DAVID_DECISION packets (room posts + DMs), keyed by message id.
@@ -31,4 +31,37 @@ export function markAnswered(ids, meta) {
31
31
  }
32
32
  return n;
33
33
  }
34
- export const isAnswered = (id) => typeof id === "string" && !!answered()[id];
34
+ /* Bus-native answered set (kit ≥ 18ffbf4): any message FROM david carrying inReplyTo:<id> answers <id>. Scanned from ~/agent-coord inbox/*.jsonl + rooms/*.jsonl, cached 10 s. Unioned with the console-owned set above. */
35
+ let busCache = null;
36
+ let coordRoot = null;
37
+ export function setCoordDir(dir) { coordRoot = dir; }
38
+ function busAnswered() {
39
+ if (!coordRoot)
40
+ return new Set();
41
+ if (busCache && Date.now() - busCache.at < 10_000)
42
+ return busCache.ids;
43
+ const ids = new Set();
44
+ for (const sub of ["inbox", "rooms"]) {
45
+ const dir = path.join(coordRoot, sub);
46
+ if (!existsSync(dir))
47
+ continue;
48
+ for (const f of readdirSync(dir).filter((n) => n.endsWith(".jsonl"))) {
49
+ try {
50
+ for (const l of readFileSync(path.join(dir, f), "utf8").split("\n")) {
51
+ if (!l.includes("inReplyTo"))
52
+ continue;
53
+ try {
54
+ const m = JSON.parse(l);
55
+ if (m.from === "david" && typeof m.inReplyTo === "string")
56
+ ids.add(m.inReplyTo);
57
+ }
58
+ catch { /* skip */ }
59
+ }
60
+ }
61
+ catch { /* skip */ }
62
+ }
63
+ }
64
+ busCache = { at: Date.now(), ids };
65
+ return ids;
66
+ }
67
+ export const isAnswered = (id) => typeof id === "string" && (!!answered()[id] || busAnswered().has(id));
@@ -1,6 +1,5 @@
1
1
  /* Groundwork + playbook CLIs, JSON mode (shipped by grok 2026-08-16). Cached briefly; both are read-only commands. */
2
2
  import { execFile } from "node:child_process";
3
- import path from "node:path";
4
3
  import { promisify } from "node:util";
5
4
  const run = promisify(execFile);
6
5
  const cache = new Map();
@@ -9,6 +8,11 @@ async function json(key, ttl, argv, fallback) {
9
8
  if (hit && Date.now() - hit.at < ttl)
10
9
  return hit.value;
11
10
  let value;
11
+ if (argv[0] === MISSING) {
12
+ value = { ...fallback, ranAt: Date.now(), error: `${key.startsWith("pb") ? "agent-coordination" : "groundwork"} CLI not found — npm i -g (or set kitPath to a kit checkout)` };
13
+ cache.set(key, { at: Date.now(), value });
14
+ return value;
15
+ }
12
16
  try {
13
17
  const r = await run("node", argv, { timeout: 20_000, maxBuffer: 4 << 20 });
14
18
  value = { ...JSON.parse(r.stdout), ranAt: Date.now() };
@@ -26,8 +30,9 @@ async function json(key, ttl, argv, fallback) {
26
30
  return value;
27
31
  }
28
32
  import { groundworkCli, playbookCli } from "./kitresolve.js";
29
- const gw = (kit) => groundworkCli(kit) ?? path.join(kit, "packages/groundwork/src/cli.mjs");
30
- const pb = (kit) => playbookCli(kit) ?? path.join(kit, "packages/coord-playbook/bin/install.mjs");
33
+ const MISSING = "/dev/null/missing-cli"; // resolver found nothing → the run fails fast with a clear message below instead of a fake kit path
34
+ const gw = (kit) => groundworkCli(kit) ?? MISSING;
35
+ const pb = (kit) => playbookCli(kit) ?? MISSING;
31
36
  export const doctor = (kit, proj) => json(`doctor:${proj}`, 30_000, [gw(kit), "doctor", proj, "--json"], { ok: false, exit: 1, checks: [], ranAt: 0 });
32
37
  export const status = (kit, proj) => json(`status:${proj}`, 15_000, [gw(kit), "status", proj, "--json"], { streams: [], next: null, queueFound: false, phases: [], ranAt: 0 });
33
38
  export const list = (kit, proj) => json(`list:${proj}`, 60_000, [gw(kit), "list", proj, "--json"], { version: "", project: proj, skills: [], ranAt: 0 });
package/dist/mcp.js CHANGED
@@ -54,7 +54,8 @@ export class BusClient {
54
54
  this.identity = identity;
55
55
  this.mcpPath = mcpPath;
56
56
  }
57
- get serverPath() { return this.mcpPath ?? mcpServer(this.kitPath) ?? path.join(this.kitPath, "packages/coord-mcp/dist/server.js"); }
57
+ get serverPath() { const p = this.mcpPath ?? mcpServer(this.kitPath); if (!p)
58
+ throw new Error("agent-coord-mcp not found — npm i -g agent-coord-mcp (or set kitPath to a kit checkout)"); return p; }
58
59
  get agentId() { return IDENTITIES[this.identity].agentId; }
59
60
  async connect(log) {
60
61
  if (this.client)
@@ -72,6 +73,13 @@ export class BusClient {
72
73
  await client.connect(transport);
73
74
  const reg = await client.callTool({ name: "register", arguments: { agentId: id.agentId, project: id.project, role: id.role, force: true } });
74
75
  log?.(`register → ${JSON.stringify(reg.structuredContent ?? textOf(reg)).slice(0, 160)}`);
76
+ // Feature detection: which args each tool accepts (e.g. send_message.inReplyTo landed in kit 18ffbf4; the live bin may predate it).
77
+ try {
78
+ const tools = await client.listTools();
79
+ for (const t of tools.tools)
80
+ this.toolArgs.set(t.name, new Set(Object.keys(t.inputSchema?.properties ?? {})));
81
+ }
82
+ catch { /* older server: no detection, pass nothing extra */ }
75
83
  this.client = client;
76
84
  return client;
77
85
  })();
@@ -82,6 +90,9 @@ export class BusClient {
82
90
  this.connecting = null;
83
91
  }
84
92
  }
93
+ toolArgs = new Map();
94
+ /** True when the connected server's tool schema lists this argument (false when unknown or not connected yet). */
95
+ supports(tool, arg) { return this.toolArgs.get(tool)?.has(arg) ?? false; }
85
96
  async call(name, args, log) {
86
97
  const isWrite = WRITE_TOOLS_GATED.has(name);
87
98
  if (!READ_ONLY_TOOLS.has(name) && !isWrite)
package/dist/provision.js CHANGED
@@ -25,7 +25,7 @@ async function fleetWindow(project, startDir, log) {
25
25
  log(`created window ${win} in session ${session} (first pane ${pane} reused for the first agent — no spare shell)`);
26
26
  return { target: `${session}:${win}`, freshPane: pane };
27
27
  }
28
- export async function spawnAgent(req, isRegistered, log, isAttached = () => true) {
28
+ export async function spawnAgent(req, isRegistered, log, isAttached = () => true, roleOf = () => null) {
29
29
  if (!/^[a-z0-9][a-z0-9-_]*$/i.test(req.agentId))
30
30
  throw new Error("agentId: letters, digits, - _");
31
31
  if (isRegistered(req.agentId))
@@ -91,7 +91,28 @@ export async function spawnAgent(req, isRegistered, log, isAttached = () => true
91
91
  }
92
92
  log(attached ? `✓ ${req.agentId} attached (tmux-push) — DMs will land in ${paneId}` : `✗ ${req.agentId} still not attached — DMs will sit in its inbox until it attaches (Fleets shows "not attached")`);
93
93
  }
94
- return { agentId: req.agentId, pane: paneId, window: target, registered, attached };
94
+ // Role: every spawned agent must carry its role type on the bus (presence bar, fleet graph, Fix→role routing all key on it). If it registered without one, tell it — into its own pane — and re-check.
95
+ const ROLE_RE = { coordinator: /coordinator/i, worker: /worker|repo-owner|consumer-owner|reference|infra|ops|lane/i, qa: /\bqa\b|quality/i, ci: /\bci\b/i, aide: /aide|liaison|curator/i, audit: /audit/i };
96
+ let roleOk = false;
97
+ if (registered) {
98
+ roleOk = ROLE_RE[req.role].test(roleOf(req.agentId) ?? "");
99
+ if (!roleOk) {
100
+ log(`⚠ registered without a ${req.role} role (role="${roleOf(req.agentId) ?? ""}") — asking it to declare one`);
101
+ await inject(`Declare your role on the coord bus now: call register (or join) again with agentId ${req.agentId} and role: { roleId: "coord-${req.role === "coordinator" ? "coordinator" : req.role}", displayName: "${req.role}" } — the console, fleet graph and Fix→role routing rely on it.`);
102
+ const d4 = Date.now() + 45_000;
103
+ while (Date.now() < d4) {
104
+ if (ROLE_RE[req.role].test(roleOf(req.agentId) ?? "")) {
105
+ roleOk = true;
106
+ break;
107
+ }
108
+ await sleep(2_000);
109
+ }
110
+ log(roleOk ? `✓ role declared: ${roleOf(req.agentId)}` : `✗ still no ${req.role} role — Fleets will show it as "—"; DM it to fix`);
111
+ }
112
+ else
113
+ log(`✓ role: ${roleOf(req.agentId)}`);
114
+ }
115
+ return { agentId: req.agentId, pane: paneId, window: target, registered, attached, roleOk };
95
116
  }
96
117
  export function suggestId(project, role, existing) {
97
118
  const base = `${project}-${role}`;
package/dist/seam.js CHANGED
@@ -18,8 +18,12 @@ export function boardOf(projectPath) {
18
18
  const dDoc = d ? parseWorkDoc(d) : null;
19
19
  const facts = f ? parseFactsDoc(f) : null;
20
20
  const now = Date.now();
21
+ // Onboarding state for the Roadmap empty state: is there a PRD, and what does its Status line say?
22
+ const prdSrc = read(path.join(docs, "PRD.md"));
23
+ const prd = prdSrc === null ? null : { status: prdSrc.match(/^\*\*Status\*\*:\s*([^\n]+)/m)?.[1]?.trim() ?? null, roadmap: existsSync(path.join(docs, "PRODUCTION_ROADMAP.md")) };
21
24
  return {
22
25
  files: { workstreams: !!ws, queue: !!q, done: !!d, facts: !!f },
26
+ prd,
23
27
  workstreams: { schema: schema ?? (ws ? "unknown" : null), rows: board, issues: wsDoc ? workDocIssues(wsDoc) : [] },
24
28
  queue: qDoc ? queueItemsOf(qDoc) : [],
25
29
  done: dDoc ? doneEntriesOf(dDoc) : [],
package/dist/server.js CHANGED
@@ -8,6 +8,7 @@ import { serve } from "@hono/node-server";
8
8
  import { serveStatic } from "@hono/node-server/serve-static";
9
9
  import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
10
10
  import path from "node:path";
11
+ import { hostname as osHostname } from "node:os";
11
12
  import { loadConfig, saveProjects, validateProjectPath, CONFIG_FILE } from "./config.js";
12
13
  import { boardOf, docOf, docsIndex, phaseTasksOf } from "./seam.js";
13
14
  import { DocWriteError, sha256, writeDoc } from "./docwrite.js";
@@ -26,7 +27,7 @@ import { BusClient, AGENT_ID, busWrites, seamWrites, saveSwitches, SWITCHES_FILE
26
27
  import { addQueueItem, reverifyFact, scopeAllows } from "./seamwrite.js";
27
28
  import { fileURLToPath } from "node:url";
28
29
  import { saveUpload, uploadPath, UPLOAD_DIR } from "./uploads.js";
29
- import { answered, markAnswered, isAnswered } from "./answered.js";
30
+ import { answered, markAnswered, isAnswered, setCoordDir } from "./answered.js";
30
31
  import { requireAuth, login, logout, isAuthed, authEnabled, tokenFile } from "./auth.js";
31
32
  import { knowledgeIndex, knowledgeDoc, knowledgePath } from "./knowledge.js";
32
33
  import { requiresReport, groundworkCli, playbookCli, packageRoot, REQUIRES } from "./kitresolve.js";
@@ -36,6 +37,7 @@ const HERE = path.dirname(fileURLToPath(import.meta.url));
36
37
  const RULES = process.env.GROUNDWORK_CONSOLE_RULES ?? [path.join(process.env.HOME ?? "", ".groundwork-console", "rules.json"), path.resolve(HERE, "../groundwork-console.rules.json"), path.resolve(HERE, "../../../groundwork-console.rules.json")].find((f) => existsSync(f)) ?? path.resolve(HERE, "../../../groundwork-console.rules.json");
37
38
  const PKG = JSON.parse(readFileSync(path.resolve(HERE, "../package.json"), "utf8"));
38
39
  const runs = new Runs();
40
+ setCoordDir(cfg.coordDir);
39
41
  const bus = new BusClient(cfg.kitPath, cfg.coordDir, "groundwork-console", process.env.AGENT_COORD_MCP);
40
42
  const events = new EventEngine(cfg, RULES, runs, (args, log) => bus.call("send_message", args, log));
41
43
  const notifier = new Notifier(cfg, runs, events);
@@ -55,7 +57,7 @@ app.post("/auth/logout", (c) => { logout(c); return c.json({ ok: true }); });
55
57
  app.get("/auth/login", (c) => { const t = c.req.query("token") ?? ""; if (!login(c, t))
56
58
  return c.json({ error: "wrong token" }, 401); return c.redirect(c.req.query("next") ?? "/"); });
57
59
  const project = (name) => cfg.projects.find((p) => p.name === name);
58
- app.get("/health", (c) => c.json({ ok: true, readOnly: !busWrites.enabled, busWrites: busWrites.enabled, version: PKG.version, requires: requiresReport(cfg.kitPath), config: CONFIG_FILE }));
60
+ app.get("/health", (c) => c.json({ ok: true, readOnly: !busWrites.enabled, busWrites: busWrites.enabled, version: PKG.version, requires: requiresReport(cfg.kitPath), config: CONFIG_FILE, hostname: osHostname().replace(/\.local$/, "") }));
59
61
  app.get("/admin/bus-writes", (c) => c.json(busWrites));
60
62
  app.get("/admin/seam-writes", (c) => c.json(seamWrites));
61
63
  app.post("/admin/seam-writes", async (c) => {
@@ -112,7 +114,13 @@ app.post("/actions/send", async (c) => {
112
114
  return c.json({ error: "room posts need a prefix (FYI / AGENT_ACTION / DAVID_DECISION / BLOCKER / RISK / DONE / GO / SCOPE CHANGE / VERDICT)" }, 400);
113
115
  const target = b.to ? `→ ${b.to}` : `#${b.room.replace(/^#/, "")}`;
114
116
  const r = await runs.exec({ kind: "bus", label: `send as ${who} ${target}`, sideEffects: true, args: { as: who, room: b.room, to: b.to, kind: b.kind, text: b.text.slice(0, 200) } }, async (log) => {
115
- const out = await clientFor(who).call("send_message", { ...(b.to ? { to: b.to } : { room: b.room.replace(/^#/, "") }), text: b.text, ...(b.kind ? { kind: b.kind } : {}) }, log);
117
+ const cl = clientFor(who);
118
+ await cl.connect(log);
119
+ const parent = b.inReplyTo ?? b.answers?.[0];
120
+ const withReply = parent && cl.supports("send_message", "inReplyTo") ? { inReplyTo: parent } : {};
121
+ if (parent && !("inReplyTo" in withReply))
122
+ log("bus predates inReplyTo — using the console-side answered set only");
123
+ const out = await cl.call("send_message", { ...(b.to ? { to: b.to } : { room: b.room.replace(/^#/, "") }), text: b.text, ...(b.kind ? { kind: b.kind } : {}), ...withReply }, log);
116
124
  // Answered bookkeeping (console-owned, until the bus has inReplyTo): explicit ids from the UI, plus — for a DM as David — every open DAVID_DECISION DM from that agent.
117
125
  if (who === "david") {
118
126
  const ids = [...(b.answers ?? [])];
@@ -540,7 +548,9 @@ app.post("/actions/groundwork-update/:name", async (c) => {
540
548
  const b = (await c.req.json().catch(() => ({})));
541
549
  if (b.confirm !== p.name)
542
550
  return c.json({ error: "confirm must equal the project name" }, 400);
543
- const cli = groundworkCli(cfg.kitPath) ?? path.join(cfg.kitPath, "packages/groundwork/src/cli.mjs");
551
+ const cli = groundworkCli(cfg.kitPath);
552
+ if (!cli)
553
+ return c.json({ error: "groundwork CLI not found — npm i -g @davidbalzan/groundwork (or set kitPath to a kit checkout)" }, 500);
544
554
  const argv = [cli, "update", p.path, ...(b.all ? ["--all"] : []), ...(b.docs ? ["--docs"] : [])];
545
555
  const r = await runs.exec({ kind: "shell", label: `groundwork update · ${p.name}${b.all ? " --all" : ""}${b.docs ? " --docs" : ""}`, project: p.name, sideEffects: true, args: { argv: argv.slice(1) } }, async (log) => {
546
556
  log(`$ node ${argv.map((a) => a.replace(cfg.kitPath, "<kit>").replace(p.path, "<repo>")).join(" ")}`);
@@ -559,7 +569,9 @@ app.post("/actions/playbook-update", async (c) => {
559
569
  const dry = b.dryRun !== false;
560
570
  if (!dry && b.confirm !== "UPDATE")
561
571
  return c.json({ error: "confirm must be UPDATE to apply" }, 400);
562
- const cli = playbookCli(cfg.kitPath) ?? path.join(cfg.kitPath, "packages/coord-playbook/bin/install.mjs");
572
+ const cli = playbookCli(cfg.kitPath);
573
+ if (!cli)
574
+ return c.json({ error: "agent-coordination CLI not found — npm i -g agent-coordination (or set kitPath to a kit checkout)" }, 500);
563
575
  const argv = [cli, "update", ...(dry ? ["--dry-run"] : [])];
564
576
  const r = await runs.exec({ kind: "shell", label: `agent-coordination update${dry ? " (dry-run)" : ""}`, sideEffects: !dry, args: { argv: argv.slice(1) } }, async (log) => {
565
577
  log(`$ node ${argv.map((a) => a.replace(cfg.kitPath, "<kit>")).join(" ")}`);
@@ -579,6 +591,7 @@ app.get("/projects/:name/fleet", async (c) => {
579
591
  const live = (await agentsAsync(cfg.coordDir)).filter((a) => a.liveness !== "dead" && (a.project === p.room || a.project === p.name));
580
592
  return c.json({ ...fleetStatus(live), templates: FLEET_TEMPLATES, window: `fleet-${p.name}` });
581
593
  });
594
+ const roleOfAgent = (id) => agents(cfg.coordDir).find((a) => a.agentId === id)?.role ?? null;
582
595
  app.post("/actions/spawn-fleet", async (c) => {
583
596
  if (!busWrites.enabled)
584
597
  return c.json({ error: "bus writes are off (header toggle)" }, 403);
@@ -600,7 +613,7 @@ app.post("/actions/spawn-fleet", async (c) => {
600
613
  for (const step of plan) {
601
614
  const agentId = suggestId(p.name, step.role, [...ids(), ...out.map((o) => o.agentId)]);
602
615
  log(`── ${step.role} → ${agentId} (${step.harness})`);
603
- const res = await spawnAgent({ project: p.name, repoPath: p.path, room: p.room, role: step.role, harness: step.harness, agentId, lane: step.lane, waitSeconds: b.waitSeconds }, (id) => ids().includes(id), log, attached);
616
+ const res = await spawnAgent({ project: p.name, repoPath: p.path, room: p.room, role: step.role, harness: step.harness, agentId, lane: step.lane, waitSeconds: b.waitSeconds }, (id) => ids().includes(id), log, attached, roleOfAgent);
604
617
  out.push({ agentId: res.agentId, pane: res.pane, registered: res.registered, attached: res.attached });
605
618
  }
606
619
  log(`fleet ${t.id}: ${out.filter((o) => o.registered).length}/${out.length} registered · ${out.filter((o) => o.attached).length}/${out.length} attached`);
@@ -625,7 +638,7 @@ app.post("/actions/spawn", async (c) => {
625
638
  const ids = () => agents(cfg.coordDir).map((a) => a.agentId);
626
639
  const attached = (id) => existsSync(path.join(cfg.coordDir, "transports", `${id}.json`));
627
640
  const agentId = b.agentId?.trim() || suggestId(p.name, b.role, ids());
628
- const r = runs.execAsync({ kind: "shell", label: `spawn ${agentId} (${b.role} · ${b.harness}) → fleet-${p.name}`, project: p.name, sideEffects: true, args: { role: b.role, harness: b.harness, agentId, lane: b.lane, model: b.model } }, (log) => spawnAgent({ project: p.name, repoPath: p.path, room: p.room, role: b.role, harness: b.harness, agentId, lane: b.lane, model: b.model, note: b.note, waitSeconds: b.waitSeconds }, (id) => ids().includes(id), log, attached));
641
+ const r = runs.execAsync({ kind: "shell", label: `spawn ${agentId} (${b.role} · ${b.harness}) → fleet-${p.name}`, project: p.name, sideEffects: true, args: { role: b.role, harness: b.harness, agentId, lane: b.lane, model: b.model } }, (log) => spawnAgent({ project: p.name, repoPath: p.path, room: p.room, role: b.role, harness: b.harness, agentId, lane: b.lane, model: b.model, note: b.note, waitSeconds: b.waitSeconds }, (id) => ids().includes(id), log, attached, roleOfAgent));
629
642
  return c.json(r);
630
643
  });
631
644
  /* ---- Gated bus admin: prune stale, unregister one (writes; require switch + confirm) ---- */
@@ -690,6 +703,25 @@ app.post("/actions/phase/:name/:phase/:verb", async (c) => {
690
703
  const r = await runs.exec({ kind: "bus", label: `${verb} ${phase} → ${target}`, project: p.name, sideEffects: true, args: { to: target, text: text.slice(0, 200) } }, (log) => busDavid.call("send_message", { to: target, text }, log));
691
704
  return c.json(r, r.status === "ok" ? 200 : 403);
692
705
  });
706
+ /* ---- Project-level onboarding actions (as david → the aide): create-prd conversation starter, /kickstart ---- */
707
+ app.post("/actions/project/:name/:verb", async (c) => {
708
+ const p = project(c.req.param("name"));
709
+ if (!p)
710
+ return c.json({ error: "unknown project" }, 404);
711
+ const verb = c.req.param("verb");
712
+ const b = (await c.req.json().catch(() => ({})));
713
+ const target = roleAgent(p.name, p.room, /aide|liaison|curator/i);
714
+ if (!target)
715
+ return c.json({ error: `no live aide for ${p.name}` }, 409);
716
+ const text = verb === "kickstart"
717
+ ? `AGENT_ACTION: run /kickstart in ${p.name} (${p.path}) — PRD is in docs/PRD.md; produce the roadmap + docs scaffold (TECH_STACK, ARCHITECTURE_GUIDE, DECISIONS, PRODUCTION_ROADMAP, WORKSTREAMS.v1, QUEUE, DONE, FACTS) and report when the doctor is clean.${b.note ? " Note: " + b.note : ""}`
718
+ : verb === "create-prd" ? `AGENT_ACTION: let's write the PRD for ${p.name} (${p.path}) — run /create-prd with me; ask what you need to know, keep it to one pass, Status: Draft until I approve.${b.note ? " Note: " + b.note : ""}`
719
+ : null;
720
+ if (!text)
721
+ return c.json({ error: "verb must be kickstart | create-prd" }, 400);
722
+ const r = await runs.exec({ kind: "bus", label: `${verb} → ${target}`, project: p.name, sideEffects: true, args: { to: target, text: text.slice(0, 200) } }, (log) => busDavid.call("send_message", { to: target, text }, log));
723
+ return c.json(r, r.status === "ok" ? 200 : 403);
724
+ });
693
725
  /* ---- Doctor → Fix: route a doctor finding to the role that owns it (live agent required); sent as david ---- */
694
726
  const DOCTOR_OWNER = {
695
727
  "orphan-wikilinks": { role: "aide", re: /aide|liaison|curator/i, how: "fix the orphan wikilinks (create the target doc or correct the link); docs are your lane" },
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@davidbalzan/groundwork-console",
3
3
  "private": false,
4
- "version": "0.1.3",
4
+ "version": "0.1.5",
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-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
+ import{m as e,t}from"./mermaid-parser.core-679COn57.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-CWXJqyrc.js";import"./chunk-I66GZJ75-DJurmtZ9.js";import{n as i,r as a,t as o}from"./chunk-6Q2QTUOP-BD4S6iuB.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-D_f4AlrR.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-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};
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-DVdstvf6.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-679COn57.js";export{e as createArchitectureServices};