@davidbalzan/groundwork-console 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/bin/groundwork-console.mjs +47 -0
  2. package/dist/answered.js +34 -0
  3. package/dist/auth.js +47 -0
  4. package/dist/bus.js +79 -0
  5. package/dist/config.js +40 -0
  6. package/dist/docwrite.js +66 -0
  7. package/dist/env.js +23 -0
  8. package/dist/events.js +170 -0
  9. package/dist/extensions.js +31 -0
  10. package/dist/gitinfo.js +69 -0
  11. package/dist/groundwork.js +34 -0
  12. package/dist/kitresolve.js +79 -0
  13. package/dist/knowledge.js +72 -0
  14. package/dist/mcp.js +106 -0
  15. package/dist/notify.js +85 -0
  16. package/dist/provision.js +124 -0
  17. package/dist/runs.js +46 -0
  18. package/dist/seam.js +125 -0
  19. package/dist/seamwrite.js +87 -0
  20. package/dist/server.js +818 -0
  21. package/dist/skills.js +48 -0
  22. package/dist/tmux.js +36 -0
  23. package/dist/uploads.js +40 -0
  24. package/groundwork-console.rules.json +85 -0
  25. package/package.json +49 -0
  26. package/public/assets/abnfDiagram-N423BO3Z-DPhyKd1N.js +1 -0
  27. package/public/assets/arc-DmkLmHHi.js +1 -0
  28. package/public/assets/architecture-TIHT7OUA-MgcjoiPc.js +1 -0
  29. package/public/assets/architectureDiagram-T3A2C74G-BXFkjpze.js +36 -0
  30. package/public/assets/array-BifhSqXX.js +1 -0
  31. package/public/assets/blockDiagram-VBNYF7ZC-Ddhca5b4.js +132 -0
  32. package/public/assets/c4Diagram-5PPSVZJV-D4M2Oz2j.js +10 -0
  33. package/public/assets/channel-BAs2g7Wn.js +1 -0
  34. package/public/assets/chunk-2GRJ4B5K-B2cLnEJA.js +1 -0
  35. package/public/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
  36. package/public/assets/chunk-4I5QYGJK-CVuqmZe1.js +1 -0
  37. package/public/assets/chunk-5RXB4S5H-CAj33Qry.js +231 -0
  38. package/public/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
  39. package/public/assets/chunk-6Q2QTUOP-B6kTvnZS.js +88 -0
  40. package/public/assets/chunk-7BUUIJ7U-Bb538aSH.js +1 -0
  41. package/public/assets/chunk-7Z6QIM7H-BCYMaGkK.js +10 -0
  42. package/public/assets/chunk-GF5L2VYU-eAfQwP-A.js +206 -0
  43. package/public/assets/chunk-I66GZJ75-DyWmv43M.js +127 -0
  44. package/public/assets/chunk-JQJVKLGR-xpwVLHiM.js +156 -0
  45. package/public/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
  46. package/public/assets/chunk-KBJHAD2P-BsIw_3BM.js +1 -0
  47. package/public/assets/chunk-KEIR6QF5-BICK3FdT.js +161 -0
  48. package/public/assets/chunk-NSK5VX7P-Dy4p7ORp.js +2 -0
  49. package/public/assets/chunk-QR6OTTB3-D8k2NFkq.js +62 -0
  50. package/public/assets/chunk-RYQCIY6F-TbGMiTbW.js +1 -0
  51. package/public/assets/chunk-UBXNYLIW-By3VqDlw.js +1 -0
  52. package/public/assets/chunk-W5SLKNZC-B6TSWP8U.js +1 -0
  53. package/public/assets/chunk-WRU74C26-CqCOF3fo.js +70 -0
  54. package/public/assets/chunk-XXDRQBXY-B6BeKGFV.js +1 -0
  55. package/public/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
  56. package/public/assets/classDiagram-JCYQIIEL-D8vKmZUF.js +1 -0
  57. package/public/assets/classDiagram-v2-OCEON4UE-D8vKmZUF.js +1 -0
  58. package/public/assets/cose-bilkent-JH36ORCC-2ieLCSa1.js +1 -0
  59. package/public/assets/cynefin-VYW2F7L2-BfajhBFb.js +1 -0
  60. package/public/assets/cynefinDiagram-MW4NZA55-DZFY7WjS.js +62 -0
  61. package/public/assets/cytoscape.esm-C2x7inlt.js +321 -0
  62. package/public/assets/dagre-Buvkdvvj.js +1 -0
  63. package/public/assets/dagre-VZM6K2ZE-DECeuEL2.js +4 -0
  64. package/public/assets/defaultLocale-BFoDCU3G.js +1 -0
  65. package/public/assets/diagram-7IWD3JNH-DA6fCDep.js +30 -0
  66. package/public/assets/diagram-B4RE2ZJO-Dj8QoIQR.js +3 -0
  67. package/public/assets/diagram-LBJQPF4R-9JYAugOO.js +24 -0
  68. package/public/assets/diagram-Q27KOJAE-ecTfssa6.js +24 -0
  69. package/public/assets/diagram-UB23O5K3-DOGgwSDm.js +41 -0
  70. package/public/assets/dist-DTWyzWtG.js +1 -0
  71. package/public/assets/ebnfDiagram-BXEA7PRR-BGmWK80p.js +1 -0
  72. package/public/assets/erDiagram-JOGREHBK-CNl1QvhN.js +85 -0
  73. package/public/assets/eventmodeling-45OFAUF4-GcvHanur.js +1 -0
  74. package/public/assets/flowDiagram-UKHOOZJN-DdgmWP6g.js +1 -0
  75. package/public/assets/ganttDiagram-PKOTCBZU-C01y-MjT.js +292 -0
  76. package/public/assets/gitGraph-TEB2WS4Q-BW4zQmf5.js +1 -0
  77. package/public/assets/gitGraphDiagram-DS77QQ5N-CnlU6XMJ.js +106 -0
  78. package/public/assets/graphlib-DS17s2tU.js +1 -0
  79. package/public/assets/index-C3zhnM_H.css +2 -0
  80. package/public/assets/index-DrqxoBmk.js +40 -0
  81. package/public/assets/info-DKCQHKI2--A5cJC9V.js +1 -0
  82. package/public/assets/infoDiagram-6WML65LV-Cz2UOAMW.js +2 -0
  83. package/public/assets/init-C-OQMol4.js +1 -0
  84. package/public/assets/ishikawaDiagram-WSZJBQD7-B4Iqm47_.js +70 -0
  85. package/public/assets/journeyDiagram-NVQOT4AX-BU0js6EE.js +139 -0
  86. package/public/assets/kanban-definition-27J2QSJJ-DmeEPzz0.js +89 -0
  87. package/public/assets/katex-CXMH3UgJ.js +257 -0
  88. package/public/assets/line-Dxi6NubD.js +1 -0
  89. package/public/assets/linear-tama2Fqh.js +1 -0
  90. package/public/assets/map-BaFkSB1l.js +1 -0
  91. package/public/assets/mermaid-parser.core-bGhrBY9T.js +7 -0
  92. package/public/assets/mermaid.core-_OoTZaAK.js +42 -0
  93. package/public/assets/mindmap-definition-FAOFIHXS-BRJt4F9_.js +96 -0
  94. package/public/assets/ordinal-BDEzSJ7C.js +1 -0
  95. package/public/assets/packet-7NZHBO7P-DAZsca60.js +1 -0
  96. package/public/assets/path-fybaL0A-.js +1 -0
  97. package/public/assets/pegDiagram-VL7TDLO6-2k0rcz9N.js +1 -0
  98. package/public/assets/pie-RZYD4A2V-ojW1YX_G.js +1 -0
  99. package/public/assets/pieDiagram-7S7Q4E2Y-CrrciDrS.js +39 -0
  100. package/public/assets/quadrantDiagram-CIZ2JOQS-Dj5lMd95.js +7 -0
  101. package/public/assets/radar-I7S5WNFK-flsKqrK_.js +1 -0
  102. package/public/assets/railroad-3IZDKUUU-BX9H_OcC.js +1 -0
  103. package/public/assets/railroad-abnf-AHOZXSZD-DD8mz__c.js +1 -0
  104. package/public/assets/railroad-ebnf-EBAXGLYW-CWer5P7V.js +1 -0
  105. package/public/assets/railroad-peg-LSFZ7HO6-DDrRJYYw.js +1 -0
  106. package/public/assets/railroadDiagram-AXF67PYL-BRNOv6Sh.js +1 -0
  107. package/public/assets/requirementDiagram-LRYGKXZP-BqJbwH3b.js +84 -0
  108. package/public/assets/rough.esm-Dy-Kn_BL.js +1 -0
  109. package/public/assets/sankeyDiagram-W5VNT64P-BE7fRCAN.js +40 -0
  110. package/public/assets/sequenceDiagram-SI44F4Z6-Cwt-L1ko.js +162 -0
  111. package/public/assets/sizeCapture-X5ZJPWSS-B0uUizjq.js +1 -0
  112. package/public/assets/src-Bc2f8joo.js +1 -0
  113. package/public/assets/stateDiagram-OKZ733FA-etLHG0qi.js +1 -0
  114. package/public/assets/stateDiagram-v2-UEYNNEHI-Crgtg4pC.js +1 -0
  115. package/public/assets/swimlanes-SLNWSIFB-B06NxeYI.js +2 -0
  116. package/public/assets/swimlanesDiagram-ULZ7WXOC-C8S-XAyy.js +8 -0
  117. package/public/assets/timeline-definition-Z64GVDOM-BihNR1uq.js +120 -0
  118. package/public/assets/treeView-QDETBFTQ-CImTfOYf.js +1 -0
  119. package/public/assets/treemap-6X3UGDF4-DBRjbghn.js +1 -0
  120. package/public/assets/vennDiagram-T6HMQDX7-HcbmXJRd.js +34 -0
  121. package/public/assets/wardley-OPB4EBWU-xY5d-6YU.js +1 -0
  122. package/public/assets/wardleyDiagram-T6FBY63Y-B6KN3TYi.js +78 -0
  123. package/public/assets/xychartDiagram-ELKLHX3M-AAW8Pwrl.js +7 -0
  124. package/public/favicon.svg +1 -0
  125. package/public/fonts/JetBrainsMono-400.woff2 +0 -0
  126. package/public/fonts/JetBrainsMono-500.woff2 +0 -0
  127. package/public/fonts/JetBrainsMono-600.woff2 +0 -0
  128. package/public/fonts/SourceSans3-400.woff2 +0 -0
  129. package/public/fonts/SourceSans3-500.woff2 +0 -0
  130. package/public/fonts/SourceSans3-600.woff2 +0 -0
  131. package/public/fonts/SourceSans3-700.woff2 +0 -0
  132. package/public/fonts/SourceSerif4-600.woff2 +0 -0
  133. package/public/icons.svg +24 -0
  134. package/public/index.html +14 -0
package/dist/skills.js ADDED
@@ -0,0 +1,48 @@
1
+ /* Supplement to the CLIs' `list --json`: byte-compare installed SKILL.md with the kit source (in-sync signal the CLIs do not report). */
2
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
3
+ import { createHash } from "node:crypto";
4
+ import { homedir } from "node:os";
5
+ import path from "node:path";
6
+ const sha = (p) => (existsSync(p) ? createHash("sha1").update(readFileSync(p)).digest("hex").slice(0, 10) : null);
7
+ const dirs = (p) => (existsSync(p) ? readdirSync(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name) : []);
8
+ const front = (p) => { if (!existsSync(p))
9
+ 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
+ o[l.slice(0, i).trim()] = l.slice(i + 1).trim(); }); return o; };
11
+ 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");
14
+ const minimal = existsSync(pathsMjs) ? [...(readFileSync(pathsMjs, "utf8").match(/MINIMAL_SKILLS = \[([\s\S]*?)\]/)?.[1] ?? "").matchAll(/"([^"]+)"/g)].map((m) => m[1]) : [];
15
+ 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;
17
+ return {
18
+ versionMarker, kitVersion, driftedVersion: !!versionMarker && versionMarker !== kitVersion,
19
+ skills: dirs(payload).map((name) => {
20
+ const src = path.join(payload, name, "SKILL.md");
21
+ const inst = path.join(projectPath, ".claude/skills", name, "SKILL.md");
22
+ const installed = existsSync(inst);
23
+ const fm = front(src);
24
+ return {
25
+ name, tier: minimal.includes(name) ? "min" : "opt", installed, inSync: installed ? sha(src) === sha(inst) : null,
26
+ description: fm.description ?? "", readOnly: /read-only|ask/i.test(fm["allowed-tools"] ?? "") ? true : undefined,
27
+ mirrors: { cursor: existsSync(path.join(projectPath, ".cursor/commands", `${name}.md`)), vscode: existsSync(path.join(projectPath, ".vscode/prompts", `${name}.prompt.md`)) },
28
+ };
29
+ }),
30
+ };
31
+ }
32
+ /* Global playbook cards live in more than one harness home: Claude → ~/.claude/skills, Grok → ~/.grok/skills (+ ~/.grok/groundwork-playbook). Measure each. */
33
+ const HARNESS_HOMES = [["claude", path.join(homedir(), ".claude/skills")], ["grok", path.join(homedir(), ".grok/skills")]];
34
+ 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;
37
+ const homes = HARNESS_HOMES.filter(([, d]) => existsSync(d));
38
+ return {
39
+ kitVersion, globalDir: HARNESS_HOMES[0][1], homes: homes.map(([h, d]) => ({ harness: h, dir: d })),
40
+ cards: dirs(srcRoot).filter((n) => n !== "references").map((name) => {
41
+ const src = path.join(srcRoot, name, "SKILL.md");
42
+ const per = Object.fromEntries(homes.map(([h, d]) => { const inst = path.join(d, name, "SKILL.md"); const installed = existsSync(inst); const slices = existsSync(path.join(d, name, "references")) ? readdirSync(path.join(d, name, "references")).filter((f) => f.endsWith(".md")) : []; return [h, { installed, inSync: installed ? sha(src) === sha(inst) : null, slices: slices.length, legacyEssay: slices.includes("playbook.md") }]; }));
43
+ const claude = per.claude ?? { installed: false, inSync: null, slices: 0, legacyEssay: false };
44
+ return { name, installed: claude.installed, inSync: claude.inSync, slices: claude.slices, legacyEssay: claude.legacyEssay, homes: per, description: front(src).description ?? "", mirrors: { opencode: existsSync(path.join(homedir(), ".config/opencode/skills", name)), cursor: existsSync(path.join(homedir(), ".cursor/commands", `${name}.md`)), vscode: existsSync(path.join(homedir(), ".vscode/prompts", `${name}.prompt.md`)) } };
45
+ }),
46
+ legacyDirs: homes.flatMap(([h, d]) => ["coord-curator", "coord-liaison"].filter((n) => existsSync(path.join(d, n))).map((n) => `${h}:${n}`)),
47
+ };
48
+ }
package/dist/tmux.js ADDED
@@ -0,0 +1,36 @@
1
+ /* Read-only tmux views: pane activity (for liveness + activity indicators) and pane capture (for the pane viewer). Never sends keys. */
2
+ import { execFile } from "node:child_process";
3
+ import { promisify } from "node:util";
4
+ const run = promisify(execFile);
5
+ let cache = { at: 0, panes: [] };
6
+ export async function listPanes(ttlMs = 3_000) {
7
+ if (Date.now() - cache.at < ttlMs)
8
+ return cache.panes;
9
+ try {
10
+ const { stdout } = await run("tmux", ["list-panes", "-a", "-F", "#{pane_id}\t#{session_name}:#{window_index}.#{pane_index}\t#{window_activity}\t#{pane_current_command}\t#{pane_dead}"], { timeout: 3_000 });
11
+ cache = { at: Date.now(), panes: stdout.split("\n").filter(Boolean).map((l) => { const [paneId, target, act, command, dead] = l.split("\t"); return { paneId, target, activityTs: Number(act) * 1000, command, dead: dead === "1" }; }) };
12
+ }
13
+ catch {
14
+ cache = { at: Date.now(), panes: [] };
15
+ }
16
+ return cache.panes;
17
+ }
18
+ export async function paneActivity(paneId) { if (!paneId)
19
+ return null; return (await listPanes()).find((p) => p.paneId === paneId || p.target === paneId) ?? null; }
20
+ const ANSI = /\x1b\[[0-9;?]*[ -/]*[@-~]/g;
21
+ export async function capturePane(paneId, lines = 200, colors = false) {
22
+ const panes = await listPanes(0);
23
+ const p = panes.find((x) => x.paneId === paneId || x.target === paneId);
24
+ if (!p)
25
+ return null;
26
+ try {
27
+ const args = ["capture-pane", "-p", "-t", p.paneId, "-S", `-${Math.min(Math.max(lines, 20), 2000)}`, "-J", ...(colors ? ["-e"] : [])];
28
+ const { stdout } = await run("tmux", args, { timeout: 3_000, maxBuffer: 4 << 20 });
29
+ const raw = stdout.replace(/\s+$/gm, "").replace(/\n{3,}/g, "\n\n").trimEnd();
30
+ const text = raw.replace(ANSI, "");
31
+ return { text, ...(colors ? { ansi: raw } : {}), lines: text.split("\n").length, capturedAt: Date.now() };
32
+ }
33
+ catch {
34
+ return null;
35
+ }
36
+ }
@@ -0,0 +1,40 @@
1
+ import { createHash } from "node:crypto";
2
+ import { existsSync, mkdirSync, readdirSync, statSync, writeFileSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import path from "node:path";
5
+ /* Pasted/dropped images for DMs. Console-owned store: ~/.groundwork-console/uploads/<date>-<sha8>.<ext>.
6
+ Agents on this machine read the PATH directly (Claude Code `Read`, grok, codex all take image files);
7
+ the same file is also served at /api/uploads/<name> for HTTP-node agents and for inline thumbnails in the console. */
8
+ export const UPLOAD_DIR = process.env.GROUNDWORK_CONSOLE_UPLOADS ?? path.join(homedir(), ".groundwork-console", "uploads");
9
+ const MAX_BYTES = 8 * 1024 * 1024;
10
+ const EXT = { "image/png": "png", "image/jpeg": "jpg", "image/gif": "gif", "image/webp": "webp", "image/svg+xml": "svg" };
11
+ export const NAME_RE = /^[\w.-]+\.(png|jpe?g|gif|webp|svg)$/i;
12
+ /** Save an image; idempotent by content hash. `ref` is the token to put in the message text. */
13
+ export function saveUpload(buf, mime, apiBase, date) {
14
+ const ext = EXT[mime];
15
+ if (!ext)
16
+ throw new Error(`unsupported type ${mime} (png/jpg/gif/webp/svg)`);
17
+ if (buf.byteLength > MAX_BYTES)
18
+ throw new Error(`too large (${Math.round(buf.byteLength / 1024)} KB > ${MAX_BYTES / 1024 / 1024} MB)`);
19
+ if (buf.byteLength === 0)
20
+ throw new Error("empty file");
21
+ mkdirSync(UPLOAD_DIR, { recursive: true });
22
+ const sha = createHash("sha256").update(buf).digest("hex").slice(0, 8);
23
+ const existing = readdirSync(UPLOAD_DIR).find((n) => n.endsWith(`-${sha}.${ext}`));
24
+ const name = existing ?? `${date}-${sha}.${ext}`;
25
+ const p = path.join(UPLOAD_DIR, name);
26
+ if (!existing)
27
+ writeFileSync(p, buf);
28
+ const url = `${apiBase}/uploads/${name}`;
29
+ return { name, path: p, url, bytes: buf.byteLength, mime, ref: `[image: ${p} · ${url}]` };
30
+ }
31
+ export function uploadPath(name) {
32
+ if (!NAME_RE.test(name))
33
+ return null;
34
+ const p = path.join(UPLOAD_DIR, name);
35
+ if (!existsSync(p))
36
+ return null;
37
+ const ext = name.split(".").pop().toLowerCase();
38
+ const mime = Object.entries(EXT).find(([, e]) => e === ext || (e === "jpg" && ext === "jpeg"))?.[0] ?? "application/octet-stream";
39
+ return { path: p, mime, bytes: statSync(p).size };
40
+ }
@@ -0,0 +1,85 @@
1
+ {
2
+ "$comment": "Event \u2192 action rules. Actions fire ONLY when: bus writes are on (header switch) AND dryRun is false AND the rule is enabled. Every send is a Run as groundwork-console (automation). Dedupe by event key (persisted), rate-limited per rule+project. The console never edits seam files.",
3
+ "identity": {
4
+ "roleId": "automation",
5
+ "displayName": "groundwork-console",
6
+ "transport": null,
7
+ "$comment": "AUTOMATION_ROLE_IDS in kit roles.ts/hooks/roles.mjs; not gate-runner, not ci, RECORD_AUTHORITY empty (cannot emit verdict/go/scope). Registers with no transport (send-only)."
8
+ },
9
+ "dryRun": true,
10
+ "rules": [
11
+ {
12
+ "id": "phase-complete-audit",
13
+ "on": "phase.completed",
14
+ "action": {
15
+ "type": "send_message",
16
+ "to": "coordinator",
17
+ "prefix": "AGENT_ACTION",
18
+ "text": "phase {phase} complete in {project} ({done}/{total}). Per playbook \u00a7Phase Boundaries: handover snapshots \u2192 /coord-audit \u2192 /clear workers switching lanes, before starting the next phase."
19
+ },
20
+ "enabled": false,
21
+ "key": "{project}:{phase}"
22
+ },
23
+ {
24
+ "id": "phase-started-brief",
25
+ "on": "phase.started",
26
+ "action": {
27
+ "type": "send_message",
28
+ "room": "{room}",
29
+ "prefix": "FYI",
30
+ "text": "phase {phase} started in {project} \u2014 first task checked ({done}/{total})."
31
+ },
32
+ "enabled": false,
33
+ "key": "{project}:{phase}"
34
+ },
35
+ {
36
+ "id": "fact-stale-nudge",
37
+ "on": "fact.stale",
38
+ "action": {
39
+ "type": "send_message",
40
+ "to": "{owner}",
41
+ "prefix": "FYI",
42
+ "text": "fact `{fact}` in {project} is {ageDays} d old (> 14) \u2014 re-verify or delete (set-fact)."
43
+ },
44
+ "enabled": false,
45
+ "key": "{project}:{fact}"
46
+ },
47
+ {
48
+ "id": "malformed-row-alert",
49
+ "on": "board.malformed",
50
+ "action": {
51
+ "type": "send_message",
52
+ "to": "coordinator",
53
+ "prefix": "RISK",
54
+ "text": "docs/WORKSTREAMS.md in {project} has {count} malformed row(s) \u2014 parser refused them; fix the table (line {line})."
55
+ },
56
+ "enabled": false,
57
+ "key": "{project}:{line}"
58
+ },
59
+ {
60
+ "id": "decision-open",
61
+ "on": "decision.posted",
62
+ "action": {
63
+ "type": "none",
64
+ "note": "surface in Needs David; David answers, not automation"
65
+ },
66
+ "enabled": false,
67
+ "key": "{project}:{id}"
68
+ },
69
+ {
70
+ "id": "done-appended",
71
+ "on": "done.appended",
72
+ "action": {
73
+ "type": "none",
74
+ "note": "telemetry only"
75
+ },
76
+ "enabled": false,
77
+ "key": "{project}:{count}"
78
+ }
79
+ ],
80
+ "limits": {
81
+ "maxPerRulePerProjectPerHour": 3,
82
+ "dedupeTtlHours": 72
83
+ },
84
+ "stateFile": "~/.groundwork-console/events-state.json"
85
+ }
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@davidbalzan/groundwork-console",
3
+ "private": false,
4
+ "version": "0.1.0",
5
+ "type": "module",
6
+ "dependencies": {
7
+ "@davidbalzan/groundwork-seam": "^0.1.0",
8
+ "@hono/node-server": "^2.1.1",
9
+ "@modelcontextprotocol/sdk": "^1.30.0",
10
+ "hono": "^4.13.2",
11
+ "open": "^11.0.1"
12
+ },
13
+ "devDependencies": {
14
+ "@types/node": "^26.2.0",
15
+ "tsx": "^4.23.12",
16
+ "typescript": "^7.0.2"
17
+ },
18
+ "description": "Groundwork Console — the cockpit for Groundwork Kit fleets: board, bus, monitor, docs, ops. One local server, token auth, tmux-aware.",
19
+ "license": "MIT",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/davidbalzan/groundwork-console.git"
23
+ },
24
+ "bin": {
25
+ "groundwork-console": "bin/groundwork-console.mjs",
26
+ "gwc": "bin/groundwork-console.mjs"
27
+ },
28
+ "files": [
29
+ "dist",
30
+ "public",
31
+ "bin",
32
+ "groundwork-console.rules.json",
33
+ "README.md"
34
+ ],
35
+ "engines": {
36
+ "node": ">=22"
37
+ },
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
41
+ "scripts": {
42
+ "dev": "tsx watch src/server.ts",
43
+ "build": "tsc -p tsconfig.json",
44
+ "build:web": "pnpm --filter @groundwork-console/web build && rm -rf public && cp -R ../web/dist public",
45
+ "typecheck": "tsc -p tsconfig.json --noEmit",
46
+ "start": "node bin/groundwork-console.mjs",
47
+ "publish-check": "node scripts/publish-check.mjs"
48
+ }
49
+ }
@@ -0,0 +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};
@@ -0,0 +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};
@@ -0,0 +1 @@
1
+ import"./chunk-KEIR6QF5-BICK3FdT.js";import{M as e}from"./mermaid-parser.core-bGhrBY9T.js";export{e as createArchitectureServices};