pi-crew 0.9.17 → 0.9.19

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.
@@ -615,7 +615,7 @@ function flushOnePendingAtomicWrite(filePath: string): void {
615
615
  throw error;
616
616
  }
617
617
  // Exponential backoff: base delay * 2^(retryCount-1), capped at 30 seconds
618
- const backoffMs = Math.min(30000, current.coalesceMs * Math.pow(2, current.retryCount - 1));
618
+ const backoffMs = Math.min(30000, current.coalesceMs * 2 ** (current.retryCount - 1));
619
619
  const timer = setTimeout(() => flushOnePendingAtomicWrite(filePath), backoffMs);
620
620
  timer.unref();
621
621
  current.timer = timer;
@@ -422,10 +422,16 @@ export function saveRunTasks(manifest: TeamRunManifest, tasks: TeamTaskState[]):
422
422
  * see the previous on-disk content while the write is still buffered).
423
423
  * Bulk update paths that fan out into multiple writer call sites are the
424
424
  * intended use case. Single-update + read-update loops (e.g.
425
- * persistSingleTaskUpdate) should keep using saveRunTasks.
425
+ * persistSingleTaskUpdate) should keep using saveRunTasks — OR call
426
+ * `flushPendingAtomicWrites()` immediately before their read to force
427
+ * any pending coalesced writes to land on disk first.
428
+ *
429
+ * (perf review 2026-07 F4) — now used by persistSingleTaskUpdate's
430
+ * non-terminal checkpoint path; that caller calls flushPendingAtomicWrites()
431
+ * before its read-modify-write load to defeat the stale-read window.
426
432
  */
427
433
  /** @internal */
428
- function saveRunTasksCoalesced(manifest: TeamRunManifest, tasks: TeamTaskState[]): void {
434
+ export function saveRunTasksCoalesced(manifest: TeamRunManifest, tasks: TeamTaskState[]): void {
429
435
  // FIX: Invalidate cache BEFORE atomic write to prevent stale cache serving.
430
436
  invalidateRunCache(manifest.stateRoot);
431
437
  try {
@@ -64,9 +64,7 @@ const IDLE_REASSERT_MAX_MS = 5000;
64
64
  const COMPLETE_FLASH_MS = 1500;
65
65
 
66
66
  /** Injected for tests (defaults write to the real /dev/tty). */
67
- export interface GhosttyWriter {
68
- (seq: string): void;
69
- }
67
+ export type GhosttyWriter = (seq: string) => void;
70
68
 
71
69
  let ghosttyWriter: GhosttyWriter | undefined;
72
70
 
@@ -6,7 +6,7 @@
6
6
  * Uses visibleWidth() for ANSI-aware padding so borders align correctly.
7
7
  */
8
8
 
9
- import { Container, Text, visibleWidth } from "@earendil-works/pi-tui";
9
+ import { type Container, Text, visibleWidth } from "@earendil-works/pi-tui";
10
10
  import type { CrewAgentRecord } from "../../runtime/crew-agent-runtime.ts";
11
11
  import { truncateToWidth } from "../../utils/visual.ts";
12
12
  import type { CrewTheme } from "../theme-adapter.ts";
@@ -85,7 +85,7 @@ function resolveWindowsCanonical(p: string): string {
85
85
  // containment checks: base (from cwd, often long-name) and target
86
86
  // (from os.tmpdir()/mkdtempSync, often short-name) must normalize to
87
87
  // the SAME form or a contained target is wrongly rejected as "outside".
88
- let real = fs.realpathSync.native(p);
88
+ const real = fs.realpathSync.native(p);
89
89
  // Guard against NTFS internal paths (e.g. C:\$Extend\$Deleted)
90
90
  if (real.includes("$Extend") || real.includes("$Deleted")) throw new Error("NTFS internal path");
91
91
  return real;
@@ -267,10 +267,6 @@ export function resolveRealContainedPath(baseDir: string, targetPath: string): s
267
267
  if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
268
268
  // For the final component (target itself), ENOENT is expected for non-existent targets.
269
269
  if (i === resolvedParts.length - 1) continue;
270
- // For non-final components (parent directories), ENOENT is also acceptable —
271
- // the caller will create them before the write operation if needed.
272
- // We only need to ensure no existing path component is a symlink.
273
- continue;
274
270
  }
275
271
  }
276
272
 
@@ -0,0 +1,30 @@
1
+ ---
2
+ name: plan-execute
3
+ description: Plan and execute a goal already analyzed by the calling session (no explore step)
4
+ topology: sequential
5
+ ---
6
+
7
+ ## plan
8
+ role: planner
9
+ output: plan.md
10
+ reads: analysis.md
11
+
12
+ Create a concise implementation plan for: {goal}
13
+
14
+ The calling session has already analyzed the problem. Its analysis is provided
15
+ as shared context (analysis.md). Build directly on that analysis; only re-verify
16
+ file paths and facts you need. Do not redo full discovery.
17
+
18
+ ## execute
19
+ role: executor
20
+ dependsOn: plan
21
+
22
+ Implement the plan for: {goal}
23
+
24
+ ## verify
25
+ role: verifier
26
+ dependsOn: execute
27
+ verify: true
28
+
29
+ Verify completion for: {goal}
30
+ Run tests ONCE (cache to .crew/cache/), read changed files from executor context. Cross-reference test output with the changes. Do NOT re-run tests. Give PASS or FAIL with specific test evidence.