pi-cohort 7.2.1 → 7.2.2

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
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [7.2.2] - 2026-10-16
4
+
5
+ ### Fixed
6
+
7
+ - A background job's result file written while macOS re-arms its FSEvents stream is no longer missed until the next `session_start`. libuv rebuilds one process-wide stream on every new directory `fs.watch` (the watcher's own start, a sibling SDK session's watcher, pi's footer git watchers), and rename events in that gap were lost. The result watcher now rescans the results directory once per second while the native watcher is healthy and consumes any file it never reported; the id-based dedup makes a duplicate hit a no-op and the EMFILE/ENOSPC polling fallback is unchanged. `test/unit/multi-session.test.ts` writes each result once instead of re-publishing it every 250 ms. (#21)
8
+
3
9
  ## [7.2.1] - 2026-10-16
4
10
 
5
11
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-cohort",
3
- "version": "7.2.1",
3
+ "version": "7.2.2",
4
4
  "description": "Delegate Pi work to focused child agents: code review, scouting, implementation, parallel audits, saved chains, and background jobs.",
5
5
  "author": "Jacek Juraszek",
6
6
  "license": "MIT",
@@ -42,6 +42,7 @@ function createChildSafeState(): SubagentState {
42
42
  completionSeen: new Map(),
43
43
  watcher: null,
44
44
  watcherRestartTimer: null,
45
+ safetyRescanTimer: null,
45
46
  resultFileCoalescer: {
46
47
  schedule: () => false,
47
48
  clear: () => {},
@@ -271,6 +271,7 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
271
271
  completionSeen: new Map(),
272
272
  watcher: null,
273
273
  watcherRestartTimer: null,
274
+ safetyRescanTimer: null,
274
275
  resultFileCoalescer: {
275
276
  schedule: () => false,
276
277
  clear: () => {},
@@ -14,6 +14,7 @@ import { projectNestedRegistryForRoot, sanitizeSummary } from "../shared/nested-
14
14
 
15
15
  const WATCHER_RESTART_DELAY_MS = 3000;
16
16
  const POLL_INTERVAL_MS = 3000;
17
+ const SAFETY_RESCAN_INTERVAL_MS = 1000;
17
18
 
18
19
  type ResultWatcherFs = Pick<typeof fs, "existsSync" | "readFileSync" | "unlinkSync" | "readdirSync" | "mkdirSync" | "watch">;
19
20
 
@@ -196,9 +197,15 @@ export function createResultWatcher(
196
197
  }
197
198
  };
198
199
 
200
+ const clearSafetyRescan = () => {
201
+ if (state.safetyRescanTimer) timers.clearInterval(state.safetyRescanTimer);
202
+ state.safetyRescanTimer = null;
203
+ };
204
+
199
205
  const startPollingFallback = (reason: unknown) => {
200
206
  state.watcher?.close();
201
207
  state.watcher = null;
208
+ clearSafetyRescan();
202
209
  if (state.watcherRestartTimer) return;
203
210
 
204
211
  console.error(
@@ -250,9 +257,14 @@ export function createResultWatcher(
250
257
  console.error(`Subagent result watcher failed for '${resultsDir}':`, error);
251
258
  state.watcher?.close();
252
259
  state.watcher = null;
260
+ clearSafetyRescan();
253
261
  scheduleRestart();
254
262
  });
255
263
  state.watcher.unref?.();
264
+ if (!state.safetyRescanTimer) {
265
+ state.safetyRescanTimer = timers.setInterval(primeExistingResults, SAFETY_RESCAN_INTERVAL_MS);
266
+ state.safetyRescanTimer.unref?.();
267
+ }
256
268
  } catch (error) {
257
269
  if (shouldFallBackToPolling(error)) {
258
270
  startPollingFallback(error);
@@ -267,6 +279,7 @@ export function createResultWatcher(
267
279
  const stopResultWatcher = () => {
268
280
  state.watcher?.close();
269
281
  state.watcher = null;
282
+ clearSafetyRescan();
270
283
  if (state.watcherRestartTimer) {
271
284
  timers.clearTimeout(state.watcherRestartTimer);
272
285
  timers.clearInterval(state.watcherRestartTimer);
@@ -718,6 +718,7 @@ export interface SubagentState {
718
718
  completionSeen: Map<string, number>;
719
719
  watcher: FSWatcher | null;
720
720
  watcherRestartTimer: ReturnType<typeof setTimeout> | null;
721
+ safetyRescanTimer: ReturnType<typeof setInterval> | null;
721
722
  resultFileCoalescer: {
722
723
  schedule(file: string, delayMs?: number): boolean;
723
724
  clear(): void;