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,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* key-utils.ts — Centralised key matching helpers.
|
|
3
|
+
*
|
|
4
|
+
* Pi 0.81+'s TUI input layer (`@earendil-works/pi-tui`) ships a `matchesKey()`
|
|
5
|
+
* helper that handles multiple terminal key encodings: legacy CSI escapes
|
|
6
|
+
* (`\x1b[A`), application cursor mode (`\x1bOA`), and Kitty keyboard protocol
|
|
7
|
+
* variants. Pi-crew components previously compared against raw escape bytes
|
|
8
|
+
* (`data === "\x1b[A"`), which silently failed on terminals that emit the
|
|
9
|
+
* alternate encodings. This module wraps `matchesKey` with a single
|
|
10
|
+
* `keyOf()` helper so overlay code reads naturally while picking up the
|
|
11
|
+
* terminal-aware match logic for free.
|
|
12
|
+
*
|
|
13
|
+
* Returns the canonical KeyId when matchesKey recognises it, otherwise the
|
|
14
|
+
* raw input string so callers can fall through to ASCII-letter shortcuts.
|
|
15
|
+
*/
|
|
16
|
+
import { type KeyId, matchesKey } from "@earendil-works/pi-tui";
|
|
17
|
+
|
|
18
|
+
export type PiKeyName = KeyId | string;
|
|
19
|
+
|
|
20
|
+
const COMMON_IDS: readonly KeyId[] = [
|
|
21
|
+
"up",
|
|
22
|
+
"down",
|
|
23
|
+
"left",
|
|
24
|
+
"right",
|
|
25
|
+
"enter",
|
|
26
|
+
"escape",
|
|
27
|
+
"tab",
|
|
28
|
+
"shift+tab",
|
|
29
|
+
"space",
|
|
30
|
+
"backspace",
|
|
31
|
+
"home",
|
|
32
|
+
"end",
|
|
33
|
+
"pageUp",
|
|
34
|
+
"pageDown",
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
export function keyOf(data: string): KeyId | string {
|
|
38
|
+
for (const id of COMMON_IDS) {
|
|
39
|
+
if (matchesKey(data, id)) return id;
|
|
40
|
+
}
|
|
41
|
+
return data;
|
|
42
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard keybinding map (L2 refactor: data-driven dispatch).
|
|
3
|
+
*
|
|
4
|
+
* Before L2 this module exposed `DASHBOARD_KEYS` (a data table) but dispatched
|
|
5
|
+
* via a 30-line `if (includes(...)) return "..."` chain — adding a key meant
|
|
6
|
+
* editing BOTH the table AND the dispatch, a DRY violation. L2 collapses the
|
|
7
|
+
* dispatch into a single `for (const b of BINDINGS)` loop driven by the
|
|
8
|
+
* `BINDINGS` table below. `DASHBOARD_KEYS` is retained as the raw key data so
|
|
9
|
+
* existing imports and the dead-but-intentional `KEY_RESERVED` set keep working.
|
|
10
|
+
*
|
|
11
|
+
* Recalibration vs. the original L2 plan: the plan also called for an
|
|
12
|
+
* `inTextInput` guard to prevent letter-key leaks into TUI text inputs.
|
|
13
|
+
* Verified during implementation that this is NOT needed — overlays are
|
|
14
|
+
* mutually exclusive and each has its own `handleInput`. `mailbox-compose-overlay.ts:111`
|
|
15
|
+
* captures every single-char key via `appendText(data)` and never delegates to
|
|
16
|
+
* `dashboardActionForKey`, so there is no leak path. Adding the guard would
|
|
17
|
+
* complicate the API (`run-dashboard.ts:485` has no text-input state to pass)
|
|
18
|
+
* for zero benefit. The input-guard half of L2 is therefore intentionally
|
|
19
|
+
* skipped; only the DRY/data-driven dispatch refactor landed.
|
|
20
|
+
*
|
|
21
|
+
* Origin pattern: deer-flow `frontend/src/components/workspace/command-palette.tsx:39-50`
|
|
22
|
+
* drives shortcuts from a single data array consumed by one loop in
|
|
23
|
+
* `use-global-shortcuts.ts:38-61`.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { type KeyId, matchesKey } from "@earendil-works/pi-tui";
|
|
27
|
+
import { keyOf } from "./key-utils.ts";
|
|
28
|
+
|
|
29
|
+
export const DASHBOARD_KEYS = {
|
|
30
|
+
close: ["q", "escape", "\u001b"],
|
|
31
|
+
select: ["enter", "s", "\r", "\n", "tab", "\t", " "],
|
|
32
|
+
help: ["?"],
|
|
33
|
+
root: {
|
|
34
|
+
summary: ["u"],
|
|
35
|
+
artifacts: ["a"],
|
|
36
|
+
api: ["i"],
|
|
37
|
+
agents: ["d"],
|
|
38
|
+
mailbox: ["m"],
|
|
39
|
+
events: ["e"],
|
|
40
|
+
output: ["o"],
|
|
41
|
+
transcript: ["v"],
|
|
42
|
+
liveConversation: ["V"],
|
|
43
|
+
reload: ["r"],
|
|
44
|
+
progressToggle: ["p"],
|
|
45
|
+
},
|
|
46
|
+
pane: {
|
|
47
|
+
agents: ["1"],
|
|
48
|
+
progress: ["2"],
|
|
49
|
+
mailbox: ["3"],
|
|
50
|
+
output: ["4"],
|
|
51
|
+
health: ["5"],
|
|
52
|
+
metrics: ["6"],
|
|
53
|
+
},
|
|
54
|
+
navigation: { up: ["k", "up"], down: ["j", "down"] },
|
|
55
|
+
mailbox: {
|
|
56
|
+
ack: ["A"],
|
|
57
|
+
nudge: ["N"],
|
|
58
|
+
compose: ["C"],
|
|
59
|
+
preview: ["P"],
|
|
60
|
+
ackAll: ["X"],
|
|
61
|
+
openDetail: ["\r", "\n"],
|
|
62
|
+
},
|
|
63
|
+
health: { recovery: ["R"], killStale: ["K"], diagnosticExport: ["D"] },
|
|
64
|
+
notification: { dismissAll: ["H"] },
|
|
65
|
+
} as const;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Pane identifiers that can scope a binding. `undefined` means the binding
|
|
69
|
+
* fires in every pane.
|
|
70
|
+
*/
|
|
71
|
+
export type ActivePane = "agents" | "progress" | "mailbox" | "output" | "health" | "metrics";
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* A single keybinding: the keys that trigger it, the action it produces, and
|
|
75
|
+
* an optional pane restriction. The dispatch loop returns the FIRST matching
|
|
76
|
+
* binding, so table ORDER IS SIGNIFICANT and must mirror the old if-chain
|
|
77
|
+
* precedence (pane-specific overrides before their generic competitors).
|
|
78
|
+
*/
|
|
79
|
+
export interface KeyBinding {
|
|
80
|
+
readonly keys: readonly string[];
|
|
81
|
+
readonly action: DashboardKeyAction;
|
|
82
|
+
/** When set, the binding only fires when `activePane === pane`. */
|
|
83
|
+
readonly pane?: ActivePane;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export type DashboardKeyAction =
|
|
87
|
+
| "close"
|
|
88
|
+
| "help"
|
|
89
|
+
| "select"
|
|
90
|
+
| "summary"
|
|
91
|
+
| "artifacts"
|
|
92
|
+
| "api"
|
|
93
|
+
| "agents"
|
|
94
|
+
| "mailbox"
|
|
95
|
+
| "events"
|
|
96
|
+
| "output"
|
|
97
|
+
| "transcript"
|
|
98
|
+
| "live-conversation"
|
|
99
|
+
| "reload"
|
|
100
|
+
| "progressToggle"
|
|
101
|
+
| "pane-agents"
|
|
102
|
+
| "pane-progress"
|
|
103
|
+
| "pane-mailbox"
|
|
104
|
+
| "pane-output"
|
|
105
|
+
| "pane-health"
|
|
106
|
+
| "pane-metrics"
|
|
107
|
+
| "up"
|
|
108
|
+
| "down"
|
|
109
|
+
| "mailbox-detail"
|
|
110
|
+
| "health-recovery"
|
|
111
|
+
| "health-kill-stale"
|
|
112
|
+
| "health-diagnostic-export"
|
|
113
|
+
| "notifications-dismiss";
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* The dispatch table. ORDER MATTERS — first match wins.
|
|
117
|
+
*
|
|
118
|
+
* Precedence notes (must match the pre-L2 if-chain exactly):
|
|
119
|
+
* 1. `close` always wins (q / Esc).
|
|
120
|
+
* 2. `mailbox-detail` (\r, \n) is pane-scoped to mailbox and MUST precede
|
|
121
|
+
* `select` (which also binds \r, \n) so Enter opens the detail instead of
|
|
122
|
+
* triggering select while in the mailbox pane.
|
|
123
|
+
* 3. `health-*` are pane-scoped to health.
|
|
124
|
+
* 4. `notifications-dismiss` (H) is global.
|
|
125
|
+
* 5. `select`, then the root actions, pane switches, and navigation.
|
|
126
|
+
*
|
|
127
|
+
* NOTE: mailbox action keys A/N/C/P/X (ack/nudge/compose/preview/ackAll) are
|
|
128
|
+
* intentionally NOT in this table. They live in `DASHBOARD_KEYS.mailbox` for
|
|
129
|
+
* reservation but are handled by the mailbox overlay's own `handleInput`,
|
|
130
|
+
* not by the dashboard dispatch. Adding them here would change behavior.
|
|
131
|
+
*/
|
|
132
|
+
const BINDINGS: readonly KeyBinding[] = [
|
|
133
|
+
{ keys: DASHBOARD_KEYS.close, action: "close" },
|
|
134
|
+
{ keys: DASHBOARD_KEYS.help, action: "help" },
|
|
135
|
+
{
|
|
136
|
+
keys: DASHBOARD_KEYS.mailbox.openDetail,
|
|
137
|
+
action: "mailbox-detail",
|
|
138
|
+
pane: "mailbox",
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
keys: DASHBOARD_KEYS.health.recovery,
|
|
142
|
+
action: "health-recovery",
|
|
143
|
+
pane: "health",
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
keys: DASHBOARD_KEYS.health.killStale,
|
|
147
|
+
action: "health-kill-stale",
|
|
148
|
+
pane: "health",
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
keys: DASHBOARD_KEYS.health.diagnosticExport,
|
|
152
|
+
action: "health-diagnostic-export",
|
|
153
|
+
pane: "health",
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
keys: DASHBOARD_KEYS.notification.dismissAll,
|
|
157
|
+
action: "notifications-dismiss",
|
|
158
|
+
},
|
|
159
|
+
{ keys: DASHBOARD_KEYS.select, action: "select" },
|
|
160
|
+
{ keys: DASHBOARD_KEYS.root.summary, action: "summary" },
|
|
161
|
+
{ keys: DASHBOARD_KEYS.root.artifacts, action: "artifacts" },
|
|
162
|
+
{ keys: DASHBOARD_KEYS.root.api, action: "api" },
|
|
163
|
+
{ keys: DASHBOARD_KEYS.root.agents, action: "agents" },
|
|
164
|
+
{ keys: DASHBOARD_KEYS.root.mailbox, action: "mailbox" },
|
|
165
|
+
{ keys: DASHBOARD_KEYS.root.events, action: "events" },
|
|
166
|
+
{ keys: DASHBOARD_KEYS.root.output, action: "output" },
|
|
167
|
+
{ keys: DASHBOARD_KEYS.root.transcript, action: "transcript" },
|
|
168
|
+
{ keys: DASHBOARD_KEYS.root.liveConversation, action: "live-conversation" },
|
|
169
|
+
{ keys: DASHBOARD_KEYS.root.reload, action: "reload" },
|
|
170
|
+
{ keys: DASHBOARD_KEYS.root.progressToggle, action: "progressToggle" },
|
|
171
|
+
{ keys: DASHBOARD_KEYS.pane.agents, action: "pane-agents" },
|
|
172
|
+
{ keys: DASHBOARD_KEYS.pane.progress, action: "pane-progress" },
|
|
173
|
+
{ keys: DASHBOARD_KEYS.pane.mailbox, action: "pane-mailbox" },
|
|
174
|
+
{ keys: DASHBOARD_KEYS.pane.output, action: "pane-output" },
|
|
175
|
+
{ keys: DASHBOARD_KEYS.pane.health, action: "pane-health" },
|
|
176
|
+
{ keys: DASHBOARD_KEYS.pane.metrics, action: "pane-metrics" },
|
|
177
|
+
{ keys: DASHBOARD_KEYS.navigation.up, action: "up" },
|
|
178
|
+
{ keys: DASHBOARD_KEYS.navigation.down, action: "down" },
|
|
179
|
+
];
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Reserved keys — every key the dashboard claims, including mailbox/health
|
|
183
|
+
* action keys that are NOT dispatched here but are handled by their own
|
|
184
|
+
* overlays. Derived from `DASHBOARD_KEYS` (the full key set) rather than from
|
|
185
|
+
* `BINDINGS` (the dispatched subset) so overlay-handled keys stay reserved.
|
|
186
|
+
*
|
|
187
|
+
* @internal Consumed by `test/unit/keybinding-map.parity.test.ts` (asserts
|
|
188
|
+
* reserved-key membership) and the L2 dispatch smoke script. It is the
|
|
189
|
+
* canonical "keys the dashboard ecosystem owns" set — NOT dead code.
|
|
190
|
+
*/
|
|
191
|
+
const KEY_RESERVED = new Set<string>([
|
|
192
|
+
...DASHBOARD_KEYS.close,
|
|
193
|
+
...DASHBOARD_KEYS.select,
|
|
194
|
+
...DASHBOARD_KEYS.help,
|
|
195
|
+
...Object.values(DASHBOARD_KEYS.root).flat(),
|
|
196
|
+
...Object.values(DASHBOARD_KEYS.pane).flat(),
|
|
197
|
+
...Object.values(DASHBOARD_KEYS.navigation).flat(),
|
|
198
|
+
...Object.values(DASHBOARD_KEYS.mailbox).flat(),
|
|
199
|
+
...Object.values(DASHBOARD_KEYS.health).flat(),
|
|
200
|
+
...Object.values(DASHBOARD_KEYS.notification).flat(),
|
|
201
|
+
]);
|
|
202
|
+
|
|
203
|
+
export { KEY_RESERVED };
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Resolve a raw input `data` string to a dashboard action.
|
|
207
|
+
*
|
|
208
|
+
* Data-driven dispatch: iterates `BINDINGS` in order and returns the action of
|
|
209
|
+
* the first binding whose `keys` contain `data` and whose optional `pane`
|
|
210
|
+
* restriction matches `activePane`. Behavior is identical to the pre-L2
|
|
211
|
+
* if-chain (verified by `test/unit/keybinding-map.parity.test.ts`).
|
|
212
|
+
*
|
|
213
|
+
* @param data Raw key input (single char or escape sequence).
|
|
214
|
+
* @param activePane Currently focused pane; pane-scoped bindings only fire
|
|
215
|
+
* when this matches. `undefined` disables all pane-scoped
|
|
216
|
+
* bindings (matching the old behavior where omitting the
|
|
217
|
+
* arg skipped the `activePane === ...` branches).
|
|
218
|
+
*/
|
|
219
|
+
export function dashboardActionForKey(data: string, activePane?: ActivePane): DashboardKeyAction | undefined {
|
|
220
|
+
// Two-pass dispatch to preserve case-sensitivity for plain ASCII keys
|
|
221
|
+
// while still normalizing escape sequences via matchesKey().
|
|
222
|
+
//
|
|
223
|
+
// Background: pi-tui's matchesKey() is case-insensitive, so matchesKey("d",
|
|
224
|
+
// "D") === true. A single-pass loop that intermixes exact + matchesKey
|
|
225
|
+
// checks would let the pane-scoped health-diagnostic-export binding
|
|
226
|
+
// (candidate "D") win over the unscoped agents binding (candidate "d")
|
|
227
|
+
// when activePane === "health" — collapsing the d/D case distinction.
|
|
228
|
+
//
|
|
229
|
+
// Pass 1 — exact string match (case-sensitive). Handles literal ASCII
|
|
230
|
+
// keystrokes ('d', 'D', 'q', 'S', …) and preserves their distinct meanings.
|
|
231
|
+
for (const binding of BINDINGS) {
|
|
232
|
+
if (binding.pane !== undefined && binding.pane !== activePane) continue;
|
|
233
|
+
if (binding.keys.includes(data)) return binding.action;
|
|
234
|
+
}
|
|
235
|
+
// Pass 2 — terminal-aware match for escape sequences / canonical KeyIds.
|
|
236
|
+
// Only reached when no exact ASCII match exists (data is e.g. '\x1b[A',
|
|
237
|
+
// '\x1bOA', or an app-cursor-mode variant). Uses matchesKey() to normalize
|
|
238
|
+
// legacy CSI, app-cursor-mode, and Kitty-protocol variants uniformly.
|
|
239
|
+
const key = keyOf(data);
|
|
240
|
+
for (const binding of BINDINGS) {
|
|
241
|
+
if (binding.pane !== undefined && binding.pane !== activePane) continue;
|
|
242
|
+
for (const candidate of binding.keys) {
|
|
243
|
+
if (key === candidate) return binding.action;
|
|
244
|
+
if (matchesKey(data, candidate as KeyId)) return binding.action;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return undefined;
|
|
248
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { pad, wrapHard } from "../utils/visual.ts";
|
|
2
|
+
|
|
3
|
+
export interface RenderableComponent {
|
|
4
|
+
invalidate(): void;
|
|
5
|
+
render(width: number): string[];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class Container implements RenderableComponent {
|
|
9
|
+
private children: RenderableComponent[] = [];
|
|
10
|
+
|
|
11
|
+
addChild(child: RenderableComponent): void {
|
|
12
|
+
this.children.push(child);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
clear(): void {
|
|
16
|
+
this.children = [];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
invalidate(): void {
|
|
20
|
+
for (const child of this.children) {
|
|
21
|
+
child.invalidate();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
render(width: number): string[] {
|
|
26
|
+
const lines: string[] = [];
|
|
27
|
+
for (const child of this.children) {
|
|
28
|
+
lines.push(...child.render(width));
|
|
29
|
+
}
|
|
30
|
+
return lines;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export class Box extends Container {
|
|
35
|
+
private readonly paddingX: number;
|
|
36
|
+
private readonly paddingY: number;
|
|
37
|
+
|
|
38
|
+
constructor(paddingX = 0, paddingY = 0) {
|
|
39
|
+
super();
|
|
40
|
+
this.paddingX = paddingX;
|
|
41
|
+
this.paddingY = paddingY;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
render(width: number): string[] {
|
|
45
|
+
const innerWidth = Math.max(1, width - this.paddingX * 2);
|
|
46
|
+
const rows = super.render(innerWidth);
|
|
47
|
+
const paddedRows: string[] = [];
|
|
48
|
+
const left = " ".repeat(this.paddingX);
|
|
49
|
+
const right = " ".repeat(this.paddingX);
|
|
50
|
+
for (const row of rows) {
|
|
51
|
+
paddedRows.push(pad(`${left}${row}${right}`, width));
|
|
52
|
+
}
|
|
53
|
+
const emptyRow = pad("", width);
|
|
54
|
+
if (this.paddingY <= 0) return paddedRows;
|
|
55
|
+
if (this.paddingY > 0) {
|
|
56
|
+
const topAndBottom = Array.from({ length: this.paddingY }, () => emptyRow);
|
|
57
|
+
return [...topAndBottom, ...paddedRows, ...topAndBottom];
|
|
58
|
+
}
|
|
59
|
+
return paddedRows;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export class Text implements RenderableComponent {
|
|
64
|
+
private text: string;
|
|
65
|
+
private cachedWidth = 0;
|
|
66
|
+
private cachedResult: string[] = [];
|
|
67
|
+
|
|
68
|
+
constructor(text = "") {
|
|
69
|
+
this.text = text;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
setText(text: string): void {
|
|
73
|
+
if (text === this.text) return;
|
|
74
|
+
this.text = text;
|
|
75
|
+
this.invalidate();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
invalidate(): void {
|
|
79
|
+
this.cachedWidth = 0;
|
|
80
|
+
this.cachedResult = [];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
render(width: number): string[] {
|
|
84
|
+
if (this.cachedWidth === width) return this.cachedResult;
|
|
85
|
+
const wrapped = wrapHard(this.text, Math.max(1, width));
|
|
86
|
+
const lines = wrapped.length ? wrapped : [""];
|
|
87
|
+
this.cachedWidth = width;
|
|
88
|
+
this.cachedResult = lines.map((line) => pad(line, width));
|
|
89
|
+
return this.cachedResult;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export class Spacer implements RenderableComponent {
|
|
94
|
+
private readonly rows: number;
|
|
95
|
+
|
|
96
|
+
constructor(rows = 0) {
|
|
97
|
+
this.rows = rows;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
render(width: number): string[] {
|
|
101
|
+
if (this.rows <= 0) return [];
|
|
102
|
+
return Array.from({ length: Math.max(0, this.rows) }, () => pad("", width));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
invalidate(): void {}
|
|
106
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* live-conversation-overlay.ts — Live conversation overlay for viewing live-session agent output.
|
|
3
|
+
*
|
|
4
|
+
* R8: Subscribes to session events for real-time streaming updates.
|
|
5
|
+
* Falls back to polling LiveAgentHandle.activity when subscribe is unavailable.
|
|
6
|
+
*/
|
|
7
|
+
import type { LiveAgentHandle } from "../runtime/live-agent-manager.ts";
|
|
8
|
+
import { pad, truncate } from "../utils/visual.ts";
|
|
9
|
+
import { computeLiveDurationMs } from "./live-duration.ts";
|
|
10
|
+
import { spinnerFrame } from "./spinner.ts";
|
|
11
|
+
import { iconForStatus } from "./status-colors.ts";
|
|
12
|
+
import type { CrewTheme } from "./theme-adapter.ts";
|
|
13
|
+
|
|
14
|
+
const CHROME_LINES = 6;
|
|
15
|
+
const MIN_VIEWPORT = 3;
|
|
16
|
+
|
|
17
|
+
export class LiveConversationOverlay {
|
|
18
|
+
private scrollOffset = 0;
|
|
19
|
+
private autoScroll = true;
|
|
20
|
+
private closed = false;
|
|
21
|
+
private pollTimer: ReturnType<typeof setInterval> | undefined;
|
|
22
|
+
cachedLines: string[] = [];
|
|
23
|
+
// H-4 fix (code-review 2026-06-23): cap the in-memory line buffer to avoid
|
|
24
|
+
// unbounded growth (OOM) during long-running live sessions. Oldest lines are
|
|
25
|
+
// dropped first; scrollOffset is adjusted to keep the viewport stable.
|
|
26
|
+
static readonly MAX_CACHED_LINES = 5000;
|
|
27
|
+
private columns: number;
|
|
28
|
+
private rows: number;
|
|
29
|
+
private unsubscribe: (() => void) | undefined;
|
|
30
|
+
|
|
31
|
+
private handle: LiveAgentHandle;
|
|
32
|
+
private theme: CrewTheme;
|
|
33
|
+
|
|
34
|
+
constructor(handle: LiveAgentHandle, theme: CrewTheme, columns = 80, rows = 24) {
|
|
35
|
+
this.handle = handle;
|
|
36
|
+
this.theme = theme;
|
|
37
|
+
this.columns = columns;
|
|
38
|
+
this.rows = rows;
|
|
39
|
+
// R8: Subscribe to real session events if available
|
|
40
|
+
const session = handle.session as Record<string, unknown>;
|
|
41
|
+
if (typeof session.subscribe === "function") {
|
|
42
|
+
try {
|
|
43
|
+
this.unsubscribe = (session.subscribe as (cb: (event: unknown) => void) => () => void)((event) => {
|
|
44
|
+
if (this.closed) return;
|
|
45
|
+
const obj = event as Record<string, unknown>;
|
|
46
|
+
const text = typeof obj.text === "string" ? obj.text : typeof obj.content === "string" ? obj.content : "";
|
|
47
|
+
if (text.trim()) {
|
|
48
|
+
this.pushLine(text);
|
|
49
|
+
if (this.autoScroll) this.scrollOffset = Math.max(0, this.cachedLines.length - this.viewportHeight());
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
} catch {
|
|
53
|
+
/* ignore */
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Also poll for summary updates. Skip when the user has scrolled up
|
|
57
|
+
// (autoScroll === false): the summary refresh also bumps scrollOffset
|
|
58
|
+
// to the tail, which would yank the viewport out from under them.
|
|
59
|
+
this.pollTimer = setInterval(() => {
|
|
60
|
+
if (this.closed) return;
|
|
61
|
+
if (!this.autoScroll) return;
|
|
62
|
+
try {
|
|
63
|
+
this.refreshSummary();
|
|
64
|
+
} catch {
|
|
65
|
+
/* ignore */
|
|
66
|
+
}
|
|
67
|
+
}, 200);
|
|
68
|
+
this.pollTimer.unref();
|
|
69
|
+
try {
|
|
70
|
+
this.refreshSummary();
|
|
71
|
+
} catch {
|
|
72
|
+
/* ignore */
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private pushLine(line: string): void {
|
|
77
|
+
this.cachedLines.push(line);
|
|
78
|
+
if (this.cachedLines.length > LiveConversationOverlay.MAX_CACHED_LINES) {
|
|
79
|
+
const drop = this.cachedLines.length - LiveConversationOverlay.MAX_CACHED_LINES;
|
|
80
|
+
this.cachedLines.splice(0, drop);
|
|
81
|
+
this.scrollOffset = Math.max(0, this.scrollOffset - drop);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private static readonly SUMMARY_PREFIX = "\u200B"; // zero-width space as summary sentinel
|
|
86
|
+
|
|
87
|
+
private refreshSummary(): void {
|
|
88
|
+
const act = this.handle.activity;
|
|
89
|
+
const summary = `${LiveConversationOverlay.SUMMARY_PREFIX}[${act.turnCount} turns · ${act.toolUses} tools · ${(computeLiveDurationMs(act) / 1000).toFixed(1)}s]`;
|
|
90
|
+
const lastLine = this.cachedLines[this.cachedLines.length - 1];
|
|
91
|
+
if (lastLine?.startsWith(LiveConversationOverlay.SUMMARY_PREFIX)) {
|
|
92
|
+
this.cachedLines[this.cachedLines.length - 1] = summary;
|
|
93
|
+
} else {
|
|
94
|
+
this.pushLine(summary);
|
|
95
|
+
}
|
|
96
|
+
if (this.autoScroll) this.scrollOffset = Math.max(0, this.cachedLines.length - this.viewportHeight());
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private viewportHeight(): number {
|
|
100
|
+
return Math.max(MIN_VIEWPORT, this.rows - CHROME_LINES);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
render(width?: number): string[] {
|
|
104
|
+
const w = width ?? this.columns;
|
|
105
|
+
if (w < 6) return [];
|
|
106
|
+
const th = this.theme;
|
|
107
|
+
const innerW = w - 4;
|
|
108
|
+
const row = (content: string) => th.fg("border", "│") + " " + pad(truncate(content, innerW), innerW) + " " + th.fg("border", "│");
|
|
109
|
+
const hrTop = th.fg("border", `╭${"─".repeat(w - 2)}╮`);
|
|
110
|
+
const hrBot = th.fg("border", `╰${"─".repeat(w - 2)}╯`);
|
|
111
|
+
const hrMid = row(th.fg("dim", "─".repeat(innerW)));
|
|
112
|
+
|
|
113
|
+
const lines: string[] = [];
|
|
114
|
+
lines.push(hrTop);
|
|
115
|
+
|
|
116
|
+
// Header
|
|
117
|
+
const statusIcon =
|
|
118
|
+
this.handle.status === "running"
|
|
119
|
+
? th.fg("accent", spinnerFrame(this.handle.taskId ?? this.handle.agentId))
|
|
120
|
+
: iconForStatus(this.handle.status);
|
|
121
|
+
const name = this.handle.agent ?? this.handle.taskId;
|
|
122
|
+
const act = this.handle.activity;
|
|
123
|
+
const elapsed = `${(computeLiveDurationMs(act) / 1000).toFixed(1)}s`;
|
|
124
|
+
const headerParts: string[] = [];
|
|
125
|
+
if (act.maxTurns != null) headerParts.push(`turn ${act.turnCount}/${act.maxTurns}`);
|
|
126
|
+
else if (act.turnCount > 0) headerParts.push(`turn ${act.turnCount}`);
|
|
127
|
+
if (act.toolUses > 0) headerParts.push(`${act.toolUses} tools`);
|
|
128
|
+
headerParts.push(elapsed);
|
|
129
|
+
|
|
130
|
+
// Context % + compaction
|
|
131
|
+
try {
|
|
132
|
+
const ctxPct = this.handle.session.getSessionStats?.()?.contextUsage?.percent;
|
|
133
|
+
if (ctxPct != null) {
|
|
134
|
+
const color = ctxPct >= 85 ? "error" : ctxPct >= 70 ? "warning" : "dim";
|
|
135
|
+
headerParts.push(th.fg(color, `${Math.round(ctxPct)}% ctx`));
|
|
136
|
+
}
|
|
137
|
+
} catch {
|
|
138
|
+
/* ignore */
|
|
139
|
+
}
|
|
140
|
+
if (act.compactionCount > 0) headerParts.push(th.fg("dim", `↻${act.compactionCount}`));
|
|
141
|
+
// Model name
|
|
142
|
+
if (this.handle.modelName) headerParts.push(th.fg("muted", this.handle.modelName));
|
|
143
|
+
|
|
144
|
+
const desc = this.handle.description ?? this.handle.role ?? "";
|
|
145
|
+
lines.push(
|
|
146
|
+
row(
|
|
147
|
+
`${statusIcon} ${th.fg("accent", name)} ${th.fg("muted", desc)} ${th.fg("dim", "·")} ${th.fg("dim", headerParts.join(" · "))}`,
|
|
148
|
+
),
|
|
149
|
+
);
|
|
150
|
+
lines.push(hrMid);
|
|
151
|
+
|
|
152
|
+
// Content
|
|
153
|
+
const vh = this.viewportHeight();
|
|
154
|
+
const visible = this.cachedLines.slice(this.scrollOffset, this.scrollOffset + vh);
|
|
155
|
+
for (const line of visible) {
|
|
156
|
+
lines.push(row(th.fg("dim", line)));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Footer
|
|
160
|
+
lines.push(hrMid);
|
|
161
|
+
const footerText = this.autoScroll
|
|
162
|
+
? "auto-scroll · esc/q close"
|
|
163
|
+
: `line ${this.scrollOffset + 1}/${this.cachedLines.length} · ↑/k ↓/j G/g · esc/q close`;
|
|
164
|
+
lines.push(row(th.fg("dim", footerText)));
|
|
165
|
+
lines.push(hrBot);
|
|
166
|
+
return lines;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
close(): void {
|
|
170
|
+
if (this.closed) return;
|
|
171
|
+
this.closed = true;
|
|
172
|
+
this.unsubscribe?.();
|
|
173
|
+
this.unsubscribe = undefined;
|
|
174
|
+
if (this.pollTimer) {
|
|
175
|
+
clearInterval(this.pollTimer);
|
|
176
|
+
this.pollTimer = undefined;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
dispose(): void {
|
|
181
|
+
this.close();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Round 23 (BUG 1 fix): live-agent duration computation.
|
|
3
|
+
*
|
|
4
|
+
* The naive `(completedAtMs ?? Date.now()) - startedAtMs` produced giant
|
|
5
|
+
* NEGATIVE durations for every running live agent whenever startedAtMs was
|
|
6
|
+
* 0/undefined/out-of-range, or a race set completedAtMs < startedAtMs.
|
|
7
|
+
*
|
|
8
|
+
* This module consolidates the validated duration math (previously duplicated
|
|
9
|
+
* between widget-formatters.ts and agents-pane.ts) into one pure, fully
|
|
10
|
+
* testable function: it normalizes seconds-vs-ms, sanity-checks the start
|
|
11
|
+
* timestamp against the current time, and never returns a negative value.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export interface LiveActivity {
|
|
15
|
+
startedAtMs?: number;
|
|
16
|
+
completedAtMs?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Normalize a raw timestamp that may be seconds or milliseconds. */
|
|
20
|
+
function toMs(v: number): number {
|
|
21
|
+
if (v <= 0) return 0;
|
|
22
|
+
// 1e9 < seconds < 1e10 → seconds, scale up
|
|
23
|
+
if (v > 1_000_000_000 && v < 10_000_000_000) return v * 1000;
|
|
24
|
+
// 1e10 < ms < 1e13 → already ms (>=10B seconds is 317+ years, implausible)
|
|
25
|
+
if (v > 10_000_000_000 && v < 10_000_000_000_000) return v;
|
|
26
|
+
return v;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Compute the live elapsed duration in milliseconds for an agent activity.
|
|
31
|
+
*
|
|
32
|
+
* - Never negative (clamped to >= 0).
|
|
33
|
+
* - Returns 0 if the start timestamp is missing or implausible.
|
|
34
|
+
* - Uses `completedAtMs` when present and sane; otherwise `nowMs` (running).
|
|
35
|
+
*
|
|
36
|
+
* @param activity the live agent activity handle
|
|
37
|
+
* @param nowMs optional override for `Date.now()` (tests / determinism)
|
|
38
|
+
*/
|
|
39
|
+
export function computeLiveDurationMs(activity: LiveActivity, nowMs: number = Date.now()): number {
|
|
40
|
+
const rawStarted = activity.startedAtMs || 0;
|
|
41
|
+
const rawCompleted = activity.completedAtMs || 0;
|
|
42
|
+
const startedMs = toMs(rawStarted);
|
|
43
|
+
const completedMs = rawCompleted > 0 ? toMs(rawCompleted) : 0;
|
|
44
|
+
// A valid start is positive, not more than 1 minute in the future, and not
|
|
45
|
+
// more than ~1000 years in the past (guards against 0 / garbage / clock skew).
|
|
46
|
+
const isValidStarted = startedMs > 0 && startedMs < nowMs + 60_000 && startedMs > nowMs - 31_556_926_000_000;
|
|
47
|
+
const end = completedMs > 0 && completedMs < nowMs + 60_000 ? completedMs : nowMs;
|
|
48
|
+
const ms = end - (isValidStarted ? startedMs : nowMs);
|
|
49
|
+
return Number.isFinite(ms) && ms >= 0 ? ms : 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Format a live duration in seconds, e.g. `12.3s`. Returns `0.0s` for 0. */
|
|
53
|
+
export function formatLiveDuration(activity: LiveActivity, nowMs: number = Date.now()): string {
|
|
54
|
+
return `${(computeLiveDurationMs(activity, nowMs) / 1000).toFixed(1)}s`;
|
|
55
|
+
}
|