pi-crew 0.9.32 → 0.9.34
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 +163 -1
- package/docs/perf/performance-audit-report-2026-07.md +948 -0
- package/package.json +1 -1
- package/src/extension/run-maintenance.ts +29 -1
- package/src/extension/team-tool/lifecycle-actions.ts +22 -0
- package/src/extension/team-tool.ts +22 -1
- package/src/observability/exporters/otlp-exporter.ts +24 -2
- package/src/runtime/live-session-runtime.ts +12 -6
- package/src/runtime/parallel-utils.ts +5 -0
- package/src/runtime/skill-instructions.ts +7 -2
- package/src/runtime/task-graph-scheduler.ts +48 -17
- package/src/runtime/task-runner/prompt-builder.ts +120 -19
- package/src/runtime/task-runner/state-helpers.ts +18 -1
- package/src/runtime/task-runner.ts +20 -7
- package/src/runtime/team-runner.ts +196 -39
- package/src/state/artifact-store.ts +5 -0
- package/src/state/atomic-write.ts +87 -8
- package/src/state/event-log.ts +71 -25
- package/src/state/state-store.ts +32 -28
package/src/state/state-store.ts
CHANGED
|
@@ -330,6 +330,21 @@ export function createRunManifest(params: {
|
|
|
330
330
|
}
|
|
331
331
|
|
|
332
332
|
export function saveRunManifest(manifest: TeamRunManifest): void {
|
|
333
|
+
// FIX: Capture the cached tasks array + mtime/size BEFORE we invalidate the
|
|
334
|
+
// cache. The previous implementation re-read tasks.json from disk after the
|
|
335
|
+
// manifest write (a JSON.parse + fs.readFileSync per call), which defeated
|
|
336
|
+
// the whole point of the manifest cache on the hot update path. Reusing the
|
|
337
|
+
// already-cached entry is safe because:
|
|
338
|
+
// 1. The cache entry's tasks array matches the tasks array reflected by
|
|
339
|
+
// its tasksMtimeMs/tasksSize — the three values move together.
|
|
340
|
+
// 2. After invalidate, saveRunTasks (or any other writer) would bump the
|
|
341
|
+
// per-stateRoot generation, so a stale cache hit cannot serve.
|
|
342
|
+
// 3. On cache miss, we fall back to tasks: [] with mtime/size 0 — the same
|
|
343
|
+
// shape the original pre-FIX code produced — so behavior is unchanged.
|
|
344
|
+
const cachedBeforeInvalidate = manifestCache.get(manifest.stateRoot);
|
|
345
|
+
const cachedTasks = cachedBeforeInvalidate?.tasks ?? [];
|
|
346
|
+
const cachedTasksMtimeMs = cachedBeforeInvalidate?.tasksMtimeMs ?? 0;
|
|
347
|
+
const cachedTasksSize = cachedBeforeInvalidate?.tasksSize ?? 0;
|
|
333
348
|
// FIX: Invalidate cache BEFORE atomic write. The order matters for crash
|
|
334
349
|
// safety: if we invalidated after the write and crashed before invalidation,
|
|
335
350
|
// the stale cache entry (up to MANIFEST_CACHE_TTL_MS old) could be served.
|
|
@@ -341,40 +356,29 @@ export function saveRunManifest(manifest: TeamRunManifest): void {
|
|
|
341
356
|
// FIX: Re-populate cache with actual mtime/size so loadRunManifestById
|
|
342
357
|
// doesn't miss the cache on next read. Without this, every load until
|
|
343
358
|
// TTL expires would hit disk because cached 0 !== any real mtime.
|
|
344
|
-
// NOTE: tasks is
|
|
345
|
-
//
|
|
346
|
-
// saveRunTasks or loadRunTasks separately.
|
|
347
|
-
// immediately after saveRunManifest, it may return empty tasks even if
|
|
348
|
-
// tasks.json exists on disk — the mtime/size cache check should invalidate
|
|
349
|
-
// on next read, but the returned empty tasks array could confuse callers
|
|
350
|
-
// that don't re-read.
|
|
359
|
+
// NOTE: tasks is reused from the pre-invalidate cache snapshot above; if no
|
|
360
|
+
// cache existed, tasks is [] (matching pre-FIX behavior). Callers that need
|
|
361
|
+
// fresh tasks should call saveRunTasks or loadRunTasks separately.
|
|
351
362
|
const manifestStat = fs.statSync(manifestPath);
|
|
352
|
-
// Read tasks.json if it exists to avoid cache inconsistency.
|
|
353
|
-
// Without this, loadRunManifestById returns empty tasks even when tasks.json
|
|
354
|
-
// has real data, causing incorrect task state display.
|
|
355
|
-
let tasks: TeamTaskState[] = [];
|
|
356
|
-
let tasksMtimeMs = 0;
|
|
357
|
-
let tasksSize = 0;
|
|
358
|
-
try {
|
|
359
|
-
const tasksPath = path.join(manifest.stateRoot, "tasks.json");
|
|
360
|
-
const tasksStat = fs.statSync(tasksPath);
|
|
361
|
-
tasks = JSON.parse(fs.readFileSync(tasksPath, "utf-8")) as TeamTaskState[];
|
|
362
|
-
tasksMtimeMs = tasksStat.mtimeMs;
|
|
363
|
-
tasksSize = tasksStat.size;
|
|
364
|
-
} catch {
|
|
365
|
-
// tasks.json doesn't exist or is invalid — leave tasks empty
|
|
366
|
-
}
|
|
367
363
|
setManifestCache(manifest.stateRoot, {
|
|
368
364
|
manifest,
|
|
369
|
-
tasks,
|
|
365
|
+
tasks: cachedTasks,
|
|
370
366
|
manifestMtimeMs: manifestStat.mtimeMs,
|
|
371
367
|
manifestSize: manifestStat.size,
|
|
372
|
-
tasksMtimeMs,
|
|
373
|
-
tasksSize,
|
|
368
|
+
tasksMtimeMs: cachedTasksMtimeMs,
|
|
369
|
+
tasksSize: cachedTasksSize,
|
|
374
370
|
});
|
|
375
371
|
}
|
|
376
372
|
|
|
377
373
|
export async function saveRunManifestAsync(manifest: TeamRunManifest): Promise<void> {
|
|
374
|
+
// FIX: Capture cached tasks array + mtime/size BEFORE invalidating, same
|
|
375
|
+
// rationale as the sync saveRunManifest above. The async path previously
|
|
376
|
+
// always set tasks: [] with mtime/size 0, so any cache hit was guaranteed
|
|
377
|
+
// to look stale to loadRunManifestById until something else wrote tasks.json.
|
|
378
|
+
const cachedBeforeInvalidate = manifestCache.get(manifest.stateRoot);
|
|
379
|
+
const cachedTasks = cachedBeforeInvalidate?.tasks ?? [];
|
|
380
|
+
const cachedTasksMtimeMs = cachedBeforeInvalidate?.tasksMtimeMs ?? 0;
|
|
381
|
+
const cachedTasksSize = cachedBeforeInvalidate?.tasksSize ?? 0;
|
|
378
382
|
// FIX: Invalidate cache BEFORE atomic write to prevent stale cache serving
|
|
379
383
|
// after a crash. See saveRunManifest for full explanation.
|
|
380
384
|
invalidateRunCache(manifest.stateRoot);
|
|
@@ -384,11 +388,11 @@ export async function saveRunManifestAsync(manifest: TeamRunManifest): Promise<v
|
|
|
384
388
|
const manifestStat = await fs.promises.stat(manifestPath);
|
|
385
389
|
setManifestCache(manifest.stateRoot, {
|
|
386
390
|
manifest,
|
|
387
|
-
tasks:
|
|
391
|
+
tasks: cachedTasks,
|
|
388
392
|
manifestMtimeMs: manifestStat.mtimeMs,
|
|
389
393
|
manifestSize: manifestStat.size,
|
|
390
|
-
tasksMtimeMs:
|
|
391
|
-
tasksSize:
|
|
394
|
+
tasksMtimeMs: cachedTasksMtimeMs,
|
|
395
|
+
tasksSize: cachedTasksSize,
|
|
392
396
|
});
|
|
393
397
|
}
|
|
394
398
|
|