pi-herdr-agents 2.0.2 → 2.0.4

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/CHANGELOG.md CHANGED
@@ -7,13 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
9
9
 
10
- ## [v2.0.2](https://github.com/giuseppecrj/pi-herdr-agents/compare/v2.0.1...v2.0.2)
10
+ ## [v2.0.4](https://github.com/giuseppecrj/pi-herdr-agents/compare/v2.0.3...v2.0.4)
11
+
12
+ ### Merged
13
+
14
+ - perf: batch persistent delivery ledger reads [`#58`](https://github.com/giuseppecrj/pi-herdr-agents/pull/58)
15
+
16
+ ## [v2.0.3](https://github.com/giuseppecrj/pi-herdr-agents/compare/v2.0.2...v2.0.3) - 2026-09-21
17
+
18
+ ### Commits
19
+
20
+ - fix: skip startup worktree inventory outside Herdr [`34800d7`](https://github.com/giuseppecrj/pi-herdr-agents/commit/34800d79464575063a61ad6f240cd49cc8acd730)
21
+ - chore: release v2.0.3 [`60888f2`](https://github.com/giuseppecrj/pi-herdr-agents/commit/60888f2dea48317257909abbcd0dd374ed861d77)
22
+
23
+ ## [v2.0.2](https://github.com/giuseppecrj/pi-herdr-agents/compare/v2.0.1...v2.0.2) - 2026-09-19
11
24
 
12
25
  ### Merged
13
26
 
14
27
  - fix(subagents): allow isolated same-family review fallback [`#54`](https://github.com/giuseppecrj/pi-herdr-agents/pull/54)
15
28
  - fix(subagents): remove conflicting Ctrl+J shortcut [`#53`](https://github.com/giuseppecrj/pi-herdr-agents/pull/53)
16
29
 
30
+ ### Commits
31
+
32
+ - chore: release v2.0.2 [`49efa52`](https://github.com/giuseppecrj/pi-herdr-agents/commit/49efa52bf671fbef00ad1be2d8b679188c5d1de3)
33
+
17
34
  ## [v2.0.1](https://github.com/giuseppecrj/pi-herdr-agents/compare/v2.0.0...v2.0.1) - 2026-09-18
18
35
 
19
36
  ### Merged
package/README.md CHANGED
@@ -23,7 +23,7 @@ Delegate investigation, implementation, and review without blocking the parent s
23
23
  - [Herdr](https://herdr.dev) and its CLI
24
24
  - `HERDR_ENV=1` — start Pi from inside Herdr
25
25
 
26
- Other terminal multiplexers are not supported. Worktrees isolate Git checkouts, not processes or permissions; child agents and installed Pi packages run with your user account's access.
26
+ Other terminal multiplexers are not supported. Outside Herdr, the extension skips automatic startup worktree inventory. Explicit inventory tools still report unavailable inspection as unknown. Worktrees isolate Git checkouts, not processes or permissions; child agents and installed Pi packages run with your user account's access.
27
27
 
28
28
  ## Install
29
29
 
@@ -231,7 +231,7 @@ Ignored files do not block cleanup. Inventory shows their exact file count, and
231
231
 
232
232
  Open workspaces are removed through Herdr. Git-only orphans use `git worktree remove`, verify checkout absence, and then prune stale Git registrations. Failed removal is reported, never forced. A reachable owned manifest is merge-updated to `removed` with `workspaceRemovedAt` only after success; absent cross-session manifests are reported and are not rewritten. A manifest update failure after removal is a removed-with-warning result, not a failed removal. Removed manifests provide already-removed no-op evidence only; a new checkout at the same path is classified independently. Missing and dangling manifest paths are non-matches. Permission errors, symlink loops, and other undecidable manifest identities remain blockers, as do genuine identity disagreements. Cleanup Git and Herdr calls have 30-second timeouts; a timed-out operation fails closed rather than proceeding with removal.
233
233
 
234
- Branches and their commits are always retained: cleanup never deletes, force-updates, or rewrites a branch. It never runs on completion, shutdown, or a timer. Parent session start emits only one compact inventory count when contained worktrees remain. Unsupported platforms or failed global process enumeration block removal; individual visibility gaps are disclosed warnings, never proof that an orphan is idle.
234
+ Branches and their commits are always retained: cleanup never deletes, force-updates, or rewrites a branch. It never runs on completion, shutdown, or a timer. Inside Herdr with its CLI available, parent session start emits only one compact inventory count when contained worktrees remain. Outside Herdr, startup skips the automatic inventory; explicit inventory tools remain available and report unavailable inspection as unknown. Unsupported platforms or failed global process enumeration block removal; individual visibility gaps are disclosed warnings, never proof that an orphan is idle.
235
235
 
236
236
  ## Current limits
237
237
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-herdr-agents",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
4
4
  "description": "Asynchronous Pi subagents in Herdr, with optional isolated Git worktrees",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -108,6 +108,7 @@ function extractHerdrWorktree(output: string): HerdrWorktreeSurface {
108
108
 
109
109
  function herdrExec(args: string[], timeout?: number): string {
110
110
  return execFileSync("herdr", args, {
111
+ stdio: "pipe",
111
112
  encoding: "utf8",
112
113
  timeout,
113
114
  killSignal: "SIGKILL",
@@ -2422,6 +2422,7 @@ export const __test__ = {
2422
2422
  resolveUnexpectedErrorPresentation,
2423
2423
  shouldAdvanceToFallback,
2424
2424
  deliverPersistentTaskEvent,
2425
+ drainPersistentTaskEvents,
2425
2426
  notifyPersistentCrash,
2426
2427
  sendSubagentResult,
2427
2428
  shouldRetainSubagentSurface,
@@ -2657,11 +2658,13 @@ function deliverPersistentTaskEvent(
2657
2658
  running: RunningSubagent,
2658
2659
  event: ReturnType<typeof readPersistentTaskEvents>[number],
2659
2660
  api: Pick<ExtensionAPI, "sendMessage">,
2661
+ ledgerSnapshot?: ReturnType<typeof readPersistentDeliveryLedger>,
2660
2662
  ): void {
2661
2663
  if (!running.persistent || event.generation !== running.generationId) return;
2662
2664
  const deliveryKey = `${running.id}:${event.type}:${event.task}`;
2663
2665
  if (inFlightPersistentTaskDeliveries.has(deliveryKey)) return;
2664
- const ledger = readPersistentDeliveryLedger(running.sessionFile);
2666
+ const ledger =
2667
+ ledgerSnapshot ?? readPersistentDeliveryLedger(running.sessionFile);
2665
2668
  if (event.type === "help-request") {
2666
2669
  if (
2667
2670
  ledger.some(
@@ -2685,13 +2688,15 @@ function deliverPersistentTaskEvent(
2685
2688
  },
2686
2689
  { triggerTurn: true, deliverAs: "steer" },
2687
2690
  );
2688
- appendPersistentDeliveryLedger(running.sessionFile, {
2689
- task: event.task,
2690
- outcome: "help-requested",
2691
- generation: running.generationId!,
2692
- logicalId: running.logicalId!,
2693
- policyHash: running.policyHash!,
2694
- });
2691
+ ledger.push(
2692
+ appendPersistentDeliveryLedger(running.sessionFile, {
2693
+ task: event.task,
2694
+ outcome: "help-requested",
2695
+ generation: running.generationId!,
2696
+ logicalId: running.logicalId!,
2697
+ policyHash: running.policyHash!,
2698
+ }),
2699
+ );
2695
2700
  if (running.taskId === event.task) running.taskId = undefined;
2696
2701
  } finally {
2697
2702
  inFlightPersistentTaskDeliveries.delete(deliveryKey);
@@ -2724,13 +2729,15 @@ function deliverPersistentTaskEvent(
2724
2729
  policyHash: running.policyHash!,
2725
2730
  },
2726
2731
  );
2727
- appendPersistentDeliveryLedger(running.sessionFile, {
2728
- task: event.task,
2729
- outcome: "delivered",
2730
- generation: running.generationId!,
2731
- logicalId: running.logicalId!,
2732
- policyHash: running.policyHash!,
2733
- });
2732
+ ledger.push(
2733
+ appendPersistentDeliveryLedger(running.sessionFile, {
2734
+ task: event.task,
2735
+ outcome: "delivered",
2736
+ generation: running.generationId!,
2737
+ logicalId: running.logicalId!,
2738
+ policyHash: running.policyHash!,
2739
+ }),
2740
+ );
2734
2741
  running.tasksCompleted = completed;
2735
2742
  if (running.taskId === event.task) running.taskId = undefined;
2736
2743
  if (running.stopState === "pending")
@@ -2743,13 +2750,25 @@ function deliverPersistentTaskEvent(
2743
2750
  function drainPersistentTaskEvents(
2744
2751
  running: RunningSubagent,
2745
2752
  api: Pick<ExtensionAPI, "sendMessage">,
2753
+ readLedger = readPersistentDeliveryLedger,
2746
2754
  ): void {
2747
2755
  const events = readPersistentTaskEvents(running.sessionFile);
2756
+ let ledger: ReturnType<typeof readPersistentDeliveryLedger> | undefined;
2748
2757
  for (const event of events.slice(running.observedTaskEvents ?? 0)) {
2758
+ if (!running.persistent || event.generation !== running.generationId)
2759
+ continue;
2760
+ if (
2761
+ inFlightPersistentTaskDeliveries.has(
2762
+ `${running.id}:${event.type}:${event.task}`,
2763
+ )
2764
+ )
2765
+ continue;
2766
+ ledger ??= readLedger(running.sessionFile);
2749
2767
  deliverPersistentTaskEvent(
2750
2768
  running,
2751
2769
  event,
2752
2770
  selectCompletionApi(api, runtime.pi),
2771
+ ledger,
2753
2772
  );
2754
2773
  }
2755
2774
  running.observedTaskEvents = events.length;
@@ -3131,7 +3150,7 @@ export default function subagentsExtension(
3131
3150
  startStatusRefresh(pi);
3132
3151
  updateWidget();
3133
3152
  }
3134
- if (parentSession && ctx.cwd && ctx.hasUI) {
3153
+ if (parentSession && ctx.cwd && ctx.hasUI && isTerminalAvailable()) {
3135
3154
  try {
3136
3155
  const notice = worktreeInventoryNotice(
3137
3156
  await listContainedWorktrees(cleanupInput(ctx)),