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,418 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Crew widget — public API and component.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports from widget submodules. The main component class and
|
|
5
|
+
* update/stop functions live here.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
9
|
+
import type { CrewUiConfig } from "../../config/config.ts";
|
|
10
|
+
import { DEFAULT_UI } from "../../config/defaults.ts";
|
|
11
|
+
import type { ManifestCache } from "../../runtime/manifest-cache.ts";
|
|
12
|
+
import type { TeamRunManifest } from "../../state/types.ts";
|
|
13
|
+
import { truncate } from "../../utils/visual.ts";
|
|
14
|
+
import { requestRender, requestRenderTarget, setExtensionWidget } from "../pi-ui-compat.ts";
|
|
15
|
+
import type { OverlaySchedulerHandle } from "../shared-overlay-scheduler.ts";
|
|
16
|
+
import { registerOverlayScheduler } from "../shared-overlay-scheduler.ts";
|
|
17
|
+
import type { RunSnapshotCache } from "../snapshot-types.ts";
|
|
18
|
+
import { spinnerBucket, spinnerFrame } from "../spinner.ts";
|
|
19
|
+
import type { CrewTheme } from "../theme-adapter.ts";
|
|
20
|
+
import { asCrewTheme, subscribeThemeChange } from "../theme-adapter.ts";
|
|
21
|
+
import { activeWidgetRuns, statusSummary } from "./widget-model.ts";
|
|
22
|
+
import { buildWidgetLines, colorWidgetLine, DEFAULT_WIDGET_WIDTH, renderLines } from "./widget-renderer.ts";
|
|
23
|
+
import type { CrewWidgetModel, CrewWidgetState, WidgetRun } from "./widget-types.ts";
|
|
24
|
+
|
|
25
|
+
export { activeWidgetRuns, statusSummary } from "./widget-model.ts";
|
|
26
|
+
export {
|
|
27
|
+
buildWidgetLines as buildCrewWidgetLines,
|
|
28
|
+
DEFAULT_WIDGET_WIDTH,
|
|
29
|
+
TASK_DESC_MAX,
|
|
30
|
+
widgetHeader,
|
|
31
|
+
} from "./widget-renderer.ts";
|
|
32
|
+
// Re-export types and helpers for backward compatibility
|
|
33
|
+
export type {
|
|
34
|
+
CrewWidgetModel,
|
|
35
|
+
CrewWidgetState,
|
|
36
|
+
WidgetRun,
|
|
37
|
+
} from "./widget-types.ts";
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Resolve the real render width for widget lines, in priority order:
|
|
41
|
+
* 1. explicit `width` argument (e.g. from caller that already knows terminal width)
|
|
42
|
+
* 2. `process.stdout.columns` (works in Node when stdout is a TTY)
|
|
43
|
+
* 3. `DEFAULT_WIDGET_WIDTH` (100) — last-resort fallback so we never paint
|
|
44
|
+
* a line wider than the smallest expected TUI.
|
|
45
|
+
*
|
|
46
|
+
* Callers SHOULD pass the width they already hold (e.g. `WidgetRender.render(width)`
|
|
47
|
+
* in this file already receives one). This helper exists for paths that don't.
|
|
48
|
+
*/
|
|
49
|
+
export function getRenderWidth(width?: number): number {
|
|
50
|
+
if (Number.isFinite(width) && width! > 0) return Math.floor(width!);
|
|
51
|
+
const stdoutCols = (globalThis as { process?: { stdout?: { columns?: number } } }).process?.stdout?.columns;
|
|
52
|
+
if (Number.isFinite(stdoutCols) && stdoutCols! > 0) return Math.floor(stdoutCols!);
|
|
53
|
+
return DEFAULT_WIDGET_WIDTH;
|
|
54
|
+
}
|
|
55
|
+
export {
|
|
56
|
+
NOTIFICATION_BADGE_CAP,
|
|
57
|
+
notificationBadge,
|
|
58
|
+
} from "./widget-formatters.ts";
|
|
59
|
+
|
|
60
|
+
// ── Constants ─────────────────────────────────────────────────────────
|
|
61
|
+
|
|
62
|
+
const MAX_LINES_DEFAULT = DEFAULT_UI.widgetMaxLines;
|
|
63
|
+
const LEGACY_WIDGET_KEY = "pi-crew";
|
|
64
|
+
const WIDGET_KEY = "pi-crew-active";
|
|
65
|
+
const STATUS_KEY = "pi-crew";
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* C4 — short-TTL safety net for the buildSignature() result cache. Combined
|
|
69
|
+
* with invalidate-on-write (onInvalidate clears the cache on every real
|
|
70
|
+
* event), this prevents redundant O(runs×agents) signature recomputation
|
|
71
|
+
* during a burst of host-driven renders within one state snapshot while
|
|
72
|
+
* ensuring the signature is always recomputed after genuine data changes.
|
|
73
|
+
*/
|
|
74
|
+
const SIGNATURE_CACHE_TTL_MS = 100;
|
|
75
|
+
|
|
76
|
+
// ── Terminal resize handling (T-2) ────────────────────────────────────
|
|
77
|
+
// On a terminal resize the widget's cached render width goes stale until the
|
|
78
|
+
// next invalidate; a mid-run resize could briefly paint a frame at the old
|
|
79
|
+
// width. We register ONE debounced process-level listener (guarded so it never
|
|
80
|
+
// accumulates across widget reinstalls) that busts the active widget's cache
|
|
81
|
+
// and pokes Pi to repaint at the new width. The listener references a
|
|
82
|
+
// module-level `activeResizeTarget` (the most-recently-mounted widget) rather
|
|
83
|
+
// than a specific instance, so replaced widgets do not leak listeners.
|
|
84
|
+
let resizeListenerInstalled = false;
|
|
85
|
+
let activeResizeTarget: { invalidate(): void; requestRepaint(): void } | undefined;
|
|
86
|
+
let resizeTimer: ReturnType<typeof setTimeout> | undefined;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* F-1: the resize callback is stored at module level so
|
|
90
|
+
* `uninstallResizeListener()` can remove the exact same reference via
|
|
91
|
+
* `process.off` (requires the identical function reference).
|
|
92
|
+
*/
|
|
93
|
+
const onResize = (): void => {
|
|
94
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
95
|
+
// Debounce (~120ms) so a drag-resize doesn't thrash renders.
|
|
96
|
+
resizeTimer = setTimeout(() => {
|
|
97
|
+
resizeTimer = undefined;
|
|
98
|
+
activeResizeTarget?.invalidate();
|
|
99
|
+
activeResizeTarget?.requestRepaint();
|
|
100
|
+
}, 120);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
function installResizeListener(): void {
|
|
104
|
+
if (resizeListenerInstalled) return;
|
|
105
|
+
resizeListenerInstalled = true;
|
|
106
|
+
process.on("SIGWINCH", onResize);
|
|
107
|
+
// Windows has no SIGWINCH; Node emits "resize" on stdout instead.
|
|
108
|
+
if (typeof process.stdout?.on === "function") process.stdout.on("resize", onResize);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* F-1: remove the process-level resize listeners so they don't outlive the
|
|
113
|
+
* extension session. Safe to call when no listener is installed (no-op).
|
|
114
|
+
* Re-installs automatically when a new widget mounts via `installResizeListener()`.
|
|
115
|
+
*/
|
|
116
|
+
export function uninstallResizeListener(): void {
|
|
117
|
+
if (!resizeListenerInstalled) return;
|
|
118
|
+
resizeListenerInstalled = false;
|
|
119
|
+
if (resizeTimer) {
|
|
120
|
+
clearTimeout(resizeTimer);
|
|
121
|
+
resizeTimer = undefined;
|
|
122
|
+
}
|
|
123
|
+
activeResizeTarget = undefined;
|
|
124
|
+
process.off("SIGWINCH", onResize);
|
|
125
|
+
// Windows has no SIGWINCH; Node emits "resize" on stdout instead.
|
|
126
|
+
if (typeof process.stdout?.off === "function") process.stdout.off("resize", onResize);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ── Widget Component ──────────────────────────────────────────────────
|
|
130
|
+
|
|
131
|
+
interface WidgetComponent {
|
|
132
|
+
render(width: number): string[];
|
|
133
|
+
invalidate(): void;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
class CrewWidgetComponent implements WidgetComponent {
|
|
137
|
+
private readonly model: CrewWidgetModel;
|
|
138
|
+
private theme: CrewTheme;
|
|
139
|
+
private cacheSignature = "";
|
|
140
|
+
/** C4 — invalidate-on-write cache for the buildSignature() result. */
|
|
141
|
+
private cachedBuildSignature = "";
|
|
142
|
+
private cachedBuildSignatureAt = 0;
|
|
143
|
+
private cachedWidth = 0;
|
|
144
|
+
private cachedLines: string[] = [];
|
|
145
|
+
private cachedBaseLines: string[] = [];
|
|
146
|
+
private cachedTheme: CrewTheme;
|
|
147
|
+
private readonly tui: unknown;
|
|
148
|
+
private readonly unsubscribeTheme: () => void;
|
|
149
|
+
private readonly schedulerHandle: OverlaySchedulerHandle;
|
|
150
|
+
|
|
151
|
+
constructor(model: CrewWidgetModel, themeLike: unknown, tui?: unknown) {
|
|
152
|
+
this.model = model;
|
|
153
|
+
this.theme = asCrewTheme(themeLike);
|
|
154
|
+
this.cachedTheme = this.theme;
|
|
155
|
+
this.tui = tui;
|
|
156
|
+
// Register as the active resize target and ensure the single, guarded
|
|
157
|
+
// terminal-resize listener is installed. On a resize the cached width
|
|
158
|
+
// goes stale; busting the cache + requesting a repaint refreshes the
|
|
159
|
+
// widget at the new width without waiting for the next event tick (T-2).
|
|
160
|
+
activeResizeTarget = this;
|
|
161
|
+
installResizeListener();
|
|
162
|
+
this.unsubscribeTheme = subscribeThemeChange(themeLike, () => this.invalidate());
|
|
163
|
+
// 1.10 (UI-P1-1): route run:state / worker:lifecycle / ui:invalidate
|
|
164
|
+
// through a RenderScheduler (debounce + fallback) instead of three
|
|
165
|
+
// direct runEventBus.onChannel subscriptions. With 3 overlays
|
|
166
|
+
// subscribing independently a single event triggered up to 9 callbacks
|
|
167
|
+
// and ~150 invalidates/sec under load. The scheduler collapses bursts
|
|
168
|
+
// into one debounced invalidate.
|
|
169
|
+
this.schedulerHandle = registerOverlayScheduler(
|
|
170
|
+
() => this.invalidate(),
|
|
171
|
+
() => {
|
|
172
|
+
// C4 invalidate-on-write: drop the cached buildSignature()
|
|
173
|
+
// result immediately when a real event arrives (run:state /
|
|
174
|
+
// worker:lifecycle / ui:invalidate). The prior blind-TTL
|
|
175
|
+
// attempt (reverted in 619a0cd) held a stale signature
|
|
176
|
+
// within the window and skipped re-render on genuine state
|
|
177
|
+
// changes. Clearing here + in invalidate() guarantees the
|
|
178
|
+
// next render tick always recomputes from fresh data.
|
|
179
|
+
this.cachedBuildSignature = "";
|
|
180
|
+
this.cachedBuildSignatureAt = 0;
|
|
181
|
+
},
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
private buildSignature(runs: WidgetRun[]): string {
|
|
186
|
+
const liveSig = [...listLiveAgents()]
|
|
187
|
+
.map(
|
|
188
|
+
(h) =>
|
|
189
|
+
`${h.agentId}:${h.status}:${h.activity.turnCount}:${h.activity.toolUses}:${[...h.activity.activeTools.values()].join(",")}:${h.activity.responseText.slice(-30)}`,
|
|
190
|
+
)
|
|
191
|
+
.join("|");
|
|
192
|
+
|
|
193
|
+
const hasRunning =
|
|
194
|
+
runs.some((entry) => entry.agents.some((a) => a.status === "running")) ||
|
|
195
|
+
[...listLiveAgents()].some((h) => h.status === "running");
|
|
196
|
+
const animation = hasRunning ? `:spin=${spinnerBucket()}` : "";
|
|
197
|
+
|
|
198
|
+
const sig =
|
|
199
|
+
runs
|
|
200
|
+
.map(
|
|
201
|
+
(entry) =>
|
|
202
|
+
entry.snapshot?.signature ??
|
|
203
|
+
`${entry.run.runId}:${entry.run.status}:${entry.run.updatedAt}:` +
|
|
204
|
+
entry.agents
|
|
205
|
+
.map((a) => {
|
|
206
|
+
const recentOutput = a.progress?.recentOutput.at(-1) ?? "";
|
|
207
|
+
const progress = [
|
|
208
|
+
a.progress?.currentTool ?? "",
|
|
209
|
+
a.progress?.toolCount ?? 0,
|
|
210
|
+
a.progress?.tokens ?? 0,
|
|
211
|
+
a.progress?.turns ?? 0,
|
|
212
|
+
a.progress?.lastActivityAt ?? "",
|
|
213
|
+
recentOutput,
|
|
214
|
+
].join(":");
|
|
215
|
+
return `${a.status}:${a.startedAt}:${a.completedAt ?? ""}:${a.toolUses ?? 0}:${progress}`;
|
|
216
|
+
})
|
|
217
|
+
.join(","),
|
|
218
|
+
)
|
|
219
|
+
.join("|") + `|live:${liveSig}${animation}`;
|
|
220
|
+
return sig;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
private colorize(lines: string[], width: number): string[] {
|
|
224
|
+
return renderLines(
|
|
225
|
+
lines.map((line, index) => colorWidgetLine(line, index, this.theme)),
|
|
226
|
+
width,
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
invalidate(): void {
|
|
231
|
+
this.cacheSignature = "";
|
|
232
|
+
this.cachedBaseLines = [];
|
|
233
|
+
this.cachedLines = [];
|
|
234
|
+
this.cachedBuildSignature = "";
|
|
235
|
+
this.cachedBuildSignatureAt = 0;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** Poke the host TUI to repaint immediately (defensive: no-op if unavailable). */
|
|
239
|
+
requestRepaint(): void {
|
|
240
|
+
requestRenderTarget(this.tui);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
dispose(): void {
|
|
244
|
+
this.unsubscribeTheme();
|
|
245
|
+
this.schedulerHandle.dispose();
|
|
246
|
+
if (activeResizeTarget === this) activeResizeTarget = undefined;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
render(width: number): string[] {
|
|
250
|
+
const runs = activeWidgetRuns(this.model.cwd, this.model.manifestCache, this.model.snapshotCache, this.model.preloadManifests);
|
|
251
|
+
// C4: invalidate-on-write signature cache. buildSignature() is
|
|
252
|
+
// O(runs×agents) string work called on every ~160ms host-driven render
|
|
253
|
+
// tick. Within one state snapshot (no event arrived → cache not cleared
|
|
254
|
+
// by onInvalidate) the result is identical, so we reuse the cached value
|
|
255
|
+
// to skip redundant recomputation. A short TTL acts as a safety net for
|
|
256
|
+
// the unlikely case where a real event is missed.
|
|
257
|
+
const now = Date.now();
|
|
258
|
+
let sigBase: string;
|
|
259
|
+
if (this.cachedBuildSignature !== "" && now - this.cachedBuildSignatureAt < SIGNATURE_CACHE_TTL_MS) {
|
|
260
|
+
sigBase = this.cachedBuildSignature;
|
|
261
|
+
} else {
|
|
262
|
+
sigBase = this.buildSignature(runs);
|
|
263
|
+
this.cachedBuildSignature = sigBase;
|
|
264
|
+
this.cachedBuildSignatureAt = now;
|
|
265
|
+
}
|
|
266
|
+
const signature = `${sigBase}:${this.model.notificationCount ?? 0}`;
|
|
267
|
+
const runningGlyph = spinnerFrame("widget-header");
|
|
268
|
+
|
|
269
|
+
if (this.cacheSignature !== signature || width !== this.cachedWidth || this.cachedTheme !== this.theme) {
|
|
270
|
+
this.cachedBaseLines = buildWidgetLines(
|
|
271
|
+
this.model.cwd,
|
|
272
|
+
0,
|
|
273
|
+
this.model.maxLines,
|
|
274
|
+
runs,
|
|
275
|
+
this.model.notificationCount ?? 0,
|
|
276
|
+
width,
|
|
277
|
+
).map((line, index) => {
|
|
278
|
+
if (index === 0 && line.length > 0) return `${runningGlyph}${line.slice(1)}`;
|
|
279
|
+
return line;
|
|
280
|
+
});
|
|
281
|
+
this.cachedLines = this.colorize(this.cachedBaseLines, width);
|
|
282
|
+
this.cachedWidth = width;
|
|
283
|
+
this.cachedTheme = this.theme;
|
|
284
|
+
this.cacheSignature = signature;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (runs.length === 0) {
|
|
288
|
+
this.invalidate();
|
|
289
|
+
// P0-6: render from snapshots only — never read disk on every render tick.
|
|
290
|
+
// When the snapshot cache is provided but hasn't populated yet, paint a
|
|
291
|
+
// single "(loading…)" line so the pre-load frame is well-formed instead
|
|
292
|
+
// of an empty panel. Without a cache (legacy/tests) keep the empty result.
|
|
293
|
+
if (this.model.snapshotCache) return ["(loading…)"];
|
|
294
|
+
return [];
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const updatedHeader = `${runningGlyph}${this.cachedBaseLines[0]?.slice(1) ?? ""}`;
|
|
298
|
+
this.cachedLines[0] = truncate(colorWidgetLine(updatedHeader, 0, this.theme), width);
|
|
299
|
+
return this.cachedLines.map((line) => truncate(line, width));
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// ── Re-export listLiveAgents for buildSignature ───────────────────────
|
|
304
|
+
|
|
305
|
+
import { listLiveAgents } from "../../runtime/live-agent-manager.ts";
|
|
306
|
+
|
|
307
|
+
// ── Public API ────────────────────────────────────────────────────────
|
|
308
|
+
|
|
309
|
+
export function updateCrewWidget(
|
|
310
|
+
ctx: Pick<ExtensionContext, "cwd" | "hasUI" | "ui" | "sessionManager">,
|
|
311
|
+
state: CrewWidgetState,
|
|
312
|
+
config?: CrewUiConfig,
|
|
313
|
+
manifestCache?: ManifestCache,
|
|
314
|
+
snapshotCache?: RunSnapshotCache,
|
|
315
|
+
preloadedManifests?: TeamRunManifest[],
|
|
316
|
+
): void {
|
|
317
|
+
if (!ctx.hasUI) return;
|
|
318
|
+
state.frame += 1;
|
|
319
|
+
const maxLines = config?.widgetMaxLines ?? MAX_LINES_DEFAULT;
|
|
320
|
+
|
|
321
|
+
let workspaceId = ctx.sessionManager?.getSessionId?.();
|
|
322
|
+
if (!workspaceId && manifestCache) {
|
|
323
|
+
const runs = manifestCache.list(20);
|
|
324
|
+
const active = runs.find((r) => r.status === "running" || r.status === "queued");
|
|
325
|
+
if (active?.ownerSessionId) workspaceId = active.ownerSessionId;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const runs = activeWidgetRuns(ctx.cwd, manifestCache, snapshotCache, preloadedManifests, workspaceId);
|
|
329
|
+
const lines = buildWidgetLines(ctx.cwd, state.frame, maxLines, runs, state.notificationCount ?? 0, getRenderWidth());
|
|
330
|
+
const placement = config?.widgetPlacement ?? DEFAULT_UI.widgetPlacement;
|
|
331
|
+
|
|
332
|
+
ctx.ui.setStatus(STATUS_KEY, lines.length ? statusSummary(runs) : undefined);
|
|
333
|
+
|
|
334
|
+
const shouldClearLegacy = state.legacyCleared !== true || state.lastPlacement !== placement;
|
|
335
|
+
if (shouldClearLegacy) {
|
|
336
|
+
setExtensionWidget(ctx, LEGACY_WIDGET_KEY, undefined, { placement });
|
|
337
|
+
state.legacyCleared = true;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (!lines.length) {
|
|
341
|
+
if (state.lastVisibility !== "hidden" || state.lastPlacement !== placement) {
|
|
342
|
+
setExtensionWidget(ctx, WIDGET_KEY, undefined, { placement });
|
|
343
|
+
state.lastVisibility = "hidden";
|
|
344
|
+
state.lastPlacement = placement;
|
|
345
|
+
state.lastKey = WIDGET_KEY;
|
|
346
|
+
state.lastMaxLines = maxLines;
|
|
347
|
+
state.lastCwd = ctx.cwd;
|
|
348
|
+
state.model = undefined;
|
|
349
|
+
}
|
|
350
|
+
requestRender(ctx);
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const needsWidgetInstall =
|
|
355
|
+
state.lastVisibility !== "visible" ||
|
|
356
|
+
state.lastPlacement !== placement ||
|
|
357
|
+
state.lastKey !== WIDGET_KEY ||
|
|
358
|
+
state.lastMaxLines !== maxLines ||
|
|
359
|
+
state.lastCwd !== ctx.cwd ||
|
|
360
|
+
!state.model;
|
|
361
|
+
|
|
362
|
+
if (!state.model)
|
|
363
|
+
state.model = {
|
|
364
|
+
cwd: ctx.cwd,
|
|
365
|
+
frame: state.frame,
|
|
366
|
+
maxLines,
|
|
367
|
+
notificationCount: state.notificationCount ?? 0,
|
|
368
|
+
manifestCache,
|
|
369
|
+
snapshotCache,
|
|
370
|
+
preloadManifests: preloadedManifests,
|
|
371
|
+
};
|
|
372
|
+
else {
|
|
373
|
+
state.model.cwd = ctx.cwd;
|
|
374
|
+
state.model.frame = state.frame;
|
|
375
|
+
state.model.maxLines = maxLines;
|
|
376
|
+
state.model.notificationCount = state.notificationCount ?? 0;
|
|
377
|
+
state.model.manifestCache = manifestCache;
|
|
378
|
+
state.model.snapshotCache = snapshotCache;
|
|
379
|
+
state.model.preloadManifests = preloadedManifests;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (needsWidgetInstall) {
|
|
383
|
+
const model = state.model;
|
|
384
|
+
setExtensionWidget(ctx, WIDGET_KEY, ((_tui: unknown, theme: unknown) => new CrewWidgetComponent(model, theme, _tui)) as never, {
|
|
385
|
+
placement,
|
|
386
|
+
persist: true,
|
|
387
|
+
});
|
|
388
|
+
state.lastVisibility = "visible";
|
|
389
|
+
state.lastPlacement = placement;
|
|
390
|
+
state.lastKey = WIDGET_KEY;
|
|
391
|
+
state.lastMaxLines = maxLines;
|
|
392
|
+
state.lastCwd = ctx.cwd;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
requestRender(ctx);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
export function stopCrewWidget(
|
|
399
|
+
ctx: Pick<ExtensionContext, "hasUI" | "ui"> | undefined,
|
|
400
|
+
state: CrewWidgetState,
|
|
401
|
+
config?: CrewUiConfig,
|
|
402
|
+
): void {
|
|
403
|
+
// F-1: remove the process-level SIGWINCH/resize listener when the widget is
|
|
404
|
+
// stopped. The listener is guarded so re-mounting a widget re-installs it.
|
|
405
|
+
uninstallResizeListener();
|
|
406
|
+
if (ctx?.hasUI) {
|
|
407
|
+
const placement = config?.widgetPlacement ?? DEFAULT_UI.widgetPlacement;
|
|
408
|
+
ctx.ui.setStatus(STATUS_KEY, undefined);
|
|
409
|
+
setExtensionWidget(ctx, LEGACY_WIDGET_KEY, undefined, { placement });
|
|
410
|
+
setExtensionWidget(ctx, WIDGET_KEY, undefined, { placement });
|
|
411
|
+
state.lastVisibility = "hidden";
|
|
412
|
+
state.lastPlacement = placement;
|
|
413
|
+
state.lastKey = WIDGET_KEY;
|
|
414
|
+
state.model = undefined;
|
|
415
|
+
state.legacyCleared = true;
|
|
416
|
+
requestRender(ctx);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Widget formatting utilities.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from crew-widget.ts for reuse and testability.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { CrewAgentRecord } from "../../runtime/crew-agent-runtime.ts";
|
|
8
|
+
import type { LiveAgentHandle } from "../../runtime/live-agent-manager.ts";
|
|
9
|
+
import { getTaskUsage } from "../../runtime/usage-tracker.ts";
|
|
10
|
+
import { visibleWidth } from "../../utils/visual.ts";
|
|
11
|
+
import { computeLiveDurationMs } from "../live-duration.ts";
|
|
12
|
+
|
|
13
|
+
// ── Token formatting ──────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
// V-1: fixed visible widths for per-agent numeric metrics so columns don't
|
|
16
|
+
// jitter every tick as values change width (e.g. 9.9s→10.0s, 950→1.0k).
|
|
17
|
+
// alignMetric right-aligns to the width; values wider than the width overflow
|
|
18
|
+
// verbatim (no truncation/crash) — these are rare one-off states, not jitter.
|
|
19
|
+
const TOOLS_METRIC_WIDTH = 8; // "127 tools"
|
|
20
|
+
const TOKENS_METRIC_WIDTH = 10; // "1.2k tok", "12.3M tok"
|
|
21
|
+
const TPS_METRIC_WIDTH = 9; // "411 tok/s"
|
|
22
|
+
const CTX_METRIC_WIDTH = 7; // "100% ctx"
|
|
23
|
+
const DURATION_METRIC_WIDTH = 6; // "120.0s"
|
|
24
|
+
|
|
25
|
+
function alignMetric(value: string, width: number): string {
|
|
26
|
+
const pad = Math.max(0, width - visibleWidth(value));
|
|
27
|
+
return " ".repeat(pad) + value;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function formatTokensCompact(count: number): string {
|
|
31
|
+
if (count >= 1_000_000) return `${(count / 1_000_000).toFixed(1)}M tok`;
|
|
32
|
+
if (count >= 1_000) return `${(count / 1_000).toFixed(1)}k tok`;
|
|
33
|
+
return `${count} tok`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ── Elapsed time ──────────────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
export function elapsed(iso: string | undefined, now = Date.now()): string | undefined {
|
|
39
|
+
if (!iso) return undefined;
|
|
40
|
+
const ms = Math.max(0, now - new Date(iso).getTime());
|
|
41
|
+
if (!Number.isFinite(ms)) return undefined;
|
|
42
|
+
if (ms < 1000) return "now";
|
|
43
|
+
if (ms < 60_000) return `${Math.floor(ms / 1000)}s`;
|
|
44
|
+
if (ms < 3_600_000) return `${Math.floor(ms / 60_000)}m`;
|
|
45
|
+
return `${Math.floor(ms / 3_600_000)}h`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ── Agent activity description ────────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
const TOOL_LABELS: Record<string, string> = {
|
|
51
|
+
read: "reading",
|
|
52
|
+
bash: "running command",
|
|
53
|
+
edit: "editing",
|
|
54
|
+
write: "writing",
|
|
55
|
+
grep: "searching",
|
|
56
|
+
find: "finding files",
|
|
57
|
+
ls: "listing",
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const TOOL_ICONS: Record<string, string> = {
|
|
61
|
+
read: "📖",
|
|
62
|
+
bash: ">",
|
|
63
|
+
edit: "✏",
|
|
64
|
+
write: "📝",
|
|
65
|
+
grep: "🔍",
|
|
66
|
+
find: "📁",
|
|
67
|
+
ls: "📋",
|
|
68
|
+
agent: "🤖",
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export function describeLiveActivity(handle: LiveAgentHandle): string {
|
|
72
|
+
const act = handle.activity;
|
|
73
|
+
if (act.activeTools.size > 0) {
|
|
74
|
+
const groups = new Map<string, number>();
|
|
75
|
+
for (const toolName of act.activeTools.values()) {
|
|
76
|
+
groups.set(toolName, (groups.get(toolName) ?? 0) + 1);
|
|
77
|
+
}
|
|
78
|
+
const parts: string[] = [];
|
|
79
|
+
for (const [toolName, count] of groups) {
|
|
80
|
+
const icon = TOOL_ICONS[toolName] ?? "?";
|
|
81
|
+
const label = TOOL_LABELS[toolName] ?? toolName;
|
|
82
|
+
if (count > 1) {
|
|
83
|
+
parts.push(`${icon}${count} ${label}s`);
|
|
84
|
+
} else {
|
|
85
|
+
parts.push(`${icon} ${label}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return parts.join(", ") + "…";
|
|
89
|
+
}
|
|
90
|
+
if (act.responseText?.trim()) {
|
|
91
|
+
const line =
|
|
92
|
+
act.responseText
|
|
93
|
+
.split("\n")
|
|
94
|
+
.find((l) => l.trim())
|
|
95
|
+
?.trim() ?? "";
|
|
96
|
+
return line.length > 60 ? line.slice(0, 60) + "…" : line;
|
|
97
|
+
}
|
|
98
|
+
return "thinking…";
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function agentActivity(agent: CrewAgentRecord, liveHandle?: LiveAgentHandle): string {
|
|
102
|
+
if (liveHandle && liveHandle.status === "running") {
|
|
103
|
+
const live = describeLiveActivity(liveHandle);
|
|
104
|
+
if (live === "thinking…" && agent.progress?.currentTool)
|
|
105
|
+
return `${TOOL_LABELS[agent.progress.currentTool] ?? agent.progress.currentTool}…`;
|
|
106
|
+
return live;
|
|
107
|
+
}
|
|
108
|
+
if (agent.progress?.currentTool) return `${TOOL_LABELS[agent.progress.currentTool] ?? agent.progress.currentTool}…`;
|
|
109
|
+
const recent = agent.progress?.recentOutput?.at(-1);
|
|
110
|
+
if (recent) {
|
|
111
|
+
const cleaned = recent.replace(/\s+/g, " ").trim();
|
|
112
|
+
return cleaned.length > 60 ? cleaned.slice(0, 60) + "…" : cleaned;
|
|
113
|
+
}
|
|
114
|
+
if (agent.progress?.activityState === "needs_attention") return "needs attention";
|
|
115
|
+
if (agent.status === "queued") return "queued";
|
|
116
|
+
if (agent.status === "running") {
|
|
117
|
+
const age = agent.startedAt ? Date.now() - new Date(agent.startedAt).getTime() : Infinity;
|
|
118
|
+
if (age < 5000 && !agent.progress?.currentTool) return "spawning…";
|
|
119
|
+
return "thinking…";
|
|
120
|
+
}
|
|
121
|
+
if (agent.status === "failed") return agent.error ?? "failed";
|
|
122
|
+
return "done";
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ── Agent stats line ──────────────────────────────────────────────────
|
|
126
|
+
|
|
127
|
+
export function agentStats(agent: CrewAgentRecord, liveHandle?: LiveAgentHandle): string {
|
|
128
|
+
const parts: string[] = [];
|
|
129
|
+
if (liveHandle) {
|
|
130
|
+
const act = liveHandle.activity;
|
|
131
|
+
if (act.toolUses > 0) parts.push(alignMetric(`${act.toolUses} tools`, TOOLS_METRIC_WIDTH));
|
|
132
|
+
const usage = getTaskUsage(liveHandle.taskId);
|
|
133
|
+
const total = (usage.input ?? 0) + (usage.output ?? 0) + (usage.cacheWrite ?? 0);
|
|
134
|
+
if (total > 0) parts.push(alignMetric(formatTokensCompact(total), TOKENS_METRIC_WIDTH));
|
|
135
|
+
try {
|
|
136
|
+
const stats = liveHandle.session.getSessionStats?.();
|
|
137
|
+
const ctxPct = stats?.contextUsage?.percent;
|
|
138
|
+
if (ctxPct != null) parts.push(alignMetric(`${Math.round(ctxPct)}% ctx`, CTX_METRIC_WIDTH));
|
|
139
|
+
} catch {
|
|
140
|
+
/* ignore */
|
|
141
|
+
}
|
|
142
|
+
const ms = computeLiveDurationMs(act);
|
|
143
|
+
if (total > 0 && ms > 1000) {
|
|
144
|
+
const tps = Math.round(total / (ms / 1000));
|
|
145
|
+
if (tps > 0) parts.push(alignMetric(`${formatTokensCompact(tps)}/s`, TPS_METRIC_WIDTH));
|
|
146
|
+
}
|
|
147
|
+
parts.push(alignMetric(`${(ms / 1000).toFixed(1)}s`, DURATION_METRIC_WIDTH));
|
|
148
|
+
} else {
|
|
149
|
+
if (agent.toolUses) parts.push(alignMetric(`${agent.toolUses} tools`, TOOLS_METRIC_WIDTH));
|
|
150
|
+
if (agent.progress?.tokens) parts.push(alignMetric(formatTokensCompact(agent.progress.tokens), TOKENS_METRIC_WIDTH));
|
|
151
|
+
const ageMs = agent.startedAt ? Math.max(0, Date.now() - new Date(agent.startedAt).getTime()) : 0;
|
|
152
|
+
if (agent.progress?.tokens && ageMs > 1000) {
|
|
153
|
+
const tps = Math.round(agent.progress.tokens / (ageMs / 1000));
|
|
154
|
+
if (tps > 0) parts.push(alignMetric(`${formatTokensCompact(tps)}/s`, TPS_METRIC_WIDTH));
|
|
155
|
+
}
|
|
156
|
+
const age = elapsed(agent.completedAt ?? agent.startedAt);
|
|
157
|
+
if (age) parts.push(alignMetric(age, DURATION_METRIC_WIDTH));
|
|
158
|
+
}
|
|
159
|
+
return parts.join(" · ");
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ── Notification badge ────────────────────────────────────────────────
|
|
163
|
+
|
|
164
|
+
// Bug 021: the bell glyph 🔔 was misread as "queued messages" — users saw
|
|
165
|
+
// `🔔227` and concluded there were 227 pending items, when the value is a
|
|
166
|
+
// CUMULATIVE warning/error/critical count with zero actual queue behind it.
|
|
167
|
+
// Fix: relabel to an explicit "alerts" segment (no bell) and cap the display
|
|
168
|
+
// at 99+ (standard badge practice). The cumulative count stays accurate
|
|
169
|
+
// internally (widgetState.notificationCount) and remains fully logged in
|
|
170
|
+
// .crew/state/notifications/YYYY-MM-DD.jsonl — this bounds presentation only.
|
|
171
|
+
// Deeper fixes (decay window, owner-scope, auto-reset on all-runs-terminal,
|
|
172
|
+
// full deprecation) are product decisions documented in
|
|
173
|
+
// docs/bugs/bug-021-notification-badge-counter-misleading.md.
|
|
174
|
+
export const NOTIFICATION_BADGE_CAP = 99;
|
|
175
|
+
|
|
176
|
+
export function notificationBadge(count: number | undefined, env: NodeJS.ProcessEnv = process.env): string {
|
|
177
|
+
if (!count || count <= 0) return "";
|
|
178
|
+
const term = `${env.TERM ?? ""} ${env.WT_SESSION ?? ""} ${env.TERM_PROGRAM ?? ""}`.toLowerCase();
|
|
179
|
+
const supportsEmoji = !term.includes("dumb") && env.NO_COLOR !== "1";
|
|
180
|
+
const label = count > NOTIFICATION_BADGE_CAP ? `${NOTIFICATION_BADGE_CAP}+ alerts` : `${count} alerts`;
|
|
181
|
+
return supportsEmoji ? ` · ${label}` : ` [${label}]`;
|
|
182
|
+
}
|