pi-crew 0.9.15 → 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 +145 -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 +193 -40
- 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 +86 -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
package/src/utils/visual.ts
CHANGED
|
@@ -6,39 +6,66 @@ const widthCache = new Map<string, number>();
|
|
|
6
6
|
/** Code-point ranges that render as width 2 in most terminals (CJK + emoji). */
|
|
7
7
|
const WIDE_RANGES: Array<[number, number]> = [
|
|
8
8
|
// CJK Unified Ideographs
|
|
9
|
-
[
|
|
9
|
+
[0x4e00, 0x9fff],
|
|
10
10
|
// CJK Extension A
|
|
11
|
-
[0x3400,
|
|
11
|
+
[0x3400, 0x4dbf],
|
|
12
12
|
// CJK Compatibility Ideographs
|
|
13
|
-
[
|
|
13
|
+
[0xf900, 0xfaff],
|
|
14
14
|
// Hangul Syllables
|
|
15
|
-
[
|
|
15
|
+
[0xac00, 0xd7af],
|
|
16
16
|
// CJK Symbols and Punctuation, Hiragana, Katakana
|
|
17
|
-
[0x3000,
|
|
17
|
+
[0x3000, 0x33ff],
|
|
18
18
|
// Fullwidth forms
|
|
19
|
-
[
|
|
19
|
+
[0xff01, 0xff60],
|
|
20
20
|
// Emoji blocks
|
|
21
21
|
// Emoji-presentation codepoints in 0x2600-0x27BF (narrow chars like ✓✗★ excluded)
|
|
22
|
-
[0x2615, 0x2615],
|
|
23
|
-
[
|
|
24
|
-
[
|
|
25
|
-
[
|
|
26
|
-
[
|
|
27
|
-
[
|
|
28
|
-
[
|
|
29
|
-
[
|
|
30
|
-
[
|
|
31
|
-
[
|
|
22
|
+
[0x2615, 0x2615],
|
|
23
|
+
[0x2648, 0x2653],
|
|
24
|
+
[0x267f, 0x267f],
|
|
25
|
+
[0x2693, 0x2693],
|
|
26
|
+
[0x26a1, 0x26a1],
|
|
27
|
+
[0x26aa, 0x26ab],
|
|
28
|
+
[0x26bd, 0x26be],
|
|
29
|
+
[0x26c4, 0x26c5],
|
|
30
|
+
[0x26ce, 0x26ce],
|
|
31
|
+
[0x26d4, 0x26d4],
|
|
32
|
+
[0x26ea, 0x26ea],
|
|
33
|
+
[0x26f2, 0x26f3],
|
|
34
|
+
[0x26f5, 0x26f5],
|
|
35
|
+
[0x26fa, 0x26fa],
|
|
36
|
+
[0x26fd, 0x26fd],
|
|
37
|
+
[0x2702, 0x2702],
|
|
38
|
+
[0x2705, 0x2705],
|
|
39
|
+
[0x2708, 0x270d],
|
|
40
|
+
[0x270f, 0x270f],
|
|
41
|
+
[0x2712, 0x2712],
|
|
42
|
+
[0x2714, 0x2714],
|
|
43
|
+
[0x2716, 0x2716],
|
|
44
|
+
[0x271d, 0x271d],
|
|
45
|
+
[0x2721, 0x2721],
|
|
46
|
+
[0x2728, 0x2728],
|
|
47
|
+
[0x2733, 0x2734],
|
|
48
|
+
[0x2744, 0x2744],
|
|
49
|
+
[0x2747, 0x2747],
|
|
50
|
+
[0x274c, 0x274c],
|
|
51
|
+
[0x274e, 0x274e],
|
|
52
|
+
[0x2753, 0x2755],
|
|
53
|
+
[0x2757, 0x2757],
|
|
54
|
+
[0x2763, 0x2764],
|
|
55
|
+
[0x2795, 0x2797],
|
|
56
|
+
[0x27a1, 0x27a1],
|
|
57
|
+
[0x27b0, 0x27b0],
|
|
58
|
+
[0x27bf, 0x27bf],
|
|
32
59
|
// Geometric Shapes / Misc Symbols-Arrows emoji that pi-tui upstream counts as
|
|
33
60
|
// width=2 (RGI emoji). Mismatch here caused the "Rendered line N exceeds
|
|
34
61
|
// terminal width (160 > 159)" TUI crash: pi-crew truncated to width 159 by
|
|
35
62
|
// its own (mismatched) measure, then Box padded to 159 chars, but pi-tui
|
|
36
63
|
// re-measured the padded line at 160 because ⬜ counts as 2 upstream.
|
|
37
|
-
[
|
|
38
|
-
[
|
|
39
|
-
[
|
|
40
|
-
[
|
|
41
|
-
[
|
|
64
|
+
[0x2b1b, 0x2b1c], // ⬛ BLACK LARGE SQUARE, ⬜ WHITE LARGE SQUARE
|
|
65
|
+
[0x1f300, 0x1f9ff], // Misc Symbols, Emoticons, Transport, Map, Supplement
|
|
66
|
+
[0x1fa00, 0x1faff], // Symbols Extended-A
|
|
67
|
+
[0x1f000, 0x1f02f], // Mahjong, Dominos
|
|
68
|
+
[0xfe00, 0xfe0f], // Variation Selectors (emoji presentation)
|
|
42
69
|
];
|
|
43
70
|
// NOTE: U+200D (Zero Width Joiner, ZWJ) is intentionally NOT listed as wide.
|
|
44
71
|
// ZWJ has zero advance width by Unicode definition; miscounting it as 2 caused
|
|
@@ -113,7 +140,7 @@ export function truncateToWidth(value: string, width: number, ellipsis = "…"):
|
|
|
113
140
|
continue;
|
|
114
141
|
}
|
|
115
142
|
const char = value[i] as string;
|
|
116
|
-
const nextIndex = (
|
|
143
|
+
const nextIndex = (char.codePointAt(0) ?? 0) > 0xffff ? i + 2 : i + 1;
|
|
117
144
|
const segment = value.slice(i, nextIndex);
|
|
118
145
|
const charWidth = visibleWidth(segment);
|
|
119
146
|
if (renderedWidth + charWidth > width - ellipsis.length) {
|
|
@@ -183,7 +210,7 @@ function readAnsiCode(input: string, index: number): string | undefined {
|
|
|
183
210
|
function takeCodePoint(input: string, index: number): { chunk: string; nextIndex: number } {
|
|
184
211
|
const code = input.codePointAt(index);
|
|
185
212
|
if (code === undefined) return { chunk: "", nextIndex: index + 1 };
|
|
186
|
-
if (code >=
|
|
213
|
+
if (code >= 0xd800 && code <= 0xdbff && index + 1 < input.length) {
|
|
187
214
|
return { chunk: input.slice(index, index + 2), nextIndex: index + 2 };
|
|
188
215
|
}
|
|
189
216
|
return { chunk: input[index] ?? "", nextIndex: index + 1 };
|
|
@@ -231,20 +258,13 @@ export interface VisualTruncateResult {
|
|
|
231
258
|
skippedCount: number;
|
|
232
259
|
}
|
|
233
260
|
|
|
234
|
-
export function truncateToVisualLines(
|
|
235
|
-
text: string,
|
|
236
|
-
maxVisualLines: number,
|
|
237
|
-
width: number,
|
|
238
|
-
paddingX = 0,
|
|
239
|
-
): VisualTruncateResult {
|
|
261
|
+
export function truncateToVisualLines(text: string, maxVisualLines: number, width: number, paddingX = 0): VisualTruncateResult {
|
|
240
262
|
if (!text) {
|
|
241
263
|
return { visualLines: [], skippedCount: 0 };
|
|
242
264
|
}
|
|
243
265
|
const effectiveWidth = Math.max(1, width - paddingX * 2);
|
|
244
266
|
const limit = Math.max(1, maxVisualLines);
|
|
245
|
-
const visualLines = text
|
|
246
|
-
.split("\n")
|
|
247
|
-
.flatMap((line) => wrapHard(pad(line, Math.max(0, effectiveWidth)).trimEnd(), effectiveWidth));
|
|
267
|
+
const visualLines = text.split("\n").flatMap((line) => wrapHard(pad(line, Math.max(0, effectiveWidth)).trimEnd(), effectiveWidth));
|
|
248
268
|
if (visualLines.length <= limit) return { visualLines, skippedCount: 0 };
|
|
249
269
|
const truncated = visualLines.slice(-limit);
|
|
250
270
|
return { visualLines: truncated, skippedCount: visualLines.length - limit };
|
|
@@ -64,57 +64,38 @@ function parseStepSection(id: string, body: string): WorkflowStep | undefined {
|
|
|
64
64
|
reads: config.reads === "false" ? false : parseCsv(config.reads),
|
|
65
65
|
model: config.model || undefined,
|
|
66
66
|
skills: config.skills === "false" ? false : parseCsv(config.skills),
|
|
67
|
-
progress:
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
: config.progress === "false"
|
|
71
|
-
? false
|
|
72
|
-
: undefined,
|
|
73
|
-
worktree:
|
|
74
|
-
config.worktree === "true"
|
|
75
|
-
? true
|
|
76
|
-
: config.worktree === "false"
|
|
77
|
-
? false
|
|
78
|
-
: undefined,
|
|
79
|
-
verify:
|
|
80
|
-
config.verify === "true"
|
|
81
|
-
? true
|
|
82
|
-
: config.verify === "false"
|
|
83
|
-
? false
|
|
84
|
-
: undefined,
|
|
67
|
+
progress: config.progress === "true" ? true : config.progress === "false" ? false : undefined,
|
|
68
|
+
worktree: config.worktree === "true" ? true : config.worktree === "false" ? false : undefined,
|
|
69
|
+
verify: config.verify === "true" ? true : config.verify === "false" ? false : undefined,
|
|
85
70
|
seedPaths: parseCsv(config.seedPaths) || undefined,
|
|
86
71
|
preStepScript: config.preStepScript || undefined,
|
|
87
72
|
preStepArgs: parseCsv(config.preStepArgs) || undefined,
|
|
88
|
-
preStepTimeout:
|
|
89
|
-
|
|
90
|
-
preStepOptional:
|
|
91
|
-
config.preStepOptional === "true" || config.preStepOptional === "1",
|
|
73
|
+
preStepTimeout: parseOptionalInteger(config.preStepTimeout) ?? undefined,
|
|
74
|
+
preStepOptional: config.preStepOptional === "true" || config.preStepOptional === "1",
|
|
92
75
|
};
|
|
93
76
|
}
|
|
94
77
|
|
|
95
|
-
const parseOptionalInteger = (
|
|
96
|
-
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
78
|
+
const parseOptionalInteger = (value: string | undefined): number | undefined => {
|
|
79
|
+
const trimmed = value?.trim();
|
|
80
|
+
if (!trimmed) return undefined;
|
|
81
|
+
const n = Number.parseInt(trimmed, 10);
|
|
82
|
+
return Number.isNaN(n) ? undefined : n;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const parseOptionalBoolean = (value: string | undefined): boolean | undefined => {
|
|
86
|
+
const trimmed = value?.trim().toLowerCase();
|
|
87
|
+
if (!trimmed) return undefined;
|
|
88
|
+
if (trimmed === "true" || trimmed === "yes" || trimmed === "1") return true;
|
|
89
|
+
if (trimmed === "false" || trimmed === "no" || trimmed === "0") return false;
|
|
90
|
+
return undefined;
|
|
102
91
|
};
|
|
103
92
|
|
|
104
93
|
/** Parse frontmatter `topology:` field. Validates against allowed enum; bad values are silently
|
|
105
94
|
* dropped (fall through to auto-classification in topology-analyzer). */
|
|
106
|
-
const parseTopology = (
|
|
107
|
-
value: string | undefined,
|
|
108
|
-
): WorkflowConfig["topology"] => {
|
|
95
|
+
const parseTopology = (value: string | undefined): WorkflowConfig["topology"] => {
|
|
109
96
|
if (!value) return undefined;
|
|
110
97
|
const v = value.trim().toLowerCase();
|
|
111
|
-
if (
|
|
112
|
-
v === "single" ||
|
|
113
|
-
v === "sequential" ||
|
|
114
|
-
v === "concurrent" ||
|
|
115
|
-
v === "complex-dag" ||
|
|
116
|
-
v === "dynamic"
|
|
117
|
-
) {
|
|
98
|
+
if (v === "single" || v === "sequential" || v === "concurrent" || v === "complex-dag" || v === "dynamic") {
|
|
118
99
|
return v;
|
|
119
100
|
}
|
|
120
101
|
return undefined;
|
|
@@ -129,15 +110,9 @@ function hasSectionBoundary(body: string, match: RegExpMatchArray): boolean {
|
|
|
129
110
|
}
|
|
130
111
|
|
|
131
112
|
function isStepHeading(body: string, match: RegExpMatchArray): boolean {
|
|
132
|
-
const sectionStart =
|
|
133
|
-
match.index! +
|
|
134
|
-
match[0].length +
|
|
135
|
-
(body[match.index! + match[0].length] === "\n" ? 1 : 0);
|
|
113
|
+
const sectionStart = match.index! + match[0].length + (body[match.index! + match[0].length] === "\n" ? 1 : 0);
|
|
136
114
|
const nextHeading = body.slice(sectionStart).search(/^##\s+.+[^\S\n]*$/m);
|
|
137
|
-
const section = body.slice(
|
|
138
|
-
sectionStart,
|
|
139
|
-
nextHeading >= 0 ? sectionStart + nextHeading : body.length,
|
|
140
|
-
);
|
|
115
|
+
const section = body.slice(sectionStart, nextHeading >= 0 ? sectionStart + nextHeading : body.length);
|
|
141
116
|
for (const line of section.split("\n")) {
|
|
142
117
|
const trimmed = line.trim();
|
|
143
118
|
if (!trimmed) continue;
|
|
@@ -148,58 +123,39 @@ function isStepHeading(body: string, match: RegExpMatchArray): boolean {
|
|
|
148
123
|
return false;
|
|
149
124
|
}
|
|
150
125
|
|
|
151
|
-
function parseWorkflowFile(
|
|
152
|
-
filePath: string,
|
|
153
|
-
source: ResourceSource,
|
|
154
|
-
): WorkflowConfig | undefined {
|
|
126
|
+
function parseWorkflowFile(filePath: string, source: ResourceSource): WorkflowConfig | undefined {
|
|
155
127
|
try {
|
|
156
128
|
const content = fs.readFileSync(filePath, "utf-8");
|
|
157
129
|
const { frontmatter, body } = parseFrontmatter(content);
|
|
158
|
-
const name =
|
|
159
|
-
frontmatter.name?.trim() || path.basename(filePath, ".workflow.md");
|
|
130
|
+
const name = frontmatter.name?.trim() || path.basename(filePath, ".workflow.md");
|
|
160
131
|
const matches = [...body.matchAll(/^##\s+(.+)[^\S\n]*$/gm)];
|
|
161
132
|
const explicitStepIndexes = new Set(
|
|
162
133
|
matches
|
|
163
|
-
.map((match, index) =>
|
|
164
|
-
isStepHeading(body, match) ? index : undefined,
|
|
165
|
-
)
|
|
134
|
+
.map((match, index) => (isStepHeading(body, match) ? index : undefined))
|
|
166
135
|
.filter((index): index is number => index !== undefined),
|
|
167
136
|
);
|
|
168
137
|
const effectiveMatches = matches.filter(
|
|
169
138
|
(match, index) =>
|
|
170
|
-
explicitStepIndexes.has(index) ||
|
|
171
|
-
(hasSectionBoundary(body, match) &&
|
|
172
|
-
/^[a-z][a-z0-9-]*$/.test(match[1]?.trim() ?? "")),
|
|
139
|
+
explicitStepIndexes.has(index) || (hasSectionBoundary(body, match) && /^[a-z][a-z0-9-]*$/.test(match[1]?.trim() ?? "")),
|
|
173
140
|
);
|
|
174
|
-
const parseMatches = explicitStepIndexes.size
|
|
175
|
-
? effectiveMatches
|
|
176
|
-
: matches;
|
|
141
|
+
const parseMatches = explicitStepIndexes.size ? effectiveMatches : matches;
|
|
177
142
|
const steps: WorkflowStep[] = [];
|
|
178
143
|
for (let i = 0; i < parseMatches.length; i++) {
|
|
179
144
|
const match = parseMatches[i]!;
|
|
180
145
|
const id = match[1]!.trim();
|
|
181
|
-
const sectionStart =
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
(body[match.index! + match[0].length] === "\n" ? 1 : 0);
|
|
185
|
-
const sectionEnd =
|
|
186
|
-
i + 1 < parseMatches.length
|
|
187
|
-
? parseMatches[i + 1]!.index!
|
|
188
|
-
: body.length;
|
|
189
|
-
const step = parseStepSection(
|
|
190
|
-
id,
|
|
191
|
-
body.slice(sectionStart, sectionEnd),
|
|
192
|
-
);
|
|
146
|
+
const sectionStart = match.index! + match[0].length + (body[match.index! + match[0].length] === "\n" ? 1 : 0);
|
|
147
|
+
const sectionEnd = i + 1 < parseMatches.length ? parseMatches[i + 1]!.index! : body.length;
|
|
148
|
+
const step = parseStepSection(id, body.slice(sectionStart, sectionEnd));
|
|
193
149
|
if (step) steps.push(step);
|
|
194
150
|
}
|
|
195
151
|
return {
|
|
196
152
|
name,
|
|
197
|
-
description:
|
|
198
|
-
frontmatter.description?.trim() || "No description provided.",
|
|
153
|
+
description: frontmatter.description?.trim() || "No description provided.",
|
|
199
154
|
source,
|
|
200
155
|
filePath,
|
|
201
156
|
maxConcurrency: parseOptionalInteger(frontmatter.maxConcurrency),
|
|
202
157
|
topology: parseTopology(frontmatter.topology),
|
|
158
|
+
coalesceMicroTasks: parseOptionalBoolean(frontmatter.coalesceMicroTasks),
|
|
203
159
|
steps,
|
|
204
160
|
};
|
|
205
161
|
} catch {
|
|
@@ -207,37 +163,25 @@ function parseWorkflowFile(
|
|
|
207
163
|
}
|
|
208
164
|
}
|
|
209
165
|
|
|
210
|
-
function readWorkflowDir(
|
|
211
|
-
dir: string,
|
|
212
|
-
source: ResourceSource,
|
|
213
|
-
): WorkflowConfig[] {
|
|
166
|
+
function readWorkflowDir(dir: string, source: ResourceSource): WorkflowConfig[] {
|
|
214
167
|
if (!fs.existsSync(dir)) return [];
|
|
215
168
|
const staticWorkflows = fs
|
|
216
169
|
.readdirSync(dir)
|
|
217
170
|
.filter((entry) => entry.endsWith(".workflow.md"))
|
|
218
171
|
.map((entry) => parseWorkflowFile(path.join(dir, entry), source))
|
|
219
|
-
.filter(
|
|
220
|
-
(workflow): workflow is WorkflowConfig => workflow !== undefined,
|
|
221
|
-
)
|
|
172
|
+
.filter((workflow): workflow is WorkflowConfig => workflow !== undefined)
|
|
222
173
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
223
174
|
// P2: also discover dynamic workflows (*.dwf.ts). A .dwf.ts's default export is a JS orchestrator.
|
|
224
175
|
const dynamicWorkflows = fs
|
|
225
176
|
.readdirSync(dir)
|
|
226
177
|
.filter((entry) => entry.endsWith(".dwf.ts"))
|
|
227
178
|
.map((entry) => parseDynamicWorkflowFile(path.join(dir, entry), source))
|
|
228
|
-
.filter(
|
|
229
|
-
|
|
230
|
-
);
|
|
231
|
-
return [...staticWorkflows, ...dynamicWorkflows].sort((a, b) =>
|
|
232
|
-
a.name.localeCompare(b.name),
|
|
233
|
-
);
|
|
179
|
+
.filter((workflow): workflow is WorkflowConfig => workflow !== undefined);
|
|
180
|
+
return [...staticWorkflows, ...dynamicWorkflows].sort((a, b) => a.name.localeCompare(b.name));
|
|
234
181
|
}
|
|
235
182
|
|
|
236
183
|
/** P2: a .dwf.ts is a dynamic workflow. Name = filename stem; script = the file itself. */
|
|
237
|
-
function parseDynamicWorkflowFile(
|
|
238
|
-
filePath: string,
|
|
239
|
-
source: ResourceSource,
|
|
240
|
-
): WorkflowConfig | undefined {
|
|
184
|
+
function parseDynamicWorkflowFile(filePath: string, source: ResourceSource): WorkflowConfig | undefined {
|
|
241
185
|
try {
|
|
242
186
|
const basename = path.basename(filePath, ".dwf.ts");
|
|
243
187
|
return {
|
|
@@ -259,28 +203,16 @@ export function discoverWorkflows(cwd: string): WorkflowDiscoveryResult {
|
|
|
259
203
|
return { builtin: [], user: [], project: [] };
|
|
260
204
|
}
|
|
261
205
|
return {
|
|
262
|
-
builtin: readWorkflowDir(
|
|
263
|
-
path.join(packageRoot(), "workflows"),
|
|
264
|
-
"builtin",
|
|
265
|
-
),
|
|
206
|
+
builtin: readWorkflowDir(path.join(packageRoot(), "workflows"), "builtin"),
|
|
266
207
|
user: readWorkflowDir(path.join(userPiRoot(), "workflows"), "user"),
|
|
267
|
-
project: readWorkflowDir(
|
|
268
|
-
path.join(projectCrewRoot(cwd), "workflows"),
|
|
269
|
-
"project",
|
|
270
|
-
),
|
|
208
|
+
project: readWorkflowDir(path.join(projectCrewRoot(cwd), "workflows"), "project"),
|
|
271
209
|
};
|
|
272
210
|
}
|
|
273
211
|
|
|
274
|
-
export function allWorkflows(
|
|
275
|
-
discovery: WorkflowDiscoveryResult | undefined,
|
|
276
|
-
): WorkflowConfig[] {
|
|
212
|
+
export function allWorkflows(discovery: WorkflowDiscoveryResult | undefined): WorkflowConfig[] {
|
|
277
213
|
if (!discovery) return [];
|
|
278
214
|
const byName = new Map<string, WorkflowConfig>();
|
|
279
|
-
for (const workflow of [
|
|
280
|
-
...discovery.project,
|
|
281
|
-
...discovery.builtin,
|
|
282
|
-
...discovery.user,
|
|
283
|
-
]) {
|
|
215
|
+
for (const workflow of [...discovery.project, ...discovery.builtin, ...discovery.user]) {
|
|
284
216
|
byName.set(workflow.name, workflow);
|
|
285
217
|
}
|
|
286
218
|
return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* - Debugging (inspect intermediate outputs)
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
13
13
|
import path from "node:path";
|
|
14
14
|
import { logInternalError } from "../utils/internal-error.ts";
|
|
15
15
|
import { isSafePathId } from "../utils/safe-paths.ts";
|
|
@@ -55,12 +55,7 @@ export function ensureIntermediateDir(config: Partial<IntermediateStoreConfig> =
|
|
|
55
55
|
* @param data - Phase output data
|
|
56
56
|
* @returns Path to the written file
|
|
57
57
|
*/
|
|
58
|
-
export function writeIntermediate(
|
|
59
|
-
config: Partial<IntermediateStoreConfig>,
|
|
60
|
-
phase: string,
|
|
61
|
-
stepId: string,
|
|
62
|
-
data: unknown,
|
|
63
|
-
): string {
|
|
58
|
+
export function writeIntermediate(config: Partial<IntermediateStoreConfig>, phase: string, stepId: string, data: unknown): string {
|
|
64
59
|
const dir = ensureIntermediateDir(config);
|
|
65
60
|
const filename = `${phase}-${stepId}.json`;
|
|
66
61
|
const filePath = path.join(dir, filename);
|
|
@@ -84,11 +79,7 @@ export function writeIntermediate(
|
|
|
84
79
|
* @param stepId - Step ID
|
|
85
80
|
* @returns Parsed intermediate output, or undefined if not found
|
|
86
81
|
*/
|
|
87
|
-
export function readIntermediate(
|
|
88
|
-
config: Partial<IntermediateStoreConfig>,
|
|
89
|
-
phase: string,
|
|
90
|
-
stepId: string,
|
|
91
|
-
): IntermediateOutput | undefined {
|
|
82
|
+
export function readIntermediate(config: Partial<IntermediateStoreConfig>, phase: string, stepId: string): IntermediateOutput | undefined {
|
|
92
83
|
// M-2 fix (code-review 2026-06-23): validate phase/stepId before building the
|
|
93
84
|
// filename to prevent path traversal via a poisoned stepId.
|
|
94
85
|
if (!isSafePathId(phase) || !isSafePathId(stepId)) return undefined;
|
|
@@ -113,10 +104,7 @@ export function readIntermediate(
|
|
|
113
104
|
* Useful when you don't know the exact stepId but want the latest
|
|
114
105
|
* output from a phase (e.g., for incremental re-runs).
|
|
115
106
|
*/
|
|
116
|
-
export function readLatestIntermediate(
|
|
117
|
-
config: Partial<IntermediateStoreConfig>,
|
|
118
|
-
phase: string,
|
|
119
|
-
): IntermediateOutput | undefined {
|
|
107
|
+
export function readLatestIntermediate(config: Partial<IntermediateStoreConfig>, phase: string): IntermediateOutput | undefined {
|
|
120
108
|
const dir = config.intermediateDir ?? DEFAULT_CONFIG.intermediateDir;
|
|
121
109
|
if (!existsSync(dir)) return undefined;
|
|
122
110
|
|
|
@@ -168,10 +156,6 @@ export function cleanupIntermediates(config: Partial<IntermediateStoreConfig> =
|
|
|
168
156
|
/**
|
|
169
157
|
* Check if a phase has completed (intermediate exists).
|
|
170
158
|
*/
|
|
171
|
-
export function hasPhaseCompleted(
|
|
172
|
-
config: Partial<IntermediateStoreConfig>,
|
|
173
|
-
phase: string,
|
|
174
|
-
stepId: string,
|
|
175
|
-
): boolean {
|
|
159
|
+
export function hasPhaseCompleted(config: Partial<IntermediateStoreConfig>, phase: string, stepId: string): boolean {
|
|
176
160
|
return readIntermediate(config, phase, stepId) !== undefined;
|
|
177
161
|
}
|
|
@@ -11,10 +11,7 @@
|
|
|
11
11
|
// result they receive. This keeps the validator side-effect free and
|
|
12
12
|
// trivially testable.
|
|
13
13
|
|
|
14
|
-
import {
|
|
15
|
-
analyzeWorkflowTopology,
|
|
16
|
-
type WorkflowTopology,
|
|
17
|
-
} from "./topology-analyzer.ts";
|
|
14
|
+
import { analyzeWorkflowTopology, type WorkflowTopology } from "./topology-analyzer.ts";
|
|
18
15
|
import type { WorkflowConfig } from "./workflow-config.ts";
|
|
19
16
|
|
|
20
17
|
export interface PreflightOptions {
|
|
@@ -43,12 +40,7 @@ export interface PreflightResult {
|
|
|
43
40
|
recommendation: string;
|
|
44
41
|
}
|
|
45
42
|
|
|
46
|
-
function info(
|
|
47
|
-
topology: WorkflowTopology,
|
|
48
|
-
stepCount: number,
|
|
49
|
-
recommendation: string,
|
|
50
|
-
message: string,
|
|
51
|
-
): PreflightResult {
|
|
43
|
+
function info(topology: WorkflowTopology, stepCount: number, recommendation: string, message: string): PreflightResult {
|
|
52
44
|
return {
|
|
53
45
|
level: "info",
|
|
54
46
|
message,
|
|
@@ -59,12 +51,7 @@ function info(
|
|
|
59
51
|
};
|
|
60
52
|
}
|
|
61
53
|
|
|
62
|
-
function note(
|
|
63
|
-
topology: WorkflowTopology,
|
|
64
|
-
stepCount: number,
|
|
65
|
-
recommendation: string,
|
|
66
|
-
message: string,
|
|
67
|
-
): PreflightResult {
|
|
54
|
+
function note(topology: WorkflowTopology, stepCount: number, recommendation: string, message: string): PreflightResult {
|
|
68
55
|
return {
|
|
69
56
|
level: "note",
|
|
70
57
|
message,
|
|
@@ -75,13 +62,7 @@ function note(
|
|
|
75
62
|
};
|
|
76
63
|
}
|
|
77
64
|
|
|
78
|
-
function warn(
|
|
79
|
-
topology: WorkflowTopology,
|
|
80
|
-
stepCount: number,
|
|
81
|
-
recommendation: string,
|
|
82
|
-
message: string,
|
|
83
|
-
suggestion: string,
|
|
84
|
-
): PreflightResult {
|
|
65
|
+
function warn(topology: WorkflowTopology, stepCount: number, recommendation: string, message: string, suggestion: string): PreflightResult {
|
|
85
66
|
return {
|
|
86
67
|
level: "warn",
|
|
87
68
|
message,
|
|
@@ -108,21 +89,13 @@ function warn(
|
|
|
108
89
|
* No `block` level exists — there is no scenario where pi-crew hard-rejects a call.
|
|
109
90
|
* The agent always gets to decide.
|
|
110
91
|
*/
|
|
111
|
-
export function validateWorkflowUsage(
|
|
112
|
-
workflow: WorkflowConfig,
|
|
113
|
-
options: PreflightOptions = {},
|
|
114
|
-
): PreflightResult {
|
|
92
|
+
export function validateWorkflowUsage(workflow: WorkflowConfig, options: PreflightOptions = {}): PreflightResult {
|
|
115
93
|
const analysis = analyzeWorkflowTopology(workflow);
|
|
116
94
|
const { topology, stepCount, recommendation } = analysis;
|
|
117
95
|
|
|
118
96
|
// Rule 0: dynamic workflows are runtime-decided.
|
|
119
97
|
if (topology === "dynamic") {
|
|
120
|
-
return info(
|
|
121
|
-
topology,
|
|
122
|
-
stepCount,
|
|
123
|
-
recommendation,
|
|
124
|
-
"Dynamic workflow — runtime decides topology.",
|
|
125
|
-
);
|
|
98
|
+
return info(topology, stepCount, recommendation, "Dynamic workflow — runtime decides topology.");
|
|
126
99
|
}
|
|
127
100
|
|
|
128
101
|
// Rule 0b: explicit force-bypass acknowledged (still log it).
|
|
@@ -20,19 +20,9 @@
|
|
|
20
20
|
|
|
21
21
|
import type { WorkflowConfig, WorkflowStep } from "./workflow-config.ts";
|
|
22
22
|
|
|
23
|
-
export type WorkflowTopology =
|
|
24
|
-
| "single"
|
|
25
|
-
| "sequential"
|
|
26
|
-
| "concurrent"
|
|
27
|
-
| "complex-dag"
|
|
28
|
-
| "dynamic";
|
|
23
|
+
export type WorkflowTopology = "single" | "sequential" | "concurrent" | "complex-dag" | "dynamic";
|
|
29
24
|
|
|
30
|
-
export type TopologyRecommendation =
|
|
31
|
-
| "raw_agent"
|
|
32
|
-
| "fast_fix"
|
|
33
|
-
| "parallel_research"
|
|
34
|
-
| "implementation_adaptive"
|
|
35
|
-
| "any";
|
|
25
|
+
export type TopologyRecommendation = "raw_agent" | "fast_fix" | "parallel_research" | "implementation_adaptive" | "any";
|
|
36
26
|
|
|
37
27
|
export interface TopologyAnalysis {
|
|
38
28
|
topology: WorkflowTopology;
|
|
@@ -58,10 +48,7 @@ export function fanOutDegreeFromSteps(steps: WorkflowStep[]): number {
|
|
|
58
48
|
const counts = new Map<string, number>();
|
|
59
49
|
for (const step of steps) {
|
|
60
50
|
if (step.parallelGroup === undefined) continue;
|
|
61
|
-
counts.set(
|
|
62
|
-
step.parallelGroup,
|
|
63
|
-
(counts.get(step.parallelGroup) ?? 0) + 1,
|
|
64
|
-
);
|
|
51
|
+
counts.set(step.parallelGroup, (counts.get(step.parallelGroup) ?? 0) + 1);
|
|
65
52
|
}
|
|
66
53
|
let max = 0;
|
|
67
54
|
for (const count of counts.values()) if (count > max) max = count;
|
|
@@ -129,9 +116,7 @@ function hasMultiDeps(steps: WorkflowStep[]): boolean {
|
|
|
129
116
|
* Classify a workflow's topology. See file header for the rule order.
|
|
130
117
|
* Pure function — no I/O, no side effects, no exceptions.
|
|
131
118
|
*/
|
|
132
|
-
export function analyzeWorkflowTopology(
|
|
133
|
-
workflow: WorkflowConfig,
|
|
134
|
-
): TopologyAnalysis {
|
|
119
|
+
export function analyzeWorkflowTopology(workflow: WorkflowConfig): TopologyAnalysis {
|
|
135
120
|
// Chain/dynamic workflows: runtime decides the topology at execution time.
|
|
136
121
|
// Don't try to classify the empty `steps: []` (DynamicWorkflowConfig forces
|
|
137
122
|
// it to be empty).
|
|
@@ -186,8 +171,7 @@ export function analyzeWorkflowTopology(
|
|
|
186
171
|
if (stepCount === 1) {
|
|
187
172
|
topology = "single";
|
|
188
173
|
recommendation = "raw_agent";
|
|
189
|
-
reason =
|
|
190
|
-
"Single-task workflow: no concurrency or DAG structure to justify pi-crew overhead.";
|
|
174
|
+
reason = "Single-task workflow: no concurrency or DAG structure to justify pi-crew overhead.";
|
|
191
175
|
} else if (parallelGroupCount >= 1 && fanOutDegree >= 3) {
|
|
192
176
|
topology = "concurrent";
|
|
193
177
|
recommendation = "parallel_research";
|
|
@@ -53,12 +53,13 @@ export interface WorkflowConfig {
|
|
|
53
53
|
* Used by preflight-validator to enforce "don't use pi-crew for sequential chains".
|
|
54
54
|
* Valid values: 'single' | 'sequential' | 'concurrent' | 'complex-dag' | 'dynamic'.
|
|
55
55
|
* Absent = auto-classify from step structure (default). */
|
|
56
|
-
topology?:
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
56
|
+
topology?: "single" | "sequential" | "concurrent" | "complex-dag" | "dynamic";
|
|
57
|
+
/** Round 25 (M6): coalesce micro-tasks. Default false (off). When true,
|
|
58
|
+
* multiple ready tasks sharing role + cwd are grouped into a single
|
|
59
|
+
* multi-task worker prompt to reduce per-task cold-start cost. Disabled
|
|
60
|
+
* in v0.9.17 unless the workflow author opts in. See
|
|
61
|
+
* src/runtime/coalesce-tasks.ts. */
|
|
62
|
+
coalesceMicroTasks?: boolean;
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
/** A dynamic workflow (runtime === "dynamic"). steps is empty — the script is the source of truth. */
|