pi-herdsman 0.23.0 → 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 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.23.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",
@@ -4415,6 +4415,9 @@ function layoutStatusRows(rows, width, options = {}) {
4415
4415
  }) ?? layouts.at(-1);
4416
4416
  return rows.map((row) => ({
4417
4417
  label: row.label,
4418
+ labelStart: visibleWidth(
4419
+ `${row.tree}${row.spinner} ${padVisible(row.definition, columns.definitionWidth)} `
4420
+ ),
4418
4421
  ...row.paneId ? { paneId: row.paneId } : {},
4419
4422
  ...row.sessionId ? { sessionId: row.sessionId } : {},
4420
4423
  text: renderStatusLine(row, columns, layout, available, options.theme)
@@ -4451,6 +4454,8 @@ function managerPresentationSnapshot(manager) {
4451
4454
  displayName: manager.displayName,
4452
4455
  project: manager.project,
4453
4456
  workspaceId: manager.workspaceId,
4457
+ paneId: manager.paneId,
4458
+ tabId: manager.tabId,
4454
4459
  runtimeState: manager.runtimeState,
4455
4460
  agentCounts: manager.agentCounts,
4456
4461
  leadCounts: manager.leadCounts,
@@ -4639,15 +4644,23 @@ var MANAGER_METADATA_LAYOUTS = [
4639
4644
  { elapsed: false, context: true },
4640
4645
  { elapsed: false, context: false }
4641
4646
  ];
4642
- function renderSupervisionLeads(reports, width, options = {}, selectedLead) {
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) {
4643
4654
  const status = options.status ?? "fresh";
4644
4655
  const role2 = options.role ?? "chief";
4645
4656
  if (status === "unavailable")
4646
4657
  return [
4647
- safeLine(
4648
- `${themed(options.theme, "success", "\u25CF")} ${themed(options.theme, "muted", `${role2} \xB7 unavailable`)}`,
4649
- width
4650
- )
4658
+ {
4659
+ text: safeLine(
4660
+ `${themed(options.theme, "success", "\u25CF")} ${themed(options.theme, "muted", `${role2} \xB7 unavailable`)}`,
4661
+ width
4662
+ )
4663
+ }
4651
4664
  ];
4652
4665
  const displays = orderedSupervisionLeads(presentationReports(reports));
4653
4666
  const groups = groupOrderedSupervisedLeads(displays);
@@ -4695,16 +4708,25 @@ function renderSupervisionLeads(reports, width, options = {}, selectedLead) {
4695
4708
  })
4696
4709
  ) ?? MANAGER_METADATA_LAYOUTS.at(-1);
4697
4710
  return [
4698
- safeLine(header, width),
4711
+ { text: safeLine(header, width) },
4699
4712
  ...visible.map((item, index) => {
4700
4713
  const branch = index === visible.length - 1 && !remaining ? "\u2514\u2500" : "\u251C\u2500";
4701
4714
  const lead = item.lead;
4702
4715
  const navigation = lead && lead.lead === selectedLead ? ">" : "";
4703
4716
  if (item.kind === "lead")
4704
- return safeLine(
4705
- `${themed(options.theme, lifecycleColor(item.lead.runtimeState), `${branch} ${navigation}${supervisionLeadMarker(item.lead)}`)} ${themed(options.theme, "muted", `${item.lead.branch ?? item.lead.displayName} \xB7 Lead`)}`,
4706
- width
4707
- );
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
+ };
4708
4730
  const marker = item.work.status === "active" && lead ? `${lead.runtimeState === "blocked" ? "!" : ""}${supervisionLeadMarker(lead)}` : workMarkers[item.work.status];
4709
4731
  const prefix = `${branch} ${navigation}${marker} `;
4710
4732
  const suffix = ` \xB7 ${item.work.status}`;
@@ -4718,48 +4740,64 @@ function renderSupervisionLeads(reports, width, options = {}, selectedLead) {
4718
4740
  );
4719
4741
  const markerColor = item.work.status === "active" && lead ? lifecycleColor(lead.runtimeState) : item.work.status === "active" ? "success" : item.work.status === "conflict" ? "warning" : "muted";
4720
4742
  const markerText = themed(options.theme, markerColor, marker);
4721
- const branchText = themed(
4722
- options.theme,
4723
- "muted",
4724
- safeLine(
4725
- item.work.branch,
4726
- width - visibleWidth(prefix) - visibleWidth(suffix) - telemetryWidth
4727
- )
4728
- );
4729
- return safeLine(
4730
- `${themed(options.theme, "muted", `${branch} ${navigation}`)}${markerText} ${branchText}${themed(options.theme, "muted", suffix)}${telemetry.map((value2) => themed(options.theme, "muted", ` ${value2}`)).join("")}`,
4731
- width
4732
- );
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
+ };
4733
4756
  }),
4734
- ...remaining ? [safeLine(`\u2514\u2500 \u2026 ${remaining} more \xB7 /manager`, width)] : []
4757
+ ...remaining ? [{ text: safeLine(`\u2514\u2500 \u2026 ${remaining} more \xB7 /manager`, width) }] : []
4735
4758
  ];
4736
4759
  }
4737
4760
  return [
4738
- safeLine(header, width),
4761
+ { text: safeLine(header, width) },
4739
4762
  ...shown.flatMap((lead, index) => {
4740
4763
  const branch = index === shown.length - 1 && hidden === 0 ? "\u2514\u2500" : "\u251C\u2500";
4741
4764
  const marker = supervisionLeadMarker(lead);
4742
4765
  const navigation = lead.lead === selectedLead ? ">" : "";
4743
4766
  const indicators = navigation;
4744
4767
  const counts = lead.leadCounts;
4745
- const row = safeLine(
4746
- `${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"}` : ""}`)}`,
4747
- width
4748
- );
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
+ };
4749
4777
  const children = (lead.leads ?? []).slice(0, 3);
4750
4778
  const childIndent = branch === "\u2514\u2500" ? " " : "\u2502 ";
4751
4779
  return [
4752
4780
  row,
4753
4781
  ...children.map((child, childIndex) => {
4754
4782
  const childBranch = childIndex === children.length - 1 ? "\u2514\u2500" : "\u251C\u2500";
4755
- return safeLine(
4756
- `${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"}` : ""}`)}`,
4757
- width
4758
- );
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
+ };
4759
4797
  })
4760
4798
  ];
4761
4799
  }),
4762
- ...hidden > 0 ? [safeLine(`\u2514\u2500 \u2026 ${hidden} more \xB7 /${role2}`, width)] : []
4800
+ ...hidden > 0 ? [{ text: safeLine(`\u2514\u2500 \u2026 ${hidden} more \xB7 /${role2}`, width) }] : []
4763
4801
  ];
4764
4802
  }
4765
4803
  function formatSupervisionNotification(reports, status = "fresh") {
@@ -4920,15 +4958,39 @@ function formatSupervisionContext(snapshot, options) {
4920
4958
  }
4921
4959
  return [...included, closing].join("\n");
4922
4960
  }
4923
- function createSupervisionWidget(getLeads, getStatus, role2 = "chief", theme) {
4961
+ function createSupervisionWidget(getLeads, getStatus, role2 = "chief", theme, onFocus) {
4962
+ let renderedWidth = -1;
4963
+ let hits = [];
4924
4964
  return {
4925
4965
  render(width) {
4926
- return renderSupervisionLeads(getLeads(), width, {
4966
+ renderedWidth = width;
4967
+ const rows = renderSupervisionRows(getLeads(), width, {
4927
4968
  status: getStatus(),
4928
4969
  ordinaryCap: 6,
4929
4970
  role: role2,
4930
4971
  theme
4931
- }).filter((line) => line.length > 0);
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 };
4932
4994
  },
4933
4995
  invalidate() {
4934
4996
  }
@@ -5001,22 +5063,38 @@ function safeDisplaySegment(value2) {
5001
5063
  return value2.replace(/\u001b\][^\u0007]*(?:\u0007|\u001b\\)/gu, "").replace(/\u001b\[[0-?]*[ -/]*[@-~]/gu, "").replace(/[\u0000-\u001f\u007f]/gu, " ").replace(/\s+/gu, " ").trim();
5002
5064
  }
5003
5065
  function renderBreadcrumb(segments, width) {
5004
- if (width <= 0) return "";
5005
- const names2 = segments.map(safeDisplaySegment).filter(Boolean);
5006
- const current = names2.at(-1) ?? "?";
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: "?" };
5007
5069
  const marker = "\u25CF";
5008
- if (width <= visibleWidth(marker)) return truncateToWidth(marker, width, "");
5070
+ if (width <= visibleWidth(marker))
5071
+ return { text: truncateToWidth(marker, width, ""), hits: [] };
5009
5072
  const prefix = `${marker} `;
5010
5073
  const available = width - visibleWidth(prefix);
5011
- if (available <= 0) return marker;
5012
- const currentText = tailTruncate(current, available);
5013
- let result = `${prefix}${currentText}`;
5014
- for (let index = names2.length - 2; index >= 0; index--) {
5015
- const candidate = `${prefix}${names2[index]} \u2192 ${result.slice(prefix.length)}`;
5016
- if (visibleWidth(candidate) <= width) result = candidate;
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]);
5017
5081
  else break;
5018
5082
  }
5019
- return result;
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 };
5020
5098
  }
5021
5099
  function renderToolMetadata(tools, width) {
5022
5100
  if (!tools?.length || width <= 0) return "";
@@ -6412,8 +6490,12 @@ var StatusWidget = class {
6412
6490
  timer;
6413
6491
  invalidateUI;
6414
6492
  theme;
6415
- constructor(invalidateUI, theme) {
6493
+ onFocus;
6494
+ renderedWidth = -1;
6495
+ hits = [];
6496
+ constructor(invalidateUI, theme, onFocus) {
6416
6497
  this.invalidateUI = invalidateUI;
6498
+ this.onFocus = onFocus;
6417
6499
  this.theme = theme ?? {
6418
6500
  fg: (_color, text) => text,
6419
6501
  bold: (text) => text
@@ -6421,6 +6503,8 @@ var StatusWidget = class {
6421
6503
  }
6422
6504
  setSnapshot(snapshot) {
6423
6505
  this.snapshot = snapshot;
6506
+ this.hits = [];
6507
+ this.renderedWidth = -1;
6424
6508
  const animated = snapshot.agents.some(
6425
6509
  (agent) => agent.state === "working" || agent.state === "settling" || agent.state === "starting"
6426
6510
  );
@@ -6440,20 +6524,36 @@ var StatusWidget = class {
6440
6524
  }
6441
6525
  render(width) {
6442
6526
  const s = this.snapshot;
6527
+ this.renderedWidth = width;
6528
+ this.hits = [];
6443
6529
  const suffix = s.unavailable ? "unavailable" : `${formatStatusCounts(s.agents)}${s.stale ? " \xB7 stale" : ""}`;
6444
6530
  const availableWidth = Math.max(0, width);
6445
6531
  const execution = s.execution ? ` \xB7 ${s.execution.kind === "managed" ? "managed" : s.execution.mode}` : "";
6446
6532
  const elapsed = formatElapsed(s.herdRunStartedAt, Date.now());
6447
6533
  let run = !s.identityOnly && elapsed ? ` \xB7 ${elapsed}` : "";
6448
6534
  const suffixText = s.identityOnly || !suffix ? "" : ` ${suffix}`;
6449
- const breadcrumbSegments = s.breadcrumb ?? ["?"];
6450
- const breadcrumb = renderBreadcrumb(breadcrumbSegments, availableWidth);
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);
6451
6542
  const remainingWidth = Math.max(
6452
6543
  0,
6453
6544
  availableWidth - visibleWidth(breadcrumb)
6454
6545
  );
6455
6546
  const executionFits = !!execution && visibleWidth(execution) + visibleWidth(suffixText) <= remainingWidth;
6456
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
+ }
6457
6557
  const tools = renderToolMetadata(
6458
6558
  s.ownTools,
6459
6559
  Math.max(
@@ -6471,24 +6571,55 @@ var StatusWidget = class {
6471
6571
  const header = `${styledBreadcrumb}${styledExecution}${styledTools}${styledRun}${styledSuffix}`;
6472
6572
  const out = [truncateToWidth(header, availableWidth, "\u2026")];
6473
6573
  if (s.identityOnly) return out;
6474
- out.push(
6475
- ...renderStatusRows(s.agents, {
6476
- now: Date.now(),
6477
- frame: this.frame,
6478
- width: Math.max(0, width),
6479
- theme: this.theme
6480
- }).map(({ text }) => text)
6481
- );
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
+ });
6482
6600
  return out;
6483
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
+ }
6484
6612
  dispose() {
6485
6613
  if (this.timer) clearInterval(this.timer);
6486
6614
  this.timer = void 0;
6487
6615
  this.invalidateUI = void 0;
6616
+ this.onFocus = void 0;
6617
+ this.hits = [];
6618
+ this.renderedWidth = -1;
6488
6619
  }
6489
6620
  };
6490
- function createStatusWidget(invalidate, theme) {
6491
- return new StatusWidget(invalidate, theme);
6621
+ function createStatusWidget(invalidate, theme, onFocus) {
6622
+ return new StatusWidget(invalidate, theme, onFocus);
6492
6623
  }
6493
6624
 
6494
6625
  // extension/config.ts
@@ -7116,8 +7247,6 @@ async function drainCoordinationInbox(options) {
7116
7247
  }
7117
7248
  continue;
7118
7249
  }
7119
- const deliverAs = options.deliveryMode ? options.deliveryMode(record) : "followUp";
7120
- if (!deliverAs) continue;
7121
7250
  let token;
7122
7251
  const clearTransaction = async () => {
7123
7252
  if (token === void 0) return;
@@ -7133,6 +7262,12 @@ async function drainCoordinationInbox(options) {
7133
7262
  await clearTransaction();
7134
7263
  continue;
7135
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
+ }
7136
7271
  let authorized;
7137
7272
  try {
7138
7273
  authorized = await options.isAuthorized(record);
@@ -7180,29 +7315,35 @@ async function drainCoordinationInbox(options) {
7180
7315
  options.sessionId,
7181
7316
  record.id
7182
7317
  );
7183
- await options.sendMessage(
7184
- {
7185
- customType: `pi-herdsman-${record.kind}`,
7186
- content: deliveredMessageContent(record),
7187
- display: true,
7188
- details: {
7189
- id: record.id,
7190
- leaseId: record.leaseId,
7191
- fromSessionId: record.fromSessionId,
7192
- toSessionId: record.toSessionId,
7193
- leadSessionId: record.leadSessionId,
7194
- ...record.branch ? { branch: record.branch } : {}
7195
- }
7196
- },
7197
- { deliverAs, triggerTurn: true },
7198
- record
7199
- );
7200
- await options.transaction?.revalidate(token, "after-send");
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
+ }
7201
7338
  } catch {
7202
7339
  await clearTransaction();
7203
7340
  continue;
7204
7341
  }
7205
- delivered += 1;
7342
+ if (!options.isDelivered(record.id)) {
7343
+ await clearTransaction();
7344
+ continue;
7345
+ }
7346
+ if (!wasAlreadyDelivered) delivered += 1;
7206
7347
  try {
7207
7348
  await options.transaction?.revalidate(token, "before-accepted");
7208
7349
  assertChiefMessageNotQuarantined(
@@ -7218,6 +7359,7 @@ async function drainCoordinationInbox(options) {
7218
7359
  }
7219
7360
  } else {
7220
7361
  try {
7362
+ if (!wasAlreadyDelivered) delivered += 1;
7221
7363
  await options.transaction?.revalidate(token, "already-delivered");
7222
7364
  assertChiefMessageNotQuarantined(
7223
7365
  options.runtime,
@@ -8333,7 +8475,7 @@ function buildAgentStatusSnapshot(view, ctx, host) {
8333
8475
  stale: false,
8334
8476
  unavailable: false,
8335
8477
  ...herdStartedAt !== void 0 ? { herdRunStartedAt: herdStartedAt } : {},
8336
- breadcrumb: host.scope.kind === "lead" ? ["lead"] : statusBreadcrumb(
8478
+ breadcrumb: host.scope.kind === "lead" ? [{ text: "lead" }] : statusBreadcrumb(
8337
8479
  view,
8338
8480
  host.environmentIdentity(ctx),
8339
8481
  host.identityFromEnvironment(),
@@ -8354,6 +8496,7 @@ function createAgentStatusRuntime() {
8354
8496
  let statusInFlight = false;
8355
8497
  let requestActive = false;
8356
8498
  let statusPrimed = false;
8499
+ let focusInFlight = false;
8357
8500
  let lastValidStatus = {
8358
8501
  agents: [],
8359
8502
  stale: false,
@@ -8468,7 +8611,28 @@ function createAgentStatusRuntime() {
8468
8611
  clearTimer();
8469
8612
  statusContext = ctx;
8470
8613
  ctx.ui.setWidget("pi-herdsman", (tui, theme) => {
8471
- const widget = createStatusWidget(() => tui.requestRender(), theme);
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
+ );
8472
8636
  widget.setSnapshot(widgetSnapshot(lastValidStatus));
8473
8637
  if (generation === statusGeneration && ctx === statusContext) {
8474
8638
  statusWidget = widget;
@@ -8488,12 +8652,14 @@ function createAgentStatusRuntime() {
8488
8652
  statusWidget?.dispose();
8489
8653
  statusWidget = void 0;
8490
8654
  requestActive = false;
8655
+ focusInFlight = false;
8491
8656
  statusPrimed = false;
8492
8657
  },
8493
8658
  prepareSession: (ctx, beforeActivate) => {
8494
8659
  clearTimer();
8495
8660
  statusRefresh = false;
8496
8661
  statusInFlight = false;
8662
+ focusInFlight = false;
8497
8663
  removeWidget();
8498
8664
  statusWidgetGeneration = 0;
8499
8665
  statusContext = void 0;
@@ -8516,6 +8682,7 @@ function createAgentStatusRuntime() {
8516
8682
  clearTimer();
8517
8683
  statusRefresh = false;
8518
8684
  statusInFlight = false;
8685
+ focusInFlight = false;
8519
8686
  removeWidget();
8520
8687
  statusWidgetGeneration = 0;
8521
8688
  statusContext = void 0;
@@ -8861,39 +9028,50 @@ function visibleAgentSnapshots(snapshot, scope, ownerSessionId) {
8861
9028
  return visible;
8862
9029
  }
8863
9030
  function statusBreadcrumb(snapshot, candidate, identity, sameIdentity) {
8864
- if (!candidate) return ["?"];
8865
- const current = snapshot.agents.find(
9031
+ if (!candidate) return [{ text: "?" }];
9032
+ const matches = snapshot.agents.filter(
8866
9033
  ({ state }) => sameIdentity(state, candidate)
8867
9034
  );
9035
+ const current = matches.length === 1 ? matches[0] : void 0;
8868
9036
  if (!current)
8869
9037
  return [
8870
- "?",
8871
- identity.definition && identity.label ? displayIdentity(identity.definition, identity.label) : identity.definition ?? "?"
9038
+ { text: "?" },
9039
+ {
9040
+ text: identity.definition && identity.label ? displayIdentity(identity.definition, identity.label) : identity.definition ?? "?"
9041
+ }
8872
9042
  ];
8873
9043
  const definitions = [
8874
- displayIdentity(current.agentDefinition, current.state.agentLabel)
9044
+ {
9045
+ text: displayIdentity(current.agentDefinition, current.state.agentLabel),
9046
+ sessionId: current.state.piSessionId
9047
+ }
8875
9048
  ];
8876
9049
  const visited = /* @__PURE__ */ new Set([current.state.piSessionId]);
8877
9050
  let ownerSessionId = current.state.ownerSessionId;
8878
9051
  while (true) {
8879
- const parent = snapshot.agents.find(
9052
+ const parents = snapshot.agents.filter(
8880
9053
  ({ state }) => state.piSessionId === ownerSessionId
8881
9054
  );
9055
+ if (parents.length > 1) return [{ text: "?" }, ...definitions.reverse()];
9056
+ const parent = parents[0];
8882
9057
  if (parent) {
8883
9058
  if (visited.has(parent.state.piSessionId))
8884
- return ["?", ...definitions.reverse()];
9059
+ return [{ text: "?" }, ...definitions.reverse()];
8885
9060
  visited.add(parent.state.piSessionId);
8886
- definitions.push(
8887
- displayIdentity(parent.agentDefinition, parent.state.agentLabel)
8888
- );
9061
+ definitions.push({
9062
+ text: displayIdentity(parent.agentDefinition, parent.state.agentLabel),
9063
+ sessionId: parent.state.piSessionId
9064
+ });
8889
9065
  ownerSessionId = parent.state.ownerSessionId;
8890
9066
  continue;
8891
9067
  }
8892
9068
  if (snapshot.mailboxes.some(
8893
9069
  ({ state }) => state.piSessionId === ownerSessionId
8894
9070
  ))
8895
- return ["?", ...definitions.reverse()];
8896
- return snapshot.leadSessionIds.includes(ownerSessionId) ? ["lead", ...definitions.reverse()] : ["?", ...definitions.reverse()];
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()];
8897
9075
  }
8898
9076
  }
8899
9077
  function sessionAgentIdentity(entries, sessionId) {
@@ -14354,6 +14532,7 @@ function createManagedAgentLeafStatus(options) {
14354
14532
  let context;
14355
14533
  let generation = 0;
14356
14534
  let inFlight = false;
14535
+ let focusInFlight = false;
14357
14536
  let breadcrumb;
14358
14537
  let ownTools;
14359
14538
  const ownToolsSnapshot = () => ownTools ? { ownTools } : {};
@@ -14368,6 +14547,7 @@ function createManagedAgentLeafStatus(options) {
14368
14547
  }
14369
14548
  context = void 0;
14370
14549
  inFlight = false;
14550
+ focusInFlight = false;
14371
14551
  };
14372
14552
  const refresh = async (ctx, activeGeneration) => {
14373
14553
  if (activeGeneration !== generation || ctx !== context || inFlight) return;
@@ -14400,11 +14580,13 @@ function createManagedAgentLeafStatus(options) {
14400
14580
  stale: false,
14401
14581
  unavailable: true,
14402
14582
  breadcrumb: breadcrumb ?? [
14403
- "?",
14404
- process.env.PI_HERDSMAN_AGENT_DEFINITION && process.env.PI_HERDSMAN_LABEL ? displayIdentity(
14405
- process.env.PI_HERDSMAN_AGENT_DEFINITION,
14406
- process.env.PI_HERDSMAN_LABEL
14407
- ) : process.env.PI_HERDSMAN_AGENT_DEFINITION ?? "?"
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
+ }
14408
14590
  ],
14409
14591
  ...ownToolsSnapshot(),
14410
14592
  identityOnly: true
@@ -14422,17 +14604,39 @@ function createManagedAgentLeafStatus(options) {
14422
14604
  const activeGeneration = generation;
14423
14605
  context = ctx;
14424
14606
  ctx.ui.setWidget("pi-herdsman", (tui, theme) => {
14425
- const next = createStatusWidget(() => tui.requestRender(), theme);
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
+ );
14426
14628
  next.setSnapshot({
14427
14629
  agents: [],
14428
14630
  stale: false,
14429
14631
  unavailable: true,
14430
14632
  breadcrumb: [
14431
- "?",
14432
- process.env.PI_HERDSMAN_AGENT_DEFINITION && process.env.PI_HERDSMAN_LABEL ? displayIdentity(
14433
- process.env.PI_HERDSMAN_AGENT_DEFINITION,
14434
- process.env.PI_HERDSMAN_LABEL
14435
- ) : process.env.PI_HERDSMAN_AGENT_DEFINITION ?? "?"
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
+ }
14436
14640
  ],
14437
14641
  ...ownToolsSnapshot(),
14438
14642
  identityOnly: true
@@ -15131,6 +15335,72 @@ function registerManagedAgentRuntime(pi, options) {
15131
15335
  clearPendingStart: (label, expected) => controller.clearPendingStart(label, expected),
15132
15336
  runtimeForLabel: (label) => controller.runtimeForLabel(label),
15133
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
+ },
15134
15404
  loadSnapshot: async (ctx) => {
15135
15405
  const view = await controller.agentSnapshotView(
15136
15406
  ctx,
@@ -15187,7 +15457,52 @@ This is the session-start definition snapshot. Use list_agents for live Agent st
15187
15457
  ),
15188
15458
  identity: (ctx) => managedAgentEnvironmentIdentity(ctx, options.build),
15189
15459
  sameIdentity: sameManagedAgentIdentity,
15190
- 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
+ }
15191
15506
  });
15192
15507
  const mutateAgentState = (update) => {
15193
15508
  const state = execution.assignment;
@@ -16196,6 +16511,12 @@ function createLeadSessionStartRuntime(host) {
16196
16511
  }
16197
16512
  }
16198
16513
  if (sessionSignal.aborted) return;
16514
+ if (host.roleTransitions.activeManager())
16515
+ await host.publishLeadRole(
16516
+ ctx,
16517
+ "inactive",
16518
+ host.roleTransitions.currentRoleGeneration()
16519
+ );
16199
16520
  if (needsLeadRoster) {
16200
16521
  try {
16201
16522
  const definitions = await host.visibleAgentDefinitionMetadata(
@@ -16266,6 +16587,7 @@ This is the session-start definition snapshot. Use list_agents for live Agent st
16266
16587
  host.herdRun.agentStarted();
16267
16588
  },
16268
16589
  async agentSettled(ctx, aborted) {
16590
+ host.leadInboxRuntime.agentSettled();
16269
16591
  host.controller.settleAsks(ctx, host.controller.sessionSignal());
16270
16592
  host.herdRun.agentSettled(ctx, aborted);
16271
16593
  await host.controller.settleResults(ctx, host.controller.sessionSignal()).catch(() => {
@@ -17145,41 +17467,67 @@ function registerLeadRuntime(pi, options) {
17145
17467
  };
17146
17468
  const roleHost = options.roleTransitionHost;
17147
17469
  let leadMetadataQueue = Promise.resolve();
17148
- const publishLeadRole = (ctx, mode, generation) => {
17149
- const paneId = roleHost.paneId();
17150
- if (!paneId) return Promise.resolve();
17151
- const activeRole = () => activeLeadRole(leadRuntime);
17152
- const leadName = mode === "inactive" && activeRole() === "lead" ? roleHost.getSessionName()?.trim() : void 0;
17153
- const args = [
17154
- "pane",
17155
- "report-metadata",
17156
- paneId,
17157
- "--source",
17158
- "pi-herdsman:lead",
17159
- "--title",
17160
- mode === "active" ? "chief" : activeRole() === "manager" ? "Pi Herdsman manager" : leadName || "Pi Herdsman lead",
17161
- ...mode === "active" ? ["--token", "pi_herdsman_role=chief"] : mode === "inactive" ? ["--token", `pi_herdsman_role=${activeRole()}`] : ["--clear-token", "pi_herdsman_role"]
17162
- ];
17163
- if (mode === "inactive" && activeRole() === "lead")
17164
- args.push(
17165
- leadName ? "--token" : "--clear-token",
17166
- leadName ? `pi_herdsman_name=${leadName}` : "pi_herdsman_name"
17167
- );
17168
- if (mode !== "inactive" || activeRole() !== "lead")
17169
- args.push(
17170
- "--clear-token",
17171
- "pi_herdsman_herd_run_started_at",
17172
- "--clear-token",
17173
- "pi_herdsman_context_percent"
17174
- );
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}`;
17175
17475
  leadMetadataQueue = leadMetadataQueue.catch(() => {
17176
17476
  }).then(async () => {
17177
- if (generation !== leadRuntime.chiefModeGeneration) return;
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
+ );
17178
17512
  await roleHost.runHerdr(pi, ctx, args, {
17179
17513
  noResult: true,
17180
17514
  timeout: 1e4
17181
17515
  });
17182
- }).catch(() => {
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
+ }
17183
17531
  });
17184
17532
  return leadMetadataQueue;
17185
17533
  };
@@ -17192,8 +17540,30 @@ function registerLeadRuntime(pi, options) {
17192
17540
  );
17193
17541
  return;
17194
17542
  }
17543
+ const sessionId = ctx.sessionManager.getSessionId();
17544
+ const sessionGeneration = leadRuntime.sessionGeneration;
17195
17545
  leadMetadataQueue = leadMetadataQueue.catch(() => {
17196
- }).then(() => roleHost.reportLeadMetadata(pi, ctx, metadata)).catch(() => {
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
+ }
17197
17567
  });
17198
17568
  };
17199
17569
  const persistRole = (role2) => {
@@ -17408,13 +17778,88 @@ function registerLeadRuntime(pi, options) {
17408
17778
  const execution = isLead && assignmentVerified ? assignment ? { kind: "managed" } : leadExecution?.valid ? { kind: "ordinary", mode: leadExecution.mode } : void 0 : void 0;
17409
17779
  return { ...snapshot, ...execution ? { execution } : {} };
17410
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
+ };
17411
17855
  statusRuntime.configure({
17412
17856
  ...options.statusSnapshotHost,
17413
17857
  pendingStartEntries: () => controller.pendingStartEntries(),
17414
17858
  hasPendingStart: (label) => controller.hasPendingStart(label),
17415
17859
  clearPendingStart: (label, expected) => controller.clearPendingStart(label, expected),
17416
17860
  loadSnapshot: (ctx) => loadStatusSnapshot(ctx, controller.sessionSignal(), false),
17417
- runtimeForLabel: (label) => controller.runtimeForLabel(label)
17861
+ runtimeForLabel: (label) => controller.runtimeForLabel(label),
17862
+ focusTarget
17418
17863
  });
17419
17864
  let projectRuntime;
17420
17865
  const projectHost = options.projectHost;
@@ -18218,6 +18663,8 @@ function createLeadSupervisionRuntime(host) {
18218
18663
  let overviewGeneration = 0;
18219
18664
  let renderOverview;
18220
18665
  let renderWidget;
18666
+ let widgetFocusInFlight = false;
18667
+ let supervisionWidgetGeneration = 0;
18221
18668
  const generation = (ctx) => [
18222
18669
  host.state.chiefModeGeneration,
18223
18670
  host.state.sessionGeneration,
@@ -18286,6 +18733,108 @@ function createLeadSupervisionRuntime(host) {
18286
18733
  });
18287
18734
  return inFlight;
18288
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
+ };
18289
18838
  const nextOverviewGeneration = () => ++overviewGeneration;
18290
18839
  const openOverview = async (ctx, uiActions) => {
18291
18840
  if (ctx.mode !== "tui") {
@@ -18591,25 +19140,7 @@ function createLeadSupervisionRuntime(host) {
18591
19140
  openOverview,
18592
19141
  loadSnapshot: loadSupervisionSnapshot,
18593
19142
  directReports,
18594
- focusLead: async (ctx, leadId) => {
18595
- const fresh = await loadSnapshot(ctx);
18596
- const lead = host.presentationReports(fresh).find((candidate) => candidate.lead === leadId);
18597
- if (!lead) throw new Error("Lead changed; reopen staff.");
18598
- const coordination = host.readLeadCoordinationState(
18599
- host.supervisionRuntime(),
18600
- lead.lead
18601
- );
18602
- if (!coordination || coordination.piSessionId !== lead.lead || lead.instanceId !== void 0 && coordination.instanceId !== lead.instanceId)
18603
- throw new Error("Lead changed; reopen staff.");
18604
- const verified = await host.listAllHerdrAgents(host.pi, ctx, ctx.signal);
18605
- const matches = verified.agents.filter(
18606
- (candidate) => candidate?.pane_id === lead.paneId && candidate?.tab_id === lead.tabId && candidate?.workspace_id === lead.workspaceId && host.isPiAgent(candidate) && host.herdrSessionId(candidate) === lead.lead
18607
- );
18608
- if (matches.length !== 1) throw new Error("Lead changed; reopen staff.");
18609
- await host.runHerdr(host.pi, ctx, ["agent", "focus", lead.paneId], {
18610
- signal: ctx.signal
18611
- });
18612
- },
19143
+ focusLead,
18613
19144
  focusChief: async (ctx) => {
18614
19145
  const confirmed = await ctx.ui.confirm(
18615
19146
  "Focus Chief?",
@@ -18655,13 +19186,35 @@ function createLeadSupervisionRuntime(host) {
18655
19186
  registerWidget: (ctx, role2) => {
18656
19187
  if (ctx.mode !== "tui" || !ctx.hasUI) return;
18657
19188
  try {
19189
+ const widgetGeneration = ++supervisionWidgetGeneration;
18658
19190
  ctx.ui.setWidget("pi-herdsman-staff", (tui, theme) => {
18659
19191
  renderWidget = () => tui.requestRender();
18660
19192
  return createSupervisionWidget(
18661
19193
  () => snapshot,
18662
19194
  () => status(ctx),
18663
19195
  role2,
18664
- 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
+ }
18665
19218
  );
18666
19219
  });
18667
19220
  } catch {
@@ -18670,6 +19223,8 @@ function createLeadSupervisionRuntime(host) {
18670
19223
  }
18671
19224
  },
18672
19225
  removeWidget: (ctx) => {
19226
+ supervisionWidgetGeneration++;
19227
+ widgetFocusInFlight = false;
18673
19228
  try {
18674
19229
  ctx.ui.setWidget("pi-herdsman-staff", void 0);
18675
19230
  } catch {
@@ -20593,6 +21148,8 @@ function createLeadInboxRuntime(host) {
20593
21148
  let chiefInboxTimer;
20594
21149
  let chiefInboxGeneration = 0;
20595
21150
  let chiefInboxAbortController;
21151
+ let currentSubmittedAt;
21152
+ let settledSubmissions = /* @__PURE__ */ new Set();
20596
21153
  const chiefStartPreflights = [];
20597
21154
  const {
20598
21155
  leadRuntime,
@@ -20651,7 +21208,7 @@ function createLeadInboxRuntime(host) {
20651
21208
  );
20652
21209
  if (index >= 0) chiefStartPreflights.splice(index, 1);
20653
21210
  };
20654
- const messageDelivered = (ctx, record) => record.toSessionId === ctx.sessionManager.getSessionId() && ctx.sessionManager.getBranch().some(
21211
+ const messageDelivered = (ctx, record) => record.toSessionId === ctx.sessionManager.getSessionId() && ctx.sessionManager.getEntries().some(
20655
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
20656
21213
  );
20657
21214
  const projectAssignmentAuthorized = (authorized, reason) => {
@@ -20790,11 +21347,25 @@ function createLeadInboxRuntime(host) {
20790
21347
  return !!chief && !!state2 && chief.piSessionId === record.fromSessionId && chief.leaseId === record.leaseId && record.leadSessionId === sessionId;
20791
21348
  }
20792
21349
  const scope = await host.currentWorktreeScope(ctx);
20793
- if (!scope || !host.projectAssignmentForScope(scope, sessionId))
20794
- return false;
21350
+ if (!scope) throw new Error("Project scope cannot be verified");
21351
+ if (!host.projectAssignmentForScope(scope, sessionId)) return false;
20795
21352
  const manager = await currentManager(ctx, scope);
20796
- const state = readLeadCoordinationState2(supervisionRuntime2(), sessionId);
20797
- return !!manager && !!state && record.leaseId === manager.leaseId && record.fromSessionId === manager.piSessionId && record.leadSessionId === sessionId && record.kind === "manager_message";
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";
20798
21369
  };
20799
21370
  const startChiefInbox = (ctx) => {
20800
21371
  const generation = ++chiefInboxGeneration;
@@ -20805,6 +21376,9 @@ function createLeadInboxRuntime(host) {
20805
21376
  const isCurrent = () => generation === chiefInboxGeneration && !chiefInboxAbortController?.signal.aborted;
20806
21377
  if (chiefInboxTimer) clearTimeout(chiefInboxTimer);
20807
21378
  const transactions = /* @__PURE__ */ new Map();
21379
+ const submittedAt = /* @__PURE__ */ new Map();
21380
+ currentSubmittedAt = submittedAt;
21381
+ settledSubmissions = /* @__PURE__ */ new Set();
20808
21382
  const revalidateTransaction = (token, phase) => {
20809
21383
  const transaction = token;
20810
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)) {
@@ -20823,6 +21397,13 @@ function createLeadInboxRuntime(host) {
20823
21397
  appendDurableError2(pi, ctx, "pi_herdsman_state_error", error2);
20824
21398
  },
20825
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
+ }
20826
21407
  const role2 = activeRole();
20827
21408
  const supervisorDownlink = role2 === "lead" && (record.kind === "chief_message" || record.kind === "manager_message") || role2 === "manager" && record.kind === "chief_message";
20828
21409
  if (supervisorDownlink) return "steer";
@@ -20921,7 +21502,17 @@ function createLeadInboxRuntime(host) {
20921
21502
  };
20922
21503
  }
20923
21504
  importResultBindings2(pi, ctx, resultBindings, record.kind);
20924
- const result = await pi.sendMessage(payload, options);
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);
20925
21516
  if (projectAssignment)
20926
21517
  managerDiagnostic("project_assignment_send", {
20927
21518
  outcome: "resolved",
@@ -20967,9 +21558,13 @@ function createLeadInboxRuntime(host) {
20967
21558
  }
20968
21559
  }
20969
21560
  },
20970
- accepted: async (_record) => {
21561
+ accepted: async (record) => {
21562
+ submittedAt.delete(record.id);
21563
+ settledSubmissions.delete(record.id);
20971
21564
  },
20972
21565
  rejected: (record) => {
21566
+ submittedAt.delete(record.id);
21567
+ settledSubmissions.delete(record.id);
20973
21568
  if (!record.build || !sameRuntimeBuild2(record.build, HERDSMAN_BUILD2))
20974
21569
  ctx.ui.notify(
20975
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.",
@@ -21084,9 +21679,15 @@ function createLeadInboxRuntime(host) {
21084
21679
  },
21085
21680
  clearTimer,
21086
21681
  beginSession: () => {
21682
+ currentSubmittedAt?.clear();
21683
+ settledSubmissions.clear();
21087
21684
  chiefInboxAbortController?.abort();
21088
21685
  chiefInboxAbortController = new AbortController();
21089
21686
  },
21687
+ agentSettled: () => {
21688
+ for (const id of currentSubmittedAt?.keys() ?? [])
21689
+ settledSubmissions.add(id);
21690
+ },
21090
21691
  beginShutdown: () => {
21091
21692
  chiefInboxGeneration++;
21092
21693
  clearTimer();
@@ -22426,6 +23027,7 @@ function createLeadRoleTransitions(state, host) {
22426
23027
  suspendMalformedRole,
22427
23028
  shouldRestoreChief: (persistedRole) => persistedRole === "chief" && state.controllerRole === "lead" && !state.roleSuspended,
22428
23029
  activeChiefGeneration: () => state.chiefMode === "active" ? state.chiefModeGeneration : void 0,
23030
+ currentRoleGeneration: () => state.chiefModeGeneration,
22429
23031
  mayPublishLeadPresence: () => state.chiefMode === "inactive" && !state.roleSuspended && host.coordinationHealthy(),
22430
23032
  canStartChiefInbox: () => !state.roleSuspended && (state.chiefMode === "inactive" || state.chiefMode === "active") && (state.chiefMode === "active" || host.coordinationHealthy()),
22431
23033
  activeManager: () => state.controllerRole === "manager" && !state.roleSuspended,
@@ -23298,12 +23900,14 @@ ${globalInstructions}
23298
23900
  definitionRoster: () => startupDefinitionRoster,
23299
23901
  isStaffTool: (name) => STAFF_TOOLS.includes(name)
23300
23902
  };
23301
- const initialStatusBreadcrumb = controllerScope.kind === "lead" ? ["lead"] : [
23302
- "?",
23303
- process.env.PI_HERDSMAN_AGENT_DEFINITION && process.env.PI_HERDSMAN_LABEL ? displayIdentity(
23304
- process.env.PI_HERDSMAN_AGENT_DEFINITION,
23305
- process.env.PI_HERDSMAN_LABEL
23306
- ) : process.env.PI_HERDSMAN_AGENT_DEFINITION ?? "?"
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
+ }
23307
23911
  ];
23308
23912
  let ownTools;
23309
23913
  const ownToolsSnapshot = () => ownTools ? { ownTools } : {};