pi-crew 0.9.50 → 0.9.52
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 +150 -0
- package/README.md +216 -20
- package/dist/build-meta.json +2222 -1761
- package/dist/index.mjs +18636 -17603
- package/docs/actions-reference.md +431 -1
- package/package.json +19 -9
- package/schema.json +41 -0
- package/scripts/check-bundle-size.mjs +38 -0
- package/scripts/test-runner.mjs +11 -1
- package/skills/distill-software/SKILL.md +24 -1
- package/dist/index.mjs.map +0 -7
- package/docs/FEATURE_INTAKE.md +0 -126
- package/docs/HARNESS.md +0 -87
- package/docs/HARNESS_BACKLOG.md +0 -89
- package/docs/PROJECT_REVIEW.md +0 -270
- package/docs/PROJECT_REVIEW_FIXES.md +0 -342
- package/docs/PROJECT_REVIEW_ROUND4.md +0 -156
- package/docs/PROJECT_REVIEW_ROUND5.md +0 -86
- package/docs/REVIEW-FINDINGS-2026-06 +0 -357
- package/docs/REVIEW-FINDINGS-2026-07-CORE.md +0 -139
- package/docs/REVIEW-FINDINGS-2026-07.md +0 -125
- package/docs/TEST_MATRIX.md +0 -51
- package/docs/archive/README.md +0 -91
- package/docs/archive/followup-review-round3-2026-05-12.md +0 -342
- package/docs/archive/followup-review-round4-2026-05-13.md +0 -107
- package/docs/archive/pi-crew-bugs.md +0 -961
- package/docs/archive/pi-crew-test-final.md +0 -120
- package/docs/archive/pi-crew-test-results.md +0 -260
- package/docs/archive/pi-crew-test-round2.md +0 -136
- package/docs/archive/pi-crew-test-round4.md +0 -100
- package/docs/archive/pi-crew-test-round5.md +0 -70
- package/docs/archive/pi-crew-test-round6.md +0 -110
- package/docs/archive/pi-crew-v0.5.10-audit-fix-plan.md +0 -60
- package/docs/archive/pi-crew-v0.5.11-audit-fix-plan.md +0 -92
- package/docs/archive/pi-crew-v0.5.12-audit-fix-plan.md +0 -76
- package/docs/archive/pi-crew-v0.5.13-audit-fix-plan.md +0 -75
- package/docs/archive/pi-crew-v0.5.14-audit-fix-plan.md +0 -75
- package/docs/archive/pi-crew-v0.5.16-audit-fix-plan.md +0 -35
- package/docs/archive/pi-crew-v0.5.17-audit-fix-plan.md +0 -80
- package/docs/archive/pi-crew-v0.5.5-audit-fix-plan.md +0 -133
- package/docs/archive/pi-crew-v0.5.9-audit-fix-plan.md +0 -88
- package/docs/archive/pi-mono-opportunities.md +0 -969
- package/docs/archive/pi-mono-review.md +0 -291
- package/docs/archive/pi-subagent4-comparison.md +0 -261
- package/docs/archive/pi-subagents3-deep-analysis.md +0 -508
- package/docs/bugs/bug-021-notification-badge-counter-misleading.md +0 -293
- package/docs/bugs/bug-023-chain-windows-path-resolution.md +0 -106
- package/docs/bugs/bug-quota-display-truncation.md +0 -223
- package/docs/bugs/cross-session-notification-leakage.md +0 -82
- package/docs/code-review-2026-05-11.md +0 -592
- package/docs/coding-agent-optimization.md +0 -268
- package/docs/comparison-pi-subagents-vs-pi-crew.md +0 -303
- package/docs/decisions/0001-durable-state.md +0 -41
- package/docs/decisions/0002-child-process-for-async.md +0 -42
- package/docs/decisions/0003-depth-guard.md +0 -36
- package/docs/decisions/0004-execfile-over-exec.md +0 -34
- package/docs/decisions/0005-no-parameter-properties.md +0 -49
- package/docs/decisions/0006-publish-bundled-esm.md +0 -63
- package/docs/decisions/0007-active-run-binary-index.md +0 -54
- package/docs/decisions/0008-child-pi-warm-pool.md +0 -61
- package/docs/decisions/2026-07-21-broker-phase4-default-on.md +0 -77
- package/docs/decisions/2026-07-21-broker-windows-perms.md +0 -91
- package/docs/decisions/2026-07-22-broker-phase4-gated-on.md +0 -99
- package/docs/decisions/2026-07-24-oidc-trusted-publishing.md +0 -112
- package/docs/decisions/README.md +0 -26
- package/docs/deep-review-report.md +0 -384
- package/docs/distillation/cybersecurity-patterns.md +0 -294
- package/docs/feature-analysis-subagent4.md +0 -305
- package/docs/fix-plan-disabletools-exit-null.md +0 -219
- package/docs/fixes/BATCH_A_H1_H2.md +0 -86
- package/docs/fixes/bug-006-foreground-cancel-concurrent.md +0 -78
- package/docs/fixes/bug-007-async-notifier-stale-ctx.md +0 -112
- package/docs/fixes/bug-008-child-process-silent-timeout.md +0 -100
- package/docs/fixes/bug-009-executor-yield-limit-needs-attention.md +0 -75
- package/docs/fixes/bug-010-child-process-api-key-filtered.md +0 -109
- package/docs/fixes/bug-011-spawn-pi-enoent.md +0 -92
- package/docs/fixes/bug-012-essential-env-stripped.md +0 -89
- package/docs/fixes/bug-013-background-runner-death.md +0 -84
- package/docs/fixes/bug-014-infinite-retry-loop-needs-attention.md +0 -82
- package/docs/fixes/bug-015-background-runner-sigterm.md +0 -65
- package/docs/fixes/bug-017-background-runner-session-shutdown.md +0 -66
- package/docs/fixes/bug-017-background-runner-sigkill-double-fork.md +0 -28
- package/docs/fixes/bug-018-child-pi-worker-stdin-hang.md +0 -61
- package/docs/fixes/bug-019-phantom-runs-temp-workspace.md +0 -52
- package/docs/fixes/bug-020-infinite-retry-loop-needs-attention.md +0 -47
- package/docs/fixes/v0.9.10/locks-fix-verify.md +0 -3
- package/docs/fixes/v0.9.10/smoke-test.md +0 -12
- package/docs/followup-plan-2026-05-12.md +0 -463
- package/docs/followup-review-2026-05-12.md +0 -297
- package/docs/goals.md +0 -59
- package/docs/implementation-plan-top3.md +0 -333
- package/docs/issue-29-analysis.md +0 -189
- package/docs/live-mailbox-runtime.md +0 -36
- package/docs/migration/atomic-write-v2-migration.md +0 -299
- package/docs/next-upgrade-roadmap.md +0 -808
- package/docs/oh-my-pi-research.md +0 -509
- package/docs/optimization-plan-2026-07.md +0 -366
- package/docs/optimization-plan.md +0 -644
- package/docs/patterns/command-agent-skill.md +0 -71
- package/docs/perf/baseline-2026-05.md +0 -113
- package/docs/perf/final-report-2026-05.md +0 -206
- package/docs/perf/optimization-plan-2026-07-verified.md +0 -396
- package/docs/perf/performance-audit-report-2026-07.md +0 -948
- package/docs/perf/performance-review-2026-07.md +0 -287
- package/docs/perf/sprint-1-report.md +0 -71
- package/docs/perf/sprint-2-report.md +0 -81
- package/docs/perf/sprint-2.5-report.md +0 -53
- package/docs/perf/sprint-3-report.md +0 -36
- package/docs/perf/sprint-4-report.md +0 -47
- package/docs/perf/sprint-5-report.md +0 -51
- package/docs/perf/sprint-6-report.md +0 -94
- package/docs/perf/sprint-7-report.md +0 -74
- package/docs/perf/upgrade-plan-2026-05.md +0 -147
- package/docs/performance-optimization-execution-plan.md +0 -520
- package/docs/phase4-triage.md +0 -58
- package/docs/pi-crew-investigation-report.md +0 -411
- package/docs/product/README.md +0 -31
- package/docs/product/platform.md +0 -27
- package/docs/product/runtime-safety.md +0 -37
- package/docs/product/team-run.md +0 -39
- package/docs/product/team-tool.md +0 -37
- package/docs/runtime-analysis-child-vs-live.md +0 -171
- package/docs/runtime-migration-in-process-analysis.md +0 -250
- package/docs/skills/REFERENCE.md +0 -138
- package/docs/stories/README.md +0 -32
- package/docs/stories/US-DEPS-major-upgrade.md +0 -62
- package/docs/stories/backlog.md +0 -36
- package/docs/superpowers/plans/2026-06-09-fallow-patterns-adoption.md +0 -1270
- package/docs/templates/decision.md +0 -27
- package/docs/templates/story.md +0 -44
- package/docs/templates/validation-report.md +0 -32
- package/docs/ui-optimization-plan.md +0 -447
- package/src/adapters/claude-adapter.ts +0 -23
- package/src/adapters/codex-adapter.ts +0 -21
- package/src/adapters/cursor-adapter.ts +0 -17
- package/src/adapters/export-util.ts +0 -143
- package/src/adapters/index.ts +0 -15
- package/src/adapters/registry.ts +0 -18
- package/src/adapters/types.ts +0 -23
- package/src/agents/agent-config.ts +0 -194
- package/src/agents/agent-search.ts +0 -98
- package/src/agents/agent-serializer.ts +0 -38
- package/src/agents/discover-agents.ts +0 -623
- package/src/benchmark/benchmark-runner.ts +0 -313
- package/src/benchmark/feedback-loop.ts +0 -73
- package/src/config/config.ts +0 -1269
- package/src/config/defaults.ts +0 -193
- package/src/config/drift-detector.ts +0 -290
- package/src/config/markers.ts +0 -330
- package/src/config/resilient-parser.ts +0 -117
- package/src/config/role-tools.ts +0 -118
- package/src/config/suggestions.ts +0 -75
- package/src/config/types.ts +0 -278
- package/src/errors.ts +0 -194
- package/src/extension/action-suggestions.ts +0 -117
- package/src/extension/async-notifier.ts +0 -179
- package/src/extension/autonomous-policy.ts +0 -209
- package/src/extension/command-completions.ts +0 -120
- package/src/extension/context-status-injection.ts +0 -185
- package/src/extension/crew-autocomplete.ts +0 -131
- package/src/extension/crew-cleanup.ts +0 -168
- package/src/extension/crew-input-router.ts +0 -93
- package/src/extension/crew-shortcuts.ts +0 -87
- package/src/extension/crew-vibes/cat-frames.ts +0 -18
- package/src/extension/crew-vibes/config.ts +0 -195
- package/src/extension/crew-vibes/figures.ts +0 -101
- package/src/extension/crew-vibes/font-detect.ts +0 -71
- package/src/extension/crew-vibes/footer.ts +0 -292
- package/src/extension/crew-vibes/index.ts +0 -432
- package/src/extension/crew-vibes/provider-usage.ts +0 -396
- package/src/extension/crew-vibes/render.ts +0 -206
- package/src/extension/crew-vibes/speed.ts +0 -286
- package/src/extension/cross-extension-rpc.ts +0 -350
- package/src/extension/help.ts +0 -62
- package/src/extension/import-index.ts +0 -74
- package/src/extension/knowledge-injection.ts +0 -402
- package/src/extension/management.ts +0 -571
- package/src/extension/message-renderers.ts +0 -108
- package/src/extension/notification-router.ts +0 -152
- package/src/extension/notification-sink.ts +0 -54
- package/src/extension/pi-api.ts +0 -56
- package/src/extension/plan-orchestrate.ts +0 -302
- package/src/extension/project-init.ts +0 -170
- package/src/extension/register.ts +0 -113
- package/src/extension/registration/artifact-cleanup.ts +0 -20
- package/src/extension/registration/command-registration.ts +0 -58
- package/src/extension/registration/command-utils.ts +0 -58
- package/src/extension/registration/commands.ts +0 -1228
- package/src/extension/registration/compaction-guard.ts +0 -333
- package/src/extension/registration/context-builder.ts +0 -135
- package/src/extension/registration/crash-recovery-cache.ts +0 -54
- package/src/extension/registration/foreground-run-controller.ts +0 -238
- package/src/extension/registration/hook-registration.ts +0 -119
- package/src/extension/registration/lazy-configurers.ts +0 -124
- package/src/extension/registration/lifecycle-handlers.ts +0 -923
- package/src/extension/registration/lifecycle.ts +0 -259
- package/src/extension/registration/observability.ts +0 -322
- package/src/extension/registration/registration-types.ts +0 -158
- package/src/extension/registration/runtime-cleanup.ts +0 -230
- package/src/extension/registration/subagent-helpers.ts +0 -125
- package/src/extension/registration/subagent-manager-setup.ts +0 -330
- package/src/extension/registration/subagent-tools.ts +0 -456
- package/src/extension/registration/team-tool.ts +0 -220
- package/src/extension/registration/tool-registration.ts +0 -50
- package/src/extension/registration/ui.ts +0 -172
- package/src/extension/registration/viewers.ts +0 -121
- package/src/extension/registration/wire-cross-extension.ts +0 -37
- package/src/extension/result-watcher.ts +0 -139
- package/src/extension/rpc-hmac.ts +0 -256
- package/src/extension/run-bundle-schema.ts +0 -104
- package/src/extension/run-export.ts +0 -97
- package/src/extension/run-import.ts +0 -168
- package/src/extension/run-index.ts +0 -131
- package/src/extension/run-maintenance.ts +0 -190
- package/src/extension/session-summary.ts +0 -18
- package/src/extension/team-manager-command.ts +0 -153
- package/src/extension/team-onboard.ts +0 -177
- package/src/extension/team-recommendation.ts +0 -288
- package/src/extension/team-tool/anchor.ts +0 -172
- package/src/extension/team-tool/api.ts +0 -1244
- package/src/extension/team-tool/auto-summarize.ts +0 -142
- package/src/extension/team-tool/cache-control.ts +0 -19
- package/src/extension/team-tool/cancel.ts +0 -337
- package/src/extension/team-tool/chain-dispatch.ts +0 -95
- package/src/extension/team-tool/chain-executor.ts +0 -379
- package/src/extension/team-tool/config-patch.ts +0 -50
- package/src/extension/team-tool/context.ts +0 -149
- package/src/extension/team-tool/destructive-gate.ts +0 -52
- package/src/extension/team-tool/doctor.ts +0 -431
- package/src/extension/team-tool/explain.ts +0 -282
- package/src/extension/team-tool/failure-patterns.ts +0 -118
- package/src/extension/team-tool/goal-wrap.ts +0 -330
- package/src/extension/team-tool/goal.ts +0 -556
- package/src/extension/team-tool/handle-schedule.ts +0 -332
- package/src/extension/team-tool/handle-settings.ts +0 -520
- package/src/extension/team-tool/health-monitor.ts +0 -481
- package/src/extension/team-tool/inspect.ts +0 -88
- package/src/extension/team-tool/intent-policy.ts +0 -45
- package/src/extension/team-tool/lifecycle-actions.ts +0 -615
- package/src/extension/team-tool/orchestrate.ts +0 -98
- package/src/extension/team-tool/parallel-dispatch.ts +0 -183
- package/src/extension/team-tool/plan.ts +0 -50
- package/src/extension/team-tool/respond.ts +0 -150
- package/src/extension/team-tool/run-not-found.ts +0 -49
- package/src/extension/team-tool/run.ts +0 -1035
- package/src/extension/team-tool/status.ts +0 -260
- package/src/extension/team-tool/workflow-manage.ts +0 -261
- package/src/extension/team-tool-types.ts +0 -26
- package/src/extension/team-tool.ts +0 -1116
- package/src/extension/tool-result.ts +0 -16
- package/src/extension/validate-resources.ts +0 -108
- package/src/hooks/registry.ts +0 -200
- package/src/hooks/types.ts +0 -69
- package/src/i18n.ts +0 -212
- package/src/observability/correlation.ts +0 -50
- package/src/observability/event-bus.ts +0 -86
- package/src/observability/event-to-metric.ts +0 -170
- package/src/observability/exporters/adapter.ts +0 -27
- package/src/observability/exporters/otlp-exporter.ts +0 -356
- package/src/observability/exporters/prometheus-exporter.ts +0 -54
- package/src/observability/metric-registry.ts +0 -100
- package/src/observability/metric-retention.ts +0 -64
- package/src/observability/metric-sink.ts +0 -99
- package/src/observability/metrics-primitives.ts +0 -219
- package/src/plugins/plugin-define.ts +0 -6
- package/src/plugins/plugin-registry.ts +0 -32
- package/src/plugins/plugins/index.ts +0 -3
- package/src/plugins/plugins/nextjs.ts +0 -19
- package/src/plugins/plugins/vite.ts +0 -10
- package/src/plugins/plugins/vitest.ts +0 -9
- package/src/prompt/prompt-runtime.ts +0 -380
- package/src/runtime/adaptive-plan.ts +0 -563
- package/src/runtime/agent-control.ts +0 -215
- package/src/runtime/agent-memory.ts +0 -81
- package/src/runtime/agent-observability.ts +0 -122
- package/src/runtime/anchor-manager.ts +0 -475
- package/src/runtime/async-marker.ts +0 -32
- package/src/runtime/async-runner.ts +0 -381
- package/src/runtime/attention-events.ts +0 -28
- package/src/runtime/auto-summarize.ts +0 -344
- package/src/runtime/background-runner.ts +0 -837
- package/src/runtime/batch-barrier.ts +0 -147
- package/src/runtime/broker-issuer.ts +0 -37
- package/src/runtime/cancellation-token.ts +0 -99
- package/src/runtime/cancellation.ts +0 -99
- package/src/runtime/capability-inventory.ts +0 -137
- package/src/runtime/chain-parser.ts +0 -237
- package/src/runtime/chain-runner.ts +0 -606
- package/src/runtime/checkpoint.ts +0 -291
- package/src/runtime/child-pi-constants.ts +0 -42
- package/src/runtime/child-pi-kill.ts +0 -180
- package/src/runtime/child-pi-pool.ts +0 -68
- package/src/runtime/child-pi-spawn.ts +0 -287
- package/src/runtime/child-pi-steering.ts +0 -128
- package/src/runtime/child-pi-streams.ts +0 -296
- package/src/runtime/child-pi-transcript.ts +0 -169
- package/src/runtime/child-pi.ts +0 -1105
- package/src/runtime/coalesce-tasks.ts +0 -268
- package/src/runtime/code-summary.ts +0 -292
- package/src/runtime/command-trace.ts +0 -105
- package/src/runtime/compact-pipeline.ts +0 -56
- package/src/runtime/compact-stages/ansi-strip-stage.ts +0 -25
- package/src/runtime/compact-stages/blank-collapse-stage.ts +0 -31
- package/src/runtime/compact-stages/deduplicate-stage.ts +0 -34
- package/src/runtime/compact-stages/head-snap-stage.ts +0 -57
- package/src/runtime/compact-stages/index.ts +0 -23
- package/src/runtime/compact-stages/tail-capture-stage.ts +0 -77
- package/src/runtime/compact-stages/truncation-stage.ts +0 -74
- package/src/runtime/compaction-summary.ts +0 -278
- package/src/runtime/completion-guard.ts +0 -207
- package/src/runtime/concurrency.ts +0 -58
- package/src/runtime/crash-classification.ts +0 -229
- package/src/runtime/crash-recovery.ts +0 -577
- package/src/runtime/crew-agent-records.ts +0 -593
- package/src/runtime/crew-agent-runtime.ts +0 -62
- package/src/runtime/crew-broker-child.ts +0 -88
- package/src/runtime/crew-broker-client.ts +0 -673
- package/src/runtime/crew-broker-tokens.ts +0 -84
- package/src/runtime/crew-broker.ts +0 -1276
- package/src/runtime/crew-hooks.ts +0 -227
- package/src/runtime/cross-extension-rpc.ts +0 -143
- package/src/runtime/custom-tools/irc-tool.ts +0 -282
- package/src/runtime/custom-tools/submit-result-tool.ts +0 -102
- package/src/runtime/deadletter.ts +0 -47
- package/src/runtime/delivery-coordinator.ts +0 -211
- package/src/runtime/delta-conflict.ts +0 -348
- package/src/runtime/deterministic-ast.ts +0 -161
- package/src/runtime/diagnostic-export.ts +0 -171
- package/src/runtime/direct-run.ts +0 -45
- package/src/runtime/dwf-state-store.ts +0 -102
- package/src/runtime/dynamic-workflow-context.ts +0 -1016
- package/src/runtime/dynamic-workflow-runner.ts +0 -310
- package/src/runtime/effectiveness.ts +0 -90
- package/src/runtime/errors/crew-errors.ts +0 -162
- package/src/runtime/event-stream-bridge.ts +0 -98
- package/src/runtime/foreground-control.ts +0 -193
- package/src/runtime/foreground-watchdog.ts +0 -132
- package/src/runtime/global-worker-cap.ts +0 -96
- package/src/runtime/goal-achievement.ts +0 -148
- package/src/runtime/goal-evaluator.ts +0 -361
- package/src/runtime/goal-loop-runner.ts +0 -828
- package/src/runtime/goal-state-store.ts +0 -219
- package/src/runtime/green-contract.ts +0 -55
- package/src/runtime/group-join.ts +0 -267
- package/src/runtime/handoff-manager.ts +0 -598
- package/src/runtime/heartbeat-gradient.ts +0 -36
- package/src/runtime/heartbeat-watcher.ts +0 -239
- package/src/runtime/hidden-handoff.ts +0 -407
- package/src/runtime/important-line-classifier.ts +0 -140
- package/src/runtime/intercom-bridge.ts +0 -187
- package/src/runtime/iteration-hooks.ts +0 -305
- package/src/runtime/live-agent-control.ts +0 -136
- package/src/runtime/live-agent-manager.ts +0 -704
- package/src/runtime/live-control-realtime.ts +0 -56
- package/src/runtime/live-extension-bridge.ts +0 -148
- package/src/runtime/live-irc.ts +0 -97
- package/src/runtime/live-session-health.ts +0 -108
- package/src/runtime/live-session-runtime.ts +0 -1139
- package/src/runtime/loop-gates.ts +0 -128
- package/src/runtime/manifest-cache.ts +0 -375
- package/src/runtime/mcp-proxy.ts +0 -105
- package/src/runtime/metric-parser.ts +0 -36
- package/src/runtime/model-fallback.ts +0 -409
- package/src/runtime/model-resolver.ts +0 -126
- package/src/runtime/model-scope.ts +0 -158
- package/src/runtime/orphan-worker-registry.ts +0 -465
- package/src/runtime/output-validator.ts +0 -202
- package/src/runtime/overflow-recovery.ts +0 -206
- package/src/runtime/parallel-research.ts +0 -68
- package/src/runtime/parallel-utils.ts +0 -160
- package/src/runtime/parent-guard.ts +0 -134
- package/src/runtime/path-overlap.ts +0 -150
- package/src/runtime/peer-dep.ts +0 -292
- package/src/runtime/per-write-validator.ts +0 -181
- package/src/runtime/phase-progress.ts +0 -217
- package/src/runtime/phase-tracker.ts +0 -385
- package/src/runtime/pi-args.ts +0 -655
- package/src/runtime/pi-json-output.ts +0 -170
- package/src/runtime/pi-spawn.ts +0 -273
- package/src/runtime/pipeline-runner.ts +0 -523
- package/src/runtime/plan-templates.ts +0 -201
- package/src/runtime/policy-engine.ts +0 -115
- package/src/runtime/post-checks.ts +0 -142
- package/src/runtime/post-exit-stdio-guard.ts +0 -104
- package/src/runtime/process-lifecycle.ts +0 -491
- package/src/runtime/process-status.ts +0 -154
- package/src/runtime/progress-event-coalescer.ts +0 -44
- package/src/runtime/progress-tracker.ts +0 -124
- package/src/runtime/prose-compressor.ts +0 -162
- package/src/runtime/recovery-recipes.ts +0 -203
- package/src/runtime/replace.ts +0 -570
- package/src/runtime/resilient-edit.ts +0 -153
- package/src/runtime/result-extractor.ts +0 -213
- package/src/runtime/retry-executor.ts +0 -100
- package/src/runtime/retry-runner.ts +0 -336
- package/src/runtime/role-permission.ts +0 -59
- package/src/runtime/run-coalesced-task-group.ts +0 -308
- package/src/runtime/run-drift.ts +0 -219
- package/src/runtime/run-tracker.ts +0 -116
- package/src/runtime/runtime-policy.ts +0 -29
- package/src/runtime/runtime-resolver.ts +0 -172
- package/src/runtime/runtime-warmup.ts +0 -160
- package/src/runtime/scheduler.ts +0 -353
- package/src/runtime/semaphore.ts +0 -141
- package/src/runtime/sensitive-paths.ts +0 -93
- package/src/runtime/session-resources.ts +0 -25
- package/src/runtime/session-snapshot.ts +0 -59
- package/src/runtime/session-usage.ts +0 -79
- package/src/runtime/settings-store.ts +0 -155
- package/src/runtime/sidechain-output.ts +0 -35
- package/src/runtime/single-agent-compose.ts +0 -84
- package/src/runtime/skill-effectiveness.ts +0 -524
- package/src/runtime/skill-instructions.ts +0 -391
- package/src/runtime/stale-reconciler.ts +0 -680
- package/src/runtime/stream-preview.ts +0 -184
- package/src/runtime/streaming-output.ts +0 -50
- package/src/runtime/subagent-manager.ts +0 -561
- package/src/runtime/subprocess-tool-registry.ts +0 -70
- package/src/runtime/supervisor-contact.ts +0 -64
- package/src/runtime/task-display.ts +0 -52
- package/src/runtime/task-graph-scheduler.ts +0 -227
- package/src/runtime/task-graph.ts +0 -290
- package/src/runtime/task-health.ts +0 -83
- package/src/runtime/task-id.ts +0 -161
- package/src/runtime/task-output-context.ts +0 -602
- package/src/runtime/task-packet.ts +0 -268
- package/src/runtime/task-quality.ts +0 -199
- package/src/runtime/task-runner/capabilities.ts +0 -78
- package/src/runtime/task-runner/context-retrieval.ts +0 -163
- package/src/runtime/task-runner/live-executor.ts +0 -227
- package/src/runtime/task-runner/output-splitter.ts +0 -152
- package/src/runtime/task-runner/progress.ts +0 -157
- package/src/runtime/task-runner/prompt-builder.ts +0 -278
- package/src/runtime/task-runner/prompt-pipeline.ts +0 -88
- package/src/runtime/task-runner/result-utils.ts +0 -16
- package/src/runtime/task-runner/retrieval-orchestrator.ts +0 -310
- package/src/runtime/task-runner/run-projection.ts +0 -125
- package/src/runtime/task-runner/state-helpers.ts +0 -176
- package/src/runtime/task-runner/tail-read.ts +0 -34
- package/src/runtime/task-runner.ts +0 -1420
- package/src/runtime/team-runner-artifacts.ts +0 -13
- package/src/runtime/team-runner.ts +0 -1993
- package/src/runtime/tool-output-pruner.ts +0 -333
- package/src/runtime/tool-progress.ts +0 -278
- package/src/runtime/usage-tracker.ts +0 -73
- package/src/runtime/verification-gates.ts +0 -571
- package/src/runtime/verification-integrity.ts +0 -105
- package/src/runtime/verification-worktree.ts +0 -186
- package/src/runtime/worker-heartbeat.ts +0 -25
- package/src/runtime/worker-startup.ts +0 -83
- package/src/runtime/workflow-state.ts +0 -195
- package/src/runtime/workspace-lock.ts +0 -443
- package/src/runtime/workspace-tree.ts +0 -312
- package/src/runtime/yield-handler.ts +0 -224
- package/src/runtime/zombie-scanner.ts +0 -298
- package/src/schema/config-schema.ts +0 -327
- package/src/schema/team-tool-schema.ts +0 -415
- package/src/schema/validation-types.ts +0 -159
- package/src/skills/discover-skills.ts +0 -197
- package/src/skills/skill-templates.ts +0 -456
- package/src/skills/validate.ts +0 -285
- package/src/state/active-run-registry.ts +0 -439
- package/src/state/artifact-store.ts +0 -176
- package/src/state/atomic-write.ts +0 -903
- package/src/state/blob-store.ts +0 -308
- package/src/state/contracts.ts +0 -158
- package/src/state/crew-init.ts +0 -269
- package/src/state/decision-ledger.ts +0 -345
- package/src/state/event-log-rotation.ts +0 -342
- package/src/state/event-log.ts +0 -1311
- package/src/state/event-reconstructor.ts +0 -229
- package/src/state/gitignore-manager.ts +0 -46
- package/src/state/health-store.ts +0 -79
- package/src/state/hook-instinct-bridge.ts +0 -94
- package/src/state/hook-integrations.ts +0 -51
- package/src/state/instinct-store.ts +0 -275
- package/src/state/jsonl-writer.ts +0 -107
- package/src/state/locks.ts +0 -562
- package/src/state/mailbox.ts +0 -916
- package/src/state/observation-store.ts +0 -176
- package/src/state/run-cache.ts +0 -193
- package/src/state/run-graph.ts +0 -183
- package/src/state/run-metrics.ts +0 -165
- package/src/state/schedule.ts +0 -166
- package/src/state/session-state-map.ts +0 -51
- package/src/state/state-store.ts +0 -958
- package/src/state/task-claims.ts +0 -61
- package/src/state/tiered-eval.ts +0 -480
- package/src/state/types-eval.ts +0 -58
- package/src/state/types.ts +0 -440
- package/src/state/usage.ts +0 -138
- package/src/state/worker-atomic-writer.ts +0 -194
- package/src/subagents/async-entry.ts +0 -1
- package/src/subagents/index.ts +0 -3
- package/src/subagents/live/control.ts +0 -1
- package/src/subagents/live/manager.ts +0 -1
- package/src/subagents/live/realtime.ts +0 -1
- package/src/subagents/live/session-runtime.ts +0 -1
- package/src/subagents/manager.ts +0 -1
- package/src/subagents/spawn.ts +0 -1
- package/src/teams/discover-teams.ts +0 -187
- package/src/teams/team-config.ts +0 -27
- package/src/teams/team-serializer.ts +0 -38
- package/src/tools/safe-bash-extension.ts +0 -54
- package/src/tools/safe-bash.ts +0 -505
- package/src/types/diff.d.ts +0 -18
- package/src/types/new-api-types.ts +0 -35
- package/src/ui/agent-management-overlay.ts +0 -160
- package/src/ui/card-colors.ts +0 -139
- package/src/ui/crew-footer.ts +0 -102
- package/src/ui/crew-select-list.ts +0 -111
- package/src/ui/dashboard-panes/agents-pane.ts +0 -164
- package/src/ui/dashboard-panes/cancellation-pane.ts +0 -66
- package/src/ui/dashboard-panes/capability-pane.ts +0 -77
- package/src/ui/dashboard-panes/health-pane.ts +0 -31
- package/src/ui/dashboard-panes/mailbox-pane.ts +0 -35
- package/src/ui/dashboard-panes/metrics-pane.ts +0 -37
- package/src/ui/dashboard-panes/progress-pane.ts +0 -38
- package/src/ui/dashboard-panes/transcript-pane.ts +0 -10
- package/src/ui/deploy-bundled-themes.ts +0 -71
- package/src/ui/dwf-phase-display.ts +0 -151
- package/src/ui/dynamic-border.ts +0 -35
- package/src/ui/heartbeat-aggregator.ts +0 -74
- package/src/ui/key-utils.ts +0 -42
- package/src/ui/keybinding-map.ts +0 -248
- package/src/ui/layout-primitives.ts +0 -106
- package/src/ui/live-conversation-overlay.ts +0 -183
- package/src/ui/live-duration.ts +0 -55
- package/src/ui/live-run-sidebar.ts +0 -301
- package/src/ui/loaders.ts +0 -176
- package/src/ui/mascot.ts +0 -436
- package/src/ui/overlays/agent-picker-overlay.ts +0 -65
- package/src/ui/overlays/confirm-overlay.ts +0 -60
- package/src/ui/overlays/help-overlay.ts +0 -177
- package/src/ui/overlays/mailbox-compose-overlay.ts +0 -181
- package/src/ui/overlays/mailbox-compose-preview.ts +0 -78
- package/src/ui/overlays/mailbox-detail-overlay.ts +0 -154
- package/src/ui/pi-ui-compat.ts +0 -68
- package/src/ui/powerbar-publisher.ts +0 -459
- package/src/ui/render-coalescer.ts +0 -101
- package/src/ui/render-diff.ts +0 -160
- package/src/ui/render-scheduler.ts +0 -224
- package/src/ui/run-action-dispatcher.ts +0 -182
- package/src/ui/run-dashboard.ts +0 -913
- package/src/ui/run-event-bus.ts +0 -381
- package/src/ui/run-snapshot-cache.ts +0 -1057
- package/src/ui/settings-overlay.ts +0 -1067
- package/src/ui/snapshot-types.ts +0 -90
- package/src/ui/spinner.ts +0 -17
- package/src/ui/status-colors.ts +0 -143
- package/src/ui/syntax-highlight.ts +0 -136
- package/src/ui/terminal-status.ts +0 -269
- package/src/ui/theme-adapter.ts +0 -271
- package/src/ui/theme-discovery.ts +0 -199
- package/src/ui/tool-progress-formatter.ts +0 -93
- package/src/ui/tool-render.ts +0 -453
- package/src/ui/tool-renderers/brief-mode.ts +0 -225
- package/src/ui/tool-renderers/index.ts +0 -726
- package/src/ui/transcript-cache.ts +0 -128
- package/src/ui/transcript-entries.ts +0 -256
- package/src/ui/transcript-viewer.ts +0 -424
- package/src/ui/widget/index.ts +0 -357
- package/src/ui/widget/widget-formatters.ts +0 -182
- package/src/ui/widget/widget-model.ts +0 -110
- package/src/ui/widget/widget-renderer.ts +0 -182
- package/src/ui/widget/widget-types.ts +0 -36
- package/src/utils/bm25-search.ts +0 -235
- package/src/utils/completion-dedupe.ts +0 -63
- package/src/utils/conflict-detect.ts +0 -668
- package/src/utils/env-allowlist.ts +0 -30
- package/src/utils/env-filter.ts +0 -155
- package/src/utils/file-coalescer.ts +0 -98
- package/src/utils/fingerprint.ts +0 -180
- package/src/utils/frontmatter.ts +0 -70
- package/src/utils/fs-watch.ts +0 -37
- package/src/utils/gh-protocol.ts +0 -556
- package/src/utils/git.ts +0 -260
- package/src/utils/guards.ts +0 -107
- package/src/utils/ids.ts +0 -24
- package/src/utils/incremental-reader.ts +0 -220
- package/src/utils/internal-error.ts +0 -10
- package/src/utils/names.ts +0 -36
- package/src/utils/ndjson.ts +0 -115
- package/src/utils/paths.ts +0 -227
- package/src/utils/project-detector.ts +0 -160
- package/src/utils/redaction.ts +0 -347
- package/src/utils/resolve-shell.ts +0 -36
- package/src/utils/run-watcher-registry.ts +0 -152
- package/src/utils/safe-paths.ts +0 -383
- package/src/utils/scan-cache.ts +0 -144
- package/src/utils/session-utils.ts +0 -110
- package/src/utils/sleep.ts +0 -54
- package/src/utils/socket-path.ts +0 -127
- package/src/utils/sse-parser.ts +0 -129
- package/src/utils/task-name-generator.ts +0 -337
- package/src/utils/timings.ts +0 -33
- package/src/utils/token-counter.ts +0 -200
- package/src/utils/visual.ts +0 -207
- package/src/workflows/cost-estimator.ts +0 -34
- package/src/workflows/discover-workflows.ts +0 -290
- package/src/workflows/intermediate-store.ts +0 -166
- package/src/workflows/preflight-validator.ts +0 -168
- package/src/workflows/topology-analyzer.ts +0 -203
- package/src/workflows/validate-workflow.ts +0 -50
- package/src/workflows/workflow-config.ts +0 -70
- package/src/workflows/workflow-serializer.ts +0 -32
- package/src/worktree/branch-freshness.ts +0 -112
- package/src/worktree/cleanup.ts +0 -341
- package/src/worktree/worktree-manager.ts +0 -1200
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
# Issue #29 Analysis: Hardcoded `.crew/state/runs` Path Crashes pi
|
|
2
|
-
|
|
3
|
-
> **Status**: ANALYZED — no code changes applied (per user request).
|
|
4
|
-
> **Reporter**: sethmorton (external, opened 2026-06-05)
|
|
5
|
-
> **Affects**: pi-crew 0.6.0 / 0.6.1 (issue present in v0.6.1 too — not fixed in any post-v0.6.1 commit as of `e95e055`).
|
|
6
|
-
> **Severity**: **CRITICAL** — full-harness uncaughtException, can crash pi.
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## 1. Reporter's Claims — Verification Matrix
|
|
11
|
-
|
|
12
|
-
| Claim | Verified? | Evidence |
|
|
13
|
-
|---|---|---|
|
|
14
|
-
| `waitForRun()` hardcodes `.crew/state/runs/<runId>` at `run-tracker.ts:82` | ✅ YES | `src/runtime/run-tracker.ts:82` — `const runDir = path.join(cwd, ".crew", "state", "runs", runId);` |
|
|
15
|
-
| `projectCrewRoot()` correctly resolves to `.pi/teams/` for `.pi/`-only projects | ✅ YES | `src/utils/paths.ts:88-97` |
|
|
16
|
-
| The throw escapes as an unhandled promise rejection | ✅ PARTIAL | Both direct call sites (`team-tool.ts:817`, `team-tool/run.ts:211,344`) wrap in `try/catch`. **However**, the issue is real when `waitForRun` is called indirectly through `subagent-manager.ts`. |
|
|
17
|
-
| `subagent-manager.ts:250` re-throws via `record.promise` IIFE | ⚠️ LINE-DRIFT | Issue says `~line 250` — in current code (commit `e95e055`), `record.promise` IIFE starts at line 258 and the `throw error;` is at line 281. The mechanism is correct; line numbers drifted from prior code. |
|
|
18
|
-
|
|
19
|
-
## 2. Root Cause Analysis
|
|
20
|
-
|
|
21
|
-
### Why it crashes (in `.pi/`-only projects)
|
|
22
|
-
|
|
23
|
-
`projectCrewRoot(cwd)` (in `src/utils/paths.ts:88-97`) returns:
|
|
24
|
-
|
|
25
|
-
```
|
|
26
|
-
1. .crew/ (if exists)
|
|
27
|
-
2. .pi/teams/ (if .pi/ exists and .crew/ doesn't)
|
|
28
|
-
3. .crew/ (default, would be created by ensureCrewDirectory)
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
In a `.pi/`-based project **without** `.crew/`, run state lives at:
|
|
32
|
-
```
|
|
33
|
-
.pi/teams/state/runs/<runId>/
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
But `waitForRun()` (line 82) hardcodes:
|
|
37
|
-
```
|
|
38
|
-
.crew/state/runs/<runId>/
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
The early-exit check `fs.existsSync(runDir)` returns `false`, throwing:
|
|
42
|
-
```
|
|
43
|
-
Error: Run <runId> not found. No run directory at <cwd>/.crew/state/runs/<runId>
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### Why this becomes a `uncaughtException`
|
|
47
|
-
|
|
48
|
-
The throw in `waitForRun` propagates differently depending on caller:
|
|
49
|
-
|
|
50
|
-
| Caller | Wrapped in try/catch? | Result |
|
|
51
|
-
|---|---|---|
|
|
52
|
-
| `team-tool.ts:817` (wait action) | ✅ YES | Returns error to user — safe |
|
|
53
|
-
| `team-tool/run.ts:211` (async.run) | ✅ YES | Returns error to user — safe |
|
|
54
|
-
| `team-tool/run.ts:344` (foreground) | ✅ YES | Returns error to user — safe |
|
|
55
|
-
| **`subagent-manager.ts:270` (pollRunToTerminal)** | ⚠️ **NO** | `record.promise` rejects → line 281 `throw error` re-throws → if no caller awaits → **unhandled rejection** |
|
|
56
|
-
|
|
57
|
-
The `subagent-manager.ts` path is the actual crash site. Direct `waitForRun` calls in `team-tool.ts` are safe.
|
|
58
|
-
|
|
59
|
-
### Why the run "exists" in `.pi/teams/...`
|
|
60
|
-
|
|
61
|
-
The background worker process (`background-runner.ts`) correctly **reads/writes** to the right path **once it uses `projectCrewRoot()`** — but it does NOT. The same hardcoding is present in `background-runner.ts:139, 172`. So the **background worker itself is writing to `.crew/state/runs/...` (wrong path)**, while the **manifest claims it lives at `.pi/teams/state/runs/...`** (correct path).
|
|
62
|
-
|
|
63
|
-
Wait — let me re-verify this. The manifest is created by which process?
|
|
64
|
-
|
|
65
|
-
Actually, the **run manifest is created at the orchestrator** (using `projectCrewRoot`), and the **background worker reads/writes log/exit-code files using the same wrong path**. The manifest's `stateRoot` field is correct (`.pi/teams/...`), but the background worker writes its log to `<cwd>/.crew/state/runs/.../background.log`, which is the wrong path.
|
|
66
|
-
|
|
67
|
-
Result: the manifest correctly points to `.pi/teams/...` but the background worker logs/exit-codes go to `.crew/.../background.log`. The manifest loader (`loadRunManifestById` → `scopeBaseRoot` → `projectCrewRoot`) reads from the correct path. So if the manifest is created and persists, polling SHOULD work. The early-exit `fs.existsSync` check fires only on the very first poll iteration before any manifest has been written.
|
|
68
|
-
|
|
69
|
-
## 3. Affected Sites — Complete Inventory
|
|
70
|
-
|
|
71
|
-
Hardcoded `.crew/state/runs/...` paths that ignore `projectCrewRoot()`:
|
|
72
|
-
|
|
73
|
-
| File | Line | Code | Used for |
|
|
74
|
-
|---|---|---|---|
|
|
75
|
-
| `src/runtime/run-tracker.ts` | 82 | `path.join(cwd, ".crew", "state", "runs", runId)` | **CRASH SITE**: `waitForRun()` early-exit |
|
|
76
|
-
| `src/runtime/background-runner.ts` | 139 | `path.join(_cwd, ".crew/state/runs", _runId, "background.log")` | Background worker log redirect |
|
|
77
|
-
| `src/runtime/background-runner.ts` | 172 | `path.join(cwd, ".crew", "state", "runs", runId, "exit-code.txt")` | Exit code persistence |
|
|
78
|
-
| `src/runtime/skill-effectiveness.ts` | 115 | `join(process.cwd(), ".crew/state/runs/${runId}/skill-metrics.jsonl")` | Skill metrics storage |
|
|
79
|
-
| `src/runtime/skill-effectiveness.ts` | 125 | `join(process.cwd(), ".crew/state/runs/${runId}/skill-activations.jsonl")` | Skill activation storage |
|
|
80
|
-
| `src/runtime/checkpoint.ts` | 166 | `path.join(process.cwd(), ".crew/state/runs", runId)` | `saveCheckpoint` |
|
|
81
|
-
| `src/runtime/checkpoint.ts` | 177 | `path.join(process.cwd(), ".crew/state/runs", runId)` | `loadCheckpoint` |
|
|
82
|
-
| `src/runtime/checkpoint.ts` | 188 | `path.join(process.cwd(), ".crew/state/runs", runId)` | `clearCheckpoint` |
|
|
83
|
-
| `src/runtime/checkpoint.ts` | 199 | `path.join(process.cwd(), ".crew/state/runs", runId)` | `hasCheckpoint` |
|
|
84
|
-
| `src/runtime/checkpoint.ts` | 209 | `path.join(process.cwd(), ".crew/state/runs", runId)` | `listCheckpoints` |
|
|
85
|
-
| `src/state/decision-ledger.ts` | 29 | `stateRoot ?? \`.crew/state/runs/${runId}\`` | `getLedgerPath` fallback (always hit when called without `stateRoot`) |
|
|
86
|
-
|
|
87
|
-
**11 sites across 5 files** confirmed affected.
|
|
88
|
-
|
|
89
|
-
### Already correct (for reference)
|
|
90
|
-
|
|
91
|
-
| File | Line | Why correct |
|
|
92
|
-
|---|---|---|
|
|
93
|
-
| `src/state/crew-init.ts` | 209 | `safeJoin(crewRoot, "state", "runs")` — uses `crewRoot` parameter |
|
|
94
|
-
| `src/extension/team-tool.ts` | 1210 | `path.join(projectCrewRoot(ctx.cwd), "state", "runs", params.runId)` ✓ |
|
|
95
|
-
| `src/extension/team-onboard.ts` | 28 | `path.join(crewRoot, "state", "runs")` — uses parameter |
|
|
96
|
-
| `src/runtime/stale-reconciler.ts` | 389 | Inside `tmpDir` workspace scan — these are pi-crew's own zombie workspaces, not user `.pi/` projects, so this is acceptable (but inconsistent) |
|
|
97
|
-
|
|
98
|
-
## 4. Why the Bug Survives (it should have been caught)
|
|
99
|
-
|
|
100
|
-
- ✅ `loadRunManifestById` and `loadRunManifestByIdAsync` in `state-store.ts` correctly use `projectCrewRoot()` via `scopeBaseRoot` → `useProjectState`.
|
|
101
|
-
- ❌ `waitForRun()` and the 10 other sites above bypass the resolver and hardcode the path.
|
|
102
|
-
- The hardcoded path is **inconsistent** with the resolver — clearly a copy-paste/regression.
|
|
103
|
-
- The issue is **only triggered in `.pi/`-only projects** (no `.crew/`). Standard `.crew/` projects (the original pi-crew use case) never hit it.
|
|
104
|
-
|
|
105
|
-
## 5. Recommended Fix (NOT APPLIED per user request)
|
|
106
|
-
|
|
107
|
-
### Phase 1 — Use the resolver everywhere
|
|
108
|
-
|
|
109
|
-
Replace each hardcoded path with:
|
|
110
|
-
|
|
111
|
-
```ts
|
|
112
|
-
import { projectCrewRoot } from "../utils/paths.ts";
|
|
113
|
-
// ...
|
|
114
|
-
const stateRoot = path.join(projectCrewRoot(cwd), "state", "runs", runId);
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
For sites that take `process.cwd()`, switch to taking a `cwd` parameter (callers pass the real cwd). This is a small refactor for `skill-effectiveness.ts` and `checkpoint.ts` since their current API uses `process.cwd()`.
|
|
118
|
-
|
|
119
|
-
### Phase 2 — Defense in depth (the reporter's second suggestion)
|
|
120
|
-
|
|
121
|
-
The reporter's point about `subagent-manager.ts` is also valid: **a single run failure should never crash the harness**. The current pattern at line 281 `throw error; // H4: Propagate rejection` deliberately rejects the promise, but if no one awaits it, it becomes unhandled.
|
|
122
|
-
|
|
123
|
-
Two options:
|
|
124
|
-
|
|
125
|
-
**A) Add a safety net in `subagent-manager.ts` (recommended)**:
|
|
126
|
-
|
|
127
|
-
```ts
|
|
128
|
-
private start(record: SubagentRecord, ...) {
|
|
129
|
-
// ...
|
|
130
|
-
record.promise = (async () => { ... })();
|
|
131
|
-
// Defense in depth: a subagent failure should never crash pi.
|
|
132
|
-
// Attach a no-op catch so that even if no caller awaits, the rejection
|
|
133
|
-
// doesn't propagate to unhandledRejection → uncaughtException.
|
|
134
|
-
record.promise.catch((error) => {
|
|
135
|
-
logInternalError("subagent-manager.start.unhandled", error, `id=${record.id}`);
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
This protects the harness against **any** future rejection path, not just the one fixed in Phase 1.
|
|
141
|
-
|
|
142
|
-
**B) Remove the `throw error;` at line 281** — the record is already marked `error` status, the caller can read it. This is a deeper change to the API contract.
|
|
143
|
-
|
|
144
|
-
Option (A) is the smaller, safer change.
|
|
145
|
-
|
|
146
|
-
## 6. Test Coverage
|
|
147
|
-
|
|
148
|
-
Tests exist for `checkpoint` (`checkpoint.test.ts`, `checkpoint-cov.test.ts`) and `skill-effectiveness` (`skill-effectiveness.test.ts`) but they likely use a `.crew/`-based temp project, so they wouldn't catch this bug. A regression test should:
|
|
149
|
-
|
|
150
|
-
1. Create a temp project with `.pi/` (no `.crew/`)
|
|
151
|
-
2. Call each affected function (`waitForRun`, `saveCheckpoint`, `getSkillMetricsPath`, etc.)
|
|
152
|
-
3. Assert the result path is `.pi/teams/...` (not `.crew/...`)
|
|
153
|
-
|
|
154
|
-
For the `subagent-manager.ts` defense-in-depth: spawn a subagent whose `runner` rejects, assert pi does not exit and the record is marked `error`.
|
|
155
|
-
|
|
156
|
-
## 7. Impact Assessment
|
|
157
|
-
|
|
158
|
-
- **Blast radius**: All pi-crew users with `.pi/`-only projects.
|
|
159
|
-
- **Trigger frequency**: Low — requires the background worker to fail/die AND `waitForRun` to be called indirectly via `subagent-manager.ts`. The `team-tool` direct paths are safe.
|
|
160
|
-
- **Severity**: CRITICAL — full-harness crash with misleading "Run not found" error pointing at a path that, by design, should never exist.
|
|
161
|
-
|
|
162
|
-
## 8. Recommended PR Description (draft)
|
|
163
|
-
|
|
164
|
-
> **Title**: fix(issue #29): use projectCrewRoot() for run-state paths in all 11 affected sites
|
|
165
|
-
>
|
|
166
|
-
> **Body**:
|
|
167
|
-
>
|
|
168
|
-
> The `.pi/`-based project layout (`.pi/teams/`) is not handled by the 11 hardcoded `.crew/state/runs/...` sites listed in the analysis. The most severe site is `waitForRun()` in `src/runtime/run-tracker.ts:82`, which throws on a non-existent path and (via `subagent-manager.ts:281`) can escape as an unhandled rejection that crashes pi.
|
|
169
|
-
>
|
|
170
|
-
> Fix:
|
|
171
|
-
> 1. Replace all 11 hardcoded paths with `path.join(projectCrewRoot(cwd), "state", "runs", runId)`.
|
|
172
|
-
> 2. For sites that use `process.cwd()` (`skill-effectiveness.ts`, `checkpoint.ts`), switch to taking a `cwd` parameter.
|
|
173
|
-
> 3. Add `record.promise.catch(...)` in `subagent-manager.ts:start()` as defense in depth — a subagent failure should never crash the harness.
|
|
174
|
-
> 4. Add regression tests using a `.pi/`-only temp project.
|
|
175
|
-
>
|
|
176
|
-
> Closes #29.
|
|
177
|
-
|
|
178
|
-
---
|
|
179
|
-
|
|
180
|
-
## Status
|
|
181
|
-
|
|
182
|
-
- ✅ Issue reproduced in code (all 11 sites verified)
|
|
183
|
-
- ✅ Root cause identified
|
|
184
|
-
- ✅ Fix plan drafted
|
|
185
|
-
- ❌ **Code changes NOT applied** (per user request: "nothing has been changed yet")
|
|
186
|
-
- ❌ Tests NOT added
|
|
187
|
-
- ❌ v0.6.2 NOT released
|
|
188
|
-
|
|
189
|
-
Ready to apply when requested by the user.
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# Live Mailbox Runtime Direction
|
|
2
|
-
|
|
3
|
-
`pi-crew` currently uses workflow child-process orchestration: a run materializes tasks, executes them through the scheduler, writes artifacts/events, and optionally launches child Pi workers.
|
|
4
|
-
|
|
5
|
-
A full live mailbox runtime is intentionally out of scope for the current stable surface. Current foundational mailbox files are intentionally simple and local:
|
|
6
|
-
|
|
7
|
-
```text
|
|
8
|
-
{stateRoot}/mailbox/inbox.jsonl
|
|
9
|
-
{stateRoot}/mailbox/outbox.jsonl
|
|
10
|
-
{stateRoot}/mailbox/delivery.json
|
|
11
|
-
{stateRoot}/mailbox/tasks/{taskId}/inbox.jsonl
|
|
12
|
-
{stateRoot}/mailbox/tasks/{taskId}/outbox.jsonl
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
They are exposed through safe API operations (`read-mailbox`, `send-message`, `ack-message`, `read-delivery`, `validate-mailbox`) but do not yet imply always-on long-lived workers. If a full runtime is added later, it should build on the foundations already present:
|
|
16
|
-
|
|
17
|
-
- `src/state/contracts.ts` for status/event contracts
|
|
18
|
-
- `src/state/task-claims.ts` for claim/lease safety
|
|
19
|
-
- `src/runtime/worker-heartbeat.ts` for liveness
|
|
20
|
-
- `src/state/locks.ts` for run-level mutation safety
|
|
21
|
-
- `action: "api"` for safe interop boundaries
|
|
22
|
-
|
|
23
|
-
## Proposed phases
|
|
24
|
-
|
|
25
|
-
1. **Read-only interop** — already started with `api` operations.
|
|
26
|
-
2. **Heartbeat writers** — allow workers to update heartbeat/progress safely.
|
|
27
|
-
3. **Claim-safe task lifecycle** — expose claim/release/transition operations with tokens.
|
|
28
|
-
4. **Mailbox** — add worker inbox/leader inbox files and delivery state.
|
|
29
|
-
5. **Live workers** — only after the above contracts are stable.
|
|
30
|
-
|
|
31
|
-
## Non-goals for now
|
|
32
|
-
|
|
33
|
-
- No always-on background worker pool.
|
|
34
|
-
- No automatic destructive cleanup of dirty worktrees.
|
|
35
|
-
- No recursive team spawning by workers.
|
|
36
|
-
- No mailbox mutation without locks and schema validation.
|
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
# atomic-write-v2 migration plan
|
|
2
|
-
|
|
3
|
-
> **Note:** `atomic-write-v2.ts` was consolidated into `atomic-write.ts` as of v0.9.42. This document is preserved as historical record — the migration was completed with v1 winning on simplicity + symlink-safety + link+unlink atomicity. The v2 class was never adopted; no v2 API surface ships with pi-crew.
|
|
4
|
-
|
|
5
|
-
> Status: **PROPOSED** — decision RECOMMEND MIGRATE (staged, feature-flagged).
|
|
6
|
-
> Source: performance review `docs/perf/performance-review-2026-07.md` (findings F3–F6).
|
|
7
|
-
> Scope: replace the standalone-function module `src/state/atomic-write.ts`
|
|
8
|
-
> with the class-based `src/state/atomic-write-v2.ts` (`AtomicWriter`) over
|
|
9
|
-
> three staged phases behind a feature flag.
|
|
10
|
-
|
|
11
|
-
## Table of contents
|
|
12
|
-
|
|
13
|
-
- [1. Why migrate](#1-why-migrate)
|
|
14
|
-
- [2. API differences](#2-api-differences)
|
|
15
|
-
- [3. Migration phases](#3-migration-phases)
|
|
16
|
-
- [Phase 1 — dual-write (feature flag)](#phase-1--dual-write-feature-flag)
|
|
17
|
-
- [Phase 2 — switch default](#phase-2--switch-default)
|
|
18
|
-
- [Phase 3 — deprecate v1](#phase-3--deprecate-v1)
|
|
19
|
-
- [4. Risks and mitigations](#4-risks-and-mitigations)
|
|
20
|
-
- [5. Effort estimate](#5-effort-estimate)
|
|
21
|
-
- [6. Decision](#6-decision)
|
|
22
|
-
- [7. Appendix — call-site inventory](#7-appendix--call-site-inventory)
|
|
23
|
-
|
|
24
|
-
## 1. Why migrate
|
|
25
|
-
|
|
26
|
-
The performance review (F3, F4, F6) traced a write-path regression to commit
|
|
27
|
-
`13f4490`. That commit hardened `atomicWriteFile` against a CI-flake stale-read
|
|
28
|
-
race (the `mailbox-replay` intermittent failure) by adding **two** `fsync`
|
|
29
|
-
calls per synchronous write:
|
|
30
|
-
|
|
31
|
-
1. **Data fsync** — `fs.fsyncSync(fd)` on the temp file before rename
|
|
32
|
-
(`atomic-write.ts` ~line 287, in the `atomicWriteFile` write body). This
|
|
33
|
-
forces the written bytes out of the page cache to disk so a subsequent
|
|
34
|
-
`readFileSync` after the rename always sees the new content.
|
|
35
|
-
2. **Directory fsync** — `fs.fsyncSync(dirFd)` on the parent directory after
|
|
36
|
-
the rename (`atomic-write.ts` ~lines 307–309, POSIX-only, skipped on
|
|
37
|
-
Windows). This makes the directory-entry update (the rename) durable so a
|
|
38
|
-
subsequent `open()` cannot race and observe `ENOENT` or stale content on a
|
|
39
|
-
high-I/O CI runner.
|
|
40
|
-
|
|
41
|
-
The dir-fsync is the expensive half. `persistSingleTaskUpdate` calls the write
|
|
42
|
-
path ~5 times per task; at 2 fsync per call that is roughly **+10 fsync per
|
|
43
|
-
task**, and directory fsync is especially costly on Windows and on
|
|
44
|
-
network/overlay filesystems. The review also had to bump the CI timeout
|
|
45
|
-
600s → 900s (commit `9bbeb45`) partly to absorb this cost.
|
|
46
|
-
|
|
47
|
-
`atomic-write-v2.ts` (the `AtomicWriter` class) keeps only the **data fsync**,
|
|
48
|
-
and even that is **best-effort** — it is wrapped in a `try/catch` that swallows
|
|
49
|
-
the error (`atomic-write-v2.ts` ~line 30 in `writeSync`, and `fd.sync()` in
|
|
50
|
-
`writeAsync`). It performs **no directory fsync at all**.
|
|
51
|
-
|
|
52
|
-
### Quantified difference
|
|
53
|
-
|
|
54
|
-
| Cost per write | atomic-write.ts (v1) | atomic-write-v2.ts (v2) |
|
|
55
|
-
| ---------------------- | ------------------------------------- | ------------------------------- |
|
|
56
|
-
| Data fsync | 1 (mandatory, throws on failure) | 1 (best-effort, swallowed) |
|
|
57
|
-
| Directory fsync | 1 (POSIX only) | 0 |
|
|
58
|
-
| `isSymlinkSafePath` | 2 full ancestor walks (pre + pre-rename) | 0 |
|
|
59
|
-
| `lstat` syscalls | ~10+ per level × 2 for a deep path | 0 |
|
|
60
|
-
| Rename mechanism | `link()` + `unlink()` (+ retry/jitter) | `rename()` (single syscall) |
|
|
61
|
-
|
|
62
|
-
The headline is roughly **2× fewer fsync operations per call** (drop the dir
|
|
63
|
-
fsync, keep data fsync), plus the elimination of two full ancestor-walk
|
|
64
|
-
symlink scans (F5) and the `link()`+`unlink()` pair in favor of a single
|
|
65
|
-
`rename()`. On a deep state-store path (`.crew/state/runs/{runId}/…`) the v1
|
|
66
|
-
path issues ~20+ `lstat` calls per write for symlink validation alone; v2
|
|
67
|
-
issues none. The net expected win on the hot `persistSingleTaskUpdate` path is
|
|
68
|
-
approximately halving the per-call durability cost, with a larger relative win
|
|
69
|
-
on syscall count.
|
|
70
|
-
|
|
71
|
-
The trade-off is explicit: **v2 loses the dir-fsync durability guarantee.** On
|
|
72
|
-
journaled Linux filesystems (ext4 with `data=ordered`, xfs) the rename is still
|
|
73
|
-
crash-atomic, but a power loss in the sub-millisecond window between write and
|
|
74
|
-
directory-entry flush can leave the *old* content visible after reboot. On
|
|
75
|
-
tmpfs this window is effectively the whole lifetime of the entry (no
|
|
76
|
-
durability at all). This is the guarantee the `13f4490` commit was added to
|
|
77
|
-
provide, so dropping it must be a conscious, documented decision (see
|
|
78
|
-
[risks](#4-risks-and-mitigations)).
|
|
79
|
-
|
|
80
|
-
## 2. API differences
|
|
81
|
-
|
|
82
|
-
The two modules are shaped very differently, so migration is not a
|
|
83
|
-
drop-in symbol rename — callers change from free functions to a constructed
|
|
84
|
-
instance.
|
|
85
|
-
|
|
86
|
-
### v1 — `atomic-write.ts` (module of standalone functions)
|
|
87
|
-
|
|
88
|
-
- `atomicWriteFile(filePath, content, expectedHash?)`
|
|
89
|
-
- `atomicWriteFileAsync(filePath, content)`
|
|
90
|
-
- `atomicWriteJson(filePath, value)`
|
|
91
|
-
- `atomicWriteJsonAsync(filePath, value)`
|
|
92
|
-
- `atomicWriteJsonCoalesced(filePath, value, coalesceMs?)` — 50 ms coalescing buffer
|
|
93
|
-
- `flushPendingAtomicWrites()` — flush the coalesce buffer
|
|
94
|
-
- `isSymlinkSafePath(filePath)` — exported symlink-safety guard
|
|
95
|
-
- `renameWithRetry(...)` / `renameWithRetryAsync(...)` — exported rename helpers with jitter
|
|
96
|
-
- `readJsonFile(filePath)` — tolerant JSON reader
|
|
97
|
-
|
|
98
|
-
Behavioral characteristics:
|
|
99
|
-
|
|
100
|
-
- **Symlink safety**: explicit `isSymlinkSafePath` check both **before open**
|
|
101
|
-
and **again immediately before rename** (TOCTOU re-check), plus a
|
|
102
|
-
post-rename `lstat` guard on failure.
|
|
103
|
-
- **Rename**: `link()` + `unlink()` (`renameWithLinkSync` /
|
|
104
|
-
`renameWithLinkAsync`) so the destination symlink is *not* followed; Windows
|
|
105
|
-
falls back to `renameSync`/`MoveFileEx`. Retries with exponential backoff and
|
|
106
|
-
±20% jitter.
|
|
107
|
-
- **Durability**: mandatory data fsync (throws on failure) + POSIX directory
|
|
108
|
-
fsync.
|
|
109
|
-
- **Tmp naming**: `${filePath}.${randomUUID()}.tmp`.
|
|
110
|
-
- **Coalescing**: a per-path buffer with generation counters, retry/backoff,
|
|
111
|
-
and process `exit`/`SIGTERM`/`SIGINT` auto-flush hooks.
|
|
112
|
-
- **Optional worker offload**: `atomicWriteFileAsync` can dispatch to a worker
|
|
113
|
-
thread when `PI_CREW_WORKER_ATOMIC_WRITER=1`.
|
|
114
|
-
|
|
115
|
-
### v2 — `atomic-write-v2.ts` (`AtomicWriter` class)
|
|
116
|
-
|
|
117
|
-
- `new AtomicWriter(baseDir)` — constructed with a base directory
|
|
118
|
-
- `writeSync(targetPath, content)`
|
|
119
|
-
- `writeAsync(targetPath, content)`
|
|
120
|
-
- `writeJsonSync(targetPath, value)`
|
|
121
|
-
- `writeJsonAsync(targetPath, value)`
|
|
122
|
-
- private `.gitignore`-on-first-use per directory (writes `*\n` the first time
|
|
123
|
-
a directory is touched)
|
|
124
|
-
|
|
125
|
-
Behavioral characteristics:
|
|
126
|
-
|
|
127
|
-
- **Symlink safety**: **none** — no `isSymlinkSafePath`, no pre/post checks.
|
|
128
|
-
- **Rename**: plain `rename()` (POSIX-atomic but **symlink-following**), single
|
|
129
|
-
syscall, no retry/jitter loop.
|
|
130
|
-
- **Durability**: best-effort data fsync (swallowed), **no directory fsync**.
|
|
131
|
-
- **Tmp naming**: `${targetPath}.${randomUUID()}.tmp` (same scheme as v1).
|
|
132
|
-
- **Coalescing**: none (no buffer, no flush hooks).
|
|
133
|
-
- **Reader**: none (no `readJsonFile` equivalent).
|
|
134
|
-
|
|
135
|
-
### Feature-gap summary (what v2 does NOT have yet)
|
|
136
|
-
|
|
137
|
-
| Capability | v1 | v2 | Notes |
|
|
138
|
-
| ---------------------------------- | --- | --- | -------------------------------------------------- |
|
|
139
|
-
| Symlink-safe rename | ✅ | ❌ | v2 uses `rename()` which follows symlinks |
|
|
140
|
-
| `isSymlinkSafePath` export | ✅ | ❌ | consumed elsewhere — must stay available |
|
|
141
|
-
| Coalesced writes + flush hooks | ✅ | ❌ | required by `saveRunTasksCoalesced` path (F4) |
|
|
142
|
-
| `readJsonFile` | ✅ | ❌ | tolerant reader used across state-store |
|
|
143
|
-
| Retry/backoff on contended rename | ✅ | ❌ | v2 throws on first `rename()` failure |
|
|
144
|
-
| Windows short/long-name handling | ✅ | ❌ | v1 has explicit `MoveFileEx` fallback |
|
|
145
|
-
| Directory fsync | ✅ | ❌ | the durability guarantee being intentionally dropped |
|
|
146
|
-
| `.gitignore` on first use | ❌ | ✅ | v2 convenience; v1 leaves this to callers |
|
|
147
|
-
|
|
148
|
-
**Implication:** a straight swap is not viable until v2 grows (or the
|
|
149
|
-
dispatcher re-provides) the coalescing buffer, the tolerant reader, the retry
|
|
150
|
-
loop, and an opt-in symlink guard. The phased plan below keeps v1 as the source
|
|
151
|
-
of those capabilities during transition rather than porting them all up front.
|
|
152
|
-
|
|
153
|
-
## 3. Migration phases
|
|
154
|
-
|
|
155
|
-
### Phase 1 — dual-write (feature flag)
|
|
156
|
-
|
|
157
|
-
Estimated ~1–2 days.
|
|
158
|
-
|
|
159
|
-
- Introduce an environment feature flag `PI_CREW_ATOMIC_WRITER` with values
|
|
160
|
-
`v1` (default) and `v2`.
|
|
161
|
-
- Add a thin adapter module `src/state/atomic-write-dispatcher.ts` that exposes
|
|
162
|
-
the v1 free-function surface (`atomicWriteFile`, `atomicWriteJson`, and their
|
|
163
|
-
async variants) and routes each call to either the v1 functions or a shared
|
|
164
|
-
`AtomicWriter` instance based on the flag. Capabilities v2 lacks
|
|
165
|
-
(`atomicWriteJsonCoalesced`, `flushPendingAtomicWrites`, `isSymlinkSafePath`,
|
|
166
|
-
`readJsonFile`) continue to delegate to v1 unconditionally in this phase.
|
|
167
|
-
- Keep `atomic-write.ts` as the default; nothing changes for users who do not
|
|
168
|
-
set the flag.
|
|
169
|
-
- Add a benchmark test that writes N files through both paths under **tmpfs**
|
|
170
|
-
and **ext4** and asserts the fsync-count / wall-clock delta matches the
|
|
171
|
-
~2× prediction. Land it under `test/bench/` (guarded so it does not run in
|
|
172
|
-
the default `test:unit` gate).
|
|
173
|
-
|
|
174
|
-
Exit criteria: flag flips implementation with zero behavior change for default
|
|
175
|
-
users; benchmark confirms the predicted delta.
|
|
176
|
-
|
|
177
|
-
### Phase 2 — switch default
|
|
178
|
-
|
|
179
|
-
Estimated ~1–2 days.
|
|
180
|
-
|
|
181
|
-
- Flip the dispatcher default to `v2`; users can opt back to the old path with
|
|
182
|
-
`PI_CREW_ATOMIC_WRITER=v1`.
|
|
183
|
-
- Route direct callers of `atomicWriteFile` / `atomicWriteJson` (in
|
|
184
|
-
`extension/team-tool.ts`, `state-store.ts`, and any other direct importers)
|
|
185
|
-
through the dispatcher rather than importing `atomic-write.ts` directly.
|
|
186
|
-
- Before flipping, back-fill v2 (or the dispatcher wrapper around v2) with the
|
|
187
|
-
currently-missing durability/safety features that production relies on:
|
|
188
|
-
retry-on-contended-rename, an **opt-in** symlink guard for
|
|
189
|
-
`userPiRoot()`-adjacent writes, and either the coalescing buffer or continued
|
|
190
|
-
delegation to v1 for the coalesced path.
|
|
191
|
-
- Monitor for one full release cycle. Watch for stale-read CI flakes (the exact
|
|
192
|
-
failure `13f4490` fixed) — if they resurface, the dir-fsync drop is the prime
|
|
193
|
-
suspect and the flag provides an instant rollback.
|
|
194
|
-
|
|
195
|
-
Exit criteria: one clean release cycle on the v2 default with no stale-read or
|
|
196
|
-
symlink regressions reported.
|
|
197
|
-
|
|
198
|
-
### Phase 3 — deprecate v1
|
|
199
|
-
|
|
200
|
-
Estimated ~1 day.
|
|
201
|
-
|
|
202
|
-
- Remove `atomic-write.ts` and the `v1` flag branch (keep any still-needed
|
|
203
|
-
utilities — notably the symlink-safe `link()`+`unlink()` helper and
|
|
204
|
-
`isSymlinkSafePath` — either in the renamed module or a small
|
|
205
|
-
`symlink-safety.ts`).
|
|
206
|
-
- Rename `atomic-write-v2.ts` → `atomic-write.ts` and update imports.
|
|
207
|
-
- Add a `CHANGELOG.md` entry under a **minor** version bump documenting the
|
|
208
|
-
durability trade-off (no directory fsync by default) and the
|
|
209
|
-
`PI_CREW_ATOMIC_WRITER` flag removal.
|
|
210
|
-
|
|
211
|
-
Exit criteria: single implementation, no flag, green CI, CHANGELOG documents
|
|
212
|
-
the durability change.
|
|
213
|
-
|
|
214
|
-
## 4. Risks and mitigations
|
|
215
|
-
|
|
216
|
-
### Drop of strict symlink safety (security)
|
|
217
|
-
|
|
218
|
-
v2 performs **no** `isSymlinkSafePath` check and uses `rename()`, which follows
|
|
219
|
-
a symlink at the destination. An attacker who can plant a symlink inside
|
|
220
|
-
`userPiRoot()` (or an ancestor of a write target) could redirect a write to an
|
|
221
|
-
arbitrary path.
|
|
222
|
-
|
|
223
|
-
Mitigations:
|
|
224
|
-
|
|
225
|
-
1. v2 callers must pre-validate every target path via the `paths.ts` helpers so
|
|
226
|
-
writes are confined to the user's own pi-crew state tree.
|
|
227
|
-
2. Keep the v1 `link()`+`unlink()` rename helper and `isSymlinkSafePath` as
|
|
228
|
-
reusable utilities even after the module rename, and offer them as an opt-in
|
|
229
|
-
"safe rename" mode in the dispatcher for `userPiRoot()`-adjacent writes.
|
|
230
|
-
3. Add a CI test that plants a symlink inside the `.pi/agent/pi-crew/` tree and
|
|
231
|
-
asserts the writer refuses (or does not follow) it.
|
|
232
|
-
|
|
233
|
-
### Lockfile / tmp collision risk
|
|
234
|
-
|
|
235
|
-
Both implementations name temp files `${target}.${randomUUID()}.tmp`. UUIDv4
|
|
236
|
-
collision probability is astronomically low (documented here for completeness).
|
|
237
|
-
The larger concern is the inode-scan cost of many `.tmp` siblings in a large
|
|
238
|
-
directory. Recommend writing tmp files into a per-process subdir
|
|
239
|
-
(`<baseDir>/.tmp/<pid>/`) to bound directory size and simplify crash cleanup.
|
|
240
|
-
|
|
241
|
-
### Crash-durability regression
|
|
242
|
-
|
|
243
|
-
v2's missing directory fsync means a power loss in the window between the data
|
|
244
|
-
write and the directory-entry flush can leave the **old** content visible after
|
|
245
|
-
reboot. This is rare on journaled filesystems (ext4/xfs) and common on tmpfs.
|
|
246
|
-
|
|
247
|
-
Mitigations:
|
|
248
|
-
|
|
249
|
-
1. Document the trade-off in the v2 module docblock and in `CHANGELOG.md`.
|
|
250
|
-
2. Keep the flag so at-risk deployments (non-journaled FS, tmpfs-backed state)
|
|
251
|
-
can pin `v1`.
|
|
252
|
-
3. Optionally expose a per-call `durable: true` option in the dispatcher that
|
|
253
|
-
re-enables the directory fsync for the small set of writes that truly need
|
|
254
|
-
it (e.g. terminal manifest writes), so the common path stays fast while the
|
|
255
|
-
critical path stays durable.
|
|
256
|
-
|
|
257
|
-
## 5. Effort estimate
|
|
258
|
-
|
|
259
|
-
**Size: M (3–5 days.)**
|
|
260
|
-
|
|
261
|
-
| Work item | Estimate |
|
|
262
|
-
| ------------------------------------------ | -------- |
|
|
263
|
-
| Phase 1 — flag + dispatcher + benchmark | ~1–2 days |
|
|
264
|
-
| Phase 2 — feature back-fill + switch + soak | ~1–2 days |
|
|
265
|
-
| Phase 3 — deprecate + rename + CHANGELOG | ~1 day |
|
|
266
|
-
| Benchmark harness (tmpfs + ext4) | ~0.5 day |
|
|
267
|
-
| Docs / review pass | ~0.5 day |
|
|
268
|
-
|
|
269
|
-
## 6. Decision
|
|
270
|
-
|
|
271
|
-
**RECOMMEND MIGRATE** — staged, feature-flagged.
|
|
272
|
-
|
|
273
|
-
Justification:
|
|
274
|
-
|
|
275
|
-
- The write path is hot: `persistSingleTaskUpdate` calls it ~5×/task and the
|
|
276
|
-
state-store fires on the same 1 Hz idle / 6 Hz active cadence as
|
|
277
|
-
`loadConfig`. Halving the per-call durability cost (drop dir fsync, keep data
|
|
278
|
-
fsync) plus eliminating the double ancestor-walk symlink scan is a meaningful
|
|
279
|
-
and broadly-applied win.
|
|
280
|
-
- The durability risk from dropping the directory fsync is bounded: it only
|
|
281
|
-
matters on non-journaled/tmpfs filesystems and only within the sub-millisecond
|
|
282
|
-
on-disk write window. The `PI_CREW_ATOMIC_WRITER=v1` fallback lets at-risk
|
|
283
|
-
setups opt out.
|
|
284
|
-
- The symlink-safety regression is the sharpest edge and is mitigated by
|
|
285
|
-
`paths.ts` pre-validation, an opt-in safe-rename mode, and a CI symlink-plant
|
|
286
|
-
test — not by accepting v2 as-is.
|
|
287
|
-
|
|
288
|
-
Because the plan is staged behind a flag with an instant rollback, the blast
|
|
289
|
-
radius at each step is small and the exact CI flake that `13f4490` fixed remains
|
|
290
|
-
observable (and reversible) during the Phase 2 soak.
|
|
291
|
-
|
|
292
|
-
## 7. Appendix — call-site inventory
|
|
293
|
-
|
|
294
|
-
Before Phase 2, enumerate the direct importers to route through the dispatcher.
|
|
295
|
-
As of this plan, `atomic-write-v2.ts` has **0 importers** (confirmed by
|
|
296
|
-
`grep -rn "atomic-write-v2" src/`). The v1 surface is consumed by
|
|
297
|
-
`state-store.ts`, `extension/team-tool.ts`, and the coalesced/reader paths;
|
|
298
|
-
run `grep -rn "atomic-write\b" src/` at the start of Phase 2 to produce the
|
|
299
|
-
authoritative list, since call sites shift between now and then.
|