@davidbalzan/groundwork-console 0.1.11 → 0.1.12
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/LICENSE +19 -0
- package/dist/panes.js +86 -0
- package/dist/provision.js +47 -7
- package/dist/seam.js +8 -1
- package/package.json +7 -4
- package/public/assets/{abnfDiagram-N423BO3Z-SmC0YbkZ.js → abnfDiagram-N423BO3Z-C7_Zpec2.js} +1 -1
- package/public/assets/{arc-Bwss940w.js → arc-Bbq8pKhn.js} +1 -1
- package/public/assets/architecture-TIHT7OUA-CJFVglth.js +1 -0
- package/public/assets/{architectureDiagram-T3A2C74G-Cq88dj_x.js → architectureDiagram-T3A2C74G-tEkFMAHO.js} +1 -1
- package/public/assets/{blockDiagram-VBNYF7ZC-Cr4QI7D6.js → blockDiagram-VBNYF7ZC-CZNrU4_z.js} +1 -1
- package/public/assets/{c4Diagram-5PPSVZJV-C1C4eJIx.js → c4Diagram-5PPSVZJV-D1-T-b--.js} +1 -1
- package/public/assets/channel-ClF6sQKu.js +1 -0
- package/public/assets/{chunk-2GRJ4B5K-Cpp7ECx6.js → chunk-2GRJ4B5K-DMzvnmxY.js} +1 -1
- package/public/assets/{chunk-4I5QYGJK-Bps2fbU8.js → chunk-4I5QYGJK-D03m5a1e.js} +1 -1
- package/public/assets/{chunk-5RXB4S5H-3UxSwRGQ.js → chunk-5RXB4S5H-B5SxHfnz.js} +1 -1
- package/public/assets/{chunk-6Q2QTUOP-zawcmdf9.js → chunk-6Q2QTUOP-BQYOf-YY.js} +1 -1
- package/public/assets/{chunk-7Z6QIM7H-Dc0octNy.js → chunk-7Z6QIM7H-DGtHjZJL.js} +1 -1
- package/public/assets/{chunk-GF5L2VYU-RHui1NJm.js → chunk-GF5L2VYU-6_YTDzGo.js} +1 -1
- package/public/assets/{chunk-I66GZJ75-BlHb3oSv.js → chunk-I66GZJ75-CfWGFqqO.js} +1 -1
- package/public/assets/{chunk-JQJVKLGR-WIlvhJ6X.js → chunk-JQJVKLGR-DrCjH1AL.js} +1 -1
- package/public/assets/{chunk-KBJHAD2P-Dr1rLwdT.js → chunk-KBJHAD2P-DovMVsOt.js} +1 -1
- package/public/assets/{chunk-NSK5VX7P-B07rzjwZ.js → chunk-NSK5VX7P-qSMdOab2.js} +1 -1
- package/public/assets/{chunk-QR6OTTB3-ComyizSZ.js → chunk-QR6OTTB3-Iraem5u-.js} +1 -1
- package/public/assets/{chunk-RYQCIY6F-k_etiI3Q.js → chunk-RYQCIY6F-8rrSNAgX.js} +1 -1
- package/public/assets/{chunk-UBXNYLIW-DldfSHAq.js → chunk-UBXNYLIW-CyzK1RD5.js} +1 -1
- package/public/assets/{chunk-W5SLKNZC-Dn5B1pXH.js → chunk-W5SLKNZC-BVK4MUw1.js} +1 -1
- package/public/assets/{chunk-WRU74C26-D34jYzyt.js → chunk-WRU74C26-C_K_UiUW.js} +1 -1
- package/public/assets/{chunk-XXDRQBXY-BQXENxTm.js → chunk-XXDRQBXY-0nuSRCEm.js} +1 -1
- package/public/assets/classDiagram-JCYQIIEL-z-TVRcqJ.js +1 -0
- package/public/assets/classDiagram-v2-OCEON4UE-z-TVRcqJ.js +1 -0
- package/public/assets/{cose-bilkent-JH36ORCC-CPGou1DN.js → cose-bilkent-JH36ORCC-R9H6hDjY.js} +1 -1
- package/public/assets/{cynefin-VYW2F7L2-DOI3jeNv.js → cynefin-VYW2F7L2-DnWlTifu.js} +1 -1
- package/public/assets/{cynefinDiagram-MW4NZA55-DoW8nM2s.js → cynefinDiagram-MW4NZA55-B-7owUyc.js} +1 -1
- package/public/assets/{dagre-VZM6K2ZE-Dq8ZHjT7.js → dagre-VZM6K2ZE-B3ZoPe5S.js} +1 -1
- package/public/assets/{diagram-7IWD3JNH-3FSn8Agr.js → diagram-7IWD3JNH-BI26fzwd.js} +1 -1
- package/public/assets/{diagram-B4RE2ZJO-BnXqbr3I.js → diagram-B4RE2ZJO-BiSCmkOd.js} +1 -1
- package/public/assets/{diagram-LBJQPF4R-B9WLcX1P.js → diagram-LBJQPF4R-BQ35r2wn.js} +1 -1
- package/public/assets/{diagram-Q27KOJAE-Cqc0NnFi.js → diagram-Q27KOJAE-258JzS88.js} +1 -1
- package/public/assets/{diagram-UB23O5K3-D3DVcxz0.js → diagram-UB23O5K3-BQLuDWQ5.js} +1 -1
- package/public/assets/{dist-D9Nkbm8B.js → dist-BhEZ2d35.js} +1 -1
- package/public/assets/{ebnfDiagram-BXEA7PRR-FHf_rewb.js → ebnfDiagram-BXEA7PRR-D6cGU6FA.js} +1 -1
- package/public/assets/{erDiagram-JOGREHBK-CvPTNoqX.js → erDiagram-JOGREHBK-x-fYPfbp.js} +1 -1
- package/public/assets/eventmodeling-45OFAUF4-CsZX8d8q.js +1 -0
- package/public/assets/flowDiagram-UKHOOZJN-B-BoRx9A.js +1 -0
- package/public/assets/{ganttDiagram-PKOTCBZU-DWUBSW9B.js → ganttDiagram-PKOTCBZU-B44E_1OW.js} +1 -1
- package/public/assets/{gitGraph-TEB2WS4Q-CjymOfrj.js → gitGraph-TEB2WS4Q-B_J5fmci.js} +1 -1
- package/public/assets/{gitGraphDiagram-DS77QQ5N-BZa0uJBE.js → gitGraphDiagram-DS77QQ5N-oi1EtSGf.js} +1 -1
- package/public/assets/{index-CS6PrVvt.js → index-D4kIibeU.js} +3 -3
- package/public/assets/{info-DKCQHKI2-DugyQgAo.js → info-DKCQHKI2-CvqAVyoT.js} +1 -1
- package/public/assets/{infoDiagram-6WML65LV-DGlBHx3m.js → infoDiagram-6WML65LV-BroSi0D-.js} +1 -1
- package/public/assets/{ishikawaDiagram-WSZJBQD7-BbqOG9Eg.js → ishikawaDiagram-WSZJBQD7-BRQ47rb2.js} +1 -1
- package/public/assets/{journeyDiagram-NVQOT4AX-Du3qH9mS.js → journeyDiagram-NVQOT4AX-DB6Xo-9Q.js} +1 -1
- package/public/assets/{kanban-definition-27J2QSJJ-CdVgOFzk.js → kanban-definition-27J2QSJJ-BBzsco6z.js} +1 -1
- package/public/assets/{line-CvLqalqu.js → line-m55PflQc.js} +1 -1
- package/public/assets/{linear-ChXKEHCZ.js → linear-Dgtz6Nrl.js} +1 -1
- package/public/assets/{mermaid-parser.core-C7RowpcN.js → mermaid-parser.core-B98Rk-oq.js} +3 -3
- package/public/assets/{mermaid.core-U0Q7d-gI.js → mermaid.core-CqRCrVqJ.js} +4 -4
- package/public/assets/{mindmap-definition-FAOFIHXS-Dd8IqZN3.js → mindmap-definition-FAOFIHXS-BPP33G4r.js} +1 -1
- package/public/assets/{packet-7NZHBO7P-rnlOmuHK.js → packet-7NZHBO7P-tO4S6ouz.js} +1 -1
- package/public/assets/{pegDiagram-VL7TDLO6-C61XZFPE.js → pegDiagram-VL7TDLO6-Bw6mp9l7.js} +1 -1
- package/public/assets/{pie-RZYD4A2V-BosRLnUR.js → pie-RZYD4A2V-C437Vvln.js} +1 -1
- package/public/assets/{pieDiagram-7S7Q4E2Y-C066dHaW.js → pieDiagram-7S7Q4E2Y-CBxtUqZy.js} +1 -1
- package/public/assets/{quadrantDiagram-CIZ2JOQS-BiL2JG5p.js → quadrantDiagram-CIZ2JOQS-Bqsvmpf9.js} +1 -1
- package/public/assets/{radar-I7S5WNFK-VRvamsSS.js → radar-I7S5WNFK-C6dNsRn9.js} +1 -1
- package/public/assets/{railroad-3IZDKUUU-_8QphIQF.js → railroad-3IZDKUUU-KaVebqGG.js} +1 -1
- package/public/assets/railroad-abnf-AHOZXSZD-vLN4fXap.js +1 -0
- package/public/assets/railroad-ebnf-EBAXGLYW-B70X8CrM.js +1 -0
- package/public/assets/railroad-peg-LSFZ7HO6-DXKtxJxs.js +1 -0
- package/public/assets/{railroadDiagram-AXF67PYL-BO0K2FSG.js → railroadDiagram-AXF67PYL-DKq4X6Uj.js} +1 -1
- package/public/assets/{requirementDiagram-LRYGKXZP-Cs5N-_5S.js → requirementDiagram-LRYGKXZP-B9fsvyjq.js} +1 -1
- package/public/assets/{sankeyDiagram-W5VNT64P-BBadz3Xa.js → sankeyDiagram-W5VNT64P-BsfVDMI2.js} +1 -1
- package/public/assets/{sequenceDiagram-SI44F4Z6-B1wwHKdi.js → sequenceDiagram-SI44F4Z6-OgERYEKg.js} +1 -1
- package/public/assets/{src-rNJ0obFg.js → src-fnYA6irH.js} +1 -1
- package/public/assets/{stateDiagram-OKZ733FA-D2BPoAkk.js → stateDiagram-OKZ733FA-CQbkYnuQ.js} +1 -1
- package/public/assets/stateDiagram-v2-UEYNNEHI-BDBAarNU.js +1 -0
- package/public/assets/{swimlanes-SLNWSIFB-CJw_VUg-.js → swimlanes-SLNWSIFB-Bjko0riO.js} +1 -1
- package/public/assets/swimlanesDiagram-ULZ7WXOC-BhW0icZR.js +8 -0
- package/public/assets/{timeline-definition-Z64GVDOM-8uI7Mh2Y.js → timeline-definition-Z64GVDOM-yK0hLw8V.js} +1 -1
- package/public/assets/{treeView-QDETBFTQ-DX9MBPTO.js → treeView-QDETBFTQ-BGpcfDZf.js} +1 -1
- package/public/assets/{treemap-6X3UGDF4-DqOdI7Cz.js → treemap-6X3UGDF4-QT7YcofM.js} +1 -1
- package/public/assets/{vennDiagram-T6HMQDX7-Dv3hlyhI.js → vennDiagram-T6HMQDX7-BuWvWEXb.js} +1 -1
- package/public/assets/{wardley-OPB4EBWU-BlsdtYE0.js → wardley-OPB4EBWU-hYpU_cIv.js} +1 -1
- package/public/assets/{wardleyDiagram-T6FBY63Y-8UP_r-p8.js → wardleyDiagram-T6FBY63Y-CgKHf2Kc.js} +1 -1
- package/public/assets/{xychartDiagram-ELKLHX3M-CqKePl1c.js → xychartDiagram-ELKLHX3M-CoNyQg1m.js} +1 -1
- package/public/index.html +1 -1
- package/public/assets/architecture-TIHT7OUA-DxbIc2EO.js +0 -1
- package/public/assets/channel-q2MiI2jw.js +0 -1
- package/public/assets/classDiagram-JCYQIIEL-BBCC64Pk.js +0 -1
- package/public/assets/classDiagram-v2-OCEON4UE-BBCC64Pk.js +0 -1
- package/public/assets/eventmodeling-45OFAUF4-B3k39kpe.js +0 -1
- package/public/assets/flowDiagram-UKHOOZJN-J20LnFn0.js +0 -1
- package/public/assets/railroad-abnf-AHOZXSZD-ySvBeK5p.js +0 -1
- package/public/assets/railroad-ebnf-EBAXGLYW-B08LkBeL.js +0 -1
- package/public/assets/railroad-peg-LSFZ7HO6-CnEVYMxD.js +0 -1
- package/public/assets/stateDiagram-v2-UEYNNEHI-CsMDmX-c.js +0 -1
- package/public/assets/swimlanesDiagram-ULZ7WXOC-D83SR1DB.js +0 -8
package/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2026 David Balzan
|
|
2
|
+
|
|
3
|
+
All rights reserved.
|
|
4
|
+
|
|
5
|
+
This software and its accompanying files are proprietary. No licence is
|
|
6
|
+
granted to use, copy, modify, merge, publish, distribute, sublicense, or sell
|
|
7
|
+
copies of this software, in whole or in part, except by a separate written
|
|
8
|
+
agreement signed by the copyright holder.
|
|
9
|
+
|
|
10
|
+
Possession of these files — including by download from a public package
|
|
11
|
+
registry — does not constitute such an agreement and grants no rights.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
SOFTWARE.
|
package/dist/panes.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/* Which tmux panes this console created.
|
|
2
|
+
*
|
|
3
|
+
* Window reuse used to be decided from `#{pane_title}`: every title in the window
|
|
4
|
+
* had to start with `<project>-`. The console DOES set those titles at spawn — and
|
|
5
|
+
* then the harness overwrites them with the conversation topic, so the check was
|
|
6
|
+
* correct for about a minute after a spawn and wrong forever after. Measured
|
|
7
|
+
* 2026-08-27: all three `groundwork-kit-*` windows on this machine were refused
|
|
8
|
+
* with intact, correct window names, and David hand-spawned three times.
|
|
9
|
+
*
|
|
10
|
+
* The fix is not a better title pattern. `pane_title` is a field ANOTHER PROGRAM
|
|
11
|
+
* owns; any regex over it is a guess about that program's output, and the next
|
|
12
|
+
* harness release changes the answer. This module records the pane ids the console
|
|
13
|
+
* itself created — identity it controls and the harness cannot touch.
|
|
14
|
+
*
|
|
15
|
+
* Pane ids are unique within a tmux server but RESET when the server restarts, so a
|
|
16
|
+
* stale id could collide with an unrelated new pane. The store records the server's
|
|
17
|
+
* pid and is discarded wholesale when it changes; a wrong-server record is worth
|
|
18
|
+
* less than no record.
|
|
19
|
+
*/
|
|
20
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
21
|
+
import { homedir } from "node:os";
|
|
22
|
+
import path from "node:path";
|
|
23
|
+
const FILE = path.join(homedir(), ".groundwork-console", "panes.json");
|
|
24
|
+
function load(serverPid) {
|
|
25
|
+
try {
|
|
26
|
+
if (existsSync(FILE)) {
|
|
27
|
+
const j = JSON.parse(readFileSync(FILE, "utf8"));
|
|
28
|
+
// A server restart resets pane ids; keeping the old map would let a recycled
|
|
29
|
+
// id read as ours. Drop it rather than carry a record we cannot trust.
|
|
30
|
+
if (j && j.serverPid === serverPid && j.owned)
|
|
31
|
+
return j;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
/* unreadable store: treat as empty — never as "everything is ours" */
|
|
36
|
+
}
|
|
37
|
+
return { serverPid, owned: {} };
|
|
38
|
+
}
|
|
39
|
+
function save(s) {
|
|
40
|
+
try {
|
|
41
|
+
mkdirSync(path.dirname(FILE), { recursive: true });
|
|
42
|
+
writeFileSync(FILE, JSON.stringify(s));
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
/* disk unavailable: ownership degrades to "unknown", which REFUSES reuse.
|
|
46
|
+
That is the safe direction — it costs a manual spawn, not an adopted window. */
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** Record a pane this console just created for `project`. */
|
|
50
|
+
export function rememberPane(serverPid, project, paneId) {
|
|
51
|
+
const s = load(serverPid);
|
|
52
|
+
const list = s.owned[project] ?? [];
|
|
53
|
+
if (!list.includes(paneId))
|
|
54
|
+
list.push(paneId);
|
|
55
|
+
s.owned[project] = list;
|
|
56
|
+
save(s);
|
|
57
|
+
}
|
|
58
|
+
/** Forget panes that no longer exist, so the store does not grow without bound. */
|
|
59
|
+
export function prunePanes(serverPid, alive) {
|
|
60
|
+
const s = load(serverPid);
|
|
61
|
+
let changed = false;
|
|
62
|
+
for (const [proj, ids] of Object.entries(s.owned)) {
|
|
63
|
+
const keep = ids.filter((id) => alive.has(id));
|
|
64
|
+
if (keep.length !== ids.length) {
|
|
65
|
+
changed = true;
|
|
66
|
+
if (keep.length)
|
|
67
|
+
s.owned[proj] = keep;
|
|
68
|
+
else
|
|
69
|
+
delete s.owned[proj];
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (changed)
|
|
73
|
+
save(s);
|
|
74
|
+
}
|
|
75
|
+
export function ownedPanes(serverPid, project) {
|
|
76
|
+
return new Set(load(serverPid).owned[project] ?? []);
|
|
77
|
+
}
|
|
78
|
+
/** Every pane id this console owns, across all projects — used to tell "another
|
|
79
|
+
fleet's pane" (a real collision) from "a pane nobody here created". */
|
|
80
|
+
export function allOwnedPanes(serverPid) {
|
|
81
|
+
const out = new Map();
|
|
82
|
+
for (const [proj, ids] of Object.entries(load(serverPid).owned))
|
|
83
|
+
for (const id of ids)
|
|
84
|
+
out.set(id, proj);
|
|
85
|
+
return out;
|
|
86
|
+
}
|
package/dist/provision.js
CHANGED
|
@@ -9,6 +9,7 @@ import { execFile } from "node:child_process";
|
|
|
9
9
|
import { promisify } from "node:util";
|
|
10
10
|
import { existsSync, readFileSync } from "node:fs";
|
|
11
11
|
import path from "node:path";
|
|
12
|
+
import { rememberPane, prunePanes, ownedPanes, allOwnedPanes } from "./panes.js";
|
|
12
13
|
const run = promisify(execFile);
|
|
13
14
|
const tmux = async (...args) => (await run("tmux", args, { timeout: 8_000 })).stdout.trim();
|
|
14
15
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
@@ -18,17 +19,52 @@ export const ROLE_COLOR = { coordinator: "green", aide: "pink", qa: "yellow", ci
|
|
|
18
19
|
const CLAUDE_HARNESS_ONLY = new Set(["claude"]); // /color and slash-skills are Claude Code; other harnesses get the skill text as a plain instruction
|
|
19
20
|
/** Window name for a role: workers share one window, singleton roles get their own (exact scheme `<project>-<role>` / `<project>-workers` — cross-fleet contract, no owner infix). */
|
|
20
21
|
export const roleWindowName = (project, role) => (role === "worker" ? `${project}-workers` : `${project}-${role}`);
|
|
22
|
+
/** Refusal reason for reusing a window, or null when it is ours.
|
|
23
|
+
*
|
|
24
|
+
* Pure so both directions are testable without tmux — and the second direction is the
|
|
25
|
+
* one that must not regress: a window we do NOT own stays refused. Ownership is pane
|
|
26
|
+
* ids the console created; `#{pane_title}` is deliberately not an input, because the
|
|
27
|
+
* harness rewrites it with the conversation topic and any pattern over it is a guess
|
|
28
|
+
* about another program's output. */
|
|
29
|
+
export function windowOwnership(a) {
|
|
30
|
+
const foreign = a.paneIds.filter((id) => !a.mine.has(id));
|
|
31
|
+
if (!foreign.length)
|
|
32
|
+
return null;
|
|
33
|
+
// Distinguish the two cases: the remedies differ, and the old message prescribed the
|
|
34
|
+
// wrong one — it said "rename or close it" when the window NAME was already correct,
|
|
35
|
+
// sending a reader to rename a correctly-named window.
|
|
36
|
+
const otherFleet = foreign.map((id) => a.everyone.get(id)).find((p) => p && p !== a.project);
|
|
37
|
+
if (otherFleet) {
|
|
38
|
+
return `window "${a.win}" (${a.target}) holds pane(s) this console created for project "${otherFleet}" — a real name collision. Close that window, or spawn under a different project name.`;
|
|
39
|
+
}
|
|
40
|
+
return (`window "${a.win}" (${a.target}) exists but this console did not create pane(s) ${foreign.join(", ")}, so it cannot claim them. ` +
|
|
41
|
+
`The window NAME is correct — do NOT rename it. Close the window (tmux kill-window -t ${a.target}) and respawn, or close just those panes. ` +
|
|
42
|
+
`Ownership is tracked by pane id, not by pane title: a title that reads like a conversation topic is expected and is not the problem.`);
|
|
43
|
+
}
|
|
21
44
|
async function roleWindow(project, role, startDir, log) {
|
|
22
45
|
const win = roleWindowName(project, role);
|
|
23
46
|
const wins = (await tmux("list-windows", "-a", "-F", "#{session_name}:#{window_index}\t#{window_name}")).split("\n").filter(Boolean).map((l) => l.split("\t"));
|
|
24
47
|
const hit = wins.find(([, name]) => name === win);
|
|
25
48
|
if (hit) {
|
|
26
|
-
// Ownership check before reuse
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
49
|
+
// Ownership check before reuse. The requirement is unchanged (contract amendment
|
|
50
|
+
// 11:46): a name-collision with panes we did not create is REFUSED, never adopted.
|
|
51
|
+
// What changed is the EVIDENCE. This read `#{pane_title}` and required every title
|
|
52
|
+
// to start with `<project>-`; the console does set those titles at spawn and the
|
|
53
|
+
// harness then overwrites them with the conversation topic, so the check was right
|
|
54
|
+
// for about a minute and wrong afterwards — measured 2026-08-27, all three
|
|
55
|
+
// groundwork-kit windows refused with intact window names.
|
|
56
|
+
//
|
|
57
|
+
// Titles are a field another program owns; a better regex over them is a guess
|
|
58
|
+
// about that program's output. Ownership is now the pane ids the console itself
|
|
59
|
+
// created (./panes.ts), which the harness cannot touch.
|
|
60
|
+
const serverPid = await tmux("display-message", "-p", "#{pid}");
|
|
61
|
+
const paneIds = (await tmux("list-panes", "-t", hit[0], "-F", "#{pane_id}")).split("\n").filter(Boolean);
|
|
62
|
+
prunePanes(serverPid, new Set((await tmux("list-panes", "-a", "-F", "#{pane_id}")).split("\n").filter(Boolean)));
|
|
63
|
+
const mine = ownedPanes(serverPid, project);
|
|
64
|
+
const everyone = allOwnedPanes(serverPid);
|
|
65
|
+
const verdict = windowOwnership({ win, target: hit[0], project, paneIds, mine, everyone });
|
|
66
|
+
if (verdict)
|
|
67
|
+
throw new Error(verdict);
|
|
32
68
|
log(`window ${win} exists (${hit[0]}) — ${role === "worker" ? "splitting another worker pane into it" : `reusing for a second ${role} spawn (split)`}`);
|
|
33
69
|
return { target: hit[0], freshPane: null };
|
|
34
70
|
}
|
|
@@ -74,7 +110,11 @@ export async function spawnAgent(req, isRegistered, log, isAttached = () => true
|
|
|
74
110
|
if (!freshPane)
|
|
75
111
|
await tmux("select-layout", "-t", target, "tiled");
|
|
76
112
|
await tmux("select-pane", "-t", paneId, "-T", req.agentId);
|
|
77
|
-
|
|
113
|
+
// Record the pane as ours BEFORE anything can fail below: ownership is about who
|
|
114
|
+
// created it, not whether the launch succeeded. A pane we made and then abandoned
|
|
115
|
+
// is still ours to reuse, and forgetting it is what blocks the window forever.
|
|
116
|
+
rememberPane(await tmux("display-message", "-p", "#{pid}"), req.project, paneId);
|
|
117
|
+
log(`pane ${paneId} in ${target} (cwd ${req.repoPath}), title ${req.agentId} (recorded as owned; title is cosmetic)`);
|
|
78
118
|
const cmd = HARNESS_CMD[req.harness];
|
|
79
119
|
await tmux("send-keys", "-t", paneId, "-l", cmd);
|
|
80
120
|
await tmux("send-keys", "-t", paneId, "C-m");
|
package/dist/seam.js
CHANGED
|
@@ -13,7 +13,14 @@ 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
|
-
|
|
16
|
+
/* Read the schema off the Active Streams BLOCK, not off its rows. A board with a valid
|
|
17
|
+
workstreams.v1 header and zero streams yields zero rows, and deriving the schema from
|
|
18
|
+
rows made "no work in flight" indistinguishable from "grammar not recognised" — the
|
|
19
|
+
console then rendered the alarming one. Only the two board grammars count here; the
|
|
20
|
+
workstreams.ext.* blocks are separate tables and must never answer this question. */
|
|
21
|
+
const boardSchemas = [SCHEMA.workstreams, SCHEMA.workstreamsLanesV0];
|
|
22
|
+
const blockSchema = wsDoc?.blocks.find((bl) => bl.kind === "board" && typeof bl.schema === "string" && boardSchemas.includes(bl.schema))?.schema ?? null;
|
|
23
|
+
const schema = blockSchema ?? board.find((r) => "schema" in r)?.schema ?? null;
|
|
17
24
|
const qDoc = q ? parseWorkDoc(q) : null;
|
|
18
25
|
const dDoc = d ? parseWorkDoc(d) : null;
|
|
19
26
|
const facts = f ? parseFactsDoc(f) : null;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@davidbalzan/groundwork-console",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.12",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@davidbalzan/groundwork-seam": "^0.1.0",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"typescript": "^7.0.2"
|
|
17
17
|
},
|
|
18
18
|
"description": "Groundwork Console — the cockpit for Groundwork Kit fleets: board, bus, monitor, docs, ops. One local server, token auth, tmux-aware.",
|
|
19
|
-
"license": "
|
|
19
|
+
"license": "UNLICENSED",
|
|
20
20
|
"repository": {
|
|
21
21
|
"type": "git",
|
|
22
22
|
"url": "git+https://github.com/davidbalzan/groundwork-console.git"
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"public",
|
|
31
31
|
"bin",
|
|
32
32
|
"groundwork-console.rules.json",
|
|
33
|
-
"README.md"
|
|
33
|
+
"README.md",
|
|
34
|
+
"LICENSE"
|
|
34
35
|
],
|
|
35
36
|
"engines": {
|
|
36
37
|
"node": ">=22"
|
|
@@ -47,6 +48,8 @@
|
|
|
47
48
|
"publish-check": "node scripts/publish-check.mjs",
|
|
48
49
|
"test:inject": "tsx test/inject.test.mts",
|
|
49
50
|
"test:skills": "tsx test/skills.test.mts",
|
|
50
|
-
"test": "pnpm run test:inject && pnpm run test:skills"
|
|
51
|
+
"test": "pnpm run test:inject && pnpm run test:skills && pnpm run test:board && pnpm run test:panes",
|
|
52
|
+
"test:board": "tsx test/board.test.mts",
|
|
53
|
+
"test:panes": "tsx test/panes.test.mts"
|
|
51
54
|
}
|
|
52
55
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{m as e,t}from"./mermaid-parser.core-
|
|
1
|
+
import{m as e,t}from"./mermaid-parser.core-B98Rk-oq.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-fnYA6irH.js";import"./chunk-I66GZJ75-CfWGFqqO.js";import{n as i,r as a,t as o}from"./chunk-6Q2QTUOP-BQYOf-YY.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-CqRCrVqJ.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-BhEZ2d35.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-B98Rk-oq.js";export{e as createArchitectureServices};
|