pi-crew 0.9.16 → 0.9.17
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 +81 -0
- package/README.md +19 -0
- package/dist/build-meta.json +21790 -0
- package/dist/index.mjs +83070 -0
- package/dist/index.mjs.map +7 -0
- package/docs/A +358 -0
- package/docs/M-A +357 -0
- package/docs/REVIEW-FINDINGS-2026-06 +357 -0
- package/docs/Y +357 -0
- package/docs/a +357 -0
- package/docs/aA +358 -0
- package/docs/archive/README.md +91 -0
- package/docs/patterns/command-agent-skill.md +1 -1
- package/docs/skills/REFERENCE.md +0 -17
- package/docs//303/242mmaAAA/303/242 +357 -0
- package/index.bundle.ts +25 -0
- package/index.ts +95 -4
- package/package.json +15 -4
- package/skills/iterative-audit/SKILL.md +0 -1
- package/skills/widget-rendering/SKILL.md +17 -0
- package/src/adapters/claude-adapter.ts +1 -3
- package/src/adapters/export-util.ts +16 -16
- package/src/adapters/index.ts +5 -5
- package/src/agents/agent-config.ts +20 -14
- package/src/agents/agent-serializer.ts +1 -1
- package/src/agents/discover-agents.ts +83 -39
- package/src/benchmark/benchmark-runner.ts +51 -51
- package/src/benchmark/feedback-loop.ts +1 -1
- package/src/config/config.ts +166 -590
- package/src/config/defaults.ts +28 -2
- package/src/config/drift-detector.ts +11 -14
- package/src/config/markers.ts +201 -203
- package/src/config/resilient-parser.ts +14 -6
- package/src/config/role-tools.ts +3 -3
- package/src/config/suggestions.ts +5 -12
- package/src/config/types.ts +9 -25
- package/src/errors.ts +151 -157
- package/src/extension/action-suggestions.ts +54 -9
- package/src/extension/async-notifier.ts +43 -13
- package/src/extension/autonomous-policy.ts +77 -37
- package/src/extension/command-completions.ts +9 -8
- package/src/extension/context-status-injection.ts +14 -12
- package/src/extension/crew-autocomplete.ts +8 -16
- package/src/extension/crew-cleanup.ts +2 -1
- package/src/extension/crew-shortcuts.ts +9 -6
- package/src/extension/cross-extension-rpc.ts +136 -42
- package/src/extension/help.ts +1 -1
- package/src/extension/import-index.ts +10 -5
- package/src/extension/knowledge-injection.ts +88 -15
- package/src/extension/management.ts +89 -349
- package/src/extension/message-renderers.ts +3 -4
- package/src/extension/notification-router.ts +22 -5
- package/src/extension/notification-sink.ts +6 -3
- package/src/extension/pi-api.ts +17 -8
- package/src/extension/plan-orchestrate.ts +8 -27
- package/src/extension/project-init.ts +21 -6
- package/src/extension/register.ts +329 -975
- package/src/extension/registration/artifact-cleanup.ts +9 -4
- package/src/extension/registration/command-utils.ts +5 -1
- package/src/extension/registration/commands.ts +806 -314
- package/src/extension/registration/compaction-guard.ts +15 -15
- package/src/extension/registration/lifecycle.ts +259 -0
- package/src/extension/registration/observability.ts +293 -0
- package/src/extension/registration/subagent-helpers.ts +29 -7
- package/src/extension/registration/subagent-tools.ts +253 -44
- package/src/extension/registration/team-tool.ts +19 -84
- package/src/extension/registration/ui.ts +168 -0
- package/src/extension/registration/viewers.ts +64 -24
- package/src/extension/result-watcher.ts +18 -7
- package/src/extension/run-bundle-schema.ts +21 -6
- package/src/extension/run-export.ts +15 -6
- package/src/extension/run-import.ts +64 -29
- package/src/extension/run-index.ts +28 -9
- package/src/extension/run-maintenance.ts +32 -12
- package/src/extension/session-summary.ts +1 -1
- package/src/extension/team-manager-command.ts +64 -7
- package/src/extension/team-onboard.ts +151 -150
- package/src/extension/team-recommendation.ts +121 -21
- package/src/extension/team-tool/anchor.ts +31 -64
- package/src/extension/team-tool/api.ts +929 -141
- package/src/extension/team-tool/auto-summarize.ts +14 -26
- package/src/extension/team-tool/cache-control.ts +1 -5
- package/src/extension/team-tool/cancel.ts +138 -38
- package/src/extension/team-tool/chain-dispatch.ts +5 -13
- package/src/extension/team-tool/chain-executor.ts +29 -51
- package/src/extension/team-tool/config-patch.ts +1 -1
- package/src/extension/team-tool/context.ts +40 -20
- package/src/extension/team-tool/destructive-gate.ts +10 -5
- package/src/extension/team-tool/doctor.ts +170 -51
- package/src/extension/team-tool/explain.ts +228 -214
- package/src/extension/team-tool/failure-patterns.ts +3 -9
- package/src/extension/team-tool/goal-wrap.ts +71 -29
- package/src/extension/team-tool/goal.ts +185 -35
- package/src/extension/team-tool/handle-schedule.ts +34 -15
- package/src/extension/team-tool/handle-settings.ts +94 -56
- package/src/extension/team-tool/health-monitor.ts +27 -108
- package/src/extension/team-tool/inspect.ts +42 -9
- package/src/extension/team-tool/intent-policy.ts +4 -1
- package/src/extension/team-tool/lifecycle-actions.ts +244 -48
- package/src/extension/team-tool/orchestrate.ts +7 -18
- package/src/extension/team-tool/parallel-dispatch.ts +51 -29
- package/src/extension/team-tool/plan.ts +29 -5
- package/src/extension/team-tool/respond.ts +49 -16
- package/src/extension/team-tool/run-not-found.ts +3 -8
- package/src/extension/team-tool/run.ts +80 -317
- package/src/extension/team-tool/status.ts +135 -43
- package/src/extension/team-tool/workflow-manage.ts +92 -25
- package/src/extension/team-tool-types.ts +8 -1
- package/src/extension/team-tool.ts +142 -551
- package/src/extension/validate-resources.ts +39 -8
- package/src/hooks/registry.ts +66 -17
- package/src/hooks/types.ts +1 -1
- package/src/i18n.ts +25 -11
- package/src/observability/correlation.ts +17 -3
- package/src/observability/event-bus.ts +51 -56
- package/src/observability/event-to-metric.ts +117 -15
- package/src/observability/exporters/otlp-exporter.ts +56 -17
- package/src/observability/exporters/prometheus-exporter.ts +1 -1
- package/src/observability/metric-registry.ts +16 -4
- package/src/observability/metric-retention.ts +8 -2
- package/src/observability/metric-sink.ts +11 -3
- package/src/observability/metrics-primitives.ts +42 -9
- package/src/plugins/plugin-define.ts +2 -2
- package/src/plugins/plugin-registry.ts +25 -25
- package/src/plugins/plugins/index.ts +1 -1
- package/src/plugins/plugins/nextjs.ts +16 -16
- package/src/plugins/plugins/vite.ts +7 -11
- package/src/plugins/plugins/vitest.ts +6 -11
- package/src/runtime/adaptive-plan.ts +225 -40
- package/src/runtime/agent-control.ts +58 -15
- package/src/runtime/agent-memory.ts +15 -9
- package/src/runtime/agent-observability.ts +10 -2
- package/src/runtime/anchor-manager.ts +27 -25
- package/src/runtime/async-marker.ts +7 -1
- package/src/runtime/async-runner.ts +27 -23
- package/src/runtime/auto-summarize.ts +7 -13
- package/src/runtime/background-runner.ts +189 -251
- package/src/runtime/batch-barrier.ts +18 -16
- package/src/runtime/cancellation-token.ts +16 -6
- package/src/runtime/cancellation.ts +46 -8
- package/src/runtime/capability-inventory.ts +6 -4
- package/src/runtime/chain-parser.ts +44 -11
- package/src/runtime/chain-runner.ts +63 -69
- package/src/runtime/checkpoint.ts +12 -56
- package/src/runtime/child-pi.ts +343 -78
- package/src/runtime/coalesce-tasks.ts +268 -0
- package/src/runtime/code-summary.ts +71 -26
- package/src/runtime/compact-stages/index.ts +15 -5
- package/src/runtime/compact-stages/tail-capture-stage.ts +7 -2
- package/src/runtime/compact-stages/truncation-stage.ts +4 -1
- package/src/runtime/compaction-summary.ts +17 -10
- package/src/runtime/completion-guard.ts +33 -16
- package/src/runtime/crash-classification.ts +28 -7
- package/src/runtime/crash-recovery.ts +177 -37
- package/src/runtime/crew-agent-records.ts +145 -47
- package/src/runtime/crew-hooks.ts +9 -24
- package/src/runtime/cross-extension-rpc.ts +25 -23
- package/src/runtime/custom-tools/irc-tool.ts +43 -15
- package/src/runtime/custom-tools/submit-result-tool.ts +16 -5
- package/src/runtime/delivery-coordinator.ts +34 -7
- package/src/runtime/delta-conflict.ts +9 -21
- package/src/runtime/deterministic-ast.ts +1 -1
- package/src/runtime/diagnostic-export.ts +53 -20
- package/src/runtime/direct-run.ts +12 -2
- package/src/runtime/dwf-state-store.ts +1 -1
- package/src/runtime/dynamic-workflow-context.ts +186 -58
- package/src/runtime/dynamic-workflow-runner.ts +42 -20
- package/src/runtime/effectiveness.ts +16 -8
- package/src/runtime/errors/crew-errors.ts +7 -11
- package/src/runtime/event-stream-bridge.ts +9 -3
- package/src/runtime/foreground-control.ts +54 -14
- package/src/runtime/foreground-watchdog.ts +9 -6
- package/src/runtime/goal-achievement.ts +27 -10
- package/src/runtime/goal-evaluator.ts +54 -19
- package/src/runtime/goal-loop-runner.ts +280 -99
- package/src/runtime/goal-state-store.ts +27 -17
- package/src/runtime/green-contract.ts +11 -2
- package/src/runtime/group-join.ts +64 -31
- package/src/runtime/handoff-manager.ts +37 -42
- package/src/runtime/heartbeat-gradient.ts +10 -2
- package/src/runtime/heartbeat-watcher.ts +32 -6
- package/src/runtime/hidden-handoff.ts +12 -30
- package/src/runtime/important-line-classifier.ts +12 -2
- package/src/runtime/iteration-hooks.ts +25 -15
- package/src/runtime/live-agent-control.ts +55 -7
- package/src/runtime/live-agent-manager.ts +130 -27
- package/src/runtime/live-control-realtime.ts +23 -3
- package/src/runtime/live-irc.ts +4 -1
- package/src/runtime/live-session-health.ts +12 -4
- package/src/runtime/live-session-runtime.ts +379 -117
- package/src/runtime/manifest-cache.ts +28 -12
- package/src/runtime/mcp-proxy.ts +8 -16
- package/src/runtime/metric-parser.ts +1 -5
- package/src/runtime/model-fallback.ts +55 -18
- package/src/runtime/model-resolver.ts +2 -6
- package/src/runtime/model-scope.ts +19 -3
- package/src/runtime/notebook-helpers.ts +60 -62
- package/src/runtime/orphan-worker-registry.ts +37 -26
- package/src/runtime/output-validator.ts +18 -3
- package/src/runtime/overflow-recovery.ts +5 -4
- package/src/runtime/parallel-research.ts +29 -5
- package/src/runtime/parallel-utils.ts +9 -11
- package/src/runtime/path-overlap.ts +150 -0
- package/src/runtime/peer-dep.ts +12 -17
- package/src/runtime/per-write-validator.ts +1 -3
- package/src/runtime/phase-tracker.ts +342 -330
- package/src/runtime/pi-args.ts +26 -8
- package/src/runtime/pi-json-output.ts +1 -1
- package/src/runtime/pi-spawn.ts +30 -19
- package/src/runtime/pipeline-runner.ts +56 -55
- package/src/runtime/plan-templates.ts +5 -6
- package/src/runtime/policy-engine.ts +43 -7
- package/src/runtime/post-checks.ts +12 -4
- package/src/runtime/post-exit-stdio-guard.ts +2 -2
- package/src/runtime/process-lifecycle.ts +20 -10
- package/src/runtime/process-status.ts +16 -5
- package/src/runtime/progress-event-coalescer.ts +2 -1
- package/src/runtime/progress-tracker.ts +103 -103
- package/src/runtime/prose-compressor.ts +9 -11
- package/src/runtime/recovery-recipes.ts +118 -24
- package/src/runtime/replace.ts +25 -10
- package/src/runtime/resilient-edit.ts +10 -25
- package/src/runtime/result-extractor.ts +1 -2
- package/src/runtime/retry-executor.ts +20 -4
- package/src/runtime/retry-runner.ts +26 -50
- package/src/runtime/role-permission.ts +6 -1
- package/src/runtime/run-coalesced-task-group.ts +256 -0
- package/src/runtime/run-drift.ts +14 -15
- package/src/runtime/run-tracker.ts +6 -28
- package/src/runtime/runtime-policy.ts +1 -6
- package/src/runtime/runtime-resolver.ts +80 -15
- package/src/runtime/scheduler.ts +47 -18
- package/src/runtime/semaphore.ts +5 -7
- package/src/runtime/sensitive-paths.ts +2 -1
- package/src/runtime/session-usage.ts +1 -1
- package/src/runtime/settings-store.ts +16 -12
- package/src/runtime/sidechain-output.ts +6 -2
- package/src/runtime/single-agent-compose.ts +1 -4
- package/src/runtime/skill-effectiveness.ts +29 -97
- package/src/runtime/skill-instructions.ts +40 -83
- package/src/runtime/stale-reconciler.ts +73 -197
- package/src/runtime/stream-preview.ts +1 -1
- package/src/runtime/streaming-output.ts +1 -1
- package/src/runtime/subagent-manager.ts +44 -169
- package/src/runtime/subprocess-tool-registry.ts +4 -1
- package/src/runtime/supervisor-contact.ts +10 -5
- package/src/runtime/task-display.ts +19 -5
- package/src/runtime/task-graph-scheduler.ts +95 -21
- package/src/runtime/task-graph.ts +5 -11
- package/src/runtime/task-health.ts +54 -47
- package/src/runtime/task-id.ts +11 -18
- package/src/runtime/task-output-context.ts +265 -81
- package/src/runtime/task-packet.ts +12 -20
- package/src/runtime/task-quality.ts +6 -14
- package/src/runtime/task-runner/context-retrieval.ts +4 -13
- package/src/runtime/task-runner/live-executor.ts +114 -36
- package/src/runtime/task-runner/output-splitter.ts +152 -0
- package/src/runtime/task-runner/progress.ts +50 -12
- package/src/runtime/task-runner/prompt-builder.ts +31 -7
- package/src/runtime/task-runner/prompt-pipeline.ts +31 -7
- package/src/runtime/task-runner/result-utils.ts +3 -1
- package/src/runtime/task-runner/retrieval-orchestrator.ts +310 -0
- package/src/runtime/task-runner/run-projection.ts +27 -8
- package/src/runtime/task-runner/state-helpers.ts +29 -8
- package/src/runtime/task-runner/tail-read.ts +2 -6
- package/src/runtime/task-runner.ts +180 -326
- package/src/runtime/team-runner-artifacts.ts +13 -0
- package/src/runtime/team-runner.ts +456 -974
- package/src/runtime/tool-output-pruner.ts +6 -9
- package/src/runtime/tool-progress.ts +11 -21
- package/src/runtime/verification-gates.ts +33 -24
- package/src/runtime/verification-integrity.ts +1 -4
- package/src/runtime/verification-worktree.ts +62 -12
- package/src/runtime/worker-heartbeat.ts +5 -1
- package/src/runtime/worker-startup.ts +29 -5
- package/src/runtime/workflow-state.ts +17 -9
- package/src/runtime/workspace-lock.ts +30 -35
- package/src/runtime/workspace-tree.ts +20 -32
- package/src/runtime/yield-handler.ts +43 -9
- package/src/runtime/zombie-scanner.ts +5 -4
- package/src/schema/config-schema.ts +266 -172
- package/src/schema/team-tool-schema.ts +29 -74
- package/src/schema/validation-types.ts +25 -17
- package/src/skills/discover-skills.ts +35 -10
- package/src/skills/skill-templates.ts +109 -27
- package/src/skills/validate.ts +26 -8
- package/src/state/active-run-registry.ts +87 -28
- package/src/state/artifact-store.ts +9 -5
- package/src/state/atomic-write-v2.ts +85 -63
- package/src/state/atomic-write.ts +105 -26
- package/src/state/blob-store.ts +47 -20
- package/src/state/contracts.ts +20 -5
- package/src/state/crew-init.ts +5 -22
- package/src/state/decision-ledger.ts +19 -73
- package/src/state/event-log-rotation.ts +41 -15
- package/src/state/event-log.ts +168 -53
- package/src/state/event-reconstructor.ts +11 -1
- package/src/state/gitignore-manager.ts +2 -8
- package/src/state/health-store.ts +57 -57
- package/src/state/hook-instinct-bridge.ts +1 -1
- package/src/state/hook-integrations.ts +1 -1
- package/src/state/instinct-store.ts +17 -5
- package/src/state/jsonl-writer.ts +1 -1
- package/src/state/locks.ts +23 -9
- package/src/state/mailbox.ts +151 -28
- package/src/state/observation-store.ts +20 -14
- package/src/state/run-cache.ts +142 -135
- package/src/state/run-graph.ts +6 -15
- package/src/state/run-metrics.ts +5 -18
- package/src/state/schedule.ts +15 -9
- package/src/state/state-store.ts +129 -45
- package/src/state/task-claims.ts +12 -2
- package/src/state/tiered-eval.ts +52 -43
- package/src/state/types-eval.ts +2 -2
- package/src/state/types.ts +24 -20
- package/src/state/usage.ts +20 -4
- package/src/state/worker-atomic-writer.ts +6 -3
- package/src/subagents/index.ts +2 -2
- package/src/teams/discover-teams.ts +21 -6
- package/src/tools/safe-bash-extension.ts +5 -6
- package/src/tools/safe-bash.ts +10 -11
- package/src/types/new-api-types.ts +6 -10
- package/src/ui/agent-management-overlay.ts +52 -40
- package/src/ui/card-colors.ts +13 -4
- package/src/ui/crew-footer.ts +8 -7
- package/src/ui/crew-select-list.ts +1 -1
- package/src/ui/dashboard-panes/agents-pane.ts +41 -25
- package/src/ui/dashboard-panes/cancellation-pane.ts +1 -1
- package/src/ui/dashboard-panes/capability-pane.ts +32 -15
- package/src/ui/dashboard-panes/health-pane.ts +2 -1
- package/src/ui/dashboard-panes/metrics-pane.ts +4 -1
- package/src/ui/dashboard-panes/progress-pane.ts +12 -9
- package/src/ui/heartbeat-aggregator.ts +15 -4
- package/src/ui/keybinding-map.ts +40 -7
- package/src/ui/live-conversation-overlay.ts +36 -20
- package/src/ui/live-duration.ts +1 -4
- package/src/ui/live-run-sidebar.ts +88 -25
- package/src/ui/loaders.ts +2 -8
- package/src/ui/mascot.ts +20 -36
- package/src/ui/overlays/agent-picker-overlay.ts +11 -3
- package/src/ui/overlays/confirm-overlay.ts +4 -2
- package/src/ui/overlays/help-overlay.ts +25 -14
- package/src/ui/overlays/mailbox-compose-overlay.ts +48 -11
- package/src/ui/overlays/mailbox-compose-preview.ts +20 -5
- package/src/ui/overlays/mailbox-detail-overlay.ts +27 -6
- package/src/ui/pi-ui-compat.ts +7 -7
- package/src/ui/powerbar-publisher.ts +120 -42
- package/src/ui/render-diff.ts +10 -3
- package/src/ui/render-scheduler.ts +12 -4
- package/src/ui/run-action-dispatcher.ts +81 -18
- package/src/ui/run-dashboard.ts +172 -76
- package/src/ui/run-event-bus.ts +59 -37
- package/src/ui/run-snapshot-cache.ts +276 -86
- package/src/ui/settings-overlay.ts +361 -74
- package/src/ui/status-colors.ts +12 -1
- package/src/ui/syntax-highlight.ts +1 -1
- package/src/ui/theme-adapter.ts +16 -14
- package/src/ui/theme-discovery.ts +13 -2
- package/src/ui/tool-progress-formatter.ts +7 -7
- package/src/ui/tool-render.ts +128 -56
- package/src/ui/tool-renderers/brief-mode.ts +45 -27
- package/src/ui/tool-renderers/index.ts +109 -43
- package/src/ui/transcript-cache.ts +32 -6
- package/src/ui/transcript-entries.ts +25 -23
- package/src/ui/transcript-viewer.ts +78 -29
- package/src/ui/widget/index.ts +99 -40
- package/src/ui/widget/widget-formatters.ts +13 -6
- package/src/ui/widget/widget-model.ts +19 -8
- package/src/ui/widget/widget-renderer.ts +23 -13
- package/src/ui/widget/widget-types.ts +1 -1
- package/src/utils/bm25-search.ts +199 -199
- package/src/utils/conflict-detect.ts +22 -21
- package/src/utils/env-filter.ts +14 -7
- package/src/utils/file-coalescer.ts +5 -1
- package/src/utils/fingerprint.ts +3 -6
- package/src/utils/frontmatter.ts +3 -1
- package/src/utils/fs-watch.ts +2 -6
- package/src/utils/gh-protocol.ts +119 -44
- package/src/utils/git.ts +13 -15
- package/src/utils/guards.ts +2 -5
- package/src/utils/ids.ts +9 -2
- package/src/utils/incremental-reader.ts +14 -3
- package/src/utils/internal-error.ts +2 -1
- package/src/utils/names.ts +12 -3
- package/src/utils/paths.ts +49 -5
- package/src/utils/project-detector.ts +2 -2
- package/src/utils/redaction.ts +29 -19
- package/src/utils/resolve-shell.ts +9 -7
- package/src/utils/run-watcher-registry.ts +19 -31
- package/src/utils/safe-paths.ts +45 -24
- package/src/utils/scan-cache.ts +9 -2
- package/src/utils/session-utils.ts +2 -4
- package/src/utils/sleep.ts +12 -5
- package/src/utils/sse-parser.ts +5 -17
- package/src/utils/visual.ts +52 -32
- package/src/workflows/discover-workflows.ts +41 -109
- package/src/workflows/intermediate-store.ts +5 -21
- package/src/workflows/preflight-validator.ts +6 -33
- package/src/workflows/topology-analyzer.ts +5 -21
- package/src/workflows/workflow-config.ts +7 -6
- package/src/worktree/branch-freshness.ts +66 -8
- package/src/worktree/cleanup.ts +130 -20
- package/src/worktree/worktree-manager.ts +212 -69
- package/skills/artifact-analysis-loop/SKILL.md +0 -303
- package/skills/detection-pipeline-design/SKILL.md +0 -286
- package/skills/hunting-investigation-loop/SKILL.md +0 -402
- package/skills/incident-playbook-construction/SKILL.md +0 -384
- package/skills/security-review/SKILL.md +0 -561
- package/skills/threat-hypothesis-framework/SKILL.md +0 -176
- package/skills/ui-render-performance/SKILL.md +0 -58
- /package/docs/{followup-review-round3-2026-05-12.md → archive/followup-review-round3-2026-05-12.md} +0 -0
- /package/docs/{followup-review-round4-2026-05-13.md → archive/followup-review-round4-2026-05-13.md} +0 -0
- /package/docs/{pi-crew-bugs.md → archive/pi-crew-bugs.md} +0 -0
- /package/docs/{pi-crew-test-final.md → archive/pi-crew-test-final.md} +0 -0
- /package/docs/{pi-crew-test-results.md → archive/pi-crew-test-results.md} +0 -0
- /package/docs/{pi-crew-test-round2.md → archive/pi-crew-test-round2.md} +0 -0
- /package/docs/{pi-crew-test-round4.md → archive/pi-crew-test-round4.md} +0 -0
- /package/docs/{pi-crew-test-round5.md → archive/pi-crew-test-round5.md} +0 -0
- /package/docs/{pi-crew-test-round6.md → archive/pi-crew-test-round6.md} +0 -0
- /package/docs/{pi-crew-v0.5.10-audit-fix-plan.md → archive/pi-crew-v0.5.10-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.11-audit-fix-plan.md → archive/pi-crew-v0.5.11-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.12-audit-fix-plan.md → archive/pi-crew-v0.5.12-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.13-audit-fix-plan.md → archive/pi-crew-v0.5.13-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.14-audit-fix-plan.md → archive/pi-crew-v0.5.14-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.16-audit-fix-plan.md → archive/pi-crew-v0.5.16-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.17-audit-fix-plan.md → archive/pi-crew-v0.5.17-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.5-audit-fix-plan.md → archive/pi-crew-v0.5.5-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.9-audit-fix-plan.md → archive/pi-crew-v0.5.9-audit-fix-plan.md} +0 -0
- /package/docs/{pi-mono-opportunities.md → archive/pi-mono-opportunities.md} +0 -0
- /package/docs/{pi-mono-review.md → archive/pi-mono-review.md} +0 -0
- /package/docs/{pi-subagent4-comparison.md → archive/pi-subagent4-comparison.md} +0 -0
- /package/docs/{pi-subagents3-deep-analysis.md → archive/pi-subagents3-deep-analysis.md} +0 -0
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import type { RunHealth } from "../runtime/task-health.ts";
|
|
3
|
+
import type { ManifestSummary, RunHealth } from "../runtime/task-health.ts";
|
|
4
4
|
import { computeRunHealth } from "../runtime/task-health.ts";
|
|
5
|
-
import type { ManifestSummary } from "../runtime/task-health.ts";
|
|
6
5
|
|
|
7
6
|
// Relative to the crew root (`<cwd>/.crew`). BUG A fix (pts/2 hang
|
|
8
7
|
// investigation 2026-06-16): this was `.crew/state/health`, which double-joined
|
|
@@ -12,65 +11,66 @@ import type { ManifestSummary } from "../runtime/task-health.ts";
|
|
|
12
11
|
const HEALTH_DIR = "state/health";
|
|
13
12
|
|
|
14
13
|
export interface HealthSnapshot {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
runId: string;
|
|
15
|
+
timestamp: number;
|
|
16
|
+
gitRef?: string;
|
|
17
|
+
score: number;
|
|
18
|
+
grade: string;
|
|
19
|
+
penalties: { reason: string; deduction: number }[];
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
export class HealthStore {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
private readonly crewRoot: string;
|
|
24
|
+
constructor(crewRoot: string) {
|
|
25
|
+
this.crewRoot = crewRoot;
|
|
26
|
+
}
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
private healthDir(): string {
|
|
29
|
+
return path.join(this.crewRoot, HEALTH_DIR);
|
|
30
|
+
}
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
32
|
+
saveSnapshot(manifest: ManifestSummary): HealthSnapshot {
|
|
33
|
+
const health = computeRunHealth(manifest);
|
|
34
|
+
const snapshot: HealthSnapshot = {
|
|
35
|
+
runId: manifest.runId,
|
|
36
|
+
timestamp: Date.now(),
|
|
37
|
+
score: health.score,
|
|
38
|
+
grade: health.grade,
|
|
39
|
+
penalties: health.penalties,
|
|
40
|
+
};
|
|
41
|
+
const dir = this.healthDir();
|
|
42
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
43
|
+
const file = path.join(dir, `${manifest.runId}.json`);
|
|
44
|
+
fs.writeFileSync(file, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
|
|
45
|
+
return snapshot;
|
|
46
|
+
}
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
48
|
+
loadLatestSnapshot(): HealthSnapshot | null {
|
|
49
|
+
const dir = this.healthDir();
|
|
50
|
+
if (!fs.existsSync(dir)) return null;
|
|
51
|
+
const snapshots = this.loadAllSnapshots();
|
|
52
|
+
if (snapshots.length === 0) return null;
|
|
53
|
+
// Sort by timestamp descending (most recent first)
|
|
54
|
+
snapshots.sort((a, b) => b.timestamp - a.timestamp);
|
|
55
|
+
return snapshots[0];
|
|
56
|
+
}
|
|
58
57
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
58
|
+
loadAllSnapshots(): HealthSnapshot[] {
|
|
59
|
+
const dir = this.healthDir();
|
|
60
|
+
if (!fs.existsSync(dir)) return [];
|
|
61
|
+
const snapshots = fs
|
|
62
|
+
.readdirSync(dir)
|
|
63
|
+
.filter((f) => f.endsWith(".json"))
|
|
64
|
+
.map((f) => {
|
|
65
|
+
try {
|
|
66
|
+
return JSON.parse(fs.readFileSync(path.join(dir, f), "utf8"));
|
|
67
|
+
} catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
.filter(Boolean) as HealthSnapshot[];
|
|
72
|
+
// Sort by timestamp ascending (oldest first) for consistent ordering
|
|
73
|
+
snapshots.sort((a, b) => a.timestamp - b.timestamp);
|
|
74
|
+
return snapshots;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
1
2
|
import * as fs from "node:fs";
|
|
2
3
|
import * as path from "node:path";
|
|
3
|
-
import { randomUUID } from "node:crypto";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Represents a learned instinct that guides agent behavior.
|
|
@@ -138,7 +138,10 @@ export class InstinctStore {
|
|
|
138
138
|
if (!scope || scope === "project") {
|
|
139
139
|
const projectsDir = path.join(this.crewRoot, "instincts", "projects");
|
|
140
140
|
if (fs.existsSync(projectsDir)) {
|
|
141
|
-
for (const projectId of fs
|
|
141
|
+
for (const projectId of fs
|
|
142
|
+
.readdirSync(projectsDir, { withFileTypes: true })
|
|
143
|
+
.filter((e) => e.isDirectory())
|
|
144
|
+
.map((e) => e.name)) {
|
|
142
145
|
const filePath = path.join(projectsDir, projectId, INSTINCT_FILE);
|
|
143
146
|
results.push(...this.readInstinctsFromFile(filePath));
|
|
144
147
|
}
|
|
@@ -176,7 +179,10 @@ export class InstinctStore {
|
|
|
176
179
|
// Search in all project instinct files
|
|
177
180
|
const projectsDir = path.join(this.crewRoot, "instincts", "projects");
|
|
178
181
|
if (fs.existsSync(projectsDir)) {
|
|
179
|
-
for (const projectId of fs
|
|
182
|
+
for (const projectId of fs
|
|
183
|
+
.readdirSync(projectsDir, { withFileTypes: true })
|
|
184
|
+
.filter((e) => e.isDirectory())
|
|
185
|
+
.map((e) => e.name)) {
|
|
180
186
|
const filePath = path.join(projectsDir, projectId, INSTINCT_FILE);
|
|
181
187
|
const instincts = this.readInstinctsFromFile(filePath);
|
|
182
188
|
const index = instincts.findIndex((i) => i.id === instinctId);
|
|
@@ -229,7 +235,10 @@ export class InstinctStore {
|
|
|
229
235
|
// Search in project instincts
|
|
230
236
|
const projectsDir = path.join(this.crewRoot, "instincts", "projects");
|
|
231
237
|
if (fs.existsSync(projectsDir)) {
|
|
232
|
-
for (const projectId of fs
|
|
238
|
+
for (const projectId of fs
|
|
239
|
+
.readdirSync(projectsDir, { withFileTypes: true })
|
|
240
|
+
.filter((e) => e.isDirectory())
|
|
241
|
+
.map((e) => e.name)) {
|
|
233
242
|
const filePath = path.join(projectsDir, projectId, INSTINCT_FILE);
|
|
234
243
|
instincts = this.readInstinctsFromFile(filePath);
|
|
235
244
|
index = instincts.findIndex((i) => i.id === instinctId);
|
|
@@ -246,4 +255,7 @@ export class InstinctStore {
|
|
|
246
255
|
}
|
|
247
256
|
}
|
|
248
257
|
|
|
249
|
-
export {
|
|
258
|
+
export {
|
|
259
|
+
getGlobalStorageDir,
|
|
260
|
+
getProjectStorageDir,
|
|
261
|
+
} from "../utils/project-detector.ts";
|
package/src/state/locks.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import { randomUUID, timingSafeEqual } from "node:crypto";
|
|
1
2
|
import * as fs from "node:fs";
|
|
2
3
|
import * as path from "node:path";
|
|
3
|
-
import { randomUUID, timingSafeEqual } from "node:crypto";
|
|
4
|
-
import type { TeamRunManifest } from "./types.ts";
|
|
5
4
|
import { DEFAULT_LOCKS } from "../config/defaults.ts";
|
|
6
5
|
import { sleepSync } from "../utils/sleep.ts";
|
|
7
6
|
import { isSymlinkSafePath } from "./atomic-write.ts";
|
|
7
|
+
import type { TeamRunManifest } from "./types.ts";
|
|
8
8
|
|
|
9
9
|
export interface RunLockOptions {
|
|
10
10
|
staleMs?: number;
|
|
@@ -16,8 +16,6 @@ function lockPath(manifest: TeamRunManifest): string {
|
|
|
16
16
|
return path.join(manifest.stateRoot, "run.lock");
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
19
|
function parseCreatedAtFromLock(raw: string): number | undefined {
|
|
22
20
|
try {
|
|
23
21
|
const payload = JSON.parse(raw) as unknown;
|
|
@@ -112,7 +110,9 @@ function readLockSnapshot(filePath: string, staleMs: number): { canSteal: boolea
|
|
|
112
110
|
isAlive = false;
|
|
113
111
|
}
|
|
114
112
|
}
|
|
115
|
-
} catch {
|
|
113
|
+
} catch {
|
|
114
|
+
/* malformed payload — keep isAlive=true */
|
|
115
|
+
}
|
|
116
116
|
// Steal if stale OR holder dead — matches the original intent.
|
|
117
117
|
return { canSteal: isStale || !isAlive };
|
|
118
118
|
}
|
|
@@ -148,7 +148,15 @@ function writeLockFile(filePath: string, token: string, kind: LockKind = "file")
|
|
|
148
148
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
149
149
|
const fd = fs.openSync(filePath, fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL, 0o600);
|
|
150
150
|
try {
|
|
151
|
-
fs.writeSync(
|
|
151
|
+
fs.writeSync(
|
|
152
|
+
fd,
|
|
153
|
+
JSON.stringify({
|
|
154
|
+
kind,
|
|
155
|
+
pid: process.pid,
|
|
156
|
+
createdAt: new Date().toISOString(),
|
|
157
|
+
token,
|
|
158
|
+
}),
|
|
159
|
+
);
|
|
152
160
|
} finally {
|
|
153
161
|
fs.closeSync(fd);
|
|
154
162
|
}
|
|
@@ -198,7 +206,9 @@ function releaseLock(filePath: string, token: string): void {
|
|
|
198
206
|
let isSymlink = false;
|
|
199
207
|
try {
|
|
200
208
|
isSymlink = fs.lstatSync(filePath).isSymbolicLink();
|
|
201
|
-
} catch {
|
|
209
|
+
} catch {
|
|
210
|
+
/* file doesn't exist — that's fine, we'll handle ENOENT below */
|
|
211
|
+
}
|
|
202
212
|
if (isSymlink) return;
|
|
203
213
|
|
|
204
214
|
const stored = readLockToken(filePath);
|
|
@@ -240,7 +250,9 @@ function acquireLockWithRetry(filePath: string, staleMs: number, kind: LockKind
|
|
|
240
250
|
// Stale or dead holder — forcibly remove the lock.
|
|
241
251
|
try {
|
|
242
252
|
fs.rmSync(filePath, { force: true });
|
|
243
|
-
} catch {
|
|
253
|
+
} catch {
|
|
254
|
+
/* race — let loop retry */
|
|
255
|
+
}
|
|
244
256
|
sleepSync(Math.min(250, 25 * 2 ** attempt));
|
|
245
257
|
attempt++;
|
|
246
258
|
}
|
|
@@ -273,7 +285,9 @@ async function acquireLockWithRetryAsync(filePath: string, staleMs: number, kind
|
|
|
273
285
|
// Stale or dead holder — forcibly remove the lock.
|
|
274
286
|
try {
|
|
275
287
|
fs.rmSync(filePath, { force: true });
|
|
276
|
-
} catch {
|
|
288
|
+
} catch {
|
|
289
|
+
/* race — let loop retry */
|
|
290
|
+
}
|
|
277
291
|
const delay = Math.min(250, 25 * 2 ** attempt);
|
|
278
292
|
await sleep(delay);
|
|
279
293
|
attempt++;
|
package/src/state/mailbox.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import
|
|
4
|
-
import { resolveRealContainedPath } from "../utils/safe-paths.ts";
|
|
5
|
-
import { redactSecrets } from "../utils/redaction.ts";
|
|
3
|
+
import { DEFAULT_MAILBOX } from "../config/defaults.ts";
|
|
6
4
|
import { logInternalError } from "../utils/internal-error.ts";
|
|
5
|
+
import { redactSecrets } from "../utils/redaction.ts";
|
|
6
|
+
import { resolveRealContainedPath } from "../utils/safe-paths.ts";
|
|
7
7
|
import { atomicWriteFile } from "./atomic-write.ts";
|
|
8
8
|
import { withEventLogLockSync } from "./event-log.ts";
|
|
9
9
|
import { withFileLockSync } from "./locks.ts";
|
|
10
|
-
import {
|
|
10
|
+
import type { TeamRunManifest } from "./types.ts";
|
|
11
11
|
|
|
12
12
|
export type MailboxDirection = "inbox" | "outbox";
|
|
13
13
|
export type MailboxMessageStatus = "queued" | "delivered" | "acknowledged";
|
|
@@ -81,7 +81,9 @@ function safeMailboxDir(manifest: TeamRunManifest, create = false): string {
|
|
|
81
81
|
const realDir = fs.realpathSync(path.dirname(dir));
|
|
82
82
|
const correctedDir = path.join(realDir, path.basename(dir));
|
|
83
83
|
fs.mkdirSync(correctedDir, { recursive: true });
|
|
84
|
-
} catch {
|
|
84
|
+
} catch {
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
85
87
|
} else {
|
|
86
88
|
throw error;
|
|
87
89
|
}
|
|
@@ -104,7 +106,8 @@ function safeMailboxDir(manifest: TeamRunManifest, create = false): string {
|
|
|
104
106
|
}
|
|
105
107
|
|
|
106
108
|
function safeTaskId(taskId: string): string {
|
|
107
|
-
if (!/^[\w.-]+$/.test(taskId) || taskId.includes("..") || path.isAbsolute(taskId))
|
|
109
|
+
if (!/^[\w.-]+$/.test(taskId) || taskId.includes("..") || path.isAbsolute(taskId))
|
|
110
|
+
throw new Error(`Invalid mailbox task id: ${taskId}`);
|
|
108
111
|
return taskId;
|
|
109
112
|
}
|
|
110
113
|
|
|
@@ -130,7 +133,9 @@ function taskMailboxDir(manifest: TeamRunManifest, taskId: string, create = fals
|
|
|
130
133
|
}
|
|
131
134
|
|
|
132
135
|
function mailboxPath(manifest: TeamRunManifest, direction: MailboxDirection, taskId?: string, create = false): string {
|
|
133
|
-
return taskId
|
|
136
|
+
return taskId
|
|
137
|
+
? path.join(taskMailboxDir(manifest, taskId, create), `${direction}.jsonl`)
|
|
138
|
+
: path.join(safeMailboxDir(manifest, create), `${direction}.jsonl`);
|
|
134
139
|
}
|
|
135
140
|
|
|
136
141
|
function deliveryPath(manifest: TeamRunManifest, create = false): string {
|
|
@@ -221,11 +226,41 @@ function isDeliveryMode(value: unknown): value is MailboxDeliveryMode {
|
|
|
221
226
|
function parseMailboxMessage(raw: unknown, expectedDirection: MailboxDirection): MailboxMessage | undefined {
|
|
222
227
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return undefined;
|
|
223
228
|
const obj = raw as Record<string, unknown>;
|
|
224
|
-
if (
|
|
229
|
+
if (
|
|
230
|
+
typeof obj.id !== "string" ||
|
|
231
|
+
typeof obj.runId !== "string" ||
|
|
232
|
+
!isDirection(obj.direction) ||
|
|
233
|
+
typeof obj.from !== "string" ||
|
|
234
|
+
typeof obj.to !== "string" ||
|
|
235
|
+
typeof obj.body !== "string" ||
|
|
236
|
+
typeof obj.createdAt !== "string" ||
|
|
237
|
+
!isStatus(obj.status)
|
|
238
|
+
)
|
|
239
|
+
return undefined;
|
|
225
240
|
if (obj.direction !== expectedDirection) return undefined;
|
|
226
|
-
const data = obj.data && typeof obj.data === "object" && !Array.isArray(obj.data) ? obj.data as Record<string, unknown> : undefined;
|
|
241
|
+
const data = obj.data && typeof obj.data === "object" && !Array.isArray(obj.data) ? (obj.data as Record<string, unknown>) : undefined;
|
|
227
242
|
const dataKind = data?.kind;
|
|
228
|
-
return {
|
|
243
|
+
return {
|
|
244
|
+
id: obj.id,
|
|
245
|
+
runId: obj.runId,
|
|
246
|
+
direction: obj.direction,
|
|
247
|
+
from: obj.from,
|
|
248
|
+
to: obj.to,
|
|
249
|
+
body: obj.body,
|
|
250
|
+
createdAt: obj.createdAt,
|
|
251
|
+
status: obj.status,
|
|
252
|
+
kind: isKind(obj.kind) ? obj.kind : isKind(dataKind) ? dataKind : undefined,
|
|
253
|
+
priority: isPriority(obj.priority) ? obj.priority : undefined,
|
|
254
|
+
deliveryMode: isDeliveryMode(obj.deliveryMode) ? obj.deliveryMode : undefined,
|
|
255
|
+
taskId: typeof obj.taskId === "string" ? obj.taskId : undefined,
|
|
256
|
+
acknowledgedAt: typeof obj.acknowledgedAt === "string" ? obj.acknowledgedAt : undefined,
|
|
257
|
+
data,
|
|
258
|
+
replyTo: typeof obj.replyTo === "string" ? obj.replyTo : undefined,
|
|
259
|
+
replyFrom: typeof obj.replyFrom === "string" ? obj.replyFrom : undefined,
|
|
260
|
+
replyDeadline: typeof obj.replyDeadline === "number" ? obj.replyDeadline : undefined,
|
|
261
|
+
repliedAt: typeof obj.repliedAt === "string" ? obj.repliedAt : undefined,
|
|
262
|
+
replyContent: typeof obj.replyContent === "string" ? obj.replyContent : undefined,
|
|
263
|
+
};
|
|
229
264
|
}
|
|
230
265
|
|
|
231
266
|
function readMailboxFile(filePath: string, direction: MailboxDirection): MailboxMessage[] {
|
|
@@ -308,13 +343,21 @@ function pruneOldMailboxArchives(mailboxFilePath: string): void {
|
|
|
308
343
|
}
|
|
309
344
|
}
|
|
310
345
|
|
|
311
|
-
export function readMailbox(
|
|
312
|
-
|
|
313
|
-
|
|
346
|
+
export function readMailbox(
|
|
347
|
+
manifest: TeamRunManifest,
|
|
348
|
+
direction?: MailboxDirection,
|
|
349
|
+
taskId?: string,
|
|
350
|
+
kind?: MailboxMessageKind,
|
|
351
|
+
): MailboxMessage[] {
|
|
352
|
+
const directions = direction ? [direction] : (["inbox", "outbox"] as const);
|
|
353
|
+
return directions
|
|
354
|
+
.flatMap((item) => safeReadMailboxFile(mailboxFile(manifest, item, taskId), item))
|
|
355
|
+
.filter((msg) => !kind || msg.kind === kind)
|
|
356
|
+
.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
314
357
|
}
|
|
315
358
|
|
|
316
359
|
export function readAllMailboxMessages(manifest: TeamRunManifest, direction?: MailboxDirection, signal?: AbortSignal): MailboxMessage[] {
|
|
317
|
-
const directions = direction ? [direction] : ["inbox", "outbox"] as const;
|
|
360
|
+
const directions = direction ? [direction] : (["inbox", "outbox"] as const);
|
|
318
361
|
return directions.flatMap((item) => readAllMessages(manifest, item, signal)).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
319
362
|
}
|
|
320
363
|
|
|
@@ -344,7 +387,10 @@ export function readDeliveryState(manifest: TeamRunManifest): MailboxDeliverySta
|
|
|
344
387
|
if (obj.messages && typeof obj.messages === "object" && !Array.isArray(obj.messages)) {
|
|
345
388
|
for (const [id, status] of Object.entries(obj.messages)) if (isStatus(status)) messages[id] = status;
|
|
346
389
|
}
|
|
347
|
-
return {
|
|
390
|
+
return {
|
|
391
|
+
messages,
|
|
392
|
+
updatedAt: typeof obj.updatedAt === "string" ? obj.updatedAt : new Date().toISOString(),
|
|
393
|
+
};
|
|
348
394
|
} catch {
|
|
349
395
|
return { messages: {}, updatedAt: new Date().toISOString() };
|
|
350
396
|
}
|
|
@@ -377,7 +423,13 @@ function writeDeliveryState(manifest: TeamRunManifest, state: MailboxDeliverySta
|
|
|
377
423
|
* If pi-crew ever exposes mailbox writes to external/untrusted input, sender
|
|
378
424
|
* authentication (HMAC or session key) must be added.
|
|
379
425
|
*/
|
|
380
|
-
export function appendMailboxMessage(
|
|
426
|
+
export function appendMailboxMessage(
|
|
427
|
+
manifest: TeamRunManifest,
|
|
428
|
+
message: Omit<MailboxMessage, "id" | "runId" | "createdAt" | "status"> & {
|
|
429
|
+
id?: string;
|
|
430
|
+
status?: MailboxMessageStatus;
|
|
431
|
+
},
|
|
432
|
+
): MailboxMessage {
|
|
381
433
|
if (message.taskId) ensureTaskMailbox(manifest, message.taskId);
|
|
382
434
|
else ensureRunMailbox(manifest);
|
|
383
435
|
const createdAt = new Date().toISOString();
|
|
@@ -403,7 +455,11 @@ export function appendMailboxMessage(manifest: TeamRunManifest, message: Omit<Ma
|
|
|
403
455
|
};
|
|
404
456
|
// H2 fix: wrap append in cross-process lock to prevent interleaving on Windows.
|
|
405
457
|
withEventLogLockSync(mailboxFile(manifest, complete.direction, complete.taskId), () => {
|
|
406
|
-
fs.appendFileSync(
|
|
458
|
+
fs.appendFileSync(
|
|
459
|
+
mailboxFile(manifest, complete.direction, complete.taskId),
|
|
460
|
+
`${JSON.stringify(redactSecrets(complete))}\n`,
|
|
461
|
+
"utf-8",
|
|
462
|
+
);
|
|
407
463
|
});
|
|
408
464
|
// 3.3 — rotate mailbox file if it has grown past 10 MB. Cheap stat
|
|
409
465
|
// check; rotates at most once per append.
|
|
@@ -421,16 +477,64 @@ export function appendMailboxMessage(manifest: TeamRunManifest, message: Omit<Ma
|
|
|
421
477
|
return complete;
|
|
422
478
|
}
|
|
423
479
|
|
|
424
|
-
export function appendSteeringMessage(
|
|
425
|
-
|
|
480
|
+
export function appendSteeringMessage(
|
|
481
|
+
manifest: TeamRunManifest,
|
|
482
|
+
input: {
|
|
483
|
+
taskId: string;
|
|
484
|
+
body: string;
|
|
485
|
+
from?: string;
|
|
486
|
+
to?: string;
|
|
487
|
+
priority?: MailboxMessagePriority;
|
|
488
|
+
status?: MailboxMessageStatus;
|
|
489
|
+
data?: Record<string, unknown>;
|
|
490
|
+
},
|
|
491
|
+
): MailboxMessage {
|
|
492
|
+
return appendMailboxMessage(manifest, {
|
|
493
|
+
direction: "inbox",
|
|
494
|
+
from: input.from ?? "leader",
|
|
495
|
+
to: input.to ?? input.taskId,
|
|
496
|
+
taskId: input.taskId,
|
|
497
|
+
body: input.body,
|
|
498
|
+
kind: "steer",
|
|
499
|
+
priority: input.priority ?? "urgent",
|
|
500
|
+
deliveryMode: "interrupt",
|
|
501
|
+
status: input.status,
|
|
502
|
+
data: { ...(input.data ?? {}), kind: "steer" },
|
|
503
|
+
});
|
|
426
504
|
}
|
|
427
505
|
|
|
428
|
-
export function appendFollowUpMessage(
|
|
429
|
-
|
|
506
|
+
export function appendFollowUpMessage(
|
|
507
|
+
manifest: TeamRunManifest,
|
|
508
|
+
input: {
|
|
509
|
+
taskId: string;
|
|
510
|
+
body: string;
|
|
511
|
+
from?: string;
|
|
512
|
+
to?: string;
|
|
513
|
+
priority?: MailboxMessagePriority;
|
|
514
|
+
status?: MailboxMessageStatus;
|
|
515
|
+
data?: Record<string, unknown>;
|
|
516
|
+
},
|
|
517
|
+
): MailboxMessage {
|
|
518
|
+
return appendMailboxMessage(manifest, {
|
|
519
|
+
direction: "inbox",
|
|
520
|
+
from: input.from ?? "leader",
|
|
521
|
+
to: input.to ?? input.taskId,
|
|
522
|
+
taskId: input.taskId,
|
|
523
|
+
body: input.body,
|
|
524
|
+
kind: "follow-up",
|
|
525
|
+
priority: input.priority ?? "normal",
|
|
526
|
+
deliveryMode: "next_turn",
|
|
527
|
+
status: input.status,
|
|
528
|
+
data: { ...(input.data ?? {}), kind: "follow-up" },
|
|
529
|
+
});
|
|
430
530
|
}
|
|
431
531
|
|
|
432
532
|
export function listMailboxByKind(manifest: TeamRunManifest, kind: MailboxMessageKind, direction?: MailboxDirection): MailboxMessage[] {
|
|
433
|
-
const messages = direction
|
|
533
|
+
const messages = direction
|
|
534
|
+
? readAllMessages(manifest, direction)
|
|
535
|
+
: [...readAllMessages(manifest, "inbox"), ...readAllMessages(manifest, "outbox")].sort((a, b) =>
|
|
536
|
+
a.createdAt.localeCompare(b.createdAt),
|
|
537
|
+
);
|
|
434
538
|
return messages.filter((message) => message.kind === kind || message.data?.kind === kind);
|
|
435
539
|
}
|
|
436
540
|
|
|
@@ -464,16 +568,25 @@ export function updateMailboxMessageReply(manifest: TeamRunManifest, originalMes
|
|
|
464
568
|
const directions: MailboxDirection[] = ["inbox", "outbox"];
|
|
465
569
|
|
|
466
570
|
// Collect all mailbox file paths (global + task-specific)
|
|
467
|
-
const filesToSearch: Array<{
|
|
571
|
+
const filesToSearch: Array<{
|
|
572
|
+
filePath: string;
|
|
573
|
+
direction: MailboxDirection;
|
|
574
|
+
}> = [];
|
|
468
575
|
for (const direction of directions) {
|
|
469
|
-
filesToSearch.push({
|
|
576
|
+
filesToSearch.push({
|
|
577
|
+
filePath: mailboxFile(manifest, direction),
|
|
578
|
+
direction,
|
|
579
|
+
});
|
|
470
580
|
}
|
|
471
581
|
const tasksDir = safeMailboxTasksRoot(manifest);
|
|
472
582
|
if (fs.existsSync(tasksDir)) {
|
|
473
583
|
for (const entry of fs.readdirSync(tasksDir, { withFileTypes: true })) {
|
|
474
584
|
if (!entry.isDirectory()) continue;
|
|
475
585
|
for (const direction of directions) {
|
|
476
|
-
filesToSearch.push({
|
|
586
|
+
filesToSearch.push({
|
|
587
|
+
filePath: mailboxFile(manifest, direction, entry.name),
|
|
588
|
+
direction,
|
|
589
|
+
});
|
|
477
590
|
}
|
|
478
591
|
}
|
|
479
592
|
}
|
|
@@ -517,7 +630,9 @@ export function replayPendingMailboxMessages(manifest: TeamRunManifest): Mailbox
|
|
|
517
630
|
// clobber concurrent appends/acknowledgments. FIX: wrap in a file lock.
|
|
518
631
|
return withFileLockSync(deliveryFile(manifest, true), () => {
|
|
519
632
|
const delivery = readDeliveryState(manifest);
|
|
520
|
-
const pending = readAllInboxMessages(manifest).filter(
|
|
633
|
+
const pending = readAllInboxMessages(manifest).filter(
|
|
634
|
+
(message) => message.status !== "acknowledged" && delivery.messages[message.id] !== "acknowledged",
|
|
635
|
+
);
|
|
521
636
|
if (!pending.length) return { messages: [], updatedAt: delivery.updatedAt };
|
|
522
637
|
const updatedAt = new Date().toISOString();
|
|
523
638
|
for (const message of pending) delivery.messages[message.id] = "delivered";
|
|
@@ -527,7 +642,10 @@ export function replayPendingMailboxMessages(manifest: TeamRunManifest): Mailbox
|
|
|
527
642
|
});
|
|
528
643
|
}
|
|
529
644
|
|
|
530
|
-
export function validateMailbox(
|
|
645
|
+
export function validateMailbox(
|
|
646
|
+
manifest: TeamRunManifest,
|
|
647
|
+
options: { repair?: boolean; signal?: AbortSignal } = {},
|
|
648
|
+
): MailboxValidationReport {
|
|
531
649
|
ensureRunMailbox(manifest);
|
|
532
650
|
const issues: MailboxValidationIssue[] = [];
|
|
533
651
|
const repaired: string[] = [];
|
|
@@ -564,7 +682,12 @@ export function validateMailbox(manifest: TeamRunManifest, options: { repair?: b
|
|
|
564
682
|
const allMessages = readMailbox(manifest);
|
|
565
683
|
for (const message of allMessages) {
|
|
566
684
|
if (options.signal?.aborted) break;
|
|
567
|
-
if (!delivery.messages[message.id])
|
|
685
|
+
if (!delivery.messages[message.id])
|
|
686
|
+
issues.push({
|
|
687
|
+
level: "warning",
|
|
688
|
+
path: deliveryFile(manifest),
|
|
689
|
+
message: `Missing delivery entry for ${message.id}.`,
|
|
690
|
+
});
|
|
568
691
|
}
|
|
569
692
|
if (options.repair) {
|
|
570
693
|
for (const message of allMessages) delivery.messages[message.id] ??= message.status;
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* Actual capture hooks into the lifecycle events (Pattern 12).
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { readFileSync, existsSync, appendFileSync } from "node:fs";
|
|
12
11
|
import * as fs from "node:fs";
|
|
12
|
+
import { appendFileSync, existsSync, readFileSync } from "node:fs";
|
|
13
13
|
import * as path from "node:path";
|
|
14
14
|
import { logInternalError } from "../utils/internal-error.ts";
|
|
15
15
|
import { atomicWriteJson } from "./atomic-write.ts";
|
|
@@ -40,7 +40,7 @@ export interface CompressedObservation {
|
|
|
40
40
|
export interface ObservationStoreConfig {
|
|
41
41
|
maxObservations: number;
|
|
42
42
|
maxCompressed: number;
|
|
43
|
-
privacyTags: string[];
|
|
43
|
+
privacyTags: string[]; // tags to strip before storage
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
const DEFAULT_CONFIG: ObservationStoreConfig = {
|
|
@@ -127,9 +127,7 @@ export class ObservationStore {
|
|
|
127
127
|
* Get compressed observations for injection.
|
|
128
128
|
*/
|
|
129
129
|
getCompressed(limit = 5): CompressedObservation[] {
|
|
130
|
-
return this.compressed
|
|
131
|
-
.sort((a, b) => b.relevanceScore - a.relevanceScore)
|
|
132
|
-
.slice(0, limit);
|
|
130
|
+
return this.compressed.sort((a, b) => b.relevanceScore - a.relevanceScore).slice(0, limit);
|
|
133
131
|
}
|
|
134
132
|
|
|
135
133
|
/**
|
|
@@ -139,14 +137,19 @@ export class ObservationStore {
|
|
|
139
137
|
const items = this.getCompressed(limit);
|
|
140
138
|
if (items.length === 0) return "";
|
|
141
139
|
|
|
142
|
-
return
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
140
|
+
return (
|
|
141
|
+
"## Observations from Previous Sessions\n\n" +
|
|
142
|
+
items
|
|
143
|
+
.map(
|
|
144
|
+
(o) =>
|
|
145
|
+
`### ${o.summary}\n` +
|
|
146
|
+
`Patterns: ${o.patterns.join(", ")}\n` +
|
|
147
|
+
`Decisions: ${o.decisions.join(", ")}\n` +
|
|
148
|
+
`Files: ${o.filesAffected.join(", ")}`,
|
|
149
|
+
)
|
|
150
|
+
.join("\n\n") +
|
|
151
|
+
"\n"
|
|
152
|
+
);
|
|
150
153
|
}
|
|
151
154
|
|
|
152
155
|
/**
|
|
@@ -167,7 +170,10 @@ export class ObservationStore {
|
|
|
167
170
|
}
|
|
168
171
|
|
|
169
172
|
get stats(): { observations: number; compressed: number } {
|
|
170
|
-
return {
|
|
173
|
+
return {
|
|
174
|
+
observations: this.observations.length,
|
|
175
|
+
compressed: this.compressed.length,
|
|
176
|
+
};
|
|
171
177
|
}
|
|
172
178
|
|
|
173
179
|
private load(): void {
|