pi-herdsman 0.22.2 → 0.24.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.
- package/dist/index.js +955 -175
- package/dist/index.js.map +3 -3
- package/dist/integrations/pi-codex-context-sharing.js +42 -0
- package/dist/integrations/pi-codex-context-sharing.js.map +7 -0
- package/docs/guides/customizing-agents.md +32 -0
- package/docs/reference/agent.md +46 -0
- package/docs/reference/status-widget.md +19 -0
- package/package.json +8 -1
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
|
15
15
|
// package.json
|
|
16
16
|
var package_default = {
|
|
17
17
|
name: "pi-herdsman",
|
|
18
|
-
version: "0.
|
|
18
|
+
version: "0.24.0",
|
|
19
19
|
type: "module",
|
|
20
20
|
description: "Asynchronous Pi subagents and agent fleet orchestration for parallel coding agents with nested delegation, background work, and supervision in herdr.",
|
|
21
21
|
license: "Apache-2.0",
|
|
@@ -90,12 +90,14 @@ var package_default = {
|
|
|
90
90
|
"@earendil-works/pi-ai": "*",
|
|
91
91
|
"@earendil-works/pi-coding-agent": "*",
|
|
92
92
|
"@earendil-works/pi-tui": "*",
|
|
93
|
+
"@howaboua/pi-codex-conversion": "^3.0.45",
|
|
93
94
|
typebox: "*"
|
|
94
95
|
},
|
|
95
96
|
devDependencies: {
|
|
96
97
|
"@earendil-works/pi-ai": "1.1.0",
|
|
97
98
|
"@earendil-works/pi-coding-agent": "1.1.0",
|
|
98
99
|
"@earendil-works/pi-tui": "1.1.0",
|
|
100
|
+
"@howaboua/pi-codex-conversion": "3.0.45",
|
|
99
101
|
esbuild: "^0.28.2",
|
|
100
102
|
typebox: "^1.3.7"
|
|
101
103
|
},
|
|
@@ -112,6 +114,11 @@ var package_default = {
|
|
|
112
114
|
],
|
|
113
115
|
publishConfig: {
|
|
114
116
|
registry: "https://registry.npmjs.org/"
|
|
117
|
+
},
|
|
118
|
+
peerDependenciesMeta: {
|
|
119
|
+
"@howaboua/pi-codex-conversion": {
|
|
120
|
+
optional: true
|
|
121
|
+
}
|
|
115
122
|
}
|
|
116
123
|
};
|
|
117
124
|
|
|
@@ -553,6 +560,8 @@ function releaseProcessLock(claimDir, ownerPath, claim, name) {
|
|
|
553
560
|
}
|
|
554
561
|
|
|
555
562
|
// extension/mailbox.ts
|
|
563
|
+
var MANAGED_AGENT_BOOTSTRAP_LIMIT_BYTES = 64 * 1024;
|
|
564
|
+
var BOOTSTRAP_ID = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/;
|
|
556
565
|
var UUID2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
557
566
|
var PREFIX = "__PI_HERDSMAN_AGENT_V5__:";
|
|
558
567
|
var MAILBOX_PROTOCOL_LIMIT_BYTES = 1024 * 1024;
|
|
@@ -563,6 +572,7 @@ var MailboxClaimOccupiedError = class extends Error {
|
|
|
563
572
|
code = "MAILBOX_CLAIM_OCCUPIED";
|
|
564
573
|
};
|
|
565
574
|
var LIMITS = {
|
|
575
|
+
bootstrap: MANAGED_AGENT_BOOTSTRAP_LIMIT_BYTES,
|
|
566
576
|
state: 64 * 1024,
|
|
567
577
|
request: MAILBOX_PROTOCOL_LIMIT_BYTES,
|
|
568
578
|
ask: MAILBOX_PROTOCOL_LIMIT_BYTES,
|
|
@@ -699,6 +709,41 @@ function validate(value2, kind) {
|
|
|
699
709
|
if (Buffer.byteLength(text, "utf8") > LIMITS[kind])
|
|
700
710
|
throw new Error("Mailbox record is too large");
|
|
701
711
|
const v = value2;
|
|
712
|
+
if (kind === "bootstrap") {
|
|
713
|
+
const allowed2 = [
|
|
714
|
+
"version",
|
|
715
|
+
"build",
|
|
716
|
+
"runId",
|
|
717
|
+
"ownerSessionId",
|
|
718
|
+
"workspaceId",
|
|
719
|
+
"agentLabel",
|
|
720
|
+
"participants"
|
|
721
|
+
];
|
|
722
|
+
if (Object.keys(v).some((key) => !allowed2.includes(key)))
|
|
723
|
+
throw new Error("Unknown mailbox field");
|
|
724
|
+
if (!isRuntimeBuild(v.build))
|
|
725
|
+
throw new Error("Invalid runtime build identity");
|
|
726
|
+
for (const field of [
|
|
727
|
+
"runId",
|
|
728
|
+
"ownerSessionId",
|
|
729
|
+
"workspaceId",
|
|
730
|
+
"agentLabel"
|
|
731
|
+
])
|
|
732
|
+
if (typeof v[field] !== "string" || !v[field].trim())
|
|
733
|
+
throw new Error(`Invalid mailbox field: ${field}`);
|
|
734
|
+
if (!UUID2.test(v.runId)) throw new Error("Invalid mailbox UUID");
|
|
735
|
+
if (!Array.isArray(v.participants) || !v.participants.length)
|
|
736
|
+
throw new Error("Invalid bootstrap participants");
|
|
737
|
+
const ids = /* @__PURE__ */ new Set();
|
|
738
|
+
for (const participant of v.participants) {
|
|
739
|
+
if (!participant || typeof participant !== "object" || Object.keys(participant).some(
|
|
740
|
+
(key) => !["id", "payload"].includes(key)
|
|
741
|
+
) || typeof participant.id !== "string" || !BOOTSTRAP_ID.test(participant.id) || ids.has(participant.id) || typeof participant.payload !== "string")
|
|
742
|
+
throw new Error("Invalid or duplicate bootstrap participant");
|
|
743
|
+
ids.add(participant.id);
|
|
744
|
+
}
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
702
747
|
const allowed = kind === "state" ? [
|
|
703
748
|
"version",
|
|
704
749
|
"build",
|
|
@@ -975,6 +1020,7 @@ function resetAgentMailbox(path) {
|
|
|
975
1020
|
for (const name of [
|
|
976
1021
|
"state.json",
|
|
977
1022
|
"ask.json",
|
|
1023
|
+
"bootstrap.json",
|
|
978
1024
|
...readdirSync3(path).filter(
|
|
979
1025
|
(x) => /^(request|result)-.*\.json$/.test(x)
|
|
980
1026
|
)
|
|
@@ -986,6 +1032,24 @@ function resetAgentMailbox(path) {
|
|
|
986
1032
|
}
|
|
987
1033
|
}
|
|
988
1034
|
}
|
|
1035
|
+
function writeAgentBootstrap(path, record) {
|
|
1036
|
+
atomic(file(path, "bootstrap.json"), record, "bootstrap");
|
|
1037
|
+
}
|
|
1038
|
+
function readAgentBootstrap(path) {
|
|
1039
|
+
const value2 = read(
|
|
1040
|
+
file(path, "bootstrap.json"),
|
|
1041
|
+
"bootstrap"
|
|
1042
|
+
);
|
|
1043
|
+
if (value2) validate(value2, "bootstrap");
|
|
1044
|
+
return value2;
|
|
1045
|
+
}
|
|
1046
|
+
function removeAgentBootstrap(path) {
|
|
1047
|
+
try {
|
|
1048
|
+
unlinkSync2(file(path, "bootstrap.json"));
|
|
1049
|
+
} catch (error2) {
|
|
1050
|
+
if (error2.code !== "ENOENT") throw error2;
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
989
1053
|
function removeAgentMailbox(path) {
|
|
990
1054
|
let names2;
|
|
991
1055
|
try {
|
|
@@ -1189,6 +1253,7 @@ function currentTurnIsSoleToolCall(ctx, name) {
|
|
|
1189
1253
|
const calls = turn.content.filter((part) => part?.type === "toolCall");
|
|
1190
1254
|
return calls.length === 1 && calls[0]?.name === name;
|
|
1191
1255
|
}
|
|
1256
|
+
var MANAGED_AGENT_BOOTSTRAP_EVENT = "pi-herdsman:managed-agent-bootstrap";
|
|
1192
1257
|
var FILE_HANDOFF_GUIDANCE = "Pass every user-supplied or already-available artifact relevant to the recipient's assignment, decisions, integration, validation, or onward handoff through `files`; do not assume the recipient inherits the sender's conversation or attachments. Preserve exact supplied result refs when forwarding them and omit unrelated evidence. `files` carries evidence, not runtime capability.";
|
|
1193
1258
|
function failUnknownResultRef(input, operation) {
|
|
1194
1259
|
fail(
|
|
@@ -4350,6 +4415,9 @@ function layoutStatusRows(rows, width, options = {}) {
|
|
|
4350
4415
|
}) ?? layouts.at(-1);
|
|
4351
4416
|
return rows.map((row) => ({
|
|
4352
4417
|
label: row.label,
|
|
4418
|
+
labelStart: visibleWidth(
|
|
4419
|
+
`${row.tree}${row.spinner} ${padVisible(row.definition, columns.definitionWidth)} `
|
|
4420
|
+
),
|
|
4353
4421
|
...row.paneId ? { paneId: row.paneId } : {},
|
|
4354
4422
|
...row.sessionId ? { sessionId: row.sessionId } : {},
|
|
4355
4423
|
text: renderStatusLine(row, columns, layout, available, options.theme)
|
|
@@ -4386,6 +4454,8 @@ function managerPresentationSnapshot(manager) {
|
|
|
4386
4454
|
displayName: manager.displayName,
|
|
4387
4455
|
project: manager.project,
|
|
4388
4456
|
workspaceId: manager.workspaceId,
|
|
4457
|
+
paneId: manager.paneId,
|
|
4458
|
+
tabId: manager.tabId,
|
|
4389
4459
|
runtimeState: manager.runtimeState,
|
|
4390
4460
|
agentCounts: manager.agentCounts,
|
|
4391
4461
|
leadCounts: manager.leadCounts,
|
|
@@ -4574,15 +4644,23 @@ var MANAGER_METADATA_LAYOUTS = [
|
|
|
4574
4644
|
{ elapsed: false, context: true },
|
|
4575
4645
|
{ elapsed: false, context: false }
|
|
4576
4646
|
];
|
|
4577
|
-
function
|
|
4647
|
+
function identifyingLabelVisible(text, label, width, expectedStart) {
|
|
4648
|
+
if (expectedStart !== void 0)
|
|
4649
|
+
return label.length > 0 && expectedStart + visibleWidth(label) <= width;
|
|
4650
|
+
const start = text.lastIndexOf(label);
|
|
4651
|
+
return label.length > 0 && start >= 0 && visibleWidth(text.slice(0, start + label.length)) <= width;
|
|
4652
|
+
}
|
|
4653
|
+
function renderSupervisionRows(reports, width, options = {}, selectedLead) {
|
|
4578
4654
|
const status = options.status ?? "fresh";
|
|
4579
4655
|
const role2 = options.role ?? "chief";
|
|
4580
4656
|
if (status === "unavailable")
|
|
4581
4657
|
return [
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4658
|
+
{
|
|
4659
|
+
text: safeLine(
|
|
4660
|
+
`${themed(options.theme, "success", "\u25CF")} ${themed(options.theme, "muted", `${role2} \xB7 unavailable`)}`,
|
|
4661
|
+
width
|
|
4662
|
+
)
|
|
4663
|
+
}
|
|
4586
4664
|
];
|
|
4587
4665
|
const displays = orderedSupervisionLeads(presentationReports(reports));
|
|
4588
4666
|
const groups = groupOrderedSupervisedLeads(displays);
|
|
@@ -4630,16 +4708,25 @@ function renderSupervisionLeads(reports, width, options = {}, selectedLead) {
|
|
|
4630
4708
|
})
|
|
4631
4709
|
) ?? MANAGER_METADATA_LAYOUTS.at(-1);
|
|
4632
4710
|
return [
|
|
4633
|
-
safeLine(header, width),
|
|
4711
|
+
{ text: safeLine(header, width) },
|
|
4634
4712
|
...visible.map((item, index) => {
|
|
4635
4713
|
const branch = index === visible.length - 1 && !remaining ? "\u2514\u2500" : "\u251C\u2500";
|
|
4636
4714
|
const lead = item.lead;
|
|
4637
4715
|
const navigation = lead && lead.lead === selectedLead ? ">" : "";
|
|
4638
4716
|
if (item.kind === "lead")
|
|
4639
|
-
return
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4717
|
+
return {
|
|
4718
|
+
text: safeLine(
|
|
4719
|
+
`${themed(options.theme, lifecycleColor(item.lead.runtimeState), `${branch} ${navigation}${supervisionLeadMarker(item.lead)}`)} ${themed(options.theme, "muted", `${item.lead.branch ?? item.lead.displayName} \xB7 Lead`)}`,
|
|
4720
|
+
width
|
|
4721
|
+
),
|
|
4722
|
+
...status === "fresh" ? {
|
|
4723
|
+
label: item.lead.branch ?? item.lead.displayName,
|
|
4724
|
+
intent: {
|
|
4725
|
+
kind: "session",
|
|
4726
|
+
sessionId: item.lead.lead
|
|
4727
|
+
}
|
|
4728
|
+
} : {}
|
|
4729
|
+
};
|
|
4643
4730
|
const marker = item.work.status === "active" && lead ? `${lead.runtimeState === "blocked" ? "!" : ""}${supervisionLeadMarker(lead)}` : workMarkers[item.work.status];
|
|
4644
4731
|
const prefix = `${branch} ${navigation}${marker} `;
|
|
4645
4732
|
const suffix = ` \xB7 ${item.work.status}`;
|
|
@@ -4653,48 +4740,64 @@ function renderSupervisionLeads(reports, width, options = {}, selectedLead) {
|
|
|
4653
4740
|
);
|
|
4654
4741
|
const markerColor = item.work.status === "active" && lead ? lifecycleColor(lead.runtimeState) : item.work.status === "active" ? "success" : item.work.status === "conflict" ? "warning" : "muted";
|
|
4655
4742
|
const markerText = themed(options.theme, markerColor, marker);
|
|
4656
|
-
const
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4743
|
+
const branchWidth = width - visibleWidth(prefix) - visibleWidth(suffix) - telemetryWidth;
|
|
4744
|
+
const displayedBranch = safeLine(item.work.branch, branchWidth);
|
|
4745
|
+
const branchText = themed(options.theme, "muted", displayedBranch);
|
|
4746
|
+
return {
|
|
4747
|
+
text: safeLine(
|
|
4748
|
+
`${themed(options.theme, "muted", `${branch} ${navigation}`)}${markerText} ${branchText}${themed(options.theme, "muted", suffix)}${telemetry.map((value2) => themed(options.theme, "muted", ` ${value2}`)).join("")}`,
|
|
4749
|
+
width
|
|
4750
|
+
),
|
|
4751
|
+
...status === "fresh" && item.work.status === "active" && lead && displayedBranch === item.work.branch ? {
|
|
4752
|
+
label: item.work.branch,
|
|
4753
|
+
intent: { kind: "session", sessionId: lead.lead }
|
|
4754
|
+
} : {}
|
|
4755
|
+
};
|
|
4668
4756
|
}),
|
|
4669
|
-
...remaining ? [safeLine(`\u2514\u2500 \u2026 ${remaining} more \xB7 /manager`, width)] : []
|
|
4757
|
+
...remaining ? [{ text: safeLine(`\u2514\u2500 \u2026 ${remaining} more \xB7 /manager`, width) }] : []
|
|
4670
4758
|
];
|
|
4671
4759
|
}
|
|
4672
4760
|
return [
|
|
4673
|
-
safeLine(header, width),
|
|
4761
|
+
{ text: safeLine(header, width) },
|
|
4674
4762
|
...shown.flatMap((lead, index) => {
|
|
4675
4763
|
const branch = index === shown.length - 1 && hidden === 0 ? "\u2514\u2500" : "\u251C\u2500";
|
|
4676
4764
|
const marker = supervisionLeadMarker(lead);
|
|
4677
4765
|
const navigation = lead.lead === selectedLead ? ">" : "";
|
|
4678
4766
|
const indicators = navigation;
|
|
4679
4767
|
const counts = lead.leadCounts;
|
|
4680
|
-
const
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4768
|
+
const intent = status === "fresh" ? { kind: "session", sessionId: lead.lead } : void 0;
|
|
4769
|
+
const row = {
|
|
4770
|
+
text: safeLine(
|
|
4771
|
+
`${themed(options.theme, lifecycleColor(lead.runtimeState), `${branch} ${indicators}${marker}`)} ${themed(options.theme, "muted", `${lead.displayName}${counts?.total ? ` \xB7 ${counts.total} lead${counts.total === 1 ? "" : "s"}` : ""}${lead.agentCounts?.total ? ` \xB7 ${lead.agentCounts.total} agent${lead.agentCounts.total === 1 ? "" : "s"}` : ""}`)}`,
|
|
4772
|
+
width
|
|
4773
|
+
),
|
|
4774
|
+
...intent ? { intent } : {},
|
|
4775
|
+
...intent ? { label: lead.displayName } : {}
|
|
4776
|
+
};
|
|
4684
4777
|
const children = (lead.leads ?? []).slice(0, 3);
|
|
4685
4778
|
const childIndent = branch === "\u2514\u2500" ? " " : "\u2502 ";
|
|
4686
4779
|
return [
|
|
4687
4780
|
row,
|
|
4688
4781
|
...children.map((child, childIndex) => {
|
|
4689
4782
|
const childBranch = childIndex === children.length - 1 ? "\u2514\u2500" : "\u251C\u2500";
|
|
4690
|
-
return
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4783
|
+
return {
|
|
4784
|
+
text: safeLine(
|
|
4785
|
+
`${themed(options.theme, "muted", `${childIndent}${childBranch} ${child.branch ?? child.display_name} \xB7 `)}${themed(options.theme, lifecycleColor(child.runtime_state), child.runtime_state)}${themed(options.theme, "muted", `${child.agent_counts.total ? ` \xB7 ${child.agent_counts.total} agent${child.agent_counts.total === 1 ? "" : "s"}` : ""}`)}`,
|
|
4786
|
+
width
|
|
4787
|
+
),
|
|
4788
|
+
...status === "fresh" ? {
|
|
4789
|
+
label: child.branch ?? child.display_name,
|
|
4790
|
+
intent: {
|
|
4791
|
+
kind: "session",
|
|
4792
|
+
sessionId: child.session,
|
|
4793
|
+
parentSessionId: lead.lead
|
|
4794
|
+
}
|
|
4795
|
+
} : {}
|
|
4796
|
+
};
|
|
4694
4797
|
})
|
|
4695
4798
|
];
|
|
4696
4799
|
}),
|
|
4697
|
-
...hidden > 0 ? [safeLine(`\u2514\u2500 \u2026 ${hidden} more \xB7 /${role2}`, width)] : []
|
|
4800
|
+
...hidden > 0 ? [{ text: safeLine(`\u2514\u2500 \u2026 ${hidden} more \xB7 /${role2}`, width) }] : []
|
|
4698
4801
|
];
|
|
4699
4802
|
}
|
|
4700
4803
|
function formatSupervisionNotification(reports, status = "fresh") {
|
|
@@ -4855,15 +4958,39 @@ function formatSupervisionContext(snapshot, options) {
|
|
|
4855
4958
|
}
|
|
4856
4959
|
return [...included, closing].join("\n");
|
|
4857
4960
|
}
|
|
4858
|
-
function createSupervisionWidget(getLeads, getStatus, role2 = "chief", theme) {
|
|
4961
|
+
function createSupervisionWidget(getLeads, getStatus, role2 = "chief", theme, onFocus) {
|
|
4962
|
+
let renderedWidth = -1;
|
|
4963
|
+
let hits = [];
|
|
4859
4964
|
return {
|
|
4860
4965
|
render(width) {
|
|
4861
|
-
|
|
4966
|
+
renderedWidth = width;
|
|
4967
|
+
const rows = renderSupervisionRows(getLeads(), width, {
|
|
4862
4968
|
status: getStatus(),
|
|
4863
4969
|
ordinaryCap: 6,
|
|
4864
4970
|
role: role2,
|
|
4865
4971
|
theme
|
|
4866
|
-
}).filter((
|
|
4972
|
+
}).filter(({ text }) => text.length > 0);
|
|
4973
|
+
hits = [];
|
|
4974
|
+
rows.forEach((row, index) => {
|
|
4975
|
+
if (row.intent && row.label && identifyingLabelVisible(row.text, row.label, width))
|
|
4976
|
+
hits.push({
|
|
4977
|
+
row: index,
|
|
4978
|
+
from: 0,
|
|
4979
|
+
to: Math.min(width, visibleWidth(row.text)),
|
|
4980
|
+
intent: row.intent
|
|
4981
|
+
});
|
|
4982
|
+
});
|
|
4983
|
+
return rows.map(({ text }) => text);
|
|
4984
|
+
},
|
|
4985
|
+
handleMouse(event) {
|
|
4986
|
+
if (event.type !== "click" || event.button !== "left" || event.width !== renderedWidth)
|
|
4987
|
+
return;
|
|
4988
|
+
const hit = hits.find(
|
|
4989
|
+
({ row, from, to }) => row === event.y && event.x >= from && event.x < to
|
|
4990
|
+
);
|
|
4991
|
+
if (!hit || !onFocus) return;
|
|
4992
|
+
onFocus(hit.intent);
|
|
4993
|
+
return { handled: true, render: false };
|
|
4867
4994
|
},
|
|
4868
4995
|
invalidate() {
|
|
4869
4996
|
}
|
|
@@ -4936,22 +5063,38 @@ function safeDisplaySegment(value2) {
|
|
|
4936
5063
|
return value2.replace(/\u001b\][^\u0007]*(?:\u0007|\u001b\\)/gu, "").replace(/\u001b\[[0-?]*[ -/]*[@-~]/gu, "").replace(/[\u0000-\u001f\u007f]/gu, " ").replace(/\s+/gu, " ").trim();
|
|
4937
5064
|
}
|
|
4938
5065
|
function renderBreadcrumb(segments, width) {
|
|
4939
|
-
if (width <= 0) return "";
|
|
4940
|
-
const
|
|
4941
|
-
const current =
|
|
5066
|
+
if (width <= 0) return { text: "", hits: [] };
|
|
5067
|
+
const visible = segments.map((segment) => ({ ...segment, text: safeDisplaySegment(segment.text) })).filter((segment) => segment.text);
|
|
5068
|
+
const current = visible.at(-1) ?? { text: "?" };
|
|
4942
5069
|
const marker = "\u25CF";
|
|
4943
|
-
if (width <= visibleWidth(marker))
|
|
5070
|
+
if (width <= visibleWidth(marker))
|
|
5071
|
+
return { text: truncateToWidth(marker, width, ""), hits: [] };
|
|
4944
5072
|
const prefix = `${marker} `;
|
|
4945
5073
|
const available = width - visibleWidth(prefix);
|
|
4946
|
-
if (available <= 0) return marker;
|
|
4947
|
-
const currentText = tailTruncate(current, available);
|
|
4948
|
-
|
|
4949
|
-
for (let index =
|
|
4950
|
-
const candidate =
|
|
4951
|
-
|
|
5074
|
+
if (available <= 0) return { text: marker, hits: [] };
|
|
5075
|
+
const currentText = tailTruncate(current.text, available);
|
|
5076
|
+
const included = [{ ...current, text: currentText }];
|
|
5077
|
+
for (let index = visible.length - 2; index >= 0; index--) {
|
|
5078
|
+
const candidate = [visible[index], ...included];
|
|
5079
|
+
const candidateText = `${prefix}${candidate.map(({ text: text2 }) => text2).join(" \u2192 ")}`;
|
|
5080
|
+
if (visibleWidth(candidateText) <= width) included.unshift(visible[index]);
|
|
4952
5081
|
else break;
|
|
4953
5082
|
}
|
|
4954
|
-
|
|
5083
|
+
const text = `${prefix}${included.map(({ text: text2 }) => text2).join(" \u2192 ")}`;
|
|
5084
|
+
const hits = [];
|
|
5085
|
+
let x = visibleWidth(prefix);
|
|
5086
|
+
included.forEach((segment, index) => {
|
|
5087
|
+
const segmentWidth = visibleWidth(segment.text);
|
|
5088
|
+
if (index < included.length - 1 && segment.sessionId)
|
|
5089
|
+
hits.push({
|
|
5090
|
+
row: 0,
|
|
5091
|
+
from: x,
|
|
5092
|
+
to: x + segmentWidth,
|
|
5093
|
+
intent: { kind: "session", sessionId: segment.sessionId }
|
|
5094
|
+
});
|
|
5095
|
+
x += segmentWidth + (index < included.length - 1 ? visibleWidth(" \u2192 ") : 0);
|
|
5096
|
+
});
|
|
5097
|
+
return { text, hits };
|
|
4955
5098
|
}
|
|
4956
5099
|
function renderToolMetadata(tools, width) {
|
|
4957
5100
|
if (!tools?.length || width <= 0) return "";
|
|
@@ -6347,8 +6490,12 @@ var StatusWidget = class {
|
|
|
6347
6490
|
timer;
|
|
6348
6491
|
invalidateUI;
|
|
6349
6492
|
theme;
|
|
6350
|
-
|
|
6493
|
+
onFocus;
|
|
6494
|
+
renderedWidth = -1;
|
|
6495
|
+
hits = [];
|
|
6496
|
+
constructor(invalidateUI, theme, onFocus) {
|
|
6351
6497
|
this.invalidateUI = invalidateUI;
|
|
6498
|
+
this.onFocus = onFocus;
|
|
6352
6499
|
this.theme = theme ?? {
|
|
6353
6500
|
fg: (_color, text) => text,
|
|
6354
6501
|
bold: (text) => text
|
|
@@ -6356,6 +6503,8 @@ var StatusWidget = class {
|
|
|
6356
6503
|
}
|
|
6357
6504
|
setSnapshot(snapshot) {
|
|
6358
6505
|
this.snapshot = snapshot;
|
|
6506
|
+
this.hits = [];
|
|
6507
|
+
this.renderedWidth = -1;
|
|
6359
6508
|
const animated = snapshot.agents.some(
|
|
6360
6509
|
(agent) => agent.state === "working" || agent.state === "settling" || agent.state === "starting"
|
|
6361
6510
|
);
|
|
@@ -6375,20 +6524,36 @@ var StatusWidget = class {
|
|
|
6375
6524
|
}
|
|
6376
6525
|
render(width) {
|
|
6377
6526
|
const s = this.snapshot;
|
|
6527
|
+
this.renderedWidth = width;
|
|
6528
|
+
this.hits = [];
|
|
6378
6529
|
const suffix = s.unavailable ? "unavailable" : `${formatStatusCounts(s.agents)}${s.stale ? " \xB7 stale" : ""}`;
|
|
6379
6530
|
const availableWidth = Math.max(0, width);
|
|
6380
6531
|
const execution = s.execution ? ` \xB7 ${s.execution.kind === "managed" ? "managed" : s.execution.mode}` : "";
|
|
6381
6532
|
const elapsed = formatElapsed(s.herdRunStartedAt, Date.now());
|
|
6382
6533
|
let run = !s.identityOnly && elapsed ? ` \xB7 ${elapsed}` : "";
|
|
6383
6534
|
const suffixText = s.identityOnly || !suffix ? "" : ` ${suffix}`;
|
|
6384
|
-
const breadcrumbSegments = s.breadcrumb ?? ["?"];
|
|
6385
|
-
const
|
|
6535
|
+
const breadcrumbSegments = s.breadcrumb ?? [{ text: "?" }];
|
|
6536
|
+
const renderedBreadcrumb = renderBreadcrumb(
|
|
6537
|
+
breadcrumbSegments,
|
|
6538
|
+
availableWidth
|
|
6539
|
+
);
|
|
6540
|
+
const breadcrumb = renderedBreadcrumb.text;
|
|
6541
|
+
if (!s.stale && !s.unavailable) this.hits.push(...renderedBreadcrumb.hits);
|
|
6386
6542
|
const remainingWidth = Math.max(
|
|
6387
6543
|
0,
|
|
6388
6544
|
availableWidth - visibleWidth(breadcrumb)
|
|
6389
6545
|
);
|
|
6390
6546
|
const executionFits = !!execution && visibleWidth(execution) + visibleWidth(suffixText) <= remainingWidth;
|
|
6391
6547
|
const shownExecution = executionFits ? execution : "";
|
|
6548
|
+
if (!s.stale && !s.unavailable && executionFits && s.execution?.kind === "managed") {
|
|
6549
|
+
const from = visibleWidth(breadcrumb) + visibleWidth(" \xB7 ");
|
|
6550
|
+
this.hits.push({
|
|
6551
|
+
row: 0,
|
|
6552
|
+
from,
|
|
6553
|
+
to: from + visibleWidth("managed"),
|
|
6554
|
+
intent: { kind: "assigned-manager" }
|
|
6555
|
+
});
|
|
6556
|
+
}
|
|
6392
6557
|
const tools = renderToolMetadata(
|
|
6393
6558
|
s.ownTools,
|
|
6394
6559
|
Math.max(
|
|
@@ -6406,24 +6571,55 @@ var StatusWidget = class {
|
|
|
6406
6571
|
const header = `${styledBreadcrumb}${styledExecution}${styledTools}${styledRun}${styledSuffix}`;
|
|
6407
6572
|
const out = [truncateToWidth(header, availableWidth, "\u2026")];
|
|
6408
6573
|
if (s.identityOnly) return out;
|
|
6409
|
-
|
|
6410
|
-
|
|
6411
|
-
|
|
6412
|
-
|
|
6413
|
-
|
|
6414
|
-
|
|
6415
|
-
|
|
6416
|
-
)
|
|
6574
|
+
const rows = renderStatusRows(s.agents, {
|
|
6575
|
+
now: Date.now(),
|
|
6576
|
+
frame: this.frame,
|
|
6577
|
+
width: Math.max(0, width),
|
|
6578
|
+
theme: this.theme
|
|
6579
|
+
});
|
|
6580
|
+
out.push(...rows.map(({ text }) => text));
|
|
6581
|
+
if (!s.stale && !s.unavailable)
|
|
6582
|
+
rows.forEach((row, index) => {
|
|
6583
|
+
const agent = s.agents.find(
|
|
6584
|
+
({ label, sessionId }) => label === row.label && sessionId === row.sessionId
|
|
6585
|
+
);
|
|
6586
|
+
if (!row.sessionId || !identifyingLabelVisible(
|
|
6587
|
+
row.text,
|
|
6588
|
+
row.label,
|
|
6589
|
+
availableWidth,
|
|
6590
|
+
row.labelStart
|
|
6591
|
+
) || s.agents.filter(({ sessionId }) => sessionId === row.sessionId).length !== 1 || !agent || agent.state === "unknown" || agent.state === "lost" || agent.state === "starting")
|
|
6592
|
+
return;
|
|
6593
|
+
this.hits.push({
|
|
6594
|
+
row: index + 1,
|
|
6595
|
+
from: 0,
|
|
6596
|
+
to: Math.min(availableWidth, visibleWidth(row.text)),
|
|
6597
|
+
intent: { kind: "session", sessionId: row.sessionId }
|
|
6598
|
+
});
|
|
6599
|
+
});
|
|
6417
6600
|
return out;
|
|
6418
6601
|
}
|
|
6602
|
+
handleMouse(event) {
|
|
6603
|
+
if (event.type !== "click" || event.button !== "left" || event.width !== this.renderedWidth)
|
|
6604
|
+
return;
|
|
6605
|
+
const hit = this.hits.find(
|
|
6606
|
+
({ row, from, to }) => row === event.y && event.x >= from && event.x < to
|
|
6607
|
+
);
|
|
6608
|
+
if (!hit || !this.onFocus) return;
|
|
6609
|
+
this.onFocus(hit.intent);
|
|
6610
|
+
return { handled: true, render: false };
|
|
6611
|
+
}
|
|
6419
6612
|
dispose() {
|
|
6420
6613
|
if (this.timer) clearInterval(this.timer);
|
|
6421
6614
|
this.timer = void 0;
|
|
6422
6615
|
this.invalidateUI = void 0;
|
|
6616
|
+
this.onFocus = void 0;
|
|
6617
|
+
this.hits = [];
|
|
6618
|
+
this.renderedWidth = -1;
|
|
6423
6619
|
}
|
|
6424
6620
|
};
|
|
6425
|
-
function createStatusWidget(invalidate, theme) {
|
|
6426
|
-
return new StatusWidget(invalidate, theme);
|
|
6621
|
+
function createStatusWidget(invalidate, theme, onFocus) {
|
|
6622
|
+
return new StatusWidget(invalidate, theme, onFocus);
|
|
6427
6623
|
}
|
|
6428
6624
|
|
|
6429
6625
|
// extension/config.ts
|
|
@@ -7051,8 +7247,6 @@ async function drainCoordinationInbox(options) {
|
|
|
7051
7247
|
}
|
|
7052
7248
|
continue;
|
|
7053
7249
|
}
|
|
7054
|
-
const deliverAs = options.deliveryMode ? options.deliveryMode(record) : "followUp";
|
|
7055
|
-
if (!deliverAs) continue;
|
|
7056
7250
|
let token;
|
|
7057
7251
|
const clearTransaction = async () => {
|
|
7058
7252
|
if (token === void 0) return;
|
|
@@ -7068,6 +7262,12 @@ async function drainCoordinationInbox(options) {
|
|
|
7068
7262
|
await clearTransaction();
|
|
7069
7263
|
continue;
|
|
7070
7264
|
}
|
|
7265
|
+
const deliverAs = options.deliveryMode ? options.deliveryMode(record) : "followUp";
|
|
7266
|
+
const wasAlreadyDelivered = options.isDelivered(record.id);
|
|
7267
|
+
if (!deliverAs && !wasAlreadyDelivered) {
|
|
7268
|
+
await clearTransaction();
|
|
7269
|
+
continue;
|
|
7270
|
+
}
|
|
7071
7271
|
let authorized;
|
|
7072
7272
|
try {
|
|
7073
7273
|
authorized = await options.isAuthorized(record);
|
|
@@ -7115,29 +7315,35 @@ async function drainCoordinationInbox(options) {
|
|
|
7115
7315
|
options.sessionId,
|
|
7116
7316
|
record.id
|
|
7117
7317
|
);
|
|
7118
|
-
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
|
|
7125
|
-
|
|
7126
|
-
|
|
7127
|
-
|
|
7128
|
-
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7132
|
-
|
|
7133
|
-
|
|
7134
|
-
|
|
7135
|
-
|
|
7318
|
+
if (!options.isDelivered(record.id)) {
|
|
7319
|
+
await options.sendMessage(
|
|
7320
|
+
{
|
|
7321
|
+
customType: `pi-herdsman-${record.kind}`,
|
|
7322
|
+
content: deliveredMessageContent(record),
|
|
7323
|
+
display: true,
|
|
7324
|
+
details: {
|
|
7325
|
+
id: record.id,
|
|
7326
|
+
leaseId: record.leaseId,
|
|
7327
|
+
fromSessionId: record.fromSessionId,
|
|
7328
|
+
toSessionId: record.toSessionId,
|
|
7329
|
+
leadSessionId: record.leadSessionId,
|
|
7330
|
+
...record.branch ? { branch: record.branch } : {}
|
|
7331
|
+
}
|
|
7332
|
+
},
|
|
7333
|
+
{ deliverAs: deliverAs ?? "followUp", triggerTurn: true },
|
|
7334
|
+
record
|
|
7335
|
+
);
|
|
7336
|
+
await options.transaction?.revalidate(token, "after-send");
|
|
7337
|
+
}
|
|
7136
7338
|
} catch {
|
|
7137
7339
|
await clearTransaction();
|
|
7138
7340
|
continue;
|
|
7139
7341
|
}
|
|
7140
|
-
|
|
7342
|
+
if (!options.isDelivered(record.id)) {
|
|
7343
|
+
await clearTransaction();
|
|
7344
|
+
continue;
|
|
7345
|
+
}
|
|
7346
|
+
if (!wasAlreadyDelivered) delivered += 1;
|
|
7141
7347
|
try {
|
|
7142
7348
|
await options.transaction?.revalidate(token, "before-accepted");
|
|
7143
7349
|
assertChiefMessageNotQuarantined(
|
|
@@ -7153,6 +7359,7 @@ async function drainCoordinationInbox(options) {
|
|
|
7153
7359
|
}
|
|
7154
7360
|
} else {
|
|
7155
7361
|
try {
|
|
7362
|
+
if (!wasAlreadyDelivered) delivered += 1;
|
|
7156
7363
|
await options.transaction?.revalidate(token, "already-delivered");
|
|
7157
7364
|
assertChiefMessageNotQuarantined(
|
|
7158
7365
|
options.runtime,
|
|
@@ -8268,7 +8475,7 @@ function buildAgentStatusSnapshot(view, ctx, host) {
|
|
|
8268
8475
|
stale: false,
|
|
8269
8476
|
unavailable: false,
|
|
8270
8477
|
...herdStartedAt !== void 0 ? { herdRunStartedAt: herdStartedAt } : {},
|
|
8271
|
-
breadcrumb: host.scope.kind === "lead" ? ["lead"] : statusBreadcrumb(
|
|
8478
|
+
breadcrumb: host.scope.kind === "lead" ? [{ text: "lead" }] : statusBreadcrumb(
|
|
8272
8479
|
view,
|
|
8273
8480
|
host.environmentIdentity(ctx),
|
|
8274
8481
|
host.identityFromEnvironment(),
|
|
@@ -8289,6 +8496,7 @@ function createAgentStatusRuntime() {
|
|
|
8289
8496
|
let statusInFlight = false;
|
|
8290
8497
|
let requestActive = false;
|
|
8291
8498
|
let statusPrimed = false;
|
|
8499
|
+
let focusInFlight = false;
|
|
8292
8500
|
let lastValidStatus = {
|
|
8293
8501
|
agents: [],
|
|
8294
8502
|
stale: false,
|
|
@@ -8403,7 +8611,28 @@ function createAgentStatusRuntime() {
|
|
|
8403
8611
|
clearTimer();
|
|
8404
8612
|
statusContext = ctx;
|
|
8405
8613
|
ctx.ui.setWidget("pi-herdsman", (tui, theme) => {
|
|
8406
|
-
|
|
8614
|
+
let widget;
|
|
8615
|
+
widget = createStatusWidget(
|
|
8616
|
+
() => tui.requestRender(),
|
|
8617
|
+
theme,
|
|
8618
|
+
(intent) => {
|
|
8619
|
+
if (generation !== statusGeneration || ctx !== statusContext || statusWidgetGeneration !== generation || statusWidget !== widget)
|
|
8620
|
+
return;
|
|
8621
|
+
const focus = options?.focusTarget;
|
|
8622
|
+
if (!focus || focusInFlight) return;
|
|
8623
|
+
const isCurrent = () => generation === statusGeneration && ctx === statusContext && statusWidgetGeneration === generation && statusWidget === widget;
|
|
8624
|
+
focusInFlight = true;
|
|
8625
|
+
void focus(ctx, intent, isCurrent).catch((error2) => {
|
|
8626
|
+
if (generation === statusGeneration && ctx === statusContext)
|
|
8627
|
+
ctx.ui.notify(
|
|
8628
|
+
String(error2).replace(/^Error: /u, ""),
|
|
8629
|
+
"warning"
|
|
8630
|
+
);
|
|
8631
|
+
}).finally(() => {
|
|
8632
|
+
if (generation === statusGeneration) focusInFlight = false;
|
|
8633
|
+
});
|
|
8634
|
+
}
|
|
8635
|
+
);
|
|
8407
8636
|
widget.setSnapshot(widgetSnapshot(lastValidStatus));
|
|
8408
8637
|
if (generation === statusGeneration && ctx === statusContext) {
|
|
8409
8638
|
statusWidget = widget;
|
|
@@ -8423,12 +8652,14 @@ function createAgentStatusRuntime() {
|
|
|
8423
8652
|
statusWidget?.dispose();
|
|
8424
8653
|
statusWidget = void 0;
|
|
8425
8654
|
requestActive = false;
|
|
8655
|
+
focusInFlight = false;
|
|
8426
8656
|
statusPrimed = false;
|
|
8427
8657
|
},
|
|
8428
8658
|
prepareSession: (ctx, beforeActivate) => {
|
|
8429
8659
|
clearTimer();
|
|
8430
8660
|
statusRefresh = false;
|
|
8431
8661
|
statusInFlight = false;
|
|
8662
|
+
focusInFlight = false;
|
|
8432
8663
|
removeWidget();
|
|
8433
8664
|
statusWidgetGeneration = 0;
|
|
8434
8665
|
statusContext = void 0;
|
|
@@ -8451,6 +8682,7 @@ function createAgentStatusRuntime() {
|
|
|
8451
8682
|
clearTimer();
|
|
8452
8683
|
statusRefresh = false;
|
|
8453
8684
|
statusInFlight = false;
|
|
8685
|
+
focusInFlight = false;
|
|
8454
8686
|
removeWidget();
|
|
8455
8687
|
statusWidgetGeneration = 0;
|
|
8456
8688
|
statusContext = void 0;
|
|
@@ -8796,39 +9028,50 @@ function visibleAgentSnapshots(snapshot, scope, ownerSessionId) {
|
|
|
8796
9028
|
return visible;
|
|
8797
9029
|
}
|
|
8798
9030
|
function statusBreadcrumb(snapshot, candidate, identity, sameIdentity) {
|
|
8799
|
-
if (!candidate) return ["?"];
|
|
8800
|
-
const
|
|
9031
|
+
if (!candidate) return [{ text: "?" }];
|
|
9032
|
+
const matches = snapshot.agents.filter(
|
|
8801
9033
|
({ state }) => sameIdentity(state, candidate)
|
|
8802
9034
|
);
|
|
9035
|
+
const current = matches.length === 1 ? matches[0] : void 0;
|
|
8803
9036
|
if (!current)
|
|
8804
9037
|
return [
|
|
8805
|
-
"?",
|
|
8806
|
-
|
|
9038
|
+
{ text: "?" },
|
|
9039
|
+
{
|
|
9040
|
+
text: identity.definition && identity.label ? displayIdentity(identity.definition, identity.label) : identity.definition ?? "?"
|
|
9041
|
+
}
|
|
8807
9042
|
];
|
|
8808
9043
|
const definitions = [
|
|
8809
|
-
|
|
9044
|
+
{
|
|
9045
|
+
text: displayIdentity(current.agentDefinition, current.state.agentLabel),
|
|
9046
|
+
sessionId: current.state.piSessionId
|
|
9047
|
+
}
|
|
8810
9048
|
];
|
|
8811
9049
|
const visited = /* @__PURE__ */ new Set([current.state.piSessionId]);
|
|
8812
9050
|
let ownerSessionId = current.state.ownerSessionId;
|
|
8813
9051
|
while (true) {
|
|
8814
|
-
const
|
|
9052
|
+
const parents = snapshot.agents.filter(
|
|
8815
9053
|
({ state }) => state.piSessionId === ownerSessionId
|
|
8816
9054
|
);
|
|
9055
|
+
if (parents.length > 1) return [{ text: "?" }, ...definitions.reverse()];
|
|
9056
|
+
const parent = parents[0];
|
|
8817
9057
|
if (parent) {
|
|
8818
9058
|
if (visited.has(parent.state.piSessionId))
|
|
8819
|
-
return ["?", ...definitions.reverse()];
|
|
9059
|
+
return [{ text: "?" }, ...definitions.reverse()];
|
|
8820
9060
|
visited.add(parent.state.piSessionId);
|
|
8821
|
-
definitions.push(
|
|
8822
|
-
displayIdentity(parent.agentDefinition, parent.state.agentLabel)
|
|
8823
|
-
|
|
9061
|
+
definitions.push({
|
|
9062
|
+
text: displayIdentity(parent.agentDefinition, parent.state.agentLabel),
|
|
9063
|
+
sessionId: parent.state.piSessionId
|
|
9064
|
+
});
|
|
8824
9065
|
ownerSessionId = parent.state.ownerSessionId;
|
|
8825
9066
|
continue;
|
|
8826
9067
|
}
|
|
8827
9068
|
if (snapshot.mailboxes.some(
|
|
8828
9069
|
({ state }) => state.piSessionId === ownerSessionId
|
|
8829
9070
|
))
|
|
8830
|
-
return ["?", ...definitions.reverse()];
|
|
8831
|
-
return snapshot.leadSessionIds.
|
|
9071
|
+
return [{ text: "?" }, ...definitions.reverse()];
|
|
9072
|
+
return snapshot.leadSessionIds.filter(
|
|
9073
|
+
(sessionId) => sessionId === ownerSessionId
|
|
9074
|
+
).length === 1 ? [{ text: "lead", sessionId: ownerSessionId }, ...definitions.reverse()] : [{ text: "?" }, ...definitions.reverse()];
|
|
8832
9075
|
}
|
|
8833
9076
|
}
|
|
8834
9077
|
function sessionAgentIdentity(entries, sessionId) {
|
|
@@ -12144,6 +12387,7 @@ function createAgentController(pi, options) {
|
|
|
12144
12387
|
let promptWriteFailed = false;
|
|
12145
12388
|
let started;
|
|
12146
12389
|
let accepted = false;
|
|
12390
|
+
const preparedBootstrap = [];
|
|
12147
12391
|
try {
|
|
12148
12392
|
try {
|
|
12149
12393
|
promptPaths = writePrivatePromptSnapshots([
|
|
@@ -12171,6 +12415,69 @@ function createAgentController(pi, options) {
|
|
|
12171
12415
|
);
|
|
12172
12416
|
ownerDisplay = displayIdentity(definition2, parentLabel);
|
|
12173
12417
|
}
|
|
12418
|
+
if (p.action === "delegate") {
|
|
12419
|
+
const registrations = /* @__PURE__ */ new Map();
|
|
12420
|
+
let open = true;
|
|
12421
|
+
let registrationError;
|
|
12422
|
+
pi.events.emit(MANAGED_AGENT_BOOTSTRAP_EVENT, {
|
|
12423
|
+
protocol: 1,
|
|
12424
|
+
phase: "prepare",
|
|
12425
|
+
context: ctx,
|
|
12426
|
+
agent: label,
|
|
12427
|
+
register(id, prepare) {
|
|
12428
|
+
if (!open)
|
|
12429
|
+
throw new Error(
|
|
12430
|
+
"Managed-agent bootstrap registration is closed"
|
|
12431
|
+
);
|
|
12432
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/.test(id)) {
|
|
12433
|
+
registrationError ??= new Error(
|
|
12434
|
+
"Invalid managed-agent bootstrap participant ID"
|
|
12435
|
+
);
|
|
12436
|
+
return;
|
|
12437
|
+
}
|
|
12438
|
+
if (registrations.has(id)) {
|
|
12439
|
+
registrationError ??= new Error(
|
|
12440
|
+
`Duplicate managed-agent bootstrap participant ID: ${id}`
|
|
12441
|
+
);
|
|
12442
|
+
return;
|
|
12443
|
+
}
|
|
12444
|
+
if (typeof prepare !== "function") {
|
|
12445
|
+
registrationError ??= new Error(
|
|
12446
|
+
"Invalid managed-agent bootstrap prepare callback"
|
|
12447
|
+
);
|
|
12448
|
+
return;
|
|
12449
|
+
}
|
|
12450
|
+
registrations.set(id, prepare);
|
|
12451
|
+
}
|
|
12452
|
+
});
|
|
12453
|
+
open = false;
|
|
12454
|
+
if (registrationError) throw registrationError;
|
|
12455
|
+
const participants = [];
|
|
12456
|
+
for (const [id, prepare] of registrations) {
|
|
12457
|
+
const result = await prepare();
|
|
12458
|
+
if (result !== void 0) {
|
|
12459
|
+
if (!result || typeof result.payload !== "string" || result.commit !== void 0 && typeof result.commit !== "function")
|
|
12460
|
+
throw new Error(
|
|
12461
|
+
`Invalid preparation from managed-agent bootstrap participant "${id}"`
|
|
12462
|
+
);
|
|
12463
|
+
participants.push({ id, payload: result.payload });
|
|
12464
|
+
preparedBootstrap.push({
|
|
12465
|
+
id,
|
|
12466
|
+
...result.commit ? { commit: result.commit } : {}
|
|
12467
|
+
});
|
|
12468
|
+
}
|
|
12469
|
+
}
|
|
12470
|
+
if (participants.length)
|
|
12471
|
+
writeAgentBootstrap(mailbox, {
|
|
12472
|
+
version: 5,
|
|
12473
|
+
build: options.build,
|
|
12474
|
+
runId,
|
|
12475
|
+
ownerSessionId: owner,
|
|
12476
|
+
workspaceId,
|
|
12477
|
+
agentLabel: label,
|
|
12478
|
+
participants
|
|
12479
|
+
});
|
|
12480
|
+
}
|
|
12174
12481
|
const env = [
|
|
12175
12482
|
`PI_HERDSMAN_MAILBOX=${mailbox}`,
|
|
12176
12483
|
`PI_HERDSMAN_RUN_ID=${runId}`,
|
|
@@ -12360,6 +12667,8 @@ ${result.stderr ?? ""}`.trim(),
|
|
|
12360
12667
|
signal,
|
|
12361
12668
|
waitForSession: true
|
|
12362
12669
|
});
|
|
12670
|
+
for (const participant of preparedBootstrap)
|
|
12671
|
+
await participant.commit?.();
|
|
12363
12672
|
runtimes.set(label, runtime);
|
|
12364
12673
|
options.onChanged();
|
|
12365
12674
|
const requestId = await submit(
|
|
@@ -14223,6 +14532,7 @@ function createManagedAgentLeafStatus(options) {
|
|
|
14223
14532
|
let context;
|
|
14224
14533
|
let generation = 0;
|
|
14225
14534
|
let inFlight = false;
|
|
14535
|
+
let focusInFlight = false;
|
|
14226
14536
|
let breadcrumb;
|
|
14227
14537
|
let ownTools;
|
|
14228
14538
|
const ownToolsSnapshot = () => ownTools ? { ownTools } : {};
|
|
@@ -14237,6 +14547,7 @@ function createManagedAgentLeafStatus(options) {
|
|
|
14237
14547
|
}
|
|
14238
14548
|
context = void 0;
|
|
14239
14549
|
inFlight = false;
|
|
14550
|
+
focusInFlight = false;
|
|
14240
14551
|
};
|
|
14241
14552
|
const refresh = async (ctx, activeGeneration) => {
|
|
14242
14553
|
if (activeGeneration !== generation || ctx !== context || inFlight) return;
|
|
@@ -14269,11 +14580,13 @@ function createManagedAgentLeafStatus(options) {
|
|
|
14269
14580
|
stale: false,
|
|
14270
14581
|
unavailable: true,
|
|
14271
14582
|
breadcrumb: breadcrumb ?? [
|
|
14272
|
-
"?",
|
|
14273
|
-
|
|
14274
|
-
process.env.PI_HERDSMAN_AGENT_DEFINITION
|
|
14275
|
-
|
|
14276
|
-
|
|
14583
|
+
{ text: "?" },
|
|
14584
|
+
{
|
|
14585
|
+
text: process.env.PI_HERDSMAN_AGENT_DEFINITION && process.env.PI_HERDSMAN_LABEL ? displayIdentity(
|
|
14586
|
+
process.env.PI_HERDSMAN_AGENT_DEFINITION,
|
|
14587
|
+
process.env.PI_HERDSMAN_LABEL
|
|
14588
|
+
) : process.env.PI_HERDSMAN_AGENT_DEFINITION ?? "?"
|
|
14589
|
+
}
|
|
14277
14590
|
],
|
|
14278
14591
|
...ownToolsSnapshot(),
|
|
14279
14592
|
identityOnly: true
|
|
@@ -14291,17 +14604,39 @@ function createManagedAgentLeafStatus(options) {
|
|
|
14291
14604
|
const activeGeneration = generation;
|
|
14292
14605
|
context = ctx;
|
|
14293
14606
|
ctx.ui.setWidget("pi-herdsman", (tui, theme) => {
|
|
14294
|
-
|
|
14607
|
+
let next;
|
|
14608
|
+
next = createStatusWidget(
|
|
14609
|
+
() => tui.requestRender(),
|
|
14610
|
+
theme,
|
|
14611
|
+
(intent) => {
|
|
14612
|
+
if (activeGeneration !== generation || ctx !== context || widget !== next || focusInFlight)
|
|
14613
|
+
return;
|
|
14614
|
+
if (!options.focusTarget) return;
|
|
14615
|
+
focusInFlight = true;
|
|
14616
|
+
const isCurrent = () => activeGeneration === generation && ctx === context && widget === next;
|
|
14617
|
+
void options.focusTarget(ctx, intent, isCurrent).catch((error2) => {
|
|
14618
|
+
if (activeGeneration === generation && ctx === context)
|
|
14619
|
+
ctx.ui.notify(
|
|
14620
|
+
String(error2).replace(/^Error: /u, ""),
|
|
14621
|
+
"warning"
|
|
14622
|
+
);
|
|
14623
|
+
}).finally(() => {
|
|
14624
|
+
if (activeGeneration === generation) focusInFlight = false;
|
|
14625
|
+
});
|
|
14626
|
+
}
|
|
14627
|
+
);
|
|
14295
14628
|
next.setSnapshot({
|
|
14296
14629
|
agents: [],
|
|
14297
14630
|
stale: false,
|
|
14298
14631
|
unavailable: true,
|
|
14299
14632
|
breadcrumb: [
|
|
14300
|
-
"?",
|
|
14301
|
-
|
|
14302
|
-
process.env.PI_HERDSMAN_AGENT_DEFINITION
|
|
14303
|
-
|
|
14304
|
-
|
|
14633
|
+
{ text: "?" },
|
|
14634
|
+
{
|
|
14635
|
+
text: process.env.PI_HERDSMAN_AGENT_DEFINITION && process.env.PI_HERDSMAN_LABEL ? displayIdentity(
|
|
14636
|
+
process.env.PI_HERDSMAN_AGENT_DEFINITION,
|
|
14637
|
+
process.env.PI_HERDSMAN_LABEL
|
|
14638
|
+
) : process.env.PI_HERDSMAN_AGENT_DEFINITION ?? "?"
|
|
14639
|
+
}
|
|
14305
14640
|
],
|
|
14306
14641
|
...ownToolsSnapshot(),
|
|
14307
14642
|
identityOnly: true
|
|
@@ -15000,6 +15335,72 @@ function registerManagedAgentRuntime(pi, options) {
|
|
|
15000
15335
|
clearPendingStart: (label, expected) => controller.clearPendingStart(label, expected),
|
|
15001
15336
|
runtimeForLabel: (label) => controller.runtimeForLabel(label),
|
|
15002
15337
|
ownToolsSnapshot: () => ({}),
|
|
15338
|
+
focusTarget: async (ctx, intent, isCurrent) => {
|
|
15339
|
+
if (intent.kind !== "session")
|
|
15340
|
+
throw new Error("Manager navigation is unavailable from an Agent.");
|
|
15341
|
+
const signal = controller.sessionSignal();
|
|
15342
|
+
if (!signal) throw new Error("Agent session is no longer active.");
|
|
15343
|
+
const ownerSessionId = ctx.sessionManager.getSessionId();
|
|
15344
|
+
const view = await controller.agentSnapshotView(
|
|
15345
|
+
ctx,
|
|
15346
|
+
scope,
|
|
15347
|
+
signal,
|
|
15348
|
+
true,
|
|
15349
|
+
false
|
|
15350
|
+
);
|
|
15351
|
+
const fresh = buildAgentStatusSnapshot(view, ctx, {
|
|
15352
|
+
scope,
|
|
15353
|
+
listedAgentRecord: controller.listedAgentRecord,
|
|
15354
|
+
runtimeForLabel: controller.runtimeForLabel,
|
|
15355
|
+
environmentIdentity: (context) => managedAgentEnvironmentIdentity(context, options.build),
|
|
15356
|
+
identityFromEnvironment: () => ({
|
|
15357
|
+
definition: process.env.PI_HERDSMAN_AGENT_DEFINITION,
|
|
15358
|
+
label: process.env.PI_HERDSMAN_LABEL
|
|
15359
|
+
}),
|
|
15360
|
+
sameIdentity: sameManagedAgentIdentity,
|
|
15361
|
+
ownToolsSnapshot: () => ({})
|
|
15362
|
+
});
|
|
15363
|
+
const currentIdentity = managedAgentEnvironmentIdentity(
|
|
15364
|
+
ctx,
|
|
15365
|
+
options.build
|
|
15366
|
+
);
|
|
15367
|
+
const breadcrumb = currentIdentity ? statusBreadcrumb(
|
|
15368
|
+
view,
|
|
15369
|
+
currentIdentity,
|
|
15370
|
+
{
|
|
15371
|
+
definition: process.env.PI_HERDSMAN_AGENT_DEFINITION,
|
|
15372
|
+
label: process.env.PI_HERDSMAN_LABEL
|
|
15373
|
+
},
|
|
15374
|
+
sameManagedAgentIdentity
|
|
15375
|
+
) : [];
|
|
15376
|
+
const statusTarget = fresh.agents.filter(
|
|
15377
|
+
(agent) => agent.sessionId === intent.sessionId
|
|
15378
|
+
);
|
|
15379
|
+
const isAncestor = breadcrumb.some(
|
|
15380
|
+
(segment) => segment.sessionId === intent.sessionId
|
|
15381
|
+
);
|
|
15382
|
+
if (!isCurrent() || signal.aborted || ctx.sessionManager.getSessionId() !== ownerSessionId || statusTarget.length !== 1 && !isAncestor)
|
|
15383
|
+
throw new Error("Agent changed; reopen status.");
|
|
15384
|
+
if (statusTarget.length === 1 && (statusTarget[0].state === "unknown" || statusTarget[0].state === "lost" || statusTarget[0].state === "starting" || !statusTarget[0].paneId))
|
|
15385
|
+
throw new Error("Agent changed; reopen status.");
|
|
15386
|
+
const { agents } = await listAllHerdrAgents(pi, ctx, signal);
|
|
15387
|
+
const live = agents.filter(
|
|
15388
|
+
(agent) => herdrSessionId(agent) === intent.sessionId && typeof agent.pane_id === "string"
|
|
15389
|
+
);
|
|
15390
|
+
if (signal.aborted || !isCurrent() || live.length !== 1 || statusTarget.length === 1 && live[0].pane_id !== statusTarget[0].paneId)
|
|
15391
|
+
throw new Error("Agent changed; reopen status.");
|
|
15392
|
+
const current = await runHerdr(
|
|
15393
|
+
pi,
|
|
15394
|
+
ctx,
|
|
15395
|
+
["agent", "get", live[0].pane_id],
|
|
15396
|
+
{ signal }
|
|
15397
|
+
);
|
|
15398
|
+
if (signal.aborted || !isCurrent() || herdrSessionId(current?.agent) !== intent.sessionId || current?.agent?.pane_id !== live[0].pane_id || current?.agent?.workspace_id !== live[0].workspace_id || current?.agent?.tab_id !== live[0].tab_id)
|
|
15399
|
+
throw new Error("Agent changed; reopen status.");
|
|
15400
|
+
await runHerdr(pi, ctx, ["agent", "focus", current.agent.pane_id], {
|
|
15401
|
+
signal
|
|
15402
|
+
});
|
|
15403
|
+
},
|
|
15003
15404
|
loadSnapshot: async (ctx) => {
|
|
15004
15405
|
const view = await controller.agentSnapshotView(
|
|
15005
15406
|
ctx,
|
|
@@ -15056,7 +15457,52 @@ This is the session-start definition snapshot. Use list_agents for live Agent st
|
|
|
15056
15457
|
),
|
|
15057
15458
|
identity: (ctx) => managedAgentEnvironmentIdentity(ctx, options.build),
|
|
15058
15459
|
sameIdentity: sameManagedAgentIdentity,
|
|
15059
|
-
signal: () => metadataPublisher.signal
|
|
15460
|
+
signal: () => metadataPublisher.signal,
|
|
15461
|
+
focusTarget: async (ctx, intent, isCurrent) => {
|
|
15462
|
+
if (intent.kind !== "session")
|
|
15463
|
+
throw new Error("Manager navigation is unavailable from an Agent.");
|
|
15464
|
+
const signal = metadataPublisher.signal;
|
|
15465
|
+
const sessionId = ctx.sessionManager.getSessionId();
|
|
15466
|
+
const snapshot = await managedAgentSnapshots(
|
|
15467
|
+
pi,
|
|
15468
|
+
ctx,
|
|
15469
|
+
options.controllerOptions.snapshotDependencies,
|
|
15470
|
+
signal,
|
|
15471
|
+
true,
|
|
15472
|
+
false,
|
|
15473
|
+
void 0,
|
|
15474
|
+
false
|
|
15475
|
+
);
|
|
15476
|
+
const identity = managedAgentEnvironmentIdentity(ctx, options.build);
|
|
15477
|
+
const breadcrumb = identity ? statusBreadcrumb(
|
|
15478
|
+
snapshot,
|
|
15479
|
+
identity,
|
|
15480
|
+
{
|
|
15481
|
+
definition: process.env.PI_HERDSMAN_AGENT_DEFINITION,
|
|
15482
|
+
label: process.env.PI_HERDSMAN_LABEL
|
|
15483
|
+
},
|
|
15484
|
+
sameManagedAgentIdentity
|
|
15485
|
+
) : [];
|
|
15486
|
+
if (signal?.aborted || !isCurrent() || ctx.sessionManager.getSessionId() !== sessionId || !breadcrumb.some((segment) => segment.sessionId === intent.sessionId))
|
|
15487
|
+
throw new Error("Agent ancestry changed; reopen status.");
|
|
15488
|
+
const { agents } = await listAllHerdrAgents(pi, ctx, signal);
|
|
15489
|
+
const matches = agents.filter(
|
|
15490
|
+
(agent) => herdrSessionId(agent) === intent.sessionId && typeof agent.pane_id === "string"
|
|
15491
|
+
);
|
|
15492
|
+
if (signal?.aborted || !isCurrent() || matches.length !== 1)
|
|
15493
|
+
throw new Error("Agent changed; reopen status.");
|
|
15494
|
+
const current = await runHerdr(
|
|
15495
|
+
pi,
|
|
15496
|
+
ctx,
|
|
15497
|
+
["agent", "get", matches[0].pane_id],
|
|
15498
|
+
{ signal }
|
|
15499
|
+
);
|
|
15500
|
+
if (signal?.aborted || !isCurrent() || herdrSessionId(current?.agent) !== intent.sessionId || current?.agent?.pane_id !== matches[0].pane_id || current?.agent?.workspace_id !== matches[0].workspace_id || current?.agent?.tab_id !== matches[0].tab_id)
|
|
15501
|
+
throw new Error("Agent changed; reopen status.");
|
|
15502
|
+
await runHerdr(pi, ctx, ["agent", "focus", current.agent.pane_id], {
|
|
15503
|
+
signal
|
|
15504
|
+
});
|
|
15505
|
+
}
|
|
15060
15506
|
});
|
|
15061
15507
|
const mutateAgentState = (update) => {
|
|
15062
15508
|
const state = execution.assignment;
|
|
@@ -15644,8 +16090,53 @@ function registerManagedAgentSessionStartHandler(pi, execution, options) {
|
|
|
15644
16090
|
}
|
|
15645
16091
|
}
|
|
15646
16092
|
}
|
|
15647
|
-
if (!existing)
|
|
16093
|
+
if (!existing) {
|
|
15648
16094
|
validateManagedAgentDefinition(await options.getAgentDefinitions(ctx));
|
|
16095
|
+
const bootstrap = readAgentBootstrap(mailbox);
|
|
16096
|
+
if (bootstrap) {
|
|
16097
|
+
if (bootstrap.runId !== candidate.runId || bootstrap.ownerSessionId !== candidate.ownerSessionId || bootstrap.workspaceId !== candidate.workspaceId || bootstrap.agentLabel !== candidate.agentLabel)
|
|
16098
|
+
throw new Error("Managed-agent bootstrap identity mismatch");
|
|
16099
|
+
if (!sameRuntimeBuild(options.build, bootstrap.build))
|
|
16100
|
+
throw new Error("Managed-agent bootstrap Herdsman build mismatch");
|
|
16101
|
+
for (const participant of bootstrap.participants) {
|
|
16102
|
+
let initializer;
|
|
16103
|
+
let acceptCount = 0;
|
|
16104
|
+
let invalidInitializer = false;
|
|
16105
|
+
pi.events.emit(MANAGED_AGENT_BOOTSTRAP_EVENT, {
|
|
16106
|
+
protocol: 1,
|
|
16107
|
+
phase: "initialize",
|
|
16108
|
+
context: ctx,
|
|
16109
|
+
agent: candidate.agentLabel,
|
|
16110
|
+
participant: { id: participant.id, payload: participant.payload },
|
|
16111
|
+
accept(callback) {
|
|
16112
|
+
acceptCount++;
|
|
16113
|
+
if (typeof callback !== "function") {
|
|
16114
|
+
invalidInitializer = true;
|
|
16115
|
+
return;
|
|
16116
|
+
}
|
|
16117
|
+
if (acceptCount === 1) initializer = callback;
|
|
16118
|
+
}
|
|
16119
|
+
});
|
|
16120
|
+
if (acceptCount === 0 || invalidInitializer)
|
|
16121
|
+
throw new Error(
|
|
16122
|
+
`Managed-agent bootstrap participant "${participant.id}" is unavailable or invalid`
|
|
16123
|
+
);
|
|
16124
|
+
if (acceptCount > 1)
|
|
16125
|
+
throw new Error(
|
|
16126
|
+
`Managed-agent bootstrap participant "${participant.id}" has multiple initializers`
|
|
16127
|
+
);
|
|
16128
|
+
try {
|
|
16129
|
+
await initializer();
|
|
16130
|
+
} catch (error2) {
|
|
16131
|
+
throw new Error(
|
|
16132
|
+
`Managed-agent bootstrap participant "${participant.id}" failed: ${String(error2)}`,
|
|
16133
|
+
{ cause: error2 }
|
|
16134
|
+
);
|
|
16135
|
+
}
|
|
16136
|
+
}
|
|
16137
|
+
removeAgentBootstrap(mailbox);
|
|
16138
|
+
}
|
|
16139
|
+
}
|
|
15649
16140
|
const release = options.claimAssignmentLock(mailbox, "session_start", {
|
|
15650
16141
|
label: execution.assignment.agentLabel,
|
|
15651
16142
|
paneId: execution.assignment.paneId
|
|
@@ -16020,6 +16511,12 @@ function createLeadSessionStartRuntime(host) {
|
|
|
16020
16511
|
}
|
|
16021
16512
|
}
|
|
16022
16513
|
if (sessionSignal.aborted) return;
|
|
16514
|
+
if (host.roleTransitions.activeManager())
|
|
16515
|
+
await host.publishLeadRole(
|
|
16516
|
+
ctx,
|
|
16517
|
+
"inactive",
|
|
16518
|
+
host.roleTransitions.currentRoleGeneration()
|
|
16519
|
+
);
|
|
16023
16520
|
if (needsLeadRoster) {
|
|
16024
16521
|
try {
|
|
16025
16522
|
const definitions = await host.visibleAgentDefinitionMetadata(
|
|
@@ -16090,6 +16587,7 @@ This is the session-start definition snapshot. Use list_agents for live Agent st
|
|
|
16090
16587
|
host.herdRun.agentStarted();
|
|
16091
16588
|
},
|
|
16092
16589
|
async agentSettled(ctx, aborted) {
|
|
16590
|
+
host.leadInboxRuntime.agentSettled();
|
|
16093
16591
|
host.controller.settleAsks(ctx, host.controller.sessionSignal());
|
|
16094
16592
|
host.herdRun.agentSettled(ctx, aborted);
|
|
16095
16593
|
await host.controller.settleResults(ctx, host.controller.sessionSignal()).catch(() => {
|
|
@@ -16969,41 +17467,67 @@ function registerLeadRuntime(pi, options) {
|
|
|
16969
17467
|
};
|
|
16970
17468
|
const roleHost = options.roleTransitionHost;
|
|
16971
17469
|
let leadMetadataQueue = Promise.resolve();
|
|
16972
|
-
|
|
16973
|
-
|
|
16974
|
-
|
|
16975
|
-
const
|
|
16976
|
-
const
|
|
16977
|
-
const args = [
|
|
16978
|
-
"pane",
|
|
16979
|
-
"report-metadata",
|
|
16980
|
-
paneId,
|
|
16981
|
-
"--source",
|
|
16982
|
-
"pi-herdsman:lead",
|
|
16983
|
-
"--title",
|
|
16984
|
-
mode === "active" ? "chief" : activeRole() === "manager" ? "Pi Herdsman manager" : leadName || "Pi Herdsman lead",
|
|
16985
|
-
...mode === "active" ? ["--token", "pi_herdsman_role=chief"] : mode === "inactive" ? ["--token", `pi_herdsman_role=${activeRole()}`] : ["--clear-token", "pi_herdsman_role"]
|
|
16986
|
-
];
|
|
16987
|
-
if (mode === "inactive" && activeRole() === "lead")
|
|
16988
|
-
args.push(
|
|
16989
|
-
leadName ? "--token" : "--clear-token",
|
|
16990
|
-
leadName ? `pi_herdsman_name=${leadName}` : "pi_herdsman_name"
|
|
16991
|
-
);
|
|
16992
|
-
if (mode !== "inactive" || activeRole() !== "lead")
|
|
16993
|
-
args.push(
|
|
16994
|
-
"--clear-token",
|
|
16995
|
-
"pi_herdsman_herd_run_started_at",
|
|
16996
|
-
"--clear-token",
|
|
16997
|
-
"pi_herdsman_context_percent"
|
|
16998
|
-
);
|
|
17470
|
+
let reportedRoleMetadataFailure;
|
|
17471
|
+
const publishLeadRole = (ctx, _mode, generation) => {
|
|
17472
|
+
const sessionId = ctx.sessionManager.getSessionId();
|
|
17473
|
+
const sessionGeneration = leadRuntime.sessionGeneration;
|
|
17474
|
+
const failureKey = `${sessionId}:${sessionGeneration}:${generation}`;
|
|
16999
17475
|
leadMetadataQueue = leadMetadataQueue.catch(() => {
|
|
17000
17476
|
}).then(async () => {
|
|
17001
|
-
if (generation !== leadRuntime.chiefModeGeneration)
|
|
17477
|
+
if (generation !== leadRuntime.chiefModeGeneration || sessionGeneration !== leadRuntime.sessionGeneration || sessionId !== ctx.sessionManager.getSessionId())
|
|
17478
|
+
return;
|
|
17479
|
+
const paneId = roleHost.paneId();
|
|
17480
|
+
if (!paneId) return;
|
|
17481
|
+
const role2 = leadRuntime.chiefMode === "active" ? "chief" : leadRuntime.controllerRole === "manager" && !leadRuntime.roleSuspended ? "manager" : leadRuntime.roleSuspended ? void 0 : "lead";
|
|
17482
|
+
const leadName = role2 === "lead" ? roleHost.getSessionName()?.trim() : void 0;
|
|
17483
|
+
const args = [
|
|
17484
|
+
"pane",
|
|
17485
|
+
"report-metadata",
|
|
17486
|
+
paneId,
|
|
17487
|
+
"--source",
|
|
17488
|
+
"pi-herdsman:lead",
|
|
17489
|
+
"--title",
|
|
17490
|
+
role2 === "chief" ? "chief" : role2 === "manager" ? "Pi Herdsman manager" : leadName || "Pi Herdsman lead",
|
|
17491
|
+
...role2 ? ["--token", `pi_herdsman_role=${role2}`] : ["--clear-token", "pi_herdsman_role"]
|
|
17492
|
+
];
|
|
17493
|
+
if (role2 === "lead")
|
|
17494
|
+
args.push(
|
|
17495
|
+
leadName ? "--token" : "--clear-token",
|
|
17496
|
+
leadName ? `pi_herdsman_name=${leadName}` : "pi_herdsman_name"
|
|
17497
|
+
);
|
|
17498
|
+
else
|
|
17499
|
+
args.push(
|
|
17500
|
+
"--clear-token",
|
|
17501
|
+
"pi_herdsman_name",
|
|
17502
|
+
"--clear-token",
|
|
17503
|
+
"pi_herdsman_ask"
|
|
17504
|
+
);
|
|
17505
|
+
if (role2 !== "lead")
|
|
17506
|
+
args.push(
|
|
17507
|
+
"--clear-token",
|
|
17508
|
+
"pi_herdsman_herd_run_started_at",
|
|
17509
|
+
"--clear-token",
|
|
17510
|
+
"pi_herdsman_context_percent"
|
|
17511
|
+
);
|
|
17002
17512
|
await roleHost.runHerdr(pi, ctx, args, {
|
|
17003
17513
|
noResult: true,
|
|
17004
17514
|
timeout: 1e4
|
|
17005
17515
|
});
|
|
17006
|
-
|
|
17516
|
+
reportedRoleMetadataFailure = void 0;
|
|
17517
|
+
}).catch((error2) => {
|
|
17518
|
+
if (sessionGeneration !== leadRuntime.sessionGeneration || sessionId !== ctx.sessionManager.getSessionId())
|
|
17519
|
+
return;
|
|
17520
|
+
if (reportedRoleMetadataFailure === failureKey) return;
|
|
17521
|
+
reportedRoleMetadataFailure = failureKey;
|
|
17522
|
+
try {
|
|
17523
|
+
roleHost.appendDurableError(
|
|
17524
|
+
pi,
|
|
17525
|
+
ctx,
|
|
17526
|
+
"pi_herdsman_state_error",
|
|
17527
|
+
error2
|
|
17528
|
+
);
|
|
17529
|
+
} catch {
|
|
17530
|
+
}
|
|
17007
17531
|
});
|
|
17008
17532
|
return leadMetadataQueue;
|
|
17009
17533
|
};
|
|
@@ -17016,8 +17540,30 @@ function registerLeadRuntime(pi, options) {
|
|
|
17016
17540
|
);
|
|
17017
17541
|
return;
|
|
17018
17542
|
}
|
|
17543
|
+
const sessionId = ctx.sessionManager.getSessionId();
|
|
17544
|
+
const sessionGeneration = leadRuntime.sessionGeneration;
|
|
17019
17545
|
leadMetadataQueue = leadMetadataQueue.catch(() => {
|
|
17020
|
-
}).then(() =>
|
|
17546
|
+
}).then(() => {
|
|
17547
|
+
if (sessionGeneration !== leadRuntime.sessionGeneration || sessionId !== ctx.sessionManager.getSessionId() || leadRuntime.controllerRole !== "lead" || leadRuntime.roleSuspended)
|
|
17548
|
+
return;
|
|
17549
|
+
return roleHost.reportLeadMetadata(pi, ctx, metadata).then(() => {
|
|
17550
|
+
reportedRoleMetadataFailure = void 0;
|
|
17551
|
+
});
|
|
17552
|
+
}).catch((error2) => {
|
|
17553
|
+
if (sessionGeneration !== leadRuntime.sessionGeneration || sessionId !== ctx.sessionManager.getSessionId())
|
|
17554
|
+
return;
|
|
17555
|
+
const failureKey = `${sessionId}:${sessionGeneration}:${leadRuntime.chiefModeGeneration}`;
|
|
17556
|
+
if (reportedRoleMetadataFailure === failureKey) return;
|
|
17557
|
+
reportedRoleMetadataFailure = failureKey;
|
|
17558
|
+
try {
|
|
17559
|
+
roleHost.appendDurableError(
|
|
17560
|
+
pi,
|
|
17561
|
+
ctx,
|
|
17562
|
+
"pi_herdsman_state_error",
|
|
17563
|
+
error2
|
|
17564
|
+
);
|
|
17565
|
+
} catch {
|
|
17566
|
+
}
|
|
17021
17567
|
});
|
|
17022
17568
|
};
|
|
17023
17569
|
const persistRole = (role2) => {
|
|
@@ -17232,13 +17778,88 @@ function registerLeadRuntime(pi, options) {
|
|
|
17232
17778
|
const execution = isLead && assignmentVerified ? assignment ? { kind: "managed" } : leadExecution?.valid ? { kind: "ordinary", mode: leadExecution.mode } : void 0 : void 0;
|
|
17233
17779
|
return { ...snapshot, ...execution ? { execution } : {} };
|
|
17234
17780
|
};
|
|
17781
|
+
const focusTarget = async (ctx, intent, isCurrent) => {
|
|
17782
|
+
const sessionId = ctx.sessionManager.getSessionId();
|
|
17783
|
+
const signal = controller.sessionSignal();
|
|
17784
|
+
const current = () => !!signal && !signal.aborted && isCurrent() && ctx.sessionManager.getSessionId() === sessionId && activeLeadRole(options.leadRuntime) === "lead" && !options.leadRuntime.roleSuspended;
|
|
17785
|
+
if (!current()) throw new Error("Navigation is no longer available.");
|
|
17786
|
+
if (intent.kind === "assigned-manager") {
|
|
17787
|
+
const scope = await roleTransitions.currentWorktreeScope(ctx);
|
|
17788
|
+
if (!current() || !scope)
|
|
17789
|
+
throw new Error("Managed project assignment changed.");
|
|
17790
|
+
const assignment = roleTransitions.projectAssignmentForScope(
|
|
17791
|
+
scope,
|
|
17792
|
+
sessionId
|
|
17793
|
+
);
|
|
17794
|
+
const manager = await roleTransitions.currentManager(ctx);
|
|
17795
|
+
if (!current() || !assignment || !manager || manager.repoKey !== assignment.repoKey)
|
|
17796
|
+
throw new Error("Managed project Manager is unavailable.");
|
|
17797
|
+
const target2 = await verifiedHerdrAgent(manager, {
|
|
17798
|
+
listAgents: async () => (await options.identityHost.listAgents(ctx)).agents,
|
|
17799
|
+
getAgent: async (paneId) => (await options.identityHost.getAgent(ctx, paneId))?.agent,
|
|
17800
|
+
expectedSession: options.identityHost.expectedSession,
|
|
17801
|
+
isPiAgent: options.identityHost.isPiAgent,
|
|
17802
|
+
matchesExpectedSession: options.identityHost.matchesExpectedSession
|
|
17803
|
+
});
|
|
17804
|
+
const currentManager = await roleTransitions.currentManager(ctx);
|
|
17805
|
+
const currentScope = await roleTransitions.currentWorktreeScope(ctx);
|
|
17806
|
+
const currentAssignment = currentScope ? roleTransitions.projectAssignmentForScope(currentScope, sessionId) : void 0;
|
|
17807
|
+
if (!current() || !target2 || !currentAssignment || currentAssignment.id !== assignment.id || currentAssignment.repoKey !== assignment.repoKey || currentAssignment.branch !== assignment.branch || !currentManager || currentManager.repoKey !== assignment.repoKey || !options.projectHost.sameManagerDescriptor(currentManager, manager))
|
|
17808
|
+
throw new Error("Managed project Manager changed.");
|
|
17809
|
+
await options.commandHost.runHerdr(
|
|
17810
|
+
pi,
|
|
17811
|
+
ctx,
|
|
17812
|
+
["agent", "focus", target2.pane_id],
|
|
17813
|
+
{
|
|
17814
|
+
signal
|
|
17815
|
+
}
|
|
17816
|
+
);
|
|
17817
|
+
return;
|
|
17818
|
+
}
|
|
17819
|
+
const fresh = await loadStatusSnapshot(ctx, signal, false);
|
|
17820
|
+
const matches = fresh.agents.filter(
|
|
17821
|
+
(agent) => agent.sessionId === intent.sessionId && agent.state !== "lost" && agent.state !== "unknown" && agent.state !== "starting" && !!agent.paneId
|
|
17822
|
+
);
|
|
17823
|
+
if (!current() || fresh.stale || fresh.unavailable || matches.length !== 1)
|
|
17824
|
+
throw new Error("Agent changed; reopen Running.");
|
|
17825
|
+
const target = matches[0];
|
|
17826
|
+
const live = await identityRuntime.liveAgent(ctx, target.sessionId);
|
|
17827
|
+
if (!current() || live.length !== 1 || live[0].pane_id !== target.paneId)
|
|
17828
|
+
throw new Error("Agent changed; reopen Running.");
|
|
17829
|
+
const verified = await verifiedHerdrAgent(
|
|
17830
|
+
{
|
|
17831
|
+
piSessionId: target.sessionId,
|
|
17832
|
+
paneId: target.paneId,
|
|
17833
|
+
tabId: live[0].tab_id,
|
|
17834
|
+
workspaceId: live[0].workspace_id
|
|
17835
|
+
},
|
|
17836
|
+
{
|
|
17837
|
+
listAgents: async () => (await options.identityHost.listAgents(ctx)).agents,
|
|
17838
|
+
getAgent: async (paneId) => (await options.identityHost.getAgent(ctx, paneId))?.agent,
|
|
17839
|
+
expectedSession: options.identityHost.expectedSession,
|
|
17840
|
+
isPiAgent: options.identityHost.isPiAgent,
|
|
17841
|
+
matchesExpectedSession: options.identityHost.matchesExpectedSession
|
|
17842
|
+
}
|
|
17843
|
+
);
|
|
17844
|
+
if (!current() || !verified)
|
|
17845
|
+
throw new Error("Agent changed; reopen Running.");
|
|
17846
|
+
await options.commandHost.runHerdr(
|
|
17847
|
+
pi,
|
|
17848
|
+
ctx,
|
|
17849
|
+
["agent", "focus", verified.pane_id],
|
|
17850
|
+
{
|
|
17851
|
+
signal
|
|
17852
|
+
}
|
|
17853
|
+
);
|
|
17854
|
+
};
|
|
17235
17855
|
statusRuntime.configure({
|
|
17236
17856
|
...options.statusSnapshotHost,
|
|
17237
17857
|
pendingStartEntries: () => controller.pendingStartEntries(),
|
|
17238
17858
|
hasPendingStart: (label) => controller.hasPendingStart(label),
|
|
17239
17859
|
clearPendingStart: (label, expected) => controller.clearPendingStart(label, expected),
|
|
17240
17860
|
loadSnapshot: (ctx) => loadStatusSnapshot(ctx, controller.sessionSignal(), false),
|
|
17241
|
-
runtimeForLabel: (label) => controller.runtimeForLabel(label)
|
|
17861
|
+
runtimeForLabel: (label) => controller.runtimeForLabel(label),
|
|
17862
|
+
focusTarget
|
|
17242
17863
|
});
|
|
17243
17864
|
let projectRuntime;
|
|
17244
17865
|
const projectHost = options.projectHost;
|
|
@@ -18042,6 +18663,8 @@ function createLeadSupervisionRuntime(host) {
|
|
|
18042
18663
|
let overviewGeneration = 0;
|
|
18043
18664
|
let renderOverview;
|
|
18044
18665
|
let renderWidget;
|
|
18666
|
+
let widgetFocusInFlight = false;
|
|
18667
|
+
let supervisionWidgetGeneration = 0;
|
|
18045
18668
|
const generation = (ctx) => [
|
|
18046
18669
|
host.state.chiefModeGeneration,
|
|
18047
18670
|
host.state.sessionGeneration,
|
|
@@ -18110,6 +18733,108 @@ function createLeadSupervisionRuntime(host) {
|
|
|
18110
18733
|
});
|
|
18111
18734
|
return inFlight;
|
|
18112
18735
|
};
|
|
18736
|
+
const focusLead = async (ctx, leadId, parentManagerSessionId, isCurrent = () => true) => {
|
|
18737
|
+
const currentGeneration = generation(ctx);
|
|
18738
|
+
const fresh = await loadSnapshot(ctx);
|
|
18739
|
+
if (!isCurrent() || currentGeneration !== generation(ctx))
|
|
18740
|
+
throw new Error("Lead changed; reopen staff.");
|
|
18741
|
+
if (host.activeRole() === "manager" && host.managerSupervisionItems(fresh).filter(
|
|
18742
|
+
(item) => item.kind === "lead" ? item.lead.lead === leadId : item.work.status === "active" && item.lead?.lead === leadId
|
|
18743
|
+
).length !== 1)
|
|
18744
|
+
throw new Error("Lead is no longer available.");
|
|
18745
|
+
const managers = host.listManagerDescriptors(host.supervisionRuntime());
|
|
18746
|
+
const verifyManager = async (sessionId, report) => {
|
|
18747
|
+
const candidates = managers.filter(
|
|
18748
|
+
(candidate) => candidate.piSessionId === sessionId
|
|
18749
|
+
);
|
|
18750
|
+
if (candidates.length !== 1) return void 0;
|
|
18751
|
+
const descriptor = candidates[0];
|
|
18752
|
+
const agents = await host.listAllHerdrAgents(host.pi, ctx, ctx.signal);
|
|
18753
|
+
const placements = agents.agents.filter(
|
|
18754
|
+
(candidate) => host.isPiAgent(candidate) && host.herdrSessionId(candidate) === sessionId && candidate.pane_id === descriptor.paneId && candidate.tab_id === descriptor.tabId && candidate.workspace_id === descriptor.workspaceId && (!report || report.paneId === descriptor.paneId && report.tabId === descriptor.tabId && report.workspaceId === descriptor.workspaceId)
|
|
18755
|
+
);
|
|
18756
|
+
return placements.length === 1 ? { descriptor, paneId: descriptor.paneId } : void 0;
|
|
18757
|
+
};
|
|
18758
|
+
let lead;
|
|
18759
|
+
let parent;
|
|
18760
|
+
let verifiedParent;
|
|
18761
|
+
if (parentManagerSessionId) {
|
|
18762
|
+
parent = host.presentationReports(fresh).find(
|
|
18763
|
+
(candidate) => candidate.role === "manager" && candidate.lead === parentManagerSessionId
|
|
18764
|
+
);
|
|
18765
|
+
const children = parent?.leads?.filter(
|
|
18766
|
+
(candidate) => candidate.session === leadId
|
|
18767
|
+
);
|
|
18768
|
+
if (!parent || children?.length !== 1)
|
|
18769
|
+
throw new Error("Lead changed; reopen staff.");
|
|
18770
|
+
lead = { lead: leadId };
|
|
18771
|
+
} else {
|
|
18772
|
+
const matches2 = host.presentationReports(fresh).filter((candidate) => candidate.lead === leadId);
|
|
18773
|
+
if (matches2.length !== 1) throw new Error("Lead changed; reopen staff.");
|
|
18774
|
+
lead = matches2[0];
|
|
18775
|
+
}
|
|
18776
|
+
if (parent || lead.role === "manager") {
|
|
18777
|
+
const managerSessionId = parent?.lead ?? lead.lead;
|
|
18778
|
+
const report = parent ?? lead;
|
|
18779
|
+
const manager = await verifyManager(managerSessionId, report);
|
|
18780
|
+
if (!manager || !isCurrent() || currentGeneration !== generation(ctx))
|
|
18781
|
+
throw new Error("Manager changed; reopen staff.");
|
|
18782
|
+
verifiedParent = manager.descriptor;
|
|
18783
|
+
if (!parent) {
|
|
18784
|
+
const currentManagers = host.listManagerDescriptors(host.supervisionRuntime()).filter((descriptor) => descriptor.piSessionId === managerSessionId);
|
|
18785
|
+
if (!isCurrent() || currentManagers.length !== 1 || !host.sameManagerDescriptor(currentManagers[0], manager.descriptor))
|
|
18786
|
+
throw new Error("Manager changed; reopen staff.");
|
|
18787
|
+
const currentAgent2 = await host.runHerdr(
|
|
18788
|
+
host.pi,
|
|
18789
|
+
ctx,
|
|
18790
|
+
["agent", "get", manager.paneId],
|
|
18791
|
+
{ signal: ctx.signal }
|
|
18792
|
+
);
|
|
18793
|
+
if (!isCurrent() || host.herdrSessionId(currentAgent2?.agent) !== managerSessionId || currentAgent2?.agent?.pane_id !== manager.paneId || currentAgent2?.agent?.tab_id !== manager.descriptor.tabId || currentAgent2?.agent?.workspace_id !== manager.descriptor.workspaceId)
|
|
18794
|
+
throw new Error("Manager changed; reopen staff.");
|
|
18795
|
+
const finalManagers = host.listManagerDescriptors(host.supervisionRuntime()).filter((descriptor) => descriptor.piSessionId === managerSessionId);
|
|
18796
|
+
if (!isCurrent() || finalManagers.length !== 1 || !host.sameManagerDescriptor(finalManagers[0], manager.descriptor))
|
|
18797
|
+
throw new Error("Manager changed; reopen staff.");
|
|
18798
|
+
await host.runHerdr(host.pi, ctx, ["agent", "focus", manager.paneId], {
|
|
18799
|
+
signal: ctx.signal
|
|
18800
|
+
});
|
|
18801
|
+
return;
|
|
18802
|
+
}
|
|
18803
|
+
}
|
|
18804
|
+
const coordination = host.readLeadCoordinationState(
|
|
18805
|
+
host.supervisionRuntime(),
|
|
18806
|
+
leadId
|
|
18807
|
+
);
|
|
18808
|
+
if (!coordination || coordination.piSessionId !== leadId || lead.instanceId !== void 0 && coordination.instanceId !== lead.instanceId)
|
|
18809
|
+
throw new Error("Lead changed; reopen staff.");
|
|
18810
|
+
const verified = await host.listAllHerdrAgents(host.pi, ctx, ctx.signal);
|
|
18811
|
+
if (!isCurrent() || currentGeneration !== generation(ctx))
|
|
18812
|
+
throw new Error("Lead changed; reopen staff.");
|
|
18813
|
+
const matches = verified.agents.filter(
|
|
18814
|
+
(candidate) => host.isPiAgent(candidate) && host.herdrSessionId(candidate) === leadId && typeof candidate?.pane_id === "string" && (parentManagerSessionId || candidate?.pane_id === lead.paneId && candidate?.tab_id === lead.tabId && candidate?.workspace_id === lead.workspaceId)
|
|
18815
|
+
);
|
|
18816
|
+
if (matches.length !== 1) throw new Error("Lead changed; reopen staff.");
|
|
18817
|
+
if (currentGeneration !== generation(ctx) || !isCurrent() || verifiedParent && !host.listManagerDescriptors(host.supervisionRuntime()).some(
|
|
18818
|
+
(descriptor) => host.sameManagerDescriptor(descriptor, verifiedParent)
|
|
18819
|
+
))
|
|
18820
|
+
throw new Error("Manager changed; reopen staff.");
|
|
18821
|
+
const currentAgent = await host.runHerdr(
|
|
18822
|
+
host.pi,
|
|
18823
|
+
ctx,
|
|
18824
|
+
["agent", "get", matches[0].pane_id],
|
|
18825
|
+
{ signal: ctx.signal }
|
|
18826
|
+
);
|
|
18827
|
+
if (!isCurrent() || host.herdrSessionId(currentAgent?.agent) !== leadId || currentAgent?.agent?.pane_id !== matches[0].pane_id || currentAgent?.agent?.workspace_id !== matches[0].workspace_id || currentAgent?.agent?.tab_id !== matches[0].tab_id)
|
|
18828
|
+
throw new Error("Lead changed; reopen staff.");
|
|
18829
|
+
await host.runHerdr(
|
|
18830
|
+
host.pi,
|
|
18831
|
+
ctx,
|
|
18832
|
+
["agent", "focus", currentAgent.agent.pane_id],
|
|
18833
|
+
{
|
|
18834
|
+
signal: ctx.signal
|
|
18835
|
+
}
|
|
18836
|
+
);
|
|
18837
|
+
};
|
|
18113
18838
|
const nextOverviewGeneration = () => ++overviewGeneration;
|
|
18114
18839
|
const openOverview = async (ctx, uiActions) => {
|
|
18115
18840
|
if (ctx.mode !== "tui") {
|
|
@@ -18415,25 +19140,7 @@ function createLeadSupervisionRuntime(host) {
|
|
|
18415
19140
|
openOverview,
|
|
18416
19141
|
loadSnapshot: loadSupervisionSnapshot,
|
|
18417
19142
|
directReports,
|
|
18418
|
-
focusLead
|
|
18419
|
-
const fresh = await loadSnapshot(ctx);
|
|
18420
|
-
const lead = host.presentationReports(fresh).find((candidate) => candidate.lead === leadId);
|
|
18421
|
-
if (!lead) throw new Error("Lead changed; reopen staff.");
|
|
18422
|
-
const coordination = host.readLeadCoordinationState(
|
|
18423
|
-
host.supervisionRuntime(),
|
|
18424
|
-
lead.lead
|
|
18425
|
-
);
|
|
18426
|
-
if (!coordination || coordination.piSessionId !== lead.lead || lead.instanceId !== void 0 && coordination.instanceId !== lead.instanceId)
|
|
18427
|
-
throw new Error("Lead changed; reopen staff.");
|
|
18428
|
-
const verified = await host.listAllHerdrAgents(host.pi, ctx, ctx.signal);
|
|
18429
|
-
const matches = verified.agents.filter(
|
|
18430
|
-
(candidate) => candidate?.pane_id === lead.paneId && candidate?.tab_id === lead.tabId && candidate?.workspace_id === lead.workspaceId && host.isPiAgent(candidate) && host.herdrSessionId(candidate) === lead.lead
|
|
18431
|
-
);
|
|
18432
|
-
if (matches.length !== 1) throw new Error("Lead changed; reopen staff.");
|
|
18433
|
-
await host.runHerdr(host.pi, ctx, ["agent", "focus", lead.paneId], {
|
|
18434
|
-
signal: ctx.signal
|
|
18435
|
-
});
|
|
18436
|
-
},
|
|
19143
|
+
focusLead,
|
|
18437
19144
|
focusChief: async (ctx) => {
|
|
18438
19145
|
const confirmed = await ctx.ui.confirm(
|
|
18439
19146
|
"Focus Chief?",
|
|
@@ -18479,13 +19186,35 @@ function createLeadSupervisionRuntime(host) {
|
|
|
18479
19186
|
registerWidget: (ctx, role2) => {
|
|
18480
19187
|
if (ctx.mode !== "tui" || !ctx.hasUI) return;
|
|
18481
19188
|
try {
|
|
19189
|
+
const widgetGeneration = ++supervisionWidgetGeneration;
|
|
18482
19190
|
ctx.ui.setWidget("pi-herdsman-staff", (tui, theme) => {
|
|
18483
19191
|
renderWidget = () => tui.requestRender();
|
|
18484
19192
|
return createSupervisionWidget(
|
|
18485
19193
|
() => snapshot,
|
|
18486
19194
|
() => status(ctx),
|
|
18487
19195
|
role2,
|
|
18488
|
-
theme
|
|
19196
|
+
theme,
|
|
19197
|
+
(intent) => {
|
|
19198
|
+
if (widgetFocusInFlight || widgetGeneration !== supervisionWidgetGeneration || generation(ctx) !== generationId || status(ctx) !== "fresh")
|
|
19199
|
+
return;
|
|
19200
|
+
if (intent.kind !== "session") return;
|
|
19201
|
+
widgetFocusInFlight = true;
|
|
19202
|
+
const isCurrent = () => widgetGeneration === supervisionWidgetGeneration && uiContext === ctx && generation(ctx) === generationId;
|
|
19203
|
+
void focusLead(
|
|
19204
|
+
ctx,
|
|
19205
|
+
intent.sessionId,
|
|
19206
|
+
intent.parentSessionId,
|
|
19207
|
+
isCurrent
|
|
19208
|
+
).catch((error2) => {
|
|
19209
|
+
if (isCurrent())
|
|
19210
|
+
ctx.ui.notify(
|
|
19211
|
+
String(error2).replace(/^Error: /u, ""),
|
|
19212
|
+
"warning"
|
|
19213
|
+
);
|
|
19214
|
+
}).finally(() => {
|
|
19215
|
+
widgetFocusInFlight = false;
|
|
19216
|
+
});
|
|
19217
|
+
}
|
|
18489
19218
|
);
|
|
18490
19219
|
});
|
|
18491
19220
|
} catch {
|
|
@@ -18494,6 +19223,8 @@ function createLeadSupervisionRuntime(host) {
|
|
|
18494
19223
|
}
|
|
18495
19224
|
},
|
|
18496
19225
|
removeWidget: (ctx) => {
|
|
19226
|
+
supervisionWidgetGeneration++;
|
|
19227
|
+
widgetFocusInFlight = false;
|
|
18497
19228
|
try {
|
|
18498
19229
|
ctx.ui.setWidget("pi-herdsman-staff", void 0);
|
|
18499
19230
|
} catch {
|
|
@@ -20417,6 +21148,8 @@ function createLeadInboxRuntime(host) {
|
|
|
20417
21148
|
let chiefInboxTimer;
|
|
20418
21149
|
let chiefInboxGeneration = 0;
|
|
20419
21150
|
let chiefInboxAbortController;
|
|
21151
|
+
let currentSubmittedAt;
|
|
21152
|
+
let settledSubmissions = /* @__PURE__ */ new Set();
|
|
20420
21153
|
const chiefStartPreflights = [];
|
|
20421
21154
|
const {
|
|
20422
21155
|
leadRuntime,
|
|
@@ -20475,7 +21208,7 @@ function createLeadInboxRuntime(host) {
|
|
|
20475
21208
|
);
|
|
20476
21209
|
if (index >= 0) chiefStartPreflights.splice(index, 1);
|
|
20477
21210
|
};
|
|
20478
|
-
const messageDelivered = (ctx, record) => record.toSessionId === ctx.sessionManager.getSessionId() && ctx.sessionManager.
|
|
21211
|
+
const messageDelivered = (ctx, record) => record.toSessionId === ctx.sessionManager.getSessionId() && ctx.sessionManager.getEntries().some(
|
|
20479
21212
|
(entry) => entry?.customType === `pi-herdsman-${record.kind}` && entry?.details?.id === record.id && entry?.details?.leaseId === record.leaseId && entry?.details?.fromSessionId === record.fromSessionId && entry?.details?.leadSessionId === record.leadSessionId && entry?.details?.branch === record.branch
|
|
20480
21213
|
);
|
|
20481
21214
|
const projectAssignmentAuthorized = (authorized, reason) => {
|
|
@@ -20614,11 +21347,25 @@ function createLeadInboxRuntime(host) {
|
|
|
20614
21347
|
return !!chief && !!state2 && chief.piSessionId === record.fromSessionId && chief.leaseId === record.leaseId && record.leadSessionId === sessionId;
|
|
20615
21348
|
}
|
|
20616
21349
|
const scope = await host.currentWorktreeScope(ctx);
|
|
20617
|
-
if (!scope
|
|
20618
|
-
|
|
21350
|
+
if (!scope) throw new Error("Project scope cannot be verified");
|
|
21351
|
+
if (!host.projectAssignmentForScope(scope, sessionId)) return false;
|
|
20619
21352
|
const manager = await currentManager(ctx, scope);
|
|
20620
|
-
|
|
20621
|
-
|
|
21353
|
+
let state;
|
|
21354
|
+
try {
|
|
21355
|
+
state = readLeadCoordinationState2(supervisionRuntime2(), sessionId);
|
|
21356
|
+
} catch (error2) {
|
|
21357
|
+
const cause = error2 instanceof Error ? error2.cause : void 0;
|
|
21358
|
+
if (cause instanceof SyntaxError || cause instanceof Error && ["invalid lead state", "lead state too large"].includes(
|
|
21359
|
+
cause.message
|
|
21360
|
+
))
|
|
21361
|
+
return false;
|
|
21362
|
+
throw error2;
|
|
21363
|
+
}
|
|
21364
|
+
if (!manager)
|
|
21365
|
+
throw new Error("Manager authority is temporarily unavailable");
|
|
21366
|
+
if (!state)
|
|
21367
|
+
throw new Error("Lead coordination state is temporarily unavailable");
|
|
21368
|
+
return (state.role ?? "lead") === "lead" && record.leaseId === manager.leaseId && record.fromSessionId === manager.piSessionId && record.leadSessionId === sessionId && record.kind === "manager_message";
|
|
20622
21369
|
};
|
|
20623
21370
|
const startChiefInbox = (ctx) => {
|
|
20624
21371
|
const generation = ++chiefInboxGeneration;
|
|
@@ -20629,6 +21376,9 @@ function createLeadInboxRuntime(host) {
|
|
|
20629
21376
|
const isCurrent = () => generation === chiefInboxGeneration && !chiefInboxAbortController?.signal.aborted;
|
|
20630
21377
|
if (chiefInboxTimer) clearTimeout(chiefInboxTimer);
|
|
20631
21378
|
const transactions = /* @__PURE__ */ new Map();
|
|
21379
|
+
const submittedAt = /* @__PURE__ */ new Map();
|
|
21380
|
+
currentSubmittedAt = submittedAt;
|
|
21381
|
+
settledSubmissions = /* @__PURE__ */ new Set();
|
|
20632
21382
|
const revalidateTransaction = (token, phase) => {
|
|
20633
21383
|
const transaction = token;
|
|
20634
21384
|
if (transaction?.generation !== chiefInboxGeneration || transaction.sessionId !== ctx.sessionManager.getSessionId() || transaction.instanceId !== getLeadInstanceId() || chiefInboxAbortController?.signal.aborted || chiefInboxAbortController?.signal !== transaction.signal || leadRuntime.chiefMode !== transaction.role || transaction.role === "active" && chiefStartPreflightHeld(ctx) || transaction.role === "inactive" && (!coordinationHealthy() || leadRuntime.roleSuspended)) {
|
|
@@ -20647,6 +21397,13 @@ function createLeadInboxRuntime(host) {
|
|
|
20647
21397
|
appendDurableError2(pi, ctx, "pi_herdsman_state_error", error2);
|
|
20648
21398
|
},
|
|
20649
21399
|
deliveryMode: (record) => {
|
|
21400
|
+
const attempted = submittedAt.get(record.id);
|
|
21401
|
+
if (attempted !== void 0 && !messageDelivered(ctx, record)) {
|
|
21402
|
+
const elapsed = Date.now() - attempted;
|
|
21403
|
+
const settled = settledSubmissions.has(record.id);
|
|
21404
|
+
if (!ctx.isIdle() || ctx.hasPendingMessages() || elapsed < (settled ? 1e3 : 3e4))
|
|
21405
|
+
return void 0;
|
|
21406
|
+
}
|
|
20650
21407
|
const role2 = activeRole();
|
|
20651
21408
|
const supervisorDownlink = role2 === "lead" && (record.kind === "chief_message" || record.kind === "manager_message") || role2 === "manager" && record.kind === "chief_message";
|
|
20652
21409
|
if (supervisorDownlink) return "steer";
|
|
@@ -20745,7 +21502,17 @@ function createLeadInboxRuntime(host) {
|
|
|
20745
21502
|
};
|
|
20746
21503
|
}
|
|
20747
21504
|
importResultBindings2(pi, ctx, resultBindings, record.kind);
|
|
20748
|
-
|
|
21505
|
+
if (messageDelivered(ctx, record)) return;
|
|
21506
|
+
let result;
|
|
21507
|
+
try {
|
|
21508
|
+
result = pi.sendMessage(payload, options);
|
|
21509
|
+
} catch (error2) {
|
|
21510
|
+
submittedAt.delete(record.id);
|
|
21511
|
+
settledSubmissions.delete(record.id);
|
|
21512
|
+
throw error2;
|
|
21513
|
+
}
|
|
21514
|
+
submittedAt.set(record.id, Date.now());
|
|
21515
|
+
settledSubmissions.delete(record.id);
|
|
20749
21516
|
if (projectAssignment)
|
|
20750
21517
|
managerDiagnostic("project_assignment_send", {
|
|
20751
21518
|
outcome: "resolved",
|
|
@@ -20791,9 +21558,13 @@ function createLeadInboxRuntime(host) {
|
|
|
20791
21558
|
}
|
|
20792
21559
|
}
|
|
20793
21560
|
},
|
|
20794
|
-
accepted: async (
|
|
21561
|
+
accepted: async (record) => {
|
|
21562
|
+
submittedAt.delete(record.id);
|
|
21563
|
+
settledSubmissions.delete(record.id);
|
|
20795
21564
|
},
|
|
20796
21565
|
rejected: (record) => {
|
|
21566
|
+
submittedAt.delete(record.id);
|
|
21567
|
+
settledSubmissions.delete(record.id);
|
|
20797
21568
|
if (!record.build || !sameRuntimeBuild2(record.build, HERDSMAN_BUILD2))
|
|
20798
21569
|
ctx.ui.notify(
|
|
20799
21570
|
record.build ? `Rejected Pi Herdsman coordination from ${formatRuntimeBuild2(record.build)}; local build is ${formatRuntimeBuild2(HERDSMAN_BUILD2)}. Restart the stale Pi session.` : "Rejected coordination from a Pi Herdsman runtime without build identity. Restart the stale Pi session.",
|
|
@@ -20908,9 +21679,15 @@ function createLeadInboxRuntime(host) {
|
|
|
20908
21679
|
},
|
|
20909
21680
|
clearTimer,
|
|
20910
21681
|
beginSession: () => {
|
|
21682
|
+
currentSubmittedAt?.clear();
|
|
21683
|
+
settledSubmissions.clear();
|
|
20911
21684
|
chiefInboxAbortController?.abort();
|
|
20912
21685
|
chiefInboxAbortController = new AbortController();
|
|
20913
21686
|
},
|
|
21687
|
+
agentSettled: () => {
|
|
21688
|
+
for (const id of currentSubmittedAt?.keys() ?? [])
|
|
21689
|
+
settledSubmissions.add(id);
|
|
21690
|
+
},
|
|
20914
21691
|
beginShutdown: () => {
|
|
20915
21692
|
chiefInboxGeneration++;
|
|
20916
21693
|
clearTimer();
|
|
@@ -22250,6 +23027,7 @@ function createLeadRoleTransitions(state, host) {
|
|
|
22250
23027
|
suspendMalformedRole,
|
|
22251
23028
|
shouldRestoreChief: (persistedRole) => persistedRole === "chief" && state.controllerRole === "lead" && !state.roleSuspended,
|
|
22252
23029
|
activeChiefGeneration: () => state.chiefMode === "active" ? state.chiefModeGeneration : void 0,
|
|
23030
|
+
currentRoleGeneration: () => state.chiefModeGeneration,
|
|
22253
23031
|
mayPublishLeadPresence: () => state.chiefMode === "inactive" && !state.roleSuspended && host.coordinationHealthy(),
|
|
22254
23032
|
canStartChiefInbox: () => !state.roleSuspended && (state.chiefMode === "inactive" || state.chiefMode === "active") && (state.chiefMode === "active" || host.coordinationHealthy()),
|
|
22255
23033
|
activeManager: () => state.controllerRole === "manager" && !state.roleSuspended,
|
|
@@ -22570,7 +23348,7 @@ async function workspacePresentationProvenance(pi, ctx, workspaceIds, workspaceC
|
|
|
22570
23348
|
);
|
|
22571
23349
|
return new Map(entries);
|
|
22572
23350
|
}
|
|
22573
|
-
function
|
|
23351
|
+
function extension_default(pi) {
|
|
22574
23352
|
let leadRuntimes;
|
|
22575
23353
|
let leadStatusRuntime;
|
|
22576
23354
|
let leadHerdRunRuntime;
|
|
@@ -23122,12 +23900,14 @@ ${globalInstructions}
|
|
|
23122
23900
|
definitionRoster: () => startupDefinitionRoster,
|
|
23123
23901
|
isStaffTool: (name) => STAFF_TOOLS.includes(name)
|
|
23124
23902
|
};
|
|
23125
|
-
const initialStatusBreadcrumb = controllerScope.kind === "lead" ? ["lead"] : [
|
|
23126
|
-
"?",
|
|
23127
|
-
|
|
23128
|
-
process.env.PI_HERDSMAN_AGENT_DEFINITION
|
|
23129
|
-
|
|
23130
|
-
|
|
23903
|
+
const initialStatusBreadcrumb = controllerScope.kind === "lead" ? [{ text: "lead" }] : [
|
|
23904
|
+
{ text: "?" },
|
|
23905
|
+
{
|
|
23906
|
+
text: process.env.PI_HERDSMAN_AGENT_DEFINITION && process.env.PI_HERDSMAN_LABEL ? displayIdentity(
|
|
23907
|
+
process.env.PI_HERDSMAN_AGENT_DEFINITION,
|
|
23908
|
+
process.env.PI_HERDSMAN_LABEL
|
|
23909
|
+
) : process.env.PI_HERDSMAN_AGENT_DEFINITION ?? "?"
|
|
23910
|
+
}
|
|
23131
23911
|
];
|
|
23132
23912
|
let ownTools;
|
|
23133
23913
|
const ownToolsSnapshot = () => ownTools ? { ownTools } : {};
|
|
@@ -23799,6 +24579,6 @@ ${summary}`,
|
|
|
23799
24579
|
});
|
|
23800
24580
|
}
|
|
23801
24581
|
export {
|
|
23802
|
-
|
|
24582
|
+
extension_default as default
|
|
23803
24583
|
};
|
|
23804
24584
|
//# sourceMappingURL=index.js.map
|