@dorokuma/herdsman 0.13.5 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +2 -2
  2. package/dist/src/agent-history/discovery.d.ts +47 -11
  3. package/dist/src/agent-history/discovery.d.ts.map +1 -1
  4. package/dist/src/agent-history/discovery.js +242 -468
  5. package/dist/src/agent-history/discovery.js.map +1 -1
  6. package/dist/src/agent-history/service.d.ts +4 -7
  7. package/dist/src/agent-history/service.d.ts.map +1 -1
  8. package/dist/src/agent-history/service.js +46 -30
  9. package/dist/src/agent-history/service.js.map +1 -1
  10. package/dist/src/daemon/agent-event-reconciler.js +6 -10
  11. package/dist/src/daemon/agent-event-reconciler.js.map +1 -1
  12. package/dist/src/daemon/herdr-session-watch-manager.js +2 -2
  13. package/dist/src/daemon/herdr-session-watch-manager.js.map +1 -1
  14. package/dist/src/daemon/observability-server.js +6 -6
  15. package/dist/src/daemon/observability-server.js.map +1 -1
  16. package/dist/src/db/agents.d.ts +0 -2
  17. package/dist/src/db/agents.d.ts.map +1 -1
  18. package/dist/src/db/agents.js +14 -57
  19. package/dist/src/db/agents.js.map +1 -1
  20. package/dist/src/herdr/pane-identity-resolver.d.ts +11 -0
  21. package/dist/src/herdr/pane-identity-resolver.d.ts.map +1 -1
  22. package/dist/src/herdr/pane-identity-resolver.js +27 -15
  23. package/dist/src/herdr/pane-identity-resolver.js.map +1 -1
  24. package/dist/src/herdr/session-list.d.ts.map +1 -1
  25. package/dist/src/herdr/session-list.js +4 -2
  26. package/dist/src/herdr/session-list.js.map +1 -1
  27. package/dist/src/observability/agent-context-service.d.ts +4 -10
  28. package/dist/src/observability/agent-context-service.d.ts.map +1 -1
  29. package/dist/src/observability/agent-context-service.js +37 -58
  30. package/dist/src/observability/agent-context-service.js.map +1 -1
  31. package/dist/src/observability/agent-index-service.d.ts.map +1 -1
  32. package/dist/src/observability/agent-index-service.js +97 -44
  33. package/dist/src/observability/agent-index-service.js.map +1 -1
  34. package/dist/src/observability/contracts.d.ts +1 -2
  35. package/dist/src/observability/contracts.d.ts.map +1 -1
  36. package/dist/src/observability/contracts.js.map +1 -1
  37. package/package.json +1 -1
  38. package/dist/src/agent-history/claude-reader.d.ts +0 -10
  39. package/dist/src/agent-history/claude-reader.d.ts.map +0 -1
  40. package/dist/src/agent-history/claude-reader.js +0 -90
  41. package/dist/src/agent-history/claude-reader.js.map +0 -1
  42. package/dist/src/agent-history/codex-reader.d.ts +0 -10
  43. package/dist/src/agent-history/codex-reader.d.ts.map +0 -1
  44. package/dist/src/agent-history/codex-reader.js +0 -119
  45. package/dist/src/agent-history/codex-reader.js.map +0 -1
  46. package/dist/src/agent-history/gemini-reader.d.ts +0 -10
  47. package/dist/src/agent-history/gemini-reader.d.ts.map +0 -1
  48. package/dist/src/agent-history/gemini-reader.js +0 -96
  49. package/dist/src/agent-history/gemini-reader.js.map +0 -1
  50. package/dist/src/agent-history/grok-reader.d.ts +0 -11
  51. package/dist/src/agent-history/grok-reader.d.ts.map +0 -1
  52. package/dist/src/agent-history/grok-reader.js +0 -54
  53. package/dist/src/agent-history/grok-reader.js.map +0 -1
  54. package/dist/src/agent-history/opencode-reader.d.ts +0 -10
  55. package/dist/src/agent-history/opencode-reader.d.ts.map +0 -1
  56. package/dist/src/agent-history/opencode-reader.js +0 -90
  57. package/dist/src/agent-history/opencode-reader.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"agent-index-service.d.ts","sourceRoot":"","sources":["../../../src/observability/agent-index-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-index-service.d.ts","sourceRoot":"","sources":["../../../src/observability/agent-index-service.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { existsSync } from "node:fs";
2
- import { safeAllowedSessionPath, sessionPathAllowedByShape } from "../agent-history/discovery.js";
2
+ import { safeAllowedSessionPath, safeOfficialSessionPath, sessionPathAllowedByShape, } from "../agent-history/discovery.js";
3
3
  import { createAgentHistoryService } from "../agent-history/service.js";
4
4
  import { hasNonEmptyAssistantMessage } from "../db/agent-events.js";
5
5
  import { runSqliteTransaction } from "../db/client.js";
@@ -27,6 +27,24 @@ function isTerminalAssistant(compact) {
27
27
  return stopReason === "stop" || stopReason === "length";
28
28
  }
29
29
  export const PLAN_WAITING_HISTORY = "PLAN_WAITING_HISTORY";
30
+ /**
31
+ * How many prior terminal rows the stale-baseline duplicate guard compares
32
+ * against, newest first. The guard used to compare only the single latest
33
+ * terminal row; M2 widens the accepted body set to unconfirmed rounds, so a body
34
+ * that was already delivered as an earlier terminal row must be recognised too.
35
+ * The window keeps that comparison bounded instead of scanning every terminal row
36
+ * the agent ever emitted (those live up to the 7-day settled TTL).
37
+ *
38
+ * Why 200: within that 7-day TTL a single agent's delivered/acked terminal rows
39
+ * in production top out around 250, and the body the guard cares about is always
40
+ * one of the most recent deliveries, so 200 covers it with margin while keeping
41
+ * the read to a few hundred KB of JSON.
42
+ *
43
+ * Above the window the guard stops recognising a duplicate, so an older body that
44
+ * resurfaces at the tail could be re-released as this round's answer once more.
45
+ * That is the accepted cost of bounding the scan instead of walking every row.
46
+ */
47
+ const STALE_DUPLICATE_GUARD_SCAN_LIMIT = 200;
30
48
  export class PlanWaitingHistoryError extends Error {
31
49
  constructor() {
32
50
  super(PLAN_WAITING_HISTORY);
@@ -1124,11 +1142,12 @@ export class AgentIndexService {
1124
1142
  const overlayByPane = new Map();
1125
1143
  for (const pane of snapshot.panes) {
1126
1144
  const value = record(pane);
1127
- const paneId = stringValue(value.pane_id) ?? stringValue(value.paneId);
1145
+ // `pane.list` panes are official `PaneInfo` records: snake_case only.
1146
+ const paneId = stringValue(value.pane_id);
1128
1147
  if (!paneId)
1129
1148
  continue;
1130
1149
  const revision = integerValue(value.revision);
1131
- const terminalTitle = stringValue(value.terminal_title) ?? stringValue(value.terminalTitle);
1150
+ const terminalTitle = stringValue(value.terminal_title);
1132
1151
  if (revision === undefined && !terminalTitle)
1133
1152
  continue;
1134
1153
  overlayByPane.set(paneId, {
@@ -1195,7 +1214,7 @@ export class AgentIndexService {
1195
1214
  const occupiedByOthers = this.#context.occupiedSessionPathsFor(agent);
1196
1215
  const occupancyConflict = Boolean(cached?.historyRef?.path && occupiedByOthers.has(cached.historyRef.path));
1197
1216
  const sessionReady = agent.agentSession?.kind === "path" &&
1198
- safeAllowedSessionPath(agent.agentSession.value) !== null;
1217
+ safeOfficialSessionPath(agent.agentSession.value) !== null;
1199
1218
  const sessionUnbound = sessionReady &&
1200
1219
  (cached?.historyRef?.kind !== "agent_session" ||
1201
1220
  cached.historyRef.path !== agent.agentSession?.value);
@@ -1442,7 +1461,7 @@ export class AgentIndexService {
1442
1461
  return result;
1443
1462
  }
1444
1463
  #isClosedPaneAgent(herdrSessionName, agent) {
1445
- const paneId = stringValue(agent.pane_id) ?? stringValue(agent.paneId);
1464
+ const paneId = stringValue(agent.pane_id);
1446
1465
  if (!paneId)
1447
1466
  return false;
1448
1467
  return this.#stores.agents.isPaneClosed({
@@ -1643,6 +1662,13 @@ export class AgentIndexService {
1643
1662
  // degraded (which is what made #runPlanRow run
1644
1663
  // invalidateById(..., "degraded_retry") on already-written content).
1645
1664
  const confirmedTerminal = turn.confirmed === true;
1665
+ // M2: the "trust the on-disk body" judgement is decoupled from
1666
+ // `confirmed`. That the turn-end signal arrived is already guaranteed by
1667
+ // the enclosing `if (turn?.received)`, so the deliverability judgement
1668
+ // below only has to decide whether the disk carries a deliverable body —
1669
+ // a round no longer needs a (systematically unreliable) client-side
1670
+ // `confirmed` to be released. `confirmedTerminal` keeps its own meaning
1671
+ // for the released/degraded logging and payload.
1646
1672
  const degradeOrRelease = (degradedReason) => {
1647
1673
  if (confirmedTerminal) {
1648
1674
  // A confirmed round stays non-degraded (see above), but the reason
@@ -1701,10 +1727,27 @@ export class AgentIndexService {
1701
1727
  // disk). It can also hold the answer of a *previous* round — the same
1702
1728
  // frozen baseline is exactly what the daemon last delivered — so a
1703
1729
  // round that writes nothing new would otherwise re-release the
1704
- // previous round's body as if it were this one's. `latestTerminal` is
1705
- // the latest non-invalidated terminal row read before this round's row
1706
- // is written: usually the last delivery, possibly an undelivered idle.
1707
- const staleBaselineDuplicate = sameTerminalAssistantContent(advanced, latestTerminal?.compactHistory, "pi");
1730
+ // previous round's body as if it were this one's. The guard compares
1731
+ // `advanced` against the prior terminal rows for this agent that can
1732
+ // have reached the orchestrator — a bounded window, newest first (the
1733
+ // `agent_events` query below). Two things changed from the single-row
1734
+ // guard: (i) it now looks at a window, because a body delivered before
1735
+ // the current latest terminal row would otherwise slip through and, now
1736
+ // that M2 accepts unconfirmed rounds, be re-released as this round's
1737
+ // answer; (ii) it only counts rows in `delivered`/`acked`, because a
1738
+ // never-deliverable row (`agent.idle` from a non-`working` status, per
1739
+ // `isDeliverableAgentEvent`; ~50% of ref-bearing `agent.idle` rows for a
1740
+ // given agent (47/94 in a 7-day sample) carry the same ref as a `done` row
1741
+ // of that agent; they are never deliverable) can sit in the window and must
1742
+ // not blank a deliverable round; the tightened guard is not a strict
1743
+ // superset of the old one (it fires only in the mismatch arm).
1744
+ const staleBaselineDuplicate = this.#stores.sqlite
1745
+ .prepare(`select compact_history_json from agent_events
1746
+ where agent_id = ? and herdr_session_name = ?
1747
+ and type in ('agent.idle', 'agent.done', 'agent.blocked')
1748
+ and status in ('delivered', 'acked')
1749
+ order by id desc limit ?`)
1750
+ .all(input.agent.id, input.agent.herdrSessionName, STALE_DUPLICATE_GUARD_SCAN_LIMIT).some((row) => sameTerminalAssistantContent(advanced, parseCompactHistoryJson(row.compact_history_json), "pi"));
1708
1751
  // A confirmed turn carrying a non-empty terminal assistant message is
1709
1752
  // trusted as-is, so `no_advance_from_input` stays reserved for rounds
1710
1753
  // with genuinely no deliverable assistant text (empty or non-terminal
@@ -1729,22 +1772,30 @@ export class AgentIndexService {
1729
1772
  else {
1730
1773
  const advancedText = advanced.lastAssistantMessage?.text?.trim() ?? "";
1731
1774
  const advancedMatchesExpected = !expectedText || advancedText.endsWith(expectedText);
1732
- if (confirmedDeliverable) {
1733
- // Event 50549: the extension confirmed the write, but its
1734
- // `expectedText` is the extension's own guess at the final tail and
1735
- // can disagree with the transcript that actually landed on disk
1736
- // (the old extension treated "the file grew" as confirmation, so a
1737
- // stale/escaped tail was reported as written). The disk tail is the
1738
- // authoritative evidence, and it already is a terminal assistant
1739
- // message with a body, so it is this round's answer: release it
1740
- // as-is (see :2012-2026 for the same judgement) and keep
1741
- // `degraded` off, because `degraded: true` makes #runPlanRow call
1742
- // invalidateById(..., "degraded_retry") on content that is already
1743
- // written. The mismatch is still recorded as a warning so the
1744
- // disagreement stays diagnosable instead of being swallowed.
1775
+ // M2 deliverability judgement: the turn-end signal already arrived
1776
+ // (the enclosing `if (turn?.received)`), so only the disk matters — a
1777
+ // non-empty terminal assistant message that was not already delivered
1778
+ // (`diskDeliverable`) is this round's answer. The
1779
+ // client's `confirmed` flag is deliberately not a conjunct here: its
1780
+ // `expectedText` is only the extension's own guess at the final tail
1781
+ // and can systematically disagree with the transcript that landed on
1782
+ // disk (rewrite-type extensions and credential redaction both make
1783
+ // the text-level confirmation never match), while the disk tail is
1784
+ // the authoritative evidence. When the guess disagrees the body is
1785
+ // still released as-is — `degraded` stays off, because `degraded:
1786
+ // true` makes #runPlanRow call invalidateById(..., "degraded_retry")
1787
+ // on content that is already written — and the mismatch is recorded
1788
+ // as a warning (split by `confirmed`) so it stays diagnosable.
1789
+ const diskDeliverable = isTerminalAssistant(advanced) &&
1790
+ hasNonEmptyAssistantMessage(advanced) &&
1791
+ !staleBaselineDuplicate;
1792
+ if (diskDeliverable) {
1745
1793
  if (!advancedMatchesExpected) {
1746
- console.warn("Herdsman accepted a confirmed pi status event despite an expectedText mismatch", {
1794
+ console.warn(confirmedTerminal
1795
+ ? "Herdsman accepted a confirmed pi status event despite an expectedText mismatch"
1796
+ : "Herdsman accepted an unconfirmed pi status event despite an expectedText mismatch", {
1747
1797
  agentId: input.agent.id,
1798
+ confirmed: confirmedTerminal,
1748
1799
  degradedReason: "expected_text_mismatch",
1749
1800
  herdrSessionName: input.agent.herdrSessionName,
1750
1801
  paneId: input.agent.paneId,
@@ -1760,11 +1811,11 @@ export class AgentIndexService {
1760
1811
  payloadExtra = degradeOrRelease("expected_text_mismatch");
1761
1812
  }
1762
1813
  else if (!isTerminalAssistant(advanced) || !hasNonEmptyAssistantMessage(advanced)) {
1763
- // `confirmedDeliverable` is false in this arm by construction (its
1814
+ // `diskDeliverable` is false in this arm by construction (its
1764
1815
  // terminal/non-empty conjuncts are exactly this condition's
1765
- // negation), so a confirmed round never reaches it and
1766
- // `non_terminal_assistant` keeps its pre-existing meaning: only a
1767
- // non-terminal or empty tail is degraded.
1816
+ // negation), so a round with a deliverable disk body never reaches
1817
+ // it and `non_terminal_assistant` keeps its pre-existing meaning:
1818
+ // only a non-terminal or empty tail is degraded.
1768
1819
  compactHistory = { ...advanced, lastAssistantMessage: null };
1769
1820
  payloadExtra = degradeOrRelease("non_terminal_assistant");
1770
1821
  }
@@ -2127,31 +2178,23 @@ export class AgentIndexService {
2127
2178
  }
2128
2179
  function withPaneRevision(agent, overlayByPane) {
2129
2180
  const raw = record(agent);
2130
- const paneId = stringValue(raw.pane_id) ?? stringValue(raw.paneId);
2181
+ // Herdr payloads are snake_case only (`AgentInfo` / `PaneInfo`); no camelCase
2182
+ // alias is accepted, so a Herdr rename surfaces as a missing field instead of
2183
+ // a silent compatibility shim.
2184
+ const paneId = stringValue(raw.pane_id);
2131
2185
  const overlay = paneId ? overlayByPane.get(paneId) : undefined;
2132
2186
  const revision = integerValue(raw.revision) ?? overlay?.revision;
2133
- const terminalTitle = stringValue(raw.terminal_title) ?? stringValue(raw.terminalTitle) ?? overlay?.terminalTitle;
2187
+ const terminalTitle = stringValue(raw.terminal_title) ?? overlay?.terminalTitle;
2134
2188
  if (revision === undefined && !terminalTitle)
2135
2189
  return raw;
2136
- // Collapse dual keys onto herdr-canonical snake_case `terminal_title`.
2137
- // Incoming snapshots may carry camelCase `terminalTitle`; spreading `raw`
2138
- // would otherwise leave both keys on the overlay object. Downstream
2139
- // HerdrAgentLike readers (AgentStore.replaceForSession) still accept
2140
- // camelCase as fallback, and AgentIndexRecord.terminalTitle is populated
2141
- // later from whichever key is present.
2142
- const rest = { ...raw };
2143
- delete rest.terminalTitle;
2144
2190
  return {
2145
- ...rest,
2191
+ ...raw,
2146
2192
  ...(revision === undefined ? {} : { revision }),
2147
2193
  ...(terminalTitle ? { terminal_title: terminalTitle } : {}),
2148
2194
  };
2149
2195
  }
2150
2196
  function paneGenerationOf(agent) {
2151
- return (stringValue(agent.pane_generation) ??
2152
- stringValue(agent.paneGeneration) ??
2153
- stringValue(agent.creation_id) ??
2154
- stringValue(agent.creationId));
2197
+ return stringValue(agent.pane_generation) ?? stringValue(agent.creation_id);
2155
2198
  }
2156
2199
  function matchingPrior(agent, previousByTerminal, previousByPane) {
2157
2200
  const terminalMatch = agent.terminalId ? previousByTerminal.get(agent.terminalId) : undefined;
@@ -2237,7 +2280,7 @@ function record(value) {
2237
2280
  return typeof value === "object" && value !== null ? value : {};
2238
2281
  }
2239
2282
  function paneGenerationFromEvent(event) {
2240
- return stringValue(event.pane_generation) ?? stringValue(event.paneGeneration);
2283
+ return stringValue(event.pane_generation);
2241
2284
  }
2242
2285
  function paneIdentityKey(paneId, paneGeneration) {
2243
2286
  return `${paneId}\0${paneGeneration ?? ""}`;
@@ -2265,6 +2308,16 @@ function sleep(ms, signal) {
2265
2308
  signal?.addEventListener("abort", onAbort, { once: true });
2266
2309
  });
2267
2310
  }
2311
+ function parseCompactHistoryJson(value) {
2312
+ if (!value)
2313
+ return null;
2314
+ try {
2315
+ return JSON.parse(value);
2316
+ }
2317
+ catch {
2318
+ return null;
2319
+ }
2320
+ }
2268
2321
  function sameTerminalAssistantContent(current, previous, agentKind) {
2269
2322
  const currentMsg = current?.lastAssistantMessage;
2270
2323
  const prevMsg = previous?.lastAssistantMessage;
@@ -2276,7 +2329,7 @@ function sameTerminalAssistantContent(current, previous, agentKind) {
2276
2329
  }
2277
2330
  return Boolean(currentMsg.text && currentMsg.text === prevMsg.text);
2278
2331
  }
2279
- // Non-agy (pi, claude, codex, grok, opencode):
2332
+ // Non-agy (pi):
2280
2333
  if (currentMsg.ref !== null && prevMsg.ref !== null) {
2281
2334
  return currentMsg.ref === prevMsg.ref;
2282
2335
  }