pi-straw-boss 0.9.2 → 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/dashboard.ts +1 -1
- package/src/index.ts +1 -1
- package/src/order.ts +10 -9
package/README.md
CHANGED
|
@@ -60,7 +60,7 @@ Subagents and sessions in Herdr worktree workspaces never join: the session that
|
|
|
60
60
|
An optional Herdr plugin in [`herdr-plugin/`](herdr-plugin) turns the sidebar's Agents list into a net view.
|
|
61
61
|
It lists the head tower's workspace first, in each workspace the tower, then each tab's main agent and members, and every subagent right under the session that launched it, even in a worktree workspace.
|
|
62
62
|
The view is on whenever the Herdr server starts, and one key switches it off and on again.
|
|
63
|
-
pi-straw-boss writes the sort key (`sb_order`), a role label (`sb_mark`) and, on subagents, a tree branch (`sb_indent`) the view and your sidebar rows can use.
|
|
63
|
+
pi-straw-boss writes the sort key (`sb_order`), a role label (`sb_mark`) and, on subagents, a tree branch (`sb_indent`) and the subagent's name (`sb_name`) the view and your sidebar rows can use.
|
|
64
64
|
It needs Herdr 0.9.3 or newer and node.
|
|
65
65
|
|
|
66
66
|
<p align="center"><img src="docs/sidebar-net-view.png" width="308" alt="Herdr's sidebar in the net view: each workspace's tower with the radio tower glyph first, each main agent on two rows with a star and its tab's label, and every subagent on a tree branch under the session that launched it"></p>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-straw-boss",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.3",
|
|
4
4
|
"description": "Straw Boss coordination for pi in Herdr: sessions join a tab's net by choice, the first joiner is its main agent, a workspace tower opens on demand with a live monitoring dashboard, and boss_broadcast reaches the rest",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/src/dashboard.ts
CHANGED
|
@@ -110,7 +110,7 @@ export function subagents(parent: Pane | undefined, all: Pane[], now: number, li
|
|
|
110
110
|
script = readdirSync(join(dir, "subagent-scripts")).find((f) => f.endsWith(`-${id}.sh`));
|
|
111
111
|
file ??= readFileSync(join(dir, "subagent-scripts", script!), "utf8").match(/PI_SUBAGENT_SESSION='([^']+)'/)?.[1];
|
|
112
112
|
} catch {} // the launch script is only a fallback source for the name and the session file
|
|
113
|
-
const name = pane?.label
|
|
113
|
+
const name = pane?.label || (script?.slice(0, -`-${id}.sh`.length) ?? id.slice(0, 8));
|
|
114
114
|
const doing = activity.toolActive ? String(activity.toolName) : String(activity.phase ?? "");
|
|
115
115
|
return { group: "net" as const, depth: 2, mark, text: name, kind: "subagent", workspace: pane?.workspace_id, id, file, pane: pane?.agent === "pi" ? pane.pane_id : undefined, note: { working: doing, waiting: "waiting on a question", done: "finished" }[mark as "working"] };
|
|
116
116
|
})
|
package/src/index.ts
CHANGED
|
@@ -473,7 +473,7 @@ export function createStrawBoss({ run = herdrRun, api = herdrApi(), call = herdr
|
|
|
473
473
|
const held = holdsTower;
|
|
474
474
|
holdsTower = false;
|
|
475
475
|
if (!role() || !at) return;
|
|
476
|
-
await report(run, "pane", at.paneId, { sb_role: null, sb_opened_by: null, sb_order: null, sb_mark: null, sb_indent: null, sb_tab: null }).catch(() => {});
|
|
476
|
+
await report(run, "pane", at.paneId, { sb_role: null, sb_opened_by: null, sb_order: null, sb_mark: null, sb_indent: null, sb_name: null, sb_tab: null }).catch(() => {});
|
|
477
477
|
await clearOrder(run, [...kids]);
|
|
478
478
|
if (held) await report(run, "workspace", at.workspaceId, { tower: null }).catch(() => {});
|
|
479
479
|
// A tower that quits leaves its tab as a plain shell: close the tab, but only when this pane is all it holds. A reload, /new, resume or fork keeps the tab.
|
package/src/order.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { subagents } from "./dashboard.ts";
|
|
2
2
|
import { ARROW, type HerdrRun, type HerdrTab, isSub, MARK, type Pane, panes, type Place, report, tabs, workspaces, type Workspace } from "./herdr.ts";
|
|
3
3
|
|
|
4
|
-
//
|
|
4
|
+
// Five display tokens for the sidebar plugin and for Herdr's own Agents rows, written next to `sb_role`:
|
|
5
5
|
// - `sb_order`: a sort key that lays the net out as the head tower's workspace first, then the other workspaces in Herdr's order, in each the tower
|
|
6
6
|
// and then the tabs in tab order, in each tab the main agent and then the members, and every subagent right after the session that launched it,
|
|
7
7
|
// its own subagents after it in turn. Segments are fixed-width and `.`-separated, so plain string order is the numeric order of every segment,
|
|
@@ -11,6 +11,7 @@ import { ARROW, type HerdrRun, type HerdrTab, isSub, MARK, type Pane, panes, typ
|
|
|
11
11
|
// - `sb_tab`: a member's tab label, which the first row shows in place of Herdr's tab item; a main agent's is in its mark instead.
|
|
12
12
|
// - `sb_indent`: a tree branch on a subagent alone, like Herdr's Spaces panel draws a worktree: `├─` while a later subagent of the same launcher is marked, `└─` on the last. A row put before the state icon shows it as the
|
|
13
13
|
// indent under the launcher. A tower, a main agent and a member carry none.
|
|
14
|
+
// - `sb_name`: a subagent's own name, as pi-herdr-agents shows it. Herdr's pane label held it until a new server dropped the label; a row can show the token instead. A subagent alone carries one.
|
|
14
15
|
// A session writes them for itself and for the subagents it launched, which never join and write nothing, on the same 4 minute refresh as `sb_role`.
|
|
15
16
|
|
|
16
17
|
/** What `sb_indent` holds on a subagent: the branch to it from its launcher, and `last` for the youngest marked sibling. */
|
|
@@ -44,16 +45,16 @@ export function descendants(parent: Pane | undefined, key: string, name: string,
|
|
|
44
45
|
if (!row.pane || seen.has(row.pane)) return [];
|
|
45
46
|
seen.add(row.pane);
|
|
46
47
|
const order = `${key}.${part(i)}`, indent = rows.slice(i + 1).some((r) => r.pane && !seen.has(r.pane)) ? INDENT.more : INDENT.last;
|
|
47
|
-
return [{ pane: row.pane, order, mark: `${ARROW} ${short(name)}`, indent }, ...descendants(ps.find((p) => p.pane_id === row.pane), order, row.text, ps, now, seen)];
|
|
48
|
+
return [{ pane: row.pane, order, mark: `${ARROW} ${short(name)}`, indent, name: short(row.text) }, ...descendants(ps.find((p) => p.pane_id === row.pane), order, row.text, ps, now, seen)];
|
|
48
49
|
});
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
/** The subagent panes a session marks: each gets `sb_order`, `sb_mark` and `
|
|
52
|
-
export interface Kid { pane: string; order: string; mark: string; indent: string }
|
|
52
|
+
/** The subagent panes a session marks: each gets `sb_order`, `sb_mark`, `sb_indent` and `sb_name`. */
|
|
53
|
+
export interface Kid { pane: string; order: string; mark: string; indent: string; name: string }
|
|
53
54
|
|
|
54
55
|
/**
|
|
55
56
|
* What a session publishes besides its role: its own tokens (null clears them when Herdr cannot place the session, a tower has no mark, and none
|
|
56
|
-
* has an indent, which clears the
|
|
57
|
+
* has an indent or a name, which clears the ones a pane keeps from when it ran a subagent) and those of the subagents it launched. Reads Herdr only.
|
|
57
58
|
*/
|
|
58
59
|
export async function netTokens(run: HerdrRun, place: Place, role: "tower" | "main" | "member", name: string, now = Date.now()): Promise<{ own: Record<string, string | null>; kids: Kid[]; joined: Set<string> }> {
|
|
59
60
|
const [ps, all, tabList] = [await panes(run), await workspaces(run), await tabs(run, place.workspaceId)];
|
|
@@ -62,7 +63,7 @@ export async function netTokens(run: HerdrRun, place: Place, role: "tower" | "ma
|
|
|
62
63
|
// A main agent's tab label goes in its mark, for a row of its own; a member's in `sb_tab`, which stands for the tab item in the first row.
|
|
63
64
|
const tab = tabList.find((t) => t.tab_id === pane?.tab_id)?.label || null;
|
|
64
65
|
const mark = role === "tower" ? null : role === "main" ? (tab ? `${MARK.main} ${tab}` : MARK.main) : MARK[role];
|
|
65
|
-
return { own: { sb_order: key ?? null, sb_mark: mark, sb_indent: null, sb_tab: role === "member" ? tab : null }, kids: key ? descendants(pane, key, name, ps, now) : [], joined };
|
|
66
|
+
return { own: { sb_order: key ?? null, sb_mark: mark, sb_indent: null, sb_name: null, sb_tab: role === "member" ? tab : null }, kids: key ? descendants(pane, key, name, ps, now) : [], joined };
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
/**
|
|
@@ -70,11 +71,11 @@ export async function netTokens(run: HerdrRun, place: Place, role: "tower" | "ma
|
|
|
70
71
|
* (a shell where a subagent ran can start a pi that writes its own). Returns the panes now marked. A failed write waits for the next refresh.
|
|
71
72
|
*/
|
|
72
73
|
export async function markKids(run: HerdrRun, kids: Kid[], before: Set<string>, joined = new Set<string>()): Promise<Set<string>> {
|
|
73
|
-
for (const kid of kids) await report(run, "pane", kid.pane, { sb_order: kid.order, sb_mark: kid.mark, sb_indent: kid.indent }).catch(() => {});
|
|
74
|
+
for (const kid of kids) await report(run, "pane", kid.pane, { sb_order: kid.order, sb_mark: kid.mark, sb_indent: kid.indent, sb_name: kid.name }).catch(() => {});
|
|
74
75
|
const marked = new Set(kids.map((k) => k.pane));
|
|
75
76
|
await clearOrder(run, [...before].filter((id) => !marked.has(id) && !joined.has(id)));
|
|
76
77
|
return marked;
|
|
77
78
|
}
|
|
78
79
|
|
|
79
|
-
/** Removes the
|
|
80
|
-
export const clearOrder = (run: HerdrRun, paneIds: string[]) => Promise.all(paneIds.map((id) => report(run, "pane", id, { sb_order: null, sb_mark: null, sb_indent: null }).catch(() => {})));
|
|
80
|
+
/** Removes the four tokens from panes, ignoring a pane that has already closed. */
|
|
81
|
+
export const clearOrder = (run: HerdrRun, paneIds: string[]) => Promise.all(paneIds.map((id) => report(run, "pane", id, { sb_order: null, sb_mark: null, sb_indent: null, sb_name: null }).catch(() => {})));
|