@davidbalzan/groundwork-console 0.1.12 → 0.1.13
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/bus.js +54 -3
- package/dist/events.js +1 -1
- package/dist/gitinfo.js +42 -2
- package/dist/seam.js +27 -10
- package/dist/seamwrite.js +5 -1
- package/dist/server.js +10 -10
- package/dist/tmux.js +1 -1
- package/package.json +7 -4
- package/public/assets/{abnfDiagram-N423BO3Z-C7_Zpec2.js → abnfDiagram-N423BO3Z-2g9UHdfw.js} +1 -1
- package/public/assets/{arc-Bbq8pKhn.js → arc-EEINoaIY.js} +1 -1
- package/public/assets/architecture-TIHT7OUA-CFm6TN4T.js +1 -0
- package/public/assets/{architectureDiagram-T3A2C74G-tEkFMAHO.js → architectureDiagram-T3A2C74G-D4F9rIiu.js} +1 -1
- package/public/assets/{blockDiagram-VBNYF7ZC-CZNrU4_z.js → blockDiagram-VBNYF7ZC-CQZAhVXz.js} +1 -1
- package/public/assets/{c4Diagram-5PPSVZJV-D1-T-b--.js → c4Diagram-5PPSVZJV-BlBzSIXs.js} +1 -1
- package/public/assets/channel-CHLtdsMA.js +1 -0
- package/public/assets/{chunk-2GRJ4B5K-DMzvnmxY.js → chunk-2GRJ4B5K-ZVZxINuZ.js} +1 -1
- package/public/assets/{chunk-4I5QYGJK-D03m5a1e.js → chunk-4I5QYGJK-8hqVPXHL.js} +1 -1
- package/public/assets/{chunk-5RXB4S5H-B5SxHfnz.js → chunk-5RXB4S5H-D1s6L_89.js} +1 -1
- package/public/assets/{chunk-6Q2QTUOP-BQYOf-YY.js → chunk-6Q2QTUOP-BWLeyKxS.js} +1 -1
- package/public/assets/{chunk-7Z6QIM7H-DGtHjZJL.js → chunk-7Z6QIM7H-DjvOr6wh.js} +1 -1
- package/public/assets/{chunk-GF5L2VYU-6_YTDzGo.js → chunk-GF5L2VYU-BCFrJAqb.js} +1 -1
- package/public/assets/{chunk-I66GZJ75-CfWGFqqO.js → chunk-I66GZJ75-XdTCBJhL.js} +1 -1
- package/public/assets/{chunk-JQJVKLGR-DrCjH1AL.js → chunk-JQJVKLGR-BwEUHZBv.js} +1 -1
- package/public/assets/{chunk-KBJHAD2P-DovMVsOt.js → chunk-KBJHAD2P-HjBUqR8F.js} +1 -1
- package/public/assets/{chunk-NSK5VX7P-qSMdOab2.js → chunk-NSK5VX7P-DkHwHrKE.js} +1 -1
- package/public/assets/{chunk-QR6OTTB3-Iraem5u-.js → chunk-QR6OTTB3-DF1_EWFH.js} +1 -1
- package/public/assets/{chunk-RYQCIY6F-8rrSNAgX.js → chunk-RYQCIY6F-BaBhRLGF.js} +1 -1
- package/public/assets/{chunk-UBXNYLIW-CyzK1RD5.js → chunk-UBXNYLIW-BNV3VrZA.js} +1 -1
- package/public/assets/{chunk-W5SLKNZC-BVK4MUw1.js → chunk-W5SLKNZC-5ymyg6B_.js} +1 -1
- package/public/assets/{chunk-WRU74C26-C_K_UiUW.js → chunk-WRU74C26-oznLCI2s.js} +1 -1
- package/public/assets/{chunk-XXDRQBXY-0nuSRCEm.js → chunk-XXDRQBXY-sauNIYLc.js} +1 -1
- package/public/assets/classDiagram-JCYQIIEL-Wf8lPn9O.js +1 -0
- package/public/assets/classDiagram-v2-OCEON4UE-Wf8lPn9O.js +1 -0
- package/public/assets/{cose-bilkent-JH36ORCC-R9H6hDjY.js → cose-bilkent-JH36ORCC-B0A4Je-o.js} +1 -1
- package/public/assets/{cynefin-VYW2F7L2-DnWlTifu.js → cynefin-VYW2F7L2-BtmksekA.js} +1 -1
- package/public/assets/{cynefinDiagram-MW4NZA55-B-7owUyc.js → cynefinDiagram-MW4NZA55-DxlB0XWy.js} +1 -1
- package/public/assets/{dagre-VZM6K2ZE-B3ZoPe5S.js → dagre-VZM6K2ZE-BwX2jQEP.js} +1 -1
- package/public/assets/{diagram-7IWD3JNH-BI26fzwd.js → diagram-7IWD3JNH-CRw4eKmV.js} +1 -1
- package/public/assets/{diagram-B4RE2ZJO-BiSCmkOd.js → diagram-B4RE2ZJO-BhSHl_HC.js} +1 -1
- package/public/assets/{diagram-LBJQPF4R-BQ35r2wn.js → diagram-LBJQPF4R-BLNDbOa-.js} +1 -1
- package/public/assets/{diagram-Q27KOJAE-258JzS88.js → diagram-Q27KOJAE-OI-WVr2z.js} +1 -1
- package/public/assets/{diagram-UB23O5K3-BQLuDWQ5.js → diagram-UB23O5K3-Dw4v-DRV.js} +1 -1
- package/public/assets/{dist-BhEZ2d35.js → dist-CkCHUIyI.js} +1 -1
- package/public/assets/{ebnfDiagram-BXEA7PRR-D6cGU6FA.js → ebnfDiagram-BXEA7PRR-_CCtytYQ.js} +1 -1
- package/public/assets/{erDiagram-JOGREHBK-x-fYPfbp.js → erDiagram-JOGREHBK-DPwktZ67.js} +1 -1
- package/public/assets/eventmodeling-45OFAUF4-COOjM2XZ.js +1 -0
- package/public/assets/flowDiagram-UKHOOZJN-ipIqOWay.js +1 -0
- package/public/assets/{ganttDiagram-PKOTCBZU-B44E_1OW.js → ganttDiagram-PKOTCBZU-ChHOAX0R.js} +1 -1
- package/public/assets/{gitGraph-TEB2WS4Q-B_J5fmci.js → gitGraph-TEB2WS4Q-DTKjAplS.js} +1 -1
- package/public/assets/{gitGraphDiagram-DS77QQ5N-oi1EtSGf.js → gitGraphDiagram-DS77QQ5N-CetQtIP1.js} +1 -1
- package/public/assets/{index-D4kIibeU.js → index-CMeHHiB8.js} +11 -11
- package/public/assets/{info-DKCQHKI2-CvqAVyoT.js → info-DKCQHKI2-CEZZoshL.js} +1 -1
- package/public/assets/{infoDiagram-6WML65LV-BroSi0D-.js → infoDiagram-6WML65LV-Dn0Ci1fh.js} +1 -1
- package/public/assets/{ishikawaDiagram-WSZJBQD7-BRQ47rb2.js → ishikawaDiagram-WSZJBQD7-C0yvCWyv.js} +1 -1
- package/public/assets/{journeyDiagram-NVQOT4AX-DB6Xo-9Q.js → journeyDiagram-NVQOT4AX-CpTSt3oh.js} +1 -1
- package/public/assets/{kanban-definition-27J2QSJJ-BBzsco6z.js → kanban-definition-27J2QSJJ-Co4MhtWb.js} +1 -1
- package/public/assets/{line-m55PflQc.js → line-CKdpDvRy.js} +1 -1
- package/public/assets/{linear-Dgtz6Nrl.js → linear-BAY9SBNB.js} +1 -1
- package/public/assets/{mermaid-parser.core-B98Rk-oq.js → mermaid-parser.core-B-yKcreq.js} +3 -3
- package/public/assets/{mermaid.core-CqRCrVqJ.js → mermaid.core-CW_jKbCL.js} +4 -4
- package/public/assets/{mindmap-definition-FAOFIHXS-BPP33G4r.js → mindmap-definition-FAOFIHXS-CejNgzQn.js} +1 -1
- package/public/assets/{packet-7NZHBO7P-tO4S6ouz.js → packet-7NZHBO7P-B53cyWv4.js} +1 -1
- package/public/assets/{pegDiagram-VL7TDLO6-Bw6mp9l7.js → pegDiagram-VL7TDLO6-DAh-rohm.js} +1 -1
- package/public/assets/{pie-RZYD4A2V-C437Vvln.js → pie-RZYD4A2V-Bbl6CzP-.js} +1 -1
- package/public/assets/{pieDiagram-7S7Q4E2Y-CBxtUqZy.js → pieDiagram-7S7Q4E2Y-BoiaUX85.js} +1 -1
- package/public/assets/{quadrantDiagram-CIZ2JOQS-Bqsvmpf9.js → quadrantDiagram-CIZ2JOQS-2EgkGrDN.js} +1 -1
- package/public/assets/{radar-I7S5WNFK-C6dNsRn9.js → radar-I7S5WNFK-1Piyk_Oc.js} +1 -1
- package/public/assets/{railroad-3IZDKUUU-KaVebqGG.js → railroad-3IZDKUUU-DcQG7hTA.js} +1 -1
- package/public/assets/railroad-abnf-AHOZXSZD-CaviTNom.js +1 -0
- package/public/assets/railroad-ebnf-EBAXGLYW-K7l-WN0j.js +1 -0
- package/public/assets/railroad-peg-LSFZ7HO6-Bu22X3mO.js +1 -0
- package/public/assets/{railroadDiagram-AXF67PYL-DKq4X6Uj.js → railroadDiagram-AXF67PYL-kPPDLWet.js} +1 -1
- package/public/assets/{requirementDiagram-LRYGKXZP-B9fsvyjq.js → requirementDiagram-LRYGKXZP-B0wNE6wF.js} +1 -1
- package/public/assets/{sankeyDiagram-W5VNT64P-BsfVDMI2.js → sankeyDiagram-W5VNT64P-CyKEUx9w.js} +1 -1
- package/public/assets/{sequenceDiagram-SI44F4Z6-OgERYEKg.js → sequenceDiagram-SI44F4Z6-DT7UmiRF.js} +1 -1
- package/public/assets/{src-fnYA6irH.js → src-EbLSa_z9.js} +1 -1
- package/public/assets/{stateDiagram-OKZ733FA-CQbkYnuQ.js → stateDiagram-OKZ733FA-BNk8YOH4.js} +1 -1
- package/public/assets/stateDiagram-v2-UEYNNEHI-8Oafa2Rm.js +1 -0
- package/public/assets/{swimlanes-SLNWSIFB-Bjko0riO.js → swimlanes-SLNWSIFB-B7eUL04h.js} +1 -1
- package/public/assets/swimlanesDiagram-ULZ7WXOC-BT5Ebr7W.js +8 -0
- package/public/assets/{timeline-definition-Z64GVDOM-yK0hLw8V.js → timeline-definition-Z64GVDOM-CDLh-h94.js} +1 -1
- package/public/assets/{treeView-QDETBFTQ-BGpcfDZf.js → treeView-QDETBFTQ-BAscBSG9.js} +1 -1
- package/public/assets/{treemap-6X3UGDF4-QT7YcofM.js → treemap-6X3UGDF4-B2ahLgfF.js} +1 -1
- package/public/assets/{vennDiagram-T6HMQDX7-BuWvWEXb.js → vennDiagram-T6HMQDX7-62WQ_264.js} +1 -1
- package/public/assets/{wardley-OPB4EBWU-hYpU_cIv.js → wardley-OPB4EBWU-DUrXideD.js} +1 -1
- package/public/assets/{wardleyDiagram-T6FBY63Y-CgKHf2Kc.js → wardleyDiagram-T6FBY63Y-Ci4DF612.js} +1 -1
- package/public/assets/{xychartDiagram-ELKLHX3M-CoNyQg1m.js → xychartDiagram-ELKLHX3M-D--O5thj.js} +1 -1
- package/public/index.html +1 -1
- package/public/assets/architecture-TIHT7OUA-CJFVglth.js +0 -1
- package/public/assets/channel-ClF6sQKu.js +0 -1
- package/public/assets/classDiagram-JCYQIIEL-z-TVRcqJ.js +0 -1
- package/public/assets/classDiagram-v2-OCEON4UE-z-TVRcqJ.js +0 -1
- package/public/assets/eventmodeling-45OFAUF4-CsZX8d8q.js +0 -1
- package/public/assets/flowDiagram-UKHOOZJN-B-BoRx9A.js +0 -1
- package/public/assets/railroad-abnf-AHOZXSZD-vLN4fXap.js +0 -1
- package/public/assets/railroad-ebnf-EBAXGLYW-B70X8CrM.js +0 -1
- package/public/assets/railroad-peg-LSFZ7HO6-DXKtxJxs.js +0 -1
- package/public/assets/stateDiagram-v2-UEYNNEHI-BDBAarNU.js +0 -1
- package/public/assets/swimlanesDiagram-ULZ7WXOC-BhW0icZR.js +0 -8
package/dist/bus.js
CHANGED
|
@@ -19,6 +19,54 @@ const tailJsonl = (p, limit) => {
|
|
|
19
19
|
return { malformed: true, raw: l };
|
|
20
20
|
} });
|
|
21
21
|
};
|
|
22
|
+
/* Thresholds are judgement, not measurement, and are stated here rather than buried: "producing"
|
|
23
|
+
is the working cadence, and >8h is the shape of an overnight stall. The 2h boundary exists
|
|
24
|
+
because the previous model put a coffee break and a seventeen-hour stall in one bucket. */
|
|
25
|
+
const PRODUCING_MS = 2 * 3_600_000;
|
|
26
|
+
const STALLED_MS = 8 * 3_600_000;
|
|
27
|
+
const SCAN_LINES = 4000;
|
|
28
|
+
/** Newest emission per agent, from the room logs and the status stream. */
|
|
29
|
+
export function outputIndex(root, scanLines = SCAN_LINES) {
|
|
30
|
+
const out = new Map();
|
|
31
|
+
const note = (from, ts, basis) => {
|
|
32
|
+
if (typeof from !== "string" || typeof ts !== "number")
|
|
33
|
+
return;
|
|
34
|
+
const prev = out.get(from);
|
|
35
|
+
if (!prev || ts > prev.ts)
|
|
36
|
+
out.set(from, { ts, basis });
|
|
37
|
+
};
|
|
38
|
+
const roomDir = path.join(root, "rooms");
|
|
39
|
+
if (existsSync(roomDir))
|
|
40
|
+
for (const f of readdirSync(roomDir).filter((x) => x.endsWith(".jsonl"))) {
|
|
41
|
+
for (const m of tailJsonl(path.join(roomDir, f), scanLines))
|
|
42
|
+
note(m.from, m.ts, "room");
|
|
43
|
+
}
|
|
44
|
+
for (const m of tailJsonl(path.join(root, "status.jsonl"), scanLines))
|
|
45
|
+
note(m.agentId ?? m.from, m.ts, "status");
|
|
46
|
+
/* DMs count as output and are NOT in the room logs — they are rows in the RECIPIENT's inbox,
|
|
47
|
+
carrying the sender in `from`. Omitting them made an agent working entirely by DM read as
|
|
48
|
+
stalled; that was caught on the first live run, where this console's own worker showed
|
|
49
|
+
`stalled` while it had been reporting by DM all morning. Scanning inboxes attributes each
|
|
50
|
+
message to its sender, not its owner. */
|
|
51
|
+
const inboxDir = path.join(root, "inbox");
|
|
52
|
+
if (existsSync(inboxDir))
|
|
53
|
+
for (const f of readdirSync(inboxDir).filter((x) => x.endsWith(".jsonl"))) {
|
|
54
|
+
for (const m of tailJsonl(path.join(inboxDir, f), scanLines))
|
|
55
|
+
note(m.from, m.ts, "dm");
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
/* `unknown` is NOT "no output" — it is "none within the scanned window", and the window is reported
|
|
60
|
+
so a caller can tell the two apart. Collapsing them would be the same defect one level down. */
|
|
61
|
+
const progressOf = (hit, now, scanLines) => {
|
|
62
|
+
if (!hit)
|
|
63
|
+
return { lastOutputAt: null, ageMs: null, state: "unknown", basis: null, scannedLines: scanLines };
|
|
64
|
+
const ageMs = now - hit.ts;
|
|
65
|
+
return { lastOutputAt: hit.ts, ageMs, state: ageMs < PRODUCING_MS ? "producing" : ageMs < STALLED_MS ? "quiet" : "stalled", basis: hit.basis, scannedLines: scanLines };
|
|
66
|
+
};
|
|
67
|
+
/* Reachability buckets. `idle` used to span 15 MINUTES to 24 HOURS, so a coffee break and an
|
|
68
|
+
overnight stall rendered identically; `dormant` splits that. */
|
|
69
|
+
export const reachOf = (age) => age < 15 * 60_000 ? "live" : age < 2 * 3_600_000 ? "idle" : age < 24 * 3_600_000 ? "dormant" : "dead";
|
|
22
70
|
export async function agentsAsync(root) {
|
|
23
71
|
const panes = await listPanes();
|
|
24
72
|
const base = agentsSync(root);
|
|
@@ -33,11 +81,14 @@ export async function agentsAsync(root) {
|
|
|
33
81
|
const paneActivity = ct === undefined || ct === null ? windowActivity : ct || null; // 0 = seeded, no change observed yet → treated as unknown, not as "now"
|
|
34
82
|
const lastSeen = Math.max(a.lastSeen ?? 0, paneActivity ?? 0);
|
|
35
83
|
const age = lastSeen ? Date.now() - lastSeen : Infinity;
|
|
36
|
-
|
|
84
|
+
/* paneActivity is another REACHABILITY input, not progress: a pane redraws when a message is pasted into
|
|
85
|
+
it. It is deliberately not folded into `progress`, which stays as agentsSync computed it. */
|
|
86
|
+
return { ...a, paneActivity, windowActivity, windowName: pane?.windowName ?? null, paneCommand: pane?.command ?? null, paneAlive: pane ? !pane.dead : null, lastSeen: lastSeen || null, heartbeatAgeMs: Number.isFinite(age) ? age : null, reachability: reachOf(age), active: paneActivity ? Date.now() - paneActivity < 60_000 : false };
|
|
37
87
|
}).sort((a, b) => (b.lastSeen ?? 0) - (a.lastSeen ?? 0));
|
|
38
88
|
}
|
|
39
89
|
export const agents = agentsSync;
|
|
40
|
-
export function agentsSync(root) {
|
|
90
|
+
export function agentsSync(root, scanLines = SCAN_LINES) {
|
|
91
|
+
const output = outputIndex(root, scanLines);
|
|
41
92
|
const reg = readJson(path.join(root, "agents.json"), {});
|
|
42
93
|
const transports = existsSync(path.join(root, "transports")) ? new Set(readdirSync(path.join(root, "transports")).map((f) => f.replace(/\.json$/, ""))) : new Set();
|
|
43
94
|
const now = Date.now();
|
|
@@ -48,7 +99,7 @@ export function agentsSync(root) {
|
|
|
48
99
|
const mtimes = [tPath, path.join(root, "inbox", `${a.agentId}.jsonl`), path.join(root, "cursors", `${a.agentId}.json`)].filter(existsSync).map((f) => statSync(f).mtimeMs);
|
|
49
100
|
const lastSeen = Math.max(a.lastHeartbeat ?? 0, ...mtimes);
|
|
50
101
|
const age = lastSeen ? now - lastSeen : Infinity;
|
|
51
|
-
return { ...a, transport: t?.transport ?? t?.kind ?? (t ? "tmux-push" : null), pane: t?.tmuxTarget ?? null,
|
|
102
|
+
return { ...a, transport: t?.transport ?? t?.kind ?? (t ? "tmux-push" : null), pane: t?.tmuxTarget ?? null, reachability: reachOf(age), heartbeatAgeMs: Number.isFinite(age) ? age : null, lastSeen: lastSeen || null, progress: progressOf(output.get(a.agentId), now, scanLines) };
|
|
52
103
|
}).sort((a, b) => (b.lastSeen ?? 0) - (a.lastSeen ?? 0));
|
|
53
104
|
}
|
|
54
105
|
export function rooms(root) {
|
package/dist/events.js
CHANGED
|
@@ -103,7 +103,7 @@ export class EventEngine {
|
|
|
103
103
|
}
|
|
104
104
|
/** The live coordinator agent for a project/room (role coordinator, project == room or name), else null. */
|
|
105
105
|
coordinatorFor(project, room) {
|
|
106
|
-
const a = agents(this.cfg.coordDir).find((x) => /coordinator/i.test(x.role ?? "") && (x.project === room || x.project === project) && x.
|
|
106
|
+
const a = agents(this.cfg.coordDir).find((x) => /coordinator/i.test(x.role ?? "") && (x.project === room || x.project === project) && x.reachability !== "dead");
|
|
107
107
|
return a?.agentId ?? null;
|
|
108
108
|
}
|
|
109
109
|
emitRaw(type, project, data) {
|
package/dist/gitinfo.js
CHANGED
|
@@ -139,6 +139,46 @@ async function ghPrs(projectPath) {
|
|
|
139
139
|
return null;
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
|
+
/* Which PR a board row is ABOUT, from its `pr` CELL — never from a `#n` appearing anywhere in the
|
|
143
|
+
row. The openPrs extension declares fields ["repo","pr","owner","status","mergeGate"], so the
|
|
144
|
+
answer has a designated column and reading the others is a guess.
|
|
145
|
+
|
|
146
|
+
The old matcher was `Object.values(r).some(v => /#n/.test(v))`, which meant a Status cell reading
|
|
147
|
+
"blocked by #39" made THAT row answer for PR 39 — and `find` returns the first hit, so a mention
|
|
148
|
+
beat the real row. Measured on a two-row fixture: qaOf(39) returned "FAIL — held" from #57's row
|
|
149
|
+
while #39's own row said PASS. A passing PR shown as failing, in the alarming direction.
|
|
150
|
+
|
|
151
|
+
Same defect the kit found in queue-done-loop the same afternoon: a ref MENTIONED in a row is a
|
|
152
|
+
different fact from the ref that IDENTIFIES it. */
|
|
153
|
+
export const prCellNumber = (cell) => {
|
|
154
|
+
const m = /#(\d+)\b/.exec(cell ?? "");
|
|
155
|
+
return m ? Number(m[1]) : null;
|
|
156
|
+
};
|
|
157
|
+
/* `owner/name` from a remote URL, ssh or https. null when there is no origin — in which case the
|
|
158
|
+
repo check below is SKIPPED rather than guessed, and matching falls back to the pr cell alone. */
|
|
159
|
+
export const slugFromRemoteUrl = (url) => {
|
|
160
|
+
const m = url ? /(?:[:/])([^/:]+\/[^/]+?)(?:\.git)?$/.exec(url.trim()) : null;
|
|
161
|
+
return m ? m[1] : null;
|
|
162
|
+
};
|
|
163
|
+
const originSlug = async (projectPath) => slugFromRemoteUrl(await git(projectPath, ["remote", "get-url", "origin"]));
|
|
164
|
+
/* A row's repo, when it states one. Boards legitimately carry several repos — the kit's own board
|
|
165
|
+
lists `kit#11` beside console PRs — so a bare number is ambiguous across them. Only rows that
|
|
166
|
+
name a DIFFERENT repo are rejected; a row with no repo cell is accepted, because absence is not
|
|
167
|
+
a claim. */
|
|
168
|
+
/* The gate a board reports for PR `n` in THIS repo, or undefined. Exported and used by
|
|
169
|
+
gitBranches directly, so the test exercises this function rather than a copy of it — a test that
|
|
170
|
+
re-implements the matcher pins the fixture, not the code. */
|
|
171
|
+
export const gateForPr = (rows, n, slug) => {
|
|
172
|
+
const row = rows?.find((r) => prCellNumber(r.pr) === n && repoMatches(r.repo, slug));
|
|
173
|
+
const qa = row?.mergeGate ?? row?.status;
|
|
174
|
+
return qa ? String(qa) : undefined;
|
|
175
|
+
};
|
|
176
|
+
export const repoMatches = (rowRepo, slug) => {
|
|
177
|
+
const cell = (rowRepo ?? "").trim();
|
|
178
|
+
if (!cell || !slug)
|
|
179
|
+
return true;
|
|
180
|
+
return cell === slug || cell.endsWith(`/${slug.split("/").pop()}`) || slug.endsWith(`/${cell}`) || cell === slug.split("/").pop();
|
|
181
|
+
};
|
|
142
182
|
export function gitBranches(projectPath, hints = {}) {
|
|
143
183
|
return cached(`branches:${projectPath}:${(hints.agentIds ?? []).join(",")}`, async () => {
|
|
144
184
|
const defaultBranch = "main";
|
|
@@ -147,8 +187,8 @@ export function gitBranches(projectPath, hints = {}) {
|
|
|
147
187
|
const rows = splitRecords(await git(projectPath, ["for-each-ref", "--sort=-committerdate", "--format=%(refname)%1f%(objectname)%1f%(objectname:short)%1f%(subject)%1f%(committerdate:iso-strict)", "refs/heads", "refs/remotes"]))
|
|
148
188
|
.filter(([ref]) => !/^refs\/remotes\/[^/]+\/HEAD$/.test(ref));
|
|
149
189
|
const [{ worktrees }, prs] = await Promise.all([gitWorktrees(projectPath, hints), ghPrs(projectPath)]);
|
|
150
|
-
const
|
|
151
|
-
|
|
190
|
+
const slug = await originSlug(projectPath);
|
|
191
|
+
const qaOf = (n) => gateForPr(hints.openPrs, n, slug);
|
|
152
192
|
const now = Date.now();
|
|
153
193
|
const branches = await Promise.all(rows.map(async ([ref, sha, short, subject, date]) => {
|
|
154
194
|
const remote = ref.startsWith("refs/remotes/");
|
package/dist/seam.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* Read-only views over a project's seam files, parsed ONLY through @davidbalzan/groundwork-seam. */
|
|
2
2
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { parseWorkDoc, queueItemsOf, doneEntriesOf, listWorkBoardOf, workDocIssues, SCHEMA } from "@davidbalzan/groundwork-seam";
|
|
4
|
+
import { parseWorkDoc, queueItemsOf, doneEntriesOf, listWorkBoardOf, workDocIssues, boardSchemaOf, SCHEMA } from "@davidbalzan/groundwork-seam";
|
|
5
5
|
import { parseFactsDoc } from "@davidbalzan/groundwork-seam";
|
|
6
6
|
const read = (p) => (existsSync(p) ? readFileSync(p, "utf8") : null);
|
|
7
7
|
const FACT_STALE_DAYS = 14; // groundwork doctor rule
|
|
@@ -13,14 +13,22 @@ export function boardOf(projectPath) {
|
|
|
13
13
|
const f = read(path.join(docs, "FACTS.md"));
|
|
14
14
|
const wsDoc = ws ? parseWorkDoc(ws) : null;
|
|
15
15
|
const board = wsDoc ? listWorkBoardOf(wsDoc) : [];
|
|
16
|
-
/*
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
/* Schema comes from the seam's boardSchemaOf, not from a local re-derivation.
|
|
17
|
+
The console used to work this out itself, and console#35 fixed the first defect in that
|
|
18
|
+
copy: it read the schema off the first parsed ROW, so an empty-but-valid board yielded
|
|
19
|
+
null and rendered "unknown workstreams grammar" — the alarming reading of an empty one.
|
|
20
|
+
The seam now exports the answer, and its version is better than ours on two counts we
|
|
21
|
+
had wrong:
|
|
22
|
+
- it EXCLUDES extension tables by deriving their ids from WORKSTREAMS_EXT, so
|
|
23
|
+
registering a new extension cannot forget to exclude it. Ours allow-listed the two
|
|
24
|
+
board grammars we knew, which meant any FUTURE board schema read as unrecognised.
|
|
25
|
+
- it returns "unknown" only when a header was actually REFUSED, and null when there
|
|
26
|
+
is simply no board block. Ours collapsed those: `schema ?? (ws ? "unknown" : null)`
|
|
27
|
+
reported "unknown grammar" for a WORKSTREAMS.md that merely has no Active Streams
|
|
28
|
+
table — the same conflation console#35 fixed, one case over, still live until now.
|
|
29
|
+
So `null` here means "no board table", NOT "no file"; the caller must not render those
|
|
30
|
+
as the same thing. `files.workstreams` is what distinguishes them. */
|
|
31
|
+
const schema = wsDoc ? boardSchemaOf(wsDoc) : null;
|
|
24
32
|
const qDoc = q ? parseWorkDoc(q) : null;
|
|
25
33
|
const dDoc = d ? parseWorkDoc(d) : null;
|
|
26
34
|
const facts = f ? parseFactsDoc(f) : null;
|
|
@@ -31,9 +39,18 @@ export function boardOf(projectPath) {
|
|
|
31
39
|
return {
|
|
32
40
|
files: { workstreams: !!ws, queue: !!q, done: !!d, facts: !!f },
|
|
33
41
|
prd,
|
|
34
|
-
workstreams: { schema
|
|
42
|
+
workstreams: { schema, rows: board, issues: wsDoc ? workDocIssues(wsDoc) : [] },
|
|
35
43
|
queue: qDoc ? queueItemsOf(qDoc) : [],
|
|
36
44
|
done: dDoc ? doneEntriesOf(dDoc) : [],
|
|
45
|
+
/* QUEUE.md and DONE.md parse issues. Only WORKSTREAMS.md's were ever surfaced, so a malformed
|
|
46
|
+
queue line was parsed, kept, rendered — and reported NOWHERE. That gap is the console's half
|
|
47
|
+
of seam 0.1.6: the seam stopped DROPPING an out-of-range priority precisely so a consumer
|
|
48
|
+
could say something about it, and this consumer said nothing. `workDocIssues` already carries
|
|
49
|
+
the message (the seam builds it with invalidPriorityIssue), so nothing here re-derives it.
|
|
50
|
+
Siblings rather than a reshape of `queue`/`done`: those are arrays every caller maps over,
|
|
51
|
+
and the gap is a missing signal, not a wrong shape. */
|
|
52
|
+
queueIssues: qDoc ? workDocIssues(qDoc) : [],
|
|
53
|
+
doneIssues: dDoc ? workDocIssues(dDoc) : [],
|
|
37
54
|
facts: facts
|
|
38
55
|
? {
|
|
39
56
|
entries: facts.entries.map((e) => {
|
package/dist/seamwrite.js
CHANGED
|
@@ -65,7 +65,11 @@ export function addQueueItem(projectPath, item, log) {
|
|
|
65
65
|
log(`wrote docs/QUEUE.md (+1 item, ${out.length - src.length} bytes)`);
|
|
66
66
|
return { file: "docs/QUEUE.md", line: renderWorkDocLine(newItem), bytesDelta: out.length - src.length };
|
|
67
67
|
}
|
|
68
|
-
|
|
68
|
+
/* Display-only echo of the line we appended. `QueueItem.priority` is nullable since seam 0.1.6, and
|
|
69
|
+
interpolating a null renders the literal "(null)" — so fall back to the raw tag the seam kept. The
|
|
70
|
+
console never CREATES such an item (addQueueItem's input is narrowed to P1|P2|P3); this guards the
|
|
71
|
+
echo against a shape the type now permits. */
|
|
72
|
+
const renderWorkDocLine = (q) => `- [${q.done ? "x" : " "}] (${q.priority ?? q.priorityRaw ?? "?"}) ${q.text}`;
|
|
69
73
|
/** Re-verify (or add) a fact: seam upsertFact with a fresh timestamp. */
|
|
70
74
|
export function reverifyFact(projectPath, entry, log) {
|
|
71
75
|
const file = path.join(projectPath, "docs/FACTS.md");
|
package/dist/server.js
CHANGED
|
@@ -48,7 +48,7 @@ const clientFor = (id) => (id === "david" ? busDavid : bus);
|
|
|
48
48
|
/** Capabilities of the connected MCP (null until a client has connected and listed tools). */
|
|
49
49
|
const mcpCaps = () => { const cl = bus.connected ? bus : busDavid.connected ? busDavid : null; return { inReplyTo: cl ? cl.supports("send_message", "inReplyTo") : null, sendCommand: cl ? cl.sendCommands : null }; };
|
|
50
50
|
/* Live tmux-attached agents — the only valid send_command targets (the MCP hard-gates to tmux-push/-remote). */
|
|
51
|
-
const liveAttached = () => agents(cfg.coordDir).filter((a) => a.
|
|
51
|
+
const liveAttached = () => agents(cfg.coordDir).filter((a) => a.reachability === "live" && (a.transport === "tmux-push" || a.transport === "tmux-push-remote")).map((a) => a.agentId);
|
|
52
52
|
const PUBLIC_DIR = path.resolve(HERE, "../public");
|
|
53
53
|
const root = new Hono();
|
|
54
54
|
const app = new Hono().basePath("/api");
|
|
@@ -286,7 +286,7 @@ app.get("/projects", (c) => {
|
|
|
286
286
|
catch {
|
|
287
287
|
return null;
|
|
288
288
|
} })();
|
|
289
|
-
const liveAgents = agents(cfg.coordDir).filter((a) => a.
|
|
289
|
+
const liveAgents = agents(cfg.coordDir).filter((a) => a.reachability !== "dead");
|
|
290
290
|
return c.json(cfg.projects.map((p) => {
|
|
291
291
|
const b = boardOf(p.path);
|
|
292
292
|
const fleet = fleetStatus(liveAgents.filter((a) => a.project === p.room || a.project === p.name));
|
|
@@ -723,7 +723,7 @@ app.get("/projects/:name/fleet", async (c) => {
|
|
|
723
723
|
const p = project(c.req.param("name"));
|
|
724
724
|
if (!p)
|
|
725
725
|
return c.json({ error: "unknown project" }, 404);
|
|
726
|
-
const live = (await agentsAsync(cfg.coordDir)).filter((a) => a.
|
|
726
|
+
const live = (await agentsAsync(cfg.coordDir)).filter((a) => a.reachability !== "dead" && (a.project === p.room || a.project === p.name));
|
|
727
727
|
return c.json({ ...fleetStatus(live), templates: FLEET_TEMPLATES, window: `fleet-${p.name}` });
|
|
728
728
|
});
|
|
729
729
|
const roleOfAgent = (id) => agents(cfg.coordDir).find((a) => a.agentId === id)?.role ?? null;
|
|
@@ -788,7 +788,7 @@ app.post("/actions/prune", async (c) => {
|
|
|
788
788
|
});
|
|
789
789
|
app.post("/actions/unregister-dead", async (c) => {
|
|
790
790
|
const b = (await c.req.json().catch(() => ({})));
|
|
791
|
-
const dead = agents(cfg.coordDir).filter((a) => a.
|
|
791
|
+
const dead = agents(cfg.coordDir).filter((a) => a.reachability === "dead" && !["groundwork-console", "david"].includes(a.agentId)).map((a) => a.agentId);
|
|
792
792
|
const ids = (b.agentIds?.length ? b.agentIds.filter((id) => dead.includes(id)) : dead);
|
|
793
793
|
if (b.confirm !== "UNREGISTER")
|
|
794
794
|
return c.json({ error: "confirm must be UNREGISTER", wouldUnregister: ids }, 400);
|
|
@@ -810,7 +810,7 @@ app.post("/actions/unregister", async (c) => {
|
|
|
810
810
|
return c.json(r, r.status === "ok" ? 200 : 403);
|
|
811
811
|
});
|
|
812
812
|
/* ---- Roadmap actions: message the project's aide (plan) or coordinator (kick off) as david ---- */
|
|
813
|
-
const roleAgent = (projectName, room, roleRe) => agents(cfg.coordDir).find((a) => roleRe.test(a.role ?? "") && (a.project === room || a.project === projectName) && a.
|
|
813
|
+
const roleAgent = (projectName, room, roleRe) => agents(cfg.coordDir).find((a) => roleRe.test(a.role ?? "") && (a.project === room || a.project === projectName) && a.reachability !== "dead")?.agentId ?? null;
|
|
814
814
|
app.get("/projects/:name/agents", (c) => {
|
|
815
815
|
const p = project(c.req.param("name"));
|
|
816
816
|
if (!p)
|
|
@@ -855,7 +855,7 @@ app.post("/actions/task/:name/:phase/:line", async (c) => {
|
|
|
855
855
|
return c.json({ error: "no task at that line" }, 404);
|
|
856
856
|
if (task.done)
|
|
857
857
|
return c.json({ error: "already ticked" }, 409);
|
|
858
|
-
const live = agents(cfg.coordDir).filter((a) => a.
|
|
858
|
+
const live = agents(cfg.coordDir).filter((a) => a.reachability !== "dead");
|
|
859
859
|
const owner = b.owner && live.some((a) => a.agentId === b.owner) ? b.owner : roleAgent(p.name, p.room, /aide|liaison|curator/i);
|
|
860
860
|
if (!owner)
|
|
861
861
|
return c.json({ error: `no live owner or aide for ${p.name}` }, 409);
|
|
@@ -897,7 +897,7 @@ app.get("/projects/:name/doctor/fixers", async (c) => {
|
|
|
897
897
|
const p = project(c.req.param("name"));
|
|
898
898
|
if (!p)
|
|
899
899
|
return c.json({ error: "unknown project" }, 404);
|
|
900
|
-
const live = (await agentsAsync(cfg.coordDir)).filter((a) => a.
|
|
900
|
+
const live = (await agentsAsync(cfg.coordDir)).filter((a) => a.reachability !== "dead" && (a.project === p.room || a.project === p.name));
|
|
901
901
|
const out = {};
|
|
902
902
|
for (const [check, o] of Object.entries(DOCTOR_OWNER)) {
|
|
903
903
|
const a = live.find((x) => o.re.test(x.role ?? ""));
|
|
@@ -913,7 +913,7 @@ app.post("/actions/doctor-fix/:name", async (c) => {
|
|
|
913
913
|
const o = DOCTOR_OWNER[b.check];
|
|
914
914
|
if (!o)
|
|
915
915
|
return c.json({ error: "no fixer role for this check" }, 400);
|
|
916
|
-
const live = (await agentsAsync(cfg.coordDir)).filter((a) => a.
|
|
916
|
+
const live = (await agentsAsync(cfg.coordDir)).filter((a) => a.reachability !== "dead" && (a.project === p.room || a.project === p.name));
|
|
917
917
|
const target = live.find((x) => o.re.test(x.role ?? ""))?.agentId;
|
|
918
918
|
if (!target)
|
|
919
919
|
return c.json({ error: `no live ${o.role} for ${p.name}` }, 409);
|
|
@@ -1036,9 +1036,9 @@ app.get("/bus/panes", async (c) => {
|
|
|
1036
1036
|
const lines = Number(c.req.query("lines") ?? 40);
|
|
1037
1037
|
const p = proj ? project(proj) : undefined;
|
|
1038
1038
|
const all = await agentsAsync(cfg.coordDir);
|
|
1039
|
-
const scoped = all.filter((a) => a.pane && a.
|
|
1039
|
+
const scoped = all.filter((a) => a.pane && a.reachability !== "dead" && (!p || a.project === p.name || (p.room && a.project === p.room)));
|
|
1040
1040
|
const colors = c.req.query("colors") === "1";
|
|
1041
|
-
const out = await Promise.all(scoped.map(async (a) => ({ agentId: a.agentId, role: a.role ?? null, project: a.project ?? null, pane: a.pane, windowName: a.windowName ?? null, command: a.paneCommand, active: a.active, paneActivity: a.paneActivity,
|
|
1041
|
+
const out = await Promise.all(scoped.map(async (a) => ({ agentId: a.agentId, role: a.role ?? null, project: a.project ?? null, pane: a.pane, windowName: a.windowName ?? null, command: a.paneCommand, active: a.active, paneActivity: a.paneActivity, reachability: a.reachability, capture: await capturePane(a.pane, lines, colors) })));
|
|
1042
1042
|
return c.json(out);
|
|
1043
1043
|
});
|
|
1044
1044
|
/* Pane viewer: read-only capture of an agent's tmux pane (never sends keys). */
|
package/dist/tmux.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Read-only tmux views: pane activity (for
|
|
1
|
+
/* Read-only tmux views: pane activity (for reachability + activity indicators) and pane capture (for the pane viewer). Never sends keys. */
|
|
2
2
|
import { execFile } from "node:child_process";
|
|
3
3
|
import { promisify } from "node:util";
|
|
4
4
|
const run = promisify(execFile);
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@davidbalzan/groundwork-console",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.13",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@davidbalzan/groundwork-seam": "
|
|
7
|
+
"@davidbalzan/groundwork-seam": "0.1.7",
|
|
8
8
|
"@hono/node-server": "^2.1.1",
|
|
9
9
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
10
10
|
"hono": "^4.13.2",
|
|
@@ -48,8 +48,11 @@
|
|
|
48
48
|
"publish-check": "node scripts/publish-check.mjs",
|
|
49
49
|
"test:inject": "tsx test/inject.test.mts",
|
|
50
50
|
"test:skills": "tsx test/skills.test.mts",
|
|
51
|
-
"test": "pnpm run test:inject && pnpm run test:skills && pnpm run test:board && pnpm run test:panes",
|
|
51
|
+
"test": "pnpm run test:inject && pnpm run test:skills && pnpm run test:board && pnpm run test:panes && pnpm run test:seam-contract && pnpm run test:prref && pnpm run test:progress",
|
|
52
52
|
"test:board": "tsx test/board.test.mts",
|
|
53
|
-
"test:panes": "tsx test/panes.test.mts"
|
|
53
|
+
"test:panes": "tsx test/panes.test.mts",
|
|
54
|
+
"test:seam-contract": "tsx test/seam-contract.test.mts",
|
|
55
|
+
"test:prref": "tsx test/prref.test.mts",
|
|
56
|
+
"test:progress": "tsx test/progress.test.mts"
|
|
54
57
|
}
|
|
55
58
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{m as e,t}from"./mermaid-parser.core-
|
|
1
|
+
import{m as e,t}from"./mermaid-parser.core-B-yKcreq.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-EbLSa_z9.js";import"./chunk-I66GZJ75-XdTCBJhL.js";import{n as i,r as a,t as o}from"./chunk-6Q2QTUOP-BWLeyKxS.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-CW_jKbCL.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-
|
|
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-CkCHUIyI.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-B-yKcreq.js";export{e as createArchitectureServices};
|