pi-crew 0.9.53 → 0.9.55
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 +45 -0
- package/package.json +6 -3
- package/scripts/clean-strip-types.mjs +60 -0
- package/src/adapters/claude-adapter.ts +23 -0
- package/src/adapters/codex-adapter.ts +21 -0
- package/src/adapters/cursor-adapter.ts +17 -0
- package/src/adapters/export-util.ts +143 -0
- package/src/adapters/index.ts +15 -0
- package/src/adapters/registry.ts +18 -0
- package/src/adapters/types.ts +23 -0
- package/src/agents/agent-config.ts +194 -0
- package/src/agents/agent-search.ts +98 -0
- package/src/agents/agent-serializer.ts +38 -0
- package/src/agents/discover-agents.ts +623 -0
- package/src/benchmark/benchmark-runner.ts +313 -0
- package/src/benchmark/feedback-loop.ts +73 -0
- package/src/config/config.ts +1270 -0
- package/src/config/defaults.ts +193 -0
- package/src/config/drift-detector.ts +290 -0
- package/src/config/markers.ts +330 -0
- package/src/config/resilient-parser.ts +117 -0
- package/src/config/role-tools.ts +118 -0
- package/src/config/suggestions.ts +75 -0
- package/src/config/types.ts +280 -0
- package/src/errors.ts +194 -0
- package/src/extension/action-suggestions.ts +117 -0
- package/src/extension/async-notifier.ts +179 -0
- package/src/extension/autonomous-policy.ts +209 -0
- package/src/extension/command-completions.ts +120 -0
- package/src/extension/context-status-injection.ts +185 -0
- package/src/extension/crew-autocomplete.ts +131 -0
- package/src/extension/crew-cleanup.ts +168 -0
- package/src/extension/crew-input-router.ts +93 -0
- package/src/extension/crew-shortcuts.ts +87 -0
- package/src/extension/crew-vibes/cat-frames.ts +18 -0
- package/src/extension/crew-vibes/config.ts +195 -0
- package/src/extension/crew-vibes/figures.ts +101 -0
- package/src/extension/crew-vibes/font-detect.ts +71 -0
- package/src/extension/crew-vibes/footer.ts +292 -0
- package/src/extension/crew-vibes/index.ts +432 -0
- package/src/extension/crew-vibes/provider-usage.ts +396 -0
- package/src/extension/crew-vibes/render.ts +206 -0
- package/src/extension/crew-vibes/speed.ts +286 -0
- package/src/extension/cross-extension-rpc.ts +350 -0
- package/src/extension/help.ts +62 -0
- package/src/extension/import-index.ts +74 -0
- package/src/extension/knowledge-injection.ts +402 -0
- package/src/extension/management.ts +571 -0
- package/src/extension/message-renderers.ts +108 -0
- package/src/extension/notification-router.ts +152 -0
- package/src/extension/notification-sink.ts +54 -0
- package/src/extension/pi-api.ts +56 -0
- package/src/extension/plan-orchestrate.ts +302 -0
- package/src/extension/project-init.ts +170 -0
- package/src/extension/register.ts +113 -0
- package/src/extension/registration/artifact-cleanup.ts +20 -0
- package/src/extension/registration/command-registration.ts +58 -0
- package/src/extension/registration/command-utils.ts +58 -0
- package/src/extension/registration/commands.ts +1228 -0
- package/src/extension/registration/compaction-guard.ts +333 -0
- package/src/extension/registration/context-builder.ts +135 -0
- package/src/extension/registration/crash-recovery-cache.ts +54 -0
- package/src/extension/registration/foreground-run-controller.ts +238 -0
- package/src/extension/registration/hook-registration.ts +119 -0
- package/src/extension/registration/lazy-configurers.ts +124 -0
- package/src/extension/registration/lifecycle-handlers.ts +923 -0
- package/src/extension/registration/lifecycle.ts +259 -0
- package/src/extension/registration/observability.ts +322 -0
- package/src/extension/registration/registration-types.ts +158 -0
- package/src/extension/registration/runtime-cleanup.ts +230 -0
- package/src/extension/registration/subagent-helpers.ts +125 -0
- package/src/extension/registration/subagent-manager-setup.ts +330 -0
- package/src/extension/registration/subagent-tools.ts +456 -0
- package/src/extension/registration/team-tool.ts +225 -0
- package/src/extension/registration/tool-registration.ts +50 -0
- package/src/extension/registration/ui.ts +172 -0
- package/src/extension/registration/viewers.ts +121 -0
- package/src/extension/registration/wire-cross-extension.ts +37 -0
- package/src/extension/result-watcher.ts +139 -0
- package/src/extension/rpc-hmac.ts +256 -0
- package/src/extension/run-bundle-schema.ts +104 -0
- package/src/extension/run-export.ts +97 -0
- package/src/extension/run-import.ts +168 -0
- package/src/extension/run-index.ts +131 -0
- package/src/extension/run-maintenance.ts +190 -0
- package/src/extension/session-summary.ts +18 -0
- package/src/extension/team-manager-command.ts +153 -0
- package/src/extension/team-onboard.ts +180 -0
- package/src/extension/team-recommendation.ts +288 -0
- package/src/extension/team-tool/anchor.ts +172 -0
- package/src/extension/team-tool/api.ts +1244 -0
- package/src/extension/team-tool/auto-summarize.ts +142 -0
- package/src/extension/team-tool/cache-control.ts +19 -0
- package/src/extension/team-tool/cancel.ts +337 -0
- package/src/extension/team-tool/chain-dispatch.ts +95 -0
- package/src/extension/team-tool/chain-executor.ts +379 -0
- package/src/extension/team-tool/config-patch.ts +50 -0
- package/src/extension/team-tool/context.ts +149 -0
- package/src/extension/team-tool/destructive-gate.ts +52 -0
- package/src/extension/team-tool/dispatch/automate.ts +80 -0
- package/src/extension/team-tool/dispatch/control.ts +42 -0
- package/src/extension/team-tool/dispatch/index.ts +95 -0
- package/src/extension/team-tool/dispatch/manage.ts +161 -0
- package/src/extension/team-tool/dispatch/run.ts +53 -0
- package/src/extension/team-tool/dispatch/status.ts +187 -0
- package/src/extension/team-tool/doctor.ts +431 -0
- package/src/extension/team-tool/explain.ts +282 -0
- package/src/extension/team-tool/failure-patterns.ts +118 -0
- package/src/extension/team-tool/goal-wrap.ts +330 -0
- package/src/extension/team-tool/goal.ts +556 -0
- package/src/extension/team-tool/handle-schedule.ts +332 -0
- package/src/extension/team-tool/handle-settings.ts +520 -0
- package/src/extension/team-tool/health-monitor.ts +481 -0
- package/src/extension/team-tool/inspect.ts +88 -0
- package/src/extension/team-tool/intent-policy.ts +45 -0
- package/src/extension/team-tool/lifecycle-actions.ts +615 -0
- package/src/extension/team-tool/orchestrate.ts +98 -0
- package/src/extension/team-tool/parallel-dispatch.ts +183 -0
- package/src/extension/team-tool/plan.ts +50 -0
- package/src/extension/team-tool/respond.ts +150 -0
- package/src/extension/team-tool/run-deadline.ts +66 -0
- package/src/extension/team-tool/run-not-found.ts +49 -0
- package/src/extension/team-tool/run.ts +1051 -0
- package/src/extension/team-tool/status.ts +260 -0
- package/src/extension/team-tool/workflow-manage.ts +261 -0
- package/src/extension/team-tool-types.ts +26 -0
- package/src/extension/team-tool.ts +750 -0
- package/src/extension/tool-result.ts +16 -0
- package/src/extension/validate-resources.ts +108 -0
- package/src/hooks/registry.ts +200 -0
- package/src/hooks/types.ts +69 -0
- package/src/i18n.ts +212 -0
- package/src/observability/correlation.ts +50 -0
- package/src/observability/event-bus.ts +86 -0
- package/src/observability/event-to-metric.ts +170 -0
- package/src/observability/exporters/adapter.ts +27 -0
- package/src/observability/exporters/otlp-exporter.ts +356 -0
- package/src/observability/exporters/prometheus-exporter.ts +54 -0
- package/src/observability/metric-registry.ts +100 -0
- package/src/observability/metric-retention.ts +64 -0
- package/src/observability/metric-sink.ts +99 -0
- package/src/observability/metrics-primitives.ts +219 -0
- package/src/plugins/plugin-define.ts +6 -0
- package/src/plugins/plugin-registry.ts +32 -0
- package/src/plugins/plugins/index.ts +3 -0
- package/src/plugins/plugins/nextjs.ts +19 -0
- package/src/plugins/plugins/vite.ts +10 -0
- package/src/plugins/plugins/vitest.ts +9 -0
- package/src/prompt/prompt-runtime.ts +380 -0
- package/src/runtime/adaptive-plan.ts +563 -0
- package/src/runtime/agent-control.ts +215 -0
- package/src/runtime/agent-memory.ts +81 -0
- package/src/runtime/agent-observability.ts +122 -0
- package/src/runtime/anchor-manager.ts +475 -0
- package/src/runtime/async-marker.ts +32 -0
- package/src/runtime/async-runner.ts +381 -0
- package/src/runtime/attention-events.ts +28 -0
- package/src/runtime/auto-summarize.ts +344 -0
- package/src/runtime/background-runner.ts +840 -0
- package/src/runtime/batch-barrier.ts +147 -0
- package/src/runtime/broker-issuer.ts +39 -0
- package/src/runtime/cancellation-token.ts +99 -0
- package/src/runtime/cancellation.ts +99 -0
- package/src/runtime/capability-inventory.ts +137 -0
- package/src/runtime/chain-parser.ts +237 -0
- package/src/runtime/chain-runner.ts +606 -0
- package/src/runtime/checkpoint.ts +291 -0
- package/src/runtime/child-pi-constants.ts +42 -0
- package/src/runtime/child-pi-kill.ts +180 -0
- package/src/runtime/child-pi-pool.ts +68 -0
- package/src/runtime/child-pi-spawn.ts +287 -0
- package/src/runtime/child-pi-steering.ts +128 -0
- package/src/runtime/child-pi-streams.ts +296 -0
- package/src/runtime/child-pi-transcript.ts +169 -0
- package/src/runtime/child-pi.ts +1105 -0
- package/src/runtime/coalesce-tasks.ts +268 -0
- package/src/runtime/code-summary.ts +292 -0
- package/src/runtime/command-trace.ts +105 -0
- package/src/runtime/compact-pipeline.ts +56 -0
- package/src/runtime/compact-stages/ansi-strip-stage.ts +25 -0
- package/src/runtime/compact-stages/blank-collapse-stage.ts +31 -0
- package/src/runtime/compact-stages/deduplicate-stage.ts +34 -0
- package/src/runtime/compact-stages/head-snap-stage.ts +57 -0
- package/src/runtime/compact-stages/index.ts +23 -0
- package/src/runtime/compact-stages/tail-capture-stage.ts +77 -0
- package/src/runtime/compact-stages/truncation-stage.ts +74 -0
- package/src/runtime/compaction-summary.ts +278 -0
- package/src/runtime/completion-guard.ts +207 -0
- package/src/runtime/concurrency.ts +58 -0
- package/src/runtime/crash-classification.ts +229 -0
- package/src/runtime/crash-recovery.ts +594 -0
- package/src/runtime/crew-agent-records.ts +595 -0
- package/src/runtime/crew-agent-runtime.ts +62 -0
- package/src/runtime/crew-broker-child.ts +88 -0
- package/src/runtime/crew-broker-client.ts +673 -0
- package/src/runtime/crew-broker-tokens.ts +159 -0
- package/src/runtime/crew-broker.ts +1304 -0
- package/src/runtime/crew-hooks.ts +227 -0
- package/src/runtime/cross-extension-rpc.ts +143 -0
- package/src/runtime/custom-tools/irc-tool.ts +282 -0
- package/src/runtime/custom-tools/submit-result-tool.ts +102 -0
- package/src/runtime/deadletter.ts +47 -0
- package/src/runtime/delivery-coordinator.ts +211 -0
- package/src/runtime/delta-conflict.ts +348 -0
- package/src/runtime/deterministic-ast.ts +161 -0
- package/src/runtime/diagnostic-export.ts +171 -0
- package/src/runtime/direct-run.ts +45 -0
- package/src/runtime/dwf-state-store.ts +102 -0
- package/src/runtime/dynamic-workflow-context.ts +1013 -0
- package/src/runtime/dynamic-workflow-runner.ts +325 -0
- package/src/runtime/effectiveness.ts +90 -0
- package/src/runtime/errors/crew-errors.ts +162 -0
- package/src/runtime/event-stream-bridge.ts +98 -0
- package/src/runtime/foreground-control.ts +193 -0
- package/src/runtime/foreground-watchdog.ts +132 -0
- package/src/runtime/global-worker-cap.ts +96 -0
- package/src/runtime/goal-achievement.ts +148 -0
- package/src/runtime/goal-evaluator.ts +365 -0
- package/src/runtime/goal-loop-runner.ts +825 -0
- package/src/runtime/goal-state-store.ts +219 -0
- package/src/runtime/green-contract.ts +55 -0
- package/src/runtime/group-join.ts +267 -0
- package/src/runtime/handoff-manager.ts +598 -0
- package/src/runtime/heartbeat-gradient.ts +36 -0
- package/src/runtime/heartbeat-watcher.ts +239 -0
- package/src/runtime/hidden-handoff.ts +407 -0
- package/src/runtime/important-line-classifier.ts +140 -0
- package/src/runtime/intercom-bridge.ts +187 -0
- package/src/runtime/iteration-hooks.ts +305 -0
- package/src/runtime/live-agent-control.ts +136 -0
- package/src/runtime/live-agent-manager.ts +704 -0
- package/src/runtime/live-control-realtime.ts +56 -0
- package/src/runtime/live-extension-bridge.ts +148 -0
- package/src/runtime/live-irc.ts +97 -0
- package/src/runtime/live-session-health.ts +108 -0
- package/src/runtime/live-session-runtime.ts +1146 -0
- package/src/runtime/loop-gates.ts +128 -0
- package/src/runtime/manifest-cache.ts +375 -0
- package/src/runtime/mcp-proxy.ts +105 -0
- package/src/runtime/metric-parser.ts +36 -0
- package/src/runtime/model-fallback.ts +409 -0
- package/src/runtime/model-resolver.ts +126 -0
- package/src/runtime/model-scope.ts +158 -0
- package/src/runtime/orphan-worker-registry.ts +465 -0
- package/src/runtime/output-validator.ts +202 -0
- package/src/runtime/overflow-recovery.ts +206 -0
- package/src/runtime/parallel-research.ts +68 -0
- package/src/runtime/parallel-utils.ts +160 -0
- package/src/runtime/parent-guard.ts +134 -0
- package/src/runtime/path-overlap.ts +150 -0
- package/src/runtime/peer-dep.ts +292 -0
- package/src/runtime/per-write-validator.ts +181 -0
- package/src/runtime/phase-progress.ts +217 -0
- package/src/runtime/phase-tracker.ts +385 -0
- package/src/runtime/pi-args.ts +655 -0
- package/src/runtime/pi-json-output.ts +170 -0
- package/src/runtime/pi-spawn.ts +273 -0
- package/src/runtime/pipeline-runner.ts +523 -0
- package/src/runtime/plan-templates.ts +201 -0
- package/src/runtime/policy-engine.ts +115 -0
- package/src/runtime/post-checks.ts +142 -0
- package/src/runtime/post-exit-stdio-guard.ts +109 -0
- package/src/runtime/process-lifecycle.ts +491 -0
- package/src/runtime/process-status.ts +154 -0
- package/src/runtime/progress-event-coalescer.ts +44 -0
- package/src/runtime/progress-tracker.ts +124 -0
- package/src/runtime/prose-compressor.ts +162 -0
- package/src/runtime/recovery-recipes.ts +203 -0
- package/src/runtime/replace.ts +570 -0
- package/src/runtime/resilient-edit.ts +153 -0
- package/src/runtime/result-extractor.ts +217 -0
- package/src/runtime/retry-executor.ts +109 -0
- package/src/runtime/retry-runner.ts +336 -0
- package/src/runtime/role-permission.ts +59 -0
- package/src/runtime/run-coalesced-task-group.ts +308 -0
- package/src/runtime/run-drift.ts +219 -0
- package/src/runtime/run-tracker.ts +116 -0
- package/src/runtime/run-worker.ts +78 -0
- package/src/runtime/runtime-policy.ts +29 -0
- package/src/runtime/runtime-resolver.ts +172 -0
- package/src/runtime/runtime-warmup.ts +160 -0
- package/src/runtime/scheduler.ts +353 -0
- package/src/runtime/semaphore.ts +141 -0
- package/src/runtime/sensitive-paths.ts +93 -0
- package/src/runtime/session-resources.ts +25 -0
- package/src/runtime/session-snapshot.ts +59 -0
- package/src/runtime/session-usage.ts +79 -0
- package/src/runtime/settings-store.ts +155 -0
- package/src/runtime/sidechain-output.ts +35 -0
- package/src/runtime/single-agent-compose.ts +84 -0
- package/src/runtime/skill-effectiveness.ts +524 -0
- package/src/runtime/skill-instructions.ts +394 -0
- package/src/runtime/stale-reconciler.ts +680 -0
- package/src/runtime/stream-preview.ts +184 -0
- package/src/runtime/streaming-output.ts +50 -0
- package/src/runtime/subagent-manager.ts +561 -0
- package/src/runtime/subprocess-tool-registry.ts +70 -0
- package/src/runtime/supervisor-contact.ts +64 -0
- package/src/runtime/task-display.ts +52 -0
- package/src/runtime/task-graph-scheduler.ts +227 -0
- package/src/runtime/task-graph.ts +290 -0
- package/src/runtime/task-health.ts +83 -0
- package/src/runtime/task-id.ts +161 -0
- package/src/runtime/task-output-context.ts +602 -0
- package/src/runtime/task-packet.ts +268 -0
- package/src/runtime/task-quality.ts +199 -0
- package/src/runtime/task-runner/capabilities.ts +78 -0
- package/src/runtime/task-runner/child-executor.ts +790 -0
- package/src/runtime/task-runner/context-retrieval.ts +163 -0
- package/src/runtime/task-runner/live-executor.ts +227 -0
- package/src/runtime/task-runner/output-splitter.ts +152 -0
- package/src/runtime/task-runner/post-execution.ts +480 -0
- package/src/runtime/task-runner/pre-execution.ts +365 -0
- package/src/runtime/task-runner/progress.ts +157 -0
- package/src/runtime/task-runner/prompt-builder.ts +278 -0
- package/src/runtime/task-runner/prompt-pipeline.ts +88 -0
- package/src/runtime/task-runner/result-utils.ts +16 -0
- package/src/runtime/task-runner/retrieval-orchestrator.ts +310 -0
- package/src/runtime/task-runner/run-projection.ts +125 -0
- package/src/runtime/task-runner/scaffold-executor.ts +25 -0
- package/src/runtime/task-runner/state-helpers.ts +176 -0
- package/src/runtime/task-runner/tail-read.ts +34 -0
- package/src/runtime/task-runner.ts +216 -0
- package/src/runtime/team-runner-artifacts.ts +13 -0
- package/src/runtime/team-runner.ts +2396 -0
- package/src/runtime/tool-output-pruner.ts +333 -0
- package/src/runtime/tool-progress.ts +278 -0
- package/src/runtime/usage-tracker.ts +73 -0
- package/src/runtime/verification-gates.ts +579 -0
- package/src/runtime/verification-integrity.ts +108 -0
- package/src/runtime/verification-worktree.ts +186 -0
- package/src/runtime/worker-heartbeat.ts +25 -0
- package/src/runtime/worker-startup.ts +83 -0
- package/src/runtime/workflow-state.ts +195 -0
- package/src/runtime/workspace-lock.ts +443 -0
- package/src/runtime/workspace-tree.ts +312 -0
- package/src/runtime/yield-handler.ts +224 -0
- package/src/runtime/zombie-scanner.ts +298 -0
- package/src/schema/config-schema.ts +327 -0
- package/src/schema/team-tool-schema.ts +492 -0
- package/src/schema/validation-types.ts +159 -0
- package/src/skills/discover-skills.ts +203 -0
- package/src/skills/skill-templates.ts +456 -0
- package/src/skills/validate.ts +285 -0
- package/src/state/active-run-registry.ts +439 -0
- package/src/state/artifact-store.ts +176 -0
- package/src/state/atomic-write.ts +970 -0
- package/src/state/blob-store.ts +308 -0
- package/src/state/contracts.ts +160 -0
- package/src/state/crew-init.ts +269 -0
- package/src/state/decision-ledger.ts +372 -0
- package/src/state/event-log-rotation.ts +399 -0
- package/src/state/event-log.ts +1465 -0
- package/src/state/event-reconstructor.ts +229 -0
- package/src/state/gitignore-manager.ts +46 -0
- package/src/state/health-store.ts +79 -0
- package/src/state/hook-instinct-bridge.ts +94 -0
- package/src/state/hook-integrations.ts +51 -0
- package/src/state/instinct-store.ts +275 -0
- package/src/state/jsonl-writer.ts +107 -0
- package/src/state/locks.ts +562 -0
- package/src/state/mailbox.ts +916 -0
- package/src/state/observation-store.ts +176 -0
- package/src/state/run-cache.ts +193 -0
- package/src/state/run-graph.ts +183 -0
- package/src/state/run-metrics.ts +165 -0
- package/src/state/schedule.ts +166 -0
- package/src/state/session-state-map.ts +51 -0
- package/src/state/state-store.ts +973 -0
- package/src/state/task-claims.ts +61 -0
- package/src/state/tiered-eval.ts +480 -0
- package/src/state/types-eval.ts +58 -0
- package/src/state/types.ts +447 -0
- package/src/state/usage.ts +138 -0
- package/src/state/worker-atomic-writer.ts +198 -0
- package/src/subagents/async-entry.ts +1 -0
- package/src/subagents/index.ts +3 -0
- package/src/subagents/live/control.ts +1 -0
- package/src/subagents/live/manager.ts +1 -0
- package/src/subagents/live/realtime.ts +1 -0
- package/src/subagents/live/session-runtime.ts +1 -0
- package/src/subagents/manager.ts +1 -0
- package/src/subagents/spawn.ts +1 -0
- package/src/teams/discover-teams.ts +187 -0
- package/src/teams/team-config.ts +27 -0
- package/src/teams/team-serializer.ts +38 -0
- package/src/tools/safe-bash-extension.ts +54 -0
- package/src/tools/safe-bash.ts +505 -0
- package/src/types/diff.d.ts +18 -0
- package/src/types/new-api-types.ts +35 -0
- package/src/ui/agent-management-overlay.ts +160 -0
- package/src/ui/card-colors.ts +139 -0
- package/src/ui/crew-footer.ts +102 -0
- package/src/ui/crew-select-list.ts +112 -0
- package/src/ui/dashboard-panes/agents-pane.ts +164 -0
- package/src/ui/dashboard-panes/cancellation-pane.ts +66 -0
- package/src/ui/dashboard-panes/capability-pane.ts +77 -0
- package/src/ui/dashboard-panes/health-pane.ts +31 -0
- package/src/ui/dashboard-panes/mailbox-pane.ts +35 -0
- package/src/ui/dashboard-panes/metrics-pane.ts +37 -0
- package/src/ui/dashboard-panes/progress-pane.ts +38 -0
- package/src/ui/dashboard-panes/transcript-pane.ts +10 -0
- package/src/ui/deploy-bundled-themes.ts +71 -0
- package/src/ui/dwf-phase-display.ts +151 -0
- package/src/ui/dynamic-border.ts +35 -0
- package/src/ui/format-helpers.ts +31 -0
- package/src/ui/heartbeat-aggregator.ts +74 -0
- package/src/ui/key-utils.ts +42 -0
- package/src/ui/keybinding-map.ts +248 -0
- package/src/ui/layout-primitives.ts +106 -0
- package/src/ui/live-conversation-overlay.ts +183 -0
- package/src/ui/live-duration.ts +55 -0
- package/src/ui/live-run-sidebar.ts +293 -0
- package/src/ui/loaders.ts +6 -0
- package/src/ui/mascot.ts +449 -0
- package/src/ui/overlays/agent-picker-overlay.ts +66 -0
- package/src/ui/overlays/confirm-overlay.ts +60 -0
- package/src/ui/overlays/help-overlay.ts +177 -0
- package/src/ui/overlays/mailbox-compose-overlay.ts +181 -0
- package/src/ui/overlays/mailbox-compose-preview.ts +78 -0
- package/src/ui/overlays/mailbox-detail-overlay.ts +155 -0
- package/src/ui/pi-ui-compat.ts +68 -0
- package/src/ui/powerbar-publisher.ts +459 -0
- package/src/ui/render-coalescer.ts +101 -0
- package/src/ui/render-diff.ts +160 -0
- package/src/ui/render-scheduler.ts +278 -0
- package/src/ui/run-action-dispatcher.ts +182 -0
- package/src/ui/run-dashboard.ts +910 -0
- package/src/ui/run-event-bus.ts +381 -0
- package/src/ui/run-snapshot-cache.ts +1057 -0
- package/src/ui/settings-overlay.ts +1067 -0
- package/src/ui/shared-overlay-scheduler.ts +96 -0
- package/src/ui/snapshot-types.ts +90 -0
- package/src/ui/spinner.ts +17 -0
- package/src/ui/status-colors.ts +143 -0
- package/src/ui/syntax-highlight.ts +136 -0
- package/src/ui/terminal-status.ts +269 -0
- package/src/ui/theme-adapter.ts +271 -0
- package/src/ui/theme-discovery.ts +199 -0
- package/src/ui/tool-progress-formatter.ts +93 -0
- package/src/ui/tool-renderers/brief-mode.ts +225 -0
- package/src/ui/tool-renderers/index.ts +726 -0
- package/src/ui/transcript-cache.ts +128 -0
- package/src/ui/transcript-entries.ts +256 -0
- package/src/ui/transcript-viewer.ts +424 -0
- package/src/ui/widget/index.ts +418 -0
- package/src/ui/widget/widget-formatters.ts +182 -0
- package/src/ui/widget/widget-model.ts +110 -0
- package/src/ui/widget/widget-renderer.ts +182 -0
- package/src/ui/widget/widget-types.ts +36 -0
- package/src/utils/bm25-search.ts +235 -0
- package/src/utils/completion-dedupe.ts +63 -0
- package/src/utils/conflict-detect.ts +668 -0
- package/src/utils/env-allowlist.ts +30 -0
- package/src/utils/env-filter.ts +155 -0
- package/src/utils/file-coalescer.ts +98 -0
- package/src/utils/fingerprint.ts +180 -0
- package/src/utils/frontmatter.ts +70 -0
- package/src/utils/fs-watch.ts +37 -0
- package/src/utils/gh-protocol.ts +556 -0
- package/src/utils/git.ts +260 -0
- package/src/utils/guards.ts +107 -0
- package/src/utils/ids.ts +24 -0
- package/src/utils/incremental-reader.ts +220 -0
- package/src/utils/internal-error.ts +10 -0
- package/src/utils/names.ts +36 -0
- package/src/utils/ndjson.ts +115 -0
- package/src/utils/paths.ts +227 -0
- package/src/utils/project-detector.ts +160 -0
- package/src/utils/redaction.ts +370 -0
- package/src/utils/resolve-shell.ts +36 -0
- package/src/utils/run-watcher-registry.ts +152 -0
- package/src/utils/safe-paths.ts +393 -0
- package/src/utils/scan-cache.ts +144 -0
- package/src/utils/session-utils.ts +110 -0
- package/src/utils/sleep.ts +54 -0
- package/src/utils/socket-path.ts +164 -0
- package/src/utils/sse-parser.ts +131 -0
- package/src/utils/task-name-generator.ts +337 -0
- package/src/utils/timings.ts +33 -0
- package/src/utils/token-counter.ts +200 -0
- package/src/utils/visual.ts +207 -0
- package/src/workflows/cost-estimator.ts +34 -0
- package/src/workflows/discover-workflows.ts +308 -0
- package/src/workflows/intermediate-store.ts +166 -0
- package/src/workflows/preflight-validator.ts +168 -0
- package/src/workflows/topology-analyzer.ts +203 -0
- package/src/workflows/validate-workflow.ts +50 -0
- package/src/workflows/workflow-config.ts +75 -0
- package/src/workflows/workflow-serializer.ts +32 -0
- package/src/worktree/branch-freshness.ts +112 -0
- package/src/worktree/cleanup.ts +341 -0
- package/src/worktree/worktree-manager.ts +1204 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { TeamRunManifest, TeamTaskState } from "../../state/types.ts";
|
|
2
|
+
|
|
3
|
+
export interface CancellationPaneOptions {
|
|
4
|
+
maxReasons?: number;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function renderCancellationPane(manifest: TeamRunManifest, tasks: TeamTaskState[], opts: CancellationPaneOptions = {}): string[] {
|
|
8
|
+
const maxReasons = opts.maxReasons ?? 5;
|
|
9
|
+
if (manifest.status !== "cancelled" && manifest.status !== "blocked") {
|
|
10
|
+
const cancellingTasks = tasks.filter((t) => t.status === "cancelled");
|
|
11
|
+
if (cancellingTasks.length === 0) return ["Cancellation pane: no active cancellations"];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const lines: string[] = ["Cancellation pane"];
|
|
15
|
+
|
|
16
|
+
if (manifest.status === "cancelled") {
|
|
17
|
+
lines.push(` Run status: cancelled`);
|
|
18
|
+
} else if (manifest.status === "blocked") {
|
|
19
|
+
lines.push(` Run status: blocked`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const cancelledTasks = tasks.filter((t) => t.status === "cancelled");
|
|
23
|
+
if (cancelledTasks.length > 0) {
|
|
24
|
+
lines.push(` Cancelled tasks (${cancelledTasks.length}):`);
|
|
25
|
+
for (const task of cancelledTasks.slice(0, maxReasons)) {
|
|
26
|
+
const reason = task.error ?? "unknown";
|
|
27
|
+
lines.push(` ✗ ${task.id}: ${reason}`);
|
|
28
|
+
}
|
|
29
|
+
if (cancelledTasks.length > maxReasons) {
|
|
30
|
+
lines.push(` ... and ${cancelledTasks.length - maxReasons} more`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (manifest.policyDecisions?.length) {
|
|
35
|
+
const decisions = manifest.policyDecisions.slice(0, maxReasons);
|
|
36
|
+
lines.push(` Policy decisions (${manifest.policyDecisions.length}):`);
|
|
37
|
+
for (const d of decisions) {
|
|
38
|
+
lines.push(` ${d.action}: ${d.message}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return lines;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* D-1 / L-2 — a one-line terminal-run reason for the dashboard detail row.
|
|
47
|
+
*
|
|
48
|
+
* Surfaces *why* a failed/cancelled/stopped run ended without forcing the
|
|
49
|
+
* user to switch panes. This also gives this module a real consumer (it was
|
|
50
|
+
* previously zero-importer dead code per the UI/UX review), wiring it in as
|
|
51
|
+
* the natural home for cancellation/failure reason display.
|
|
52
|
+
*
|
|
53
|
+
* Resolution order: structured `run.cancelled` event reason → first failed
|
|
54
|
+
* task's error → first policy-decision message.
|
|
55
|
+
*/
|
|
56
|
+
export function summarizeTerminalReason(
|
|
57
|
+
manifest: TeamRunManifest,
|
|
58
|
+
tasks: TeamTaskState[],
|
|
59
|
+
cancellationReason?: string,
|
|
60
|
+
): string | undefined {
|
|
61
|
+
if (cancellationReason) return cancellationReason;
|
|
62
|
+
const failed = tasks.find((task) => task.status === "failed" && task.error);
|
|
63
|
+
if (failed?.error) return failed.error;
|
|
64
|
+
if (manifest.policyDecisions?.length) return manifest.policyDecisions[0]?.message;
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { PiTeamsConfig } from "../../config/config.ts";
|
|
2
|
+
import type { CapabilityItem } from "../../runtime/capability-inventory.ts";
|
|
3
|
+
import { buildCapabilityInventory } from "../../runtime/capability-inventory.ts";
|
|
4
|
+
|
|
5
|
+
export interface CapabilityPaneOptions {
|
|
6
|
+
config?: PiTeamsConfig;
|
|
7
|
+
filter?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function kindIcon(kind: string): string {
|
|
11
|
+
switch (kind) {
|
|
12
|
+
case "team":
|
|
13
|
+
return "👥";
|
|
14
|
+
case "workflow":
|
|
15
|
+
return "📋";
|
|
16
|
+
case "agent":
|
|
17
|
+
return "🤖";
|
|
18
|
+
case "skill":
|
|
19
|
+
return "🔧";
|
|
20
|
+
case "tool":
|
|
21
|
+
return "🛠";
|
|
22
|
+
case "runtime":
|
|
23
|
+
return "⚙";
|
|
24
|
+
default:
|
|
25
|
+
return "•";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function stateLabel(state: string): string {
|
|
30
|
+
switch (state) {
|
|
31
|
+
case "active":
|
|
32
|
+
return "";
|
|
33
|
+
case "disabled":
|
|
34
|
+
return " [DISABLED]";
|
|
35
|
+
case "shadowed":
|
|
36
|
+
return " [SHADOWED]";
|
|
37
|
+
case "missing":
|
|
38
|
+
return " [MISSING]";
|
|
39
|
+
default:
|
|
40
|
+
return "";
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function renderCapabilityPane(cwd: string, opts: CapabilityPaneOptions = {}): string[] {
|
|
45
|
+
const inventory = buildCapabilityInventory(cwd, opts.config);
|
|
46
|
+
const filtered = opts.filter
|
|
47
|
+
? inventory.filter(
|
|
48
|
+
(item) =>
|
|
49
|
+
item.kind.includes(opts.filter!.toLowerCase()) ||
|
|
50
|
+
item.name.toLowerCase().includes(opts.filter!.toLowerCase()) ||
|
|
51
|
+
item.id.toLowerCase().includes(opts.filter!.toLowerCase()),
|
|
52
|
+
)
|
|
53
|
+
: inventory;
|
|
54
|
+
|
|
55
|
+
if (filtered.length === 0) return ["Capability pane: no items found"];
|
|
56
|
+
|
|
57
|
+
const byKind = new Map<string, CapabilityItem[]>();
|
|
58
|
+
for (const item of filtered) {
|
|
59
|
+
const group = byKind.get(item.kind) ?? [];
|
|
60
|
+
group.push(item);
|
|
61
|
+
byKind.set(item.kind, group);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const lines = [`Capability pane: ${filtered.length} item(s) (filter: ${opts.filter ?? "none"})`];
|
|
65
|
+
for (const [kind, items] of byKind) {
|
|
66
|
+
lines.push(` ${kindIcon(kind)} ${kind} (${items.length}):`);
|
|
67
|
+
for (const item of items.slice(0, 10)) {
|
|
68
|
+
const icon = item.state === "active" ? "✓" : "✗";
|
|
69
|
+
lines.push(` ${icon} ${item.name}${stateLabel(item.state)} [${item.source}]`);
|
|
70
|
+
}
|
|
71
|
+
if (items.length > 10) lines.push(` ... and ${items.length - 10} more`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const disabled = filtered.filter((i) => i.state === "disabled").length;
|
|
75
|
+
if (disabled > 0) lines.push(` Disabled: ${disabled}`);
|
|
76
|
+
return lines;
|
|
77
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { summarizeHeartbeats } from "../heartbeat-aggregator.ts";
|
|
2
|
+
import type { RunUiSnapshot } from "../snapshot-types.ts";
|
|
3
|
+
|
|
4
|
+
export interface HealthPaneOptions {
|
|
5
|
+
staleMs?: number;
|
|
6
|
+
deadMs?: number;
|
|
7
|
+
isForeground?: boolean;
|
|
8
|
+
now?: number | Date;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function seconds(ms: number): string {
|
|
12
|
+
return `${Math.round(ms / 1000)}s`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function renderHealthPane(snapshot: RunUiSnapshot | undefined, opts: HealthPaneOptions = {}): string[] {
|
|
16
|
+
if (!snapshot) return ["Health pane: snapshot unavailable"];
|
|
17
|
+
const summary = summarizeHeartbeats(snapshot, opts);
|
|
18
|
+
const lines = [
|
|
19
|
+
`Health pane: ${summary.healthy}/${summary.totalTasks} healthy · stale=${summary.stale} · dead=${summary.dead} · missing=${summary.missing}`,
|
|
20
|
+
];
|
|
21
|
+
if (summary.worstStaleMs > 0) lines.push(`Worst stale: ${seconds(summary.worstStaleMs)} ago`);
|
|
22
|
+
const hints: string[] = [];
|
|
23
|
+
const foreground = opts.isForeground !== false;
|
|
24
|
+
if ((summary.dead > 0 || summary.missing > 0) && foreground) hints.push("R recovery");
|
|
25
|
+
if ((summary.dead > 0 || summary.stale > 0) && foreground) hints.push("K kill stale");
|
|
26
|
+
hints.push("D diagnostic export");
|
|
27
|
+
lines.push(`Actions: ${hints.join(" · ")}`);
|
|
28
|
+
if (!foreground && (summary.dead > 0 || summary.missing > 0 || summary.stale > 0))
|
|
29
|
+
lines.push("Async run: R/K disabled — inspect process manually or use /team-api.");
|
|
30
|
+
return lines;
|
|
31
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { RunUiSnapshot } from "../snapshot-types.ts";
|
|
2
|
+
|
|
3
|
+
export function renderMailboxPane(snapshot: RunUiSnapshot | undefined): string[] {
|
|
4
|
+
if (!snapshot) return ["Mailbox pane: snapshot unavailable"];
|
|
5
|
+
const mailbox = snapshot.mailbox;
|
|
6
|
+
const approx = mailbox.approximate ? " · approximate (tail)" : "";
|
|
7
|
+
const lines: string[] = [
|
|
8
|
+
`Mailbox pane: inbox unread=${mailbox.inboxUnread} · outbox pending=${mailbox.outboxPending} · attention=${mailbox.needsAttention}${approx}`,
|
|
9
|
+
];
|
|
10
|
+
// Kind-separated breakdown
|
|
11
|
+
const kindParts: string[] = [];
|
|
12
|
+
const steer = mailbox.steerUnread ?? 0;
|
|
13
|
+
const followUp = mailbox.followUpUnread ?? 0;
|
|
14
|
+
const response = mailbox.responseUnread ?? 0;
|
|
15
|
+
const message = mailbox.messageUnread ?? 0;
|
|
16
|
+
if (steer > 0) kindParts.push(`steer=${steer}`);
|
|
17
|
+
if (followUp > 0) kindParts.push(`follow-up=${followUp}`);
|
|
18
|
+
if (response > 0) kindParts.push(`response=${response}`);
|
|
19
|
+
if (message > 0) kindParts.push(`message=${message}`);
|
|
20
|
+
if (kindParts.length > 0) {
|
|
21
|
+
lines.push(` Breakdown: ${kindParts.join(" · ")}`);
|
|
22
|
+
if (steer > 0) {
|
|
23
|
+
lines.push(" ⚠ Urgent: steering messages require immediate attention.");
|
|
24
|
+
}
|
|
25
|
+
if (followUp > 0) {
|
|
26
|
+
lines.push(` 📋 ${followUp} follow-up(s) pending review.`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (mailbox.needsAttention > 0) {
|
|
30
|
+
lines.push("Needs attention: press Enter for detail · A ack · N nudge · C compose · X ack all.");
|
|
31
|
+
} else {
|
|
32
|
+
lines.push("No mailbox items need attention. Press Enter for detail or C compose.");
|
|
33
|
+
}
|
|
34
|
+
return lines;
|
|
35
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { MetricRegistry } from "../../observability/metric-registry.ts";
|
|
2
|
+
import type { HistogramPoint, MetricLabels, MetricPoint } from "../../observability/metrics-primitives.ts";
|
|
3
|
+
import type { RunUiSnapshot } from "../snapshot-types.ts";
|
|
4
|
+
|
|
5
|
+
export interface MetricsPaneOptions {
|
|
6
|
+
registry?: MetricRegistry;
|
|
7
|
+
maxCounters?: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function labelsText(labels: MetricLabels): string {
|
|
11
|
+
const entries = Object.entries(labels);
|
|
12
|
+
return entries.length ? `{${entries.map(([key, value]) => `${key}=${value}`).join(",")}}` : "";
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function isHistogramPoint(point: MetricPoint | HistogramPoint): point is HistogramPoint {
|
|
16
|
+
return "quantiles" in point;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function renderMetricsPane(_snapshot: RunUiSnapshot | undefined, opts: MetricsPaneOptions = {}): string[] {
|
|
20
|
+
if (!opts.registry) return ["Metrics pane: registry unavailable"];
|
|
21
|
+
const snapshots = opts.registry.snapshot();
|
|
22
|
+
if (!snapshots.length) return ["Metrics pane: no metrics recorded"];
|
|
23
|
+
const lines = ["Metrics pane: top metrics"];
|
|
24
|
+
for (const snapshot of snapshots.slice(0, opts.maxCounters ?? 10)) {
|
|
25
|
+
const first = snapshot.values[0];
|
|
26
|
+
if (!first) {
|
|
27
|
+
lines.push(`${snapshot.name}: empty`);
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (isHistogramPoint(first))
|
|
31
|
+
lines.push(
|
|
32
|
+
`${snapshot.name}${labelsText(first.labels)} count=${first.count} p95=${Number.isFinite(first.quantiles.p95) ? Math.round(first.quantiles.p95) : "n/a"}`,
|
|
33
|
+
);
|
|
34
|
+
else lines.push(`${snapshot.name}${labelsText(first.labels)} ${first.value}`);
|
|
35
|
+
}
|
|
36
|
+
return lines;
|
|
37
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { computePhaseProgress, formatPhaseProgressLine } from "../../runtime/phase-progress.ts";
|
|
2
|
+
import { renderDwfPhaseLines } from "../dwf-phase-display.ts";
|
|
3
|
+
import type { RunUiSnapshot } from "../snapshot-types.ts";
|
|
4
|
+
|
|
5
|
+
export function renderProgressPane(snapshot: RunUiSnapshot | undefined): string[] {
|
|
6
|
+
if (!snapshot) return ["Progress pane: snapshot unavailable"];
|
|
7
|
+
const progress = snapshot.progress;
|
|
8
|
+
const groupJoins = snapshot.groupJoins ?? [];
|
|
9
|
+
const groupJoinLines = groupJoins.length
|
|
10
|
+
? groupJoins.map((item) => `group join ${item.partial ? "partial" : "completed"}: ${item.requestId} ack=${item.ack}`)
|
|
11
|
+
: ["group joins: none"];
|
|
12
|
+
const cancellationLine = snapshot.cancellationReason ? [`cancelled: reason=${snapshot.cancellationReason}`] : [];
|
|
13
|
+
const runProgress = computePhaseProgress(snapshot.tasks);
|
|
14
|
+
const phaseLines =
|
|
15
|
+
runProgress.phases.length > 0
|
|
16
|
+
? runProgress.phases.map((p) => {
|
|
17
|
+
const done = p.completed + p.failed;
|
|
18
|
+
const status = p.running > 0 ? "running" : p.queued > 0 ? "queued" : done >= p.total ? "done" : "waiting";
|
|
19
|
+
return ` Phase ${p.index + 1} ${p.phase}: ${p.percentage}% (${done}/${p.total}) [${status}]`;
|
|
20
|
+
})
|
|
21
|
+
: [];
|
|
22
|
+
const phaseHeader = phaseLines.length > 0 ? [formatPhaseProgressLine(runProgress), ...phaseLines] : [];
|
|
23
|
+
// DWF logical phases (round-15 P1-4): derived from dwf.phase_* events.
|
|
24
|
+
// Null/absent for non-DWF runs → zero visible change.
|
|
25
|
+
const dwfPhaseLines = snapshot.dwfPhaseState ? renderDwfPhaseLines(snapshot.dwfPhaseState) : [];
|
|
26
|
+
return [
|
|
27
|
+
`Progress pane: ${progress.completed}/${progress.total} completed · running=${progress.running} queued=${progress.queued} failed=${progress.failed}`,
|
|
28
|
+
...dwfPhaseLines,
|
|
29
|
+
...phaseHeader,
|
|
30
|
+
...cancellationLine,
|
|
31
|
+
...groupJoinLines,
|
|
32
|
+
...snapshot.recentEvents.slice(-10).map((event) => {
|
|
33
|
+
const seq = event.metadata?.seq !== undefined ? `#${event.metadata.seq}` : "#?";
|
|
34
|
+
return `${seq} ${event.time} ${event.type}${event.taskId ? ` ${event.taskId}` : ""}${event.message ? ` · ${event.message}` : ""}`;
|
|
35
|
+
}),
|
|
36
|
+
...(snapshot.recentEvents.length ? [] : ["No recent events"]),
|
|
37
|
+
];
|
|
38
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { RunUiSnapshot } from "../snapshot-types.ts";
|
|
2
|
+
|
|
3
|
+
export function renderTranscriptPane(snapshot: RunUiSnapshot | undefined): string[] {
|
|
4
|
+
if (!snapshot) return ["Output pane: snapshot unavailable"];
|
|
5
|
+
return [
|
|
6
|
+
`Output pane: ${snapshot.recentOutputLines.length} recent lines · press v for transcript viewer · o for raw output`,
|
|
7
|
+
...snapshot.recentOutputLines.slice(-12).map((line) => `⎿ ${line}`),
|
|
8
|
+
...(snapshot.recentOutputLines.length ? [] : ["No recent output"]),
|
|
9
|
+
];
|
|
10
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deploy pi-crew's bundled themes to ~/.pi/agent/themes/ so Pi's theme
|
|
3
|
+
* loader discovers them (Pi scans that directory for custom themes).
|
|
4
|
+
*
|
|
5
|
+
* Best-effort and idempotent: compares content to avoid unnecessary writes,
|
|
6
|
+
* logs errors but never crashes registration.
|
|
7
|
+
*/
|
|
8
|
+
import * as fs from "node:fs";
|
|
9
|
+
import * as path from "node:path";
|
|
10
|
+
import { packageRoot, userPiRoot } from "../utils/paths.ts";
|
|
11
|
+
|
|
12
|
+
/** Directory containing pi-crew's bundled theme JSON files. */
|
|
13
|
+
function bundledThemesDir(): string {
|
|
14
|
+
return path.join(packageRoot(), "themes");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Target directory: ~/.pi/agent/themes/ (where Pi loads custom themes from). */
|
|
18
|
+
function customThemesDir(): string {
|
|
19
|
+
return path.join(userPiRoot(), "themes");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function readIfExists(filePath: string): string | undefined {
|
|
23
|
+
try {
|
|
24
|
+
return fs.readFileSync(filePath, "utf8");
|
|
25
|
+
} catch {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Copy bundled themes to ~/.pi/agent/themes/, skipping files whose content
|
|
32
|
+
* already matches (idempotent). Returns the number of themes deployed/updated.
|
|
33
|
+
*
|
|
34
|
+
* Safe to call on every registration. Never throws.
|
|
35
|
+
*/
|
|
36
|
+
export function deployBundledThemes(): number {
|
|
37
|
+
try {
|
|
38
|
+
const srcDir = bundledThemesDir();
|
|
39
|
+
const dstDir = customThemesDir();
|
|
40
|
+
|
|
41
|
+
if (!fs.existsSync(srcDir)) return 0;
|
|
42
|
+
|
|
43
|
+
const files = (fs.readdirSync(srcDir) as string[]).filter((f) => f.endsWith(".json"));
|
|
44
|
+
if (files.length === 0) return 0;
|
|
45
|
+
|
|
46
|
+
// Ensure target directory exists
|
|
47
|
+
fs.mkdirSync(dstDir, { recursive: true });
|
|
48
|
+
|
|
49
|
+
let deployed = 0;
|
|
50
|
+
for (const file of files) {
|
|
51
|
+
const srcPath = path.join(srcDir, file);
|
|
52
|
+
const dstPath = path.join(dstDir, file);
|
|
53
|
+
const srcContent = fs.readFileSync(srcPath, "utf8");
|
|
54
|
+
const dstContent = readIfExists(dstPath);
|
|
55
|
+
|
|
56
|
+
// Skip if content matches exactly (idempotent — no churn)
|
|
57
|
+
if (dstContent !== undefined && dstContent === srcContent) continue;
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
fs.writeFileSync(dstPath, srcContent, "utf8");
|
|
61
|
+
deployed++;
|
|
62
|
+
} catch {
|
|
63
|
+
// Individual file write failure — skip but continue
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return deployed;
|
|
68
|
+
} catch {
|
|
69
|
+
return 0;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DWF phase display — pure functions for extracting DWF phase state from the
|
|
3
|
+
* run's recent event window and rendering phase markers (▶/✓/⏸) in the
|
|
4
|
+
* progress pane.
|
|
5
|
+
*
|
|
6
|
+
* round-15 (P1-4). These functions are side-effect free and perform no I/O;
|
|
7
|
+
* they derive phase state entirely from the `recentEvents` slice already
|
|
8
|
+
* tailed by `run-snapshot-cache.ts`. Non-DWF runs (no `dwf.phase_*` events)
|
|
9
|
+
* yield `null`, so the progress pane stays unchanged for them.
|
|
10
|
+
*/
|
|
11
|
+
import type { TeamEvent } from "../state/event-log.ts";
|
|
12
|
+
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Types
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
export type DwfPhaseStatus = "running" | "completed" | "pending";
|
|
18
|
+
|
|
19
|
+
export interface DwfPhaseEntry {
|
|
20
|
+
/** Phase title as passed to `ctx.phase(title)`. */
|
|
21
|
+
name: string;
|
|
22
|
+
/** Derived lifecycle status for display. */
|
|
23
|
+
status: DwfPhaseStatus;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface DwfPhaseState {
|
|
27
|
+
/** Ordered list of phases seen in the event window (first-seen order). */
|
|
28
|
+
phases: DwfPhaseEntry[];
|
|
29
|
+
/** Name of the currently running phase, or null if all are completed. */
|
|
30
|
+
currentPhase: string | null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface RenderDwfPhaseOptions {
|
|
34
|
+
/** When true, render ASCII fallback markers instead of Unicode glyphs. */
|
|
35
|
+
ascii?: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Markers
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
|
|
42
|
+
// Unicode markers — consistent with the ▸/● glyphs already used in the dashboard.
|
|
43
|
+
const MARKER_RUNNING = "▶";
|
|
44
|
+
const MARKER_COMPLETED = "✓";
|
|
45
|
+
const MARKER_PENDING = "⏸";
|
|
46
|
+
|
|
47
|
+
// ASCII fallbacks for terminals that mis-render the Unicode glyphs above.
|
|
48
|
+
const MARKER_RUNNING_ASCII = "[>]";
|
|
49
|
+
const MARKER_COMPLETED_ASCII = "[v]";
|
|
50
|
+
const MARKER_PENDING_ASCII = "[ ]";
|
|
51
|
+
|
|
52
|
+
const DWF_PHASE_HEADER = " ── DWF Phases ──";
|
|
53
|
+
|
|
54
|
+
function markerFor(status: DwfPhaseStatus, ascii: boolean): string {
|
|
55
|
+
if (ascii) {
|
|
56
|
+
if (status === "running") return MARKER_RUNNING_ASCII;
|
|
57
|
+
if (status === "completed") return MARKER_COMPLETED_ASCII;
|
|
58
|
+
return MARKER_PENDING_ASCII;
|
|
59
|
+
}
|
|
60
|
+
if (status === "running") return MARKER_RUNNING;
|
|
61
|
+
if (status === "completed") return MARKER_COMPLETED;
|
|
62
|
+
return MARKER_PENDING;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
// Extraction
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
|
|
69
|
+
function phaseNameFrom(event: TeamEvent): string | undefined {
|
|
70
|
+
const phase = event.data?.phase;
|
|
71
|
+
return typeof phase === "string" && phase.length > 0 ? phase : undefined;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Derive DWF phase state from a (chronological) event window.
|
|
76
|
+
*
|
|
77
|
+
* Returns `null` when the window contains no `dwf.phase_started` /
|
|
78
|
+
* `dwf.phase_completed` events — i.e. a non-DWF run — so callers can short
|
|
79
|
+
* circuit phase rendering entirely.
|
|
80
|
+
*
|
|
81
|
+
* Because the window is bounded, the oldest phase events may have scrolled
|
|
82
|
+
* off. A phase whose `dwf.phase_started` scrolled off but whose
|
|
83
|
+
* `dwf.phase_completed` is still visible is still tracked (as completed). A
|
|
84
|
+
* phase that started but whose completion scrolled off and which is not the
|
|
85
|
+
* current phase is shown as `pending` (indeterminate).
|
|
86
|
+
*/
|
|
87
|
+
export function extractDwfPhaseState(events: TeamEvent[]): DwfPhaseState | null {
|
|
88
|
+
const order: string[] = [];
|
|
89
|
+
const seen = new Set<string>();
|
|
90
|
+
const completed = new Set<string>();
|
|
91
|
+
let currentPhase: string | null = null;
|
|
92
|
+
|
|
93
|
+
const remember = (phase: string): void => {
|
|
94
|
+
if (!seen.has(phase)) {
|
|
95
|
+
seen.add(phase);
|
|
96
|
+
order.push(phase);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
for (const event of events) {
|
|
101
|
+
if (event.type === "dwf.phase_started") {
|
|
102
|
+
const phase = phaseNameFrom(event);
|
|
103
|
+
if (phase === undefined) continue;
|
|
104
|
+
remember(phase);
|
|
105
|
+
// The most recent phase_started marks the running phase.
|
|
106
|
+
currentPhase = phase;
|
|
107
|
+
} else if (event.type === "dwf.phase_completed") {
|
|
108
|
+
const phase = phaseNameFrom(event);
|
|
109
|
+
if (phase === undefined) continue;
|
|
110
|
+
remember(phase);
|
|
111
|
+
completed.add(phase);
|
|
112
|
+
// If the phase just closed was the running one, it is no longer running.
|
|
113
|
+
if (phase === currentPhase) {
|
|
114
|
+
currentPhase = null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (order.length === 0) return null;
|
|
120
|
+
|
|
121
|
+
const phases: DwfPhaseEntry[] = order.map((name) => {
|
|
122
|
+
if (name === currentPhase) return { name, status: "running" as const };
|
|
123
|
+
if (completed.has(name)) return { name, status: "completed" as const };
|
|
124
|
+
return { name, status: "pending" as const };
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
return { phases, currentPhase };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
// Rendering
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Render phase marker lines for the progress pane.
|
|
136
|
+
*
|
|
137
|
+
* - One line per phase: ` ▶ Phase: Scan`, ` ✓ Phase: Scan`, ` ⏸ Phase: Review`.
|
|
138
|
+
* - A grouping header is emitted only when more than one phase is present.
|
|
139
|
+
* - When `options.ascii` is true, ASCII fallback markers are used.
|
|
140
|
+
*
|
|
141
|
+
* Always returns a non-empty array (the caller guarantees a non-null state).
|
|
142
|
+
*/
|
|
143
|
+
export function renderDwfPhaseLines(state: DwfPhaseState, options?: RenderDwfPhaseOptions): string[] {
|
|
144
|
+
const ascii = options?.ascii === true;
|
|
145
|
+
const lines: string[] = [];
|
|
146
|
+
if (state.phases.length > 1) lines.push(DWF_PHASE_HEADER);
|
|
147
|
+
for (const entry of state.phases) {
|
|
148
|
+
lines.push(` ${markerFor(entry.status, ascii)} Phase: ${entry.name}`);
|
|
149
|
+
}
|
|
150
|
+
return lines;
|
|
151
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { CrewTheme } from "./theme-adapter.ts";
|
|
2
|
+
|
|
3
|
+
export interface DynamicCrewBorderOptions {
|
|
4
|
+
color?: (value: string) => string;
|
|
5
|
+
char?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class DynamicCrewBorder {
|
|
9
|
+
private readonly theme: CrewTheme;
|
|
10
|
+
private readonly color?: (value: string) => string;
|
|
11
|
+
private readonly char: string;
|
|
12
|
+
private cachedWidth = -1;
|
|
13
|
+
private cachedLine = "";
|
|
14
|
+
|
|
15
|
+
constructor(theme: CrewTheme, options: DynamicCrewBorderOptions = {}) {
|
|
16
|
+
this.theme = theme;
|
|
17
|
+
this.color = options.color;
|
|
18
|
+
this.char = options.char && options.char.length > 0 ? options.char : "─";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
render(width: number): string[] {
|
|
22
|
+
const w = Math.max(0, width);
|
|
23
|
+
if (w !== this.cachedWidth) {
|
|
24
|
+
const line = this.char.repeat(w);
|
|
25
|
+
this.cachedLine = this.color ? this.color(line) : this.theme.fg("border", line);
|
|
26
|
+
this.cachedWidth = w;
|
|
27
|
+
}
|
|
28
|
+
return [this.cachedLine];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
invalidate(): void {
|
|
32
|
+
this.cachedWidth = -1;
|
|
33
|
+
this.cachedLine = "";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared formatting helpers extracted from the deprecated tool-render.ts
|
|
3
|
+
* (F-21 Sprint 6 cleanup). Only the 3 utilities that are used by production
|
|
4
|
+
* code live here; the deprecated render functions were removed with tool-render.ts.
|
|
5
|
+
*/
|
|
6
|
+
import { truncateToWidth } from "../utils/visual.ts";
|
|
7
|
+
|
|
8
|
+
export function formatTokens(n: number): string {
|
|
9
|
+
if (n < 1000) return String(n);
|
|
10
|
+
if (n < 10_000) return `${(n / 1000).toFixed(1)}k`;
|
|
11
|
+
if (n < 1_000_000) return `${Math.round(n / 1000)}k`;
|
|
12
|
+
return `${(n / 1_000_000).toFixed(1)}M`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function formatDuration(ms: number): string {
|
|
16
|
+
if (ms < 1000) return `${ms}ms`;
|
|
17
|
+
if (ms < 60_000) return `${(ms / 1000).toFixed(1)}s`;
|
|
18
|
+
const m = Math.floor(ms / 60_000),
|
|
19
|
+
s = Math.floor((ms % 60_000) / 1000);
|
|
20
|
+
return s > 0 ? `${m}m${s}s` : `${m}m`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function truncLine(text: string, maxWidth: number): string {
|
|
24
|
+
if (text.includes("\n") || text.includes("\r")) text = text.replace(/\r?\n/g, "↵ ");
|
|
25
|
+
// Round 23 (BUG 4): previously this loop counted 1 visual column per UTF-16
|
|
26
|
+
// code unit and indexed text[i], so for CJK it emitted up to 2x the visual
|
|
27
|
+
// width (frame overflow) and for emoji it split surrogate pairs (U+FFFD).
|
|
28
|
+
// Delegate to the grapheme/ANSI-aware truncateToWidth (keeps ANSI codes,
|
|
29
|
+
// respects double-wide CJK + surrogate pairs, adds the '…' ellipsis).
|
|
30
|
+
return truncateToWidth(text, maxWidth);
|
|
31
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { MetricRegistry } from "../observability/metric-registry.ts";
|
|
2
|
+
import { classifyHeartbeat, heartbeatAgeMs } from "../runtime/heartbeat-gradient.ts";
|
|
3
|
+
import type { TeamTaskState } from "../state/types.ts";
|
|
4
|
+
import type { RunUiSnapshot } from "./snapshot-types.ts";
|
|
5
|
+
|
|
6
|
+
export interface HeartbeatSummary {
|
|
7
|
+
runId: string;
|
|
8
|
+
totalTasks: number;
|
|
9
|
+
healthy: number;
|
|
10
|
+
stale: number;
|
|
11
|
+
dead: number;
|
|
12
|
+
missing: number;
|
|
13
|
+
worstStaleMs: number;
|
|
14
|
+
gradient: { healthy: number; warn: number; stale: number; dead: number };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface HeartbeatSummaryOptions {
|
|
18
|
+
staleMs?: number;
|
|
19
|
+
deadMs?: number;
|
|
20
|
+
now?: number | Date;
|
|
21
|
+
registry?: MetricRegistry;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function nowMs(now: number | Date | undefined): number {
|
|
25
|
+
if (typeof now === "number") return now;
|
|
26
|
+
if (now instanceof Date) return now.getTime();
|
|
27
|
+
return Date.now();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function isActiveTask(task: TeamTaskState): boolean {
|
|
31
|
+
return task.status === "running";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function summarizeHeartbeats(snapshot: RunUiSnapshot, opts: HeartbeatSummaryOptions = {}): HeartbeatSummary {
|
|
35
|
+
const staleMs = opts.staleMs ?? 60_000;
|
|
36
|
+
const deadMs = opts.deadMs ?? 5 * 60_000;
|
|
37
|
+
const current = nowMs(opts.now);
|
|
38
|
+
const summary: HeartbeatSummary = {
|
|
39
|
+
runId: snapshot.runId,
|
|
40
|
+
totalTasks: snapshot.tasks.length,
|
|
41
|
+
healthy: 0,
|
|
42
|
+
stale: 0,
|
|
43
|
+
dead: 0,
|
|
44
|
+
missing: 0,
|
|
45
|
+
worstStaleMs: 0,
|
|
46
|
+
gradient: { healthy: 0, warn: 0, stale: 0, dead: 0 },
|
|
47
|
+
};
|
|
48
|
+
for (const task of snapshot.tasks) {
|
|
49
|
+
if (!isActiveTask(task)) continue;
|
|
50
|
+
const heartbeat = task.heartbeat;
|
|
51
|
+
if (!heartbeat) {
|
|
52
|
+
summary.missing += 1;
|
|
53
|
+
summary.gradient.dead += 1;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const age = heartbeatAgeMs(heartbeat, current);
|
|
57
|
+
if (!Number.isFinite(age)) {
|
|
58
|
+
summary.missing += 1;
|
|
59
|
+
summary.gradient.dead += 1;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
summary.worstStaleMs = Math.max(summary.worstStaleMs, age);
|
|
63
|
+
const level = classifyHeartbeat(heartbeat, { warnMs: Math.max(1, Math.floor(staleMs / 2)), staleMs, deadMs }, current);
|
|
64
|
+
summary.gradient[level] += 1;
|
|
65
|
+
opts.registry
|
|
66
|
+
?.gauge("crew.heartbeat.staleness_ms", "Heartbeat elapsed since last seen, milliseconds")
|
|
67
|
+
.set({ runId: snapshot.runId, taskId: task.id }, age);
|
|
68
|
+
opts.registry?.counter("crew.heartbeat.level_total", "Heartbeat classifications by level").inc({ runId: snapshot.runId, level });
|
|
69
|
+
if (level === "dead") summary.dead += 1;
|
|
70
|
+
else if (level === "stale") summary.stale += 1;
|
|
71
|
+
else summary.healthy += 1;
|
|
72
|
+
}
|
|
73
|
+
return summary;
|
|
74
|
+
}
|