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,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Widget data model — fetching, filtering, and caching.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from crew-widget.ts.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { listRecentRuns } from "../../extension/run-index.ts";
|
|
8
|
+
import { reconcileAllStaleRuns } from "../../runtime/crash-recovery.ts";
|
|
9
|
+
import { readCrewAgents } from "../../runtime/crew-agent-records.ts";
|
|
10
|
+
import type { CrewAgentRecord } from "../../runtime/crew-agent-runtime.ts";
|
|
11
|
+
import { evictStaleLiveAgentHandles } from "../../runtime/live-agent-manager.ts";
|
|
12
|
+
import type { ManifestCache } from "../../runtime/manifest-cache.ts";
|
|
13
|
+
import { isDisplayActiveRun } from "../../runtime/process-status.ts";
|
|
14
|
+
import type { TeamRunManifest } from "../../state/types.ts";
|
|
15
|
+
import type { RunSnapshotCache } from "../snapshot-types.ts";
|
|
16
|
+
import type { WidgetRun } from "./widget-types.ts";
|
|
17
|
+
|
|
18
|
+
let lastStaleReconcileAt = 0;
|
|
19
|
+
const STALE_RECONCILE_INTERVAL_MS = 60_000;
|
|
20
|
+
|
|
21
|
+
function agentsFor(run: TeamRunManifest): CrewAgentRecord[] {
|
|
22
|
+
try {
|
|
23
|
+
return readCrewAgents(run);
|
|
24
|
+
} catch {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Get active widget runs for display.
|
|
31
|
+
*/
|
|
32
|
+
export function activeWidgetRuns(
|
|
33
|
+
cwd: string,
|
|
34
|
+
manifestCache?: ManifestCache,
|
|
35
|
+
snapshotCache?: RunSnapshotCache,
|
|
36
|
+
preloadedManifests?: TeamRunManifest[],
|
|
37
|
+
workspaceId?: string,
|
|
38
|
+
): WidgetRun[] {
|
|
39
|
+
evictStaleLiveAgentHandles();
|
|
40
|
+
|
|
41
|
+
const now = Date.now();
|
|
42
|
+
if (now - lastStaleReconcileAt > STALE_RECONCILE_INTERVAL_MS && manifestCache) {
|
|
43
|
+
lastStaleReconcileAt = now;
|
|
44
|
+
try {
|
|
45
|
+
reconcileAllStaleRuns(cwd, manifestCache);
|
|
46
|
+
} catch {
|
|
47
|
+
/* non-critical */
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let runs = preloadedManifests ?? (manifestCache ? manifestCache.list(20) : listRecentRuns(cwd, 20));
|
|
52
|
+
if (workspaceId) {
|
|
53
|
+
runs = runs.filter((run) => !run.ownerSessionId || run.ownerSessionId === workspaceId);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return runs
|
|
57
|
+
.map((run) => {
|
|
58
|
+
try {
|
|
59
|
+
const snapshot = snapshotCache?.get(run.runId);
|
|
60
|
+
if (snapshot) {
|
|
61
|
+
return {
|
|
62
|
+
run: snapshot.manifest,
|
|
63
|
+
agents: snapshot.agents,
|
|
64
|
+
snapshot,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
// P0-6: render from snapshots only — never read disk on every
|
|
68
|
+
// render tick. When the snapshot cache is provided but hasn't
|
|
69
|
+
// populated yet (first frame after `updateCrewWidget`), drop the
|
|
70
|
+
// run from the result so the widget paints "(loading…)" instead
|
|
71
|
+
// of calling `agentsFor(run) → readCrewAgents`. Legacy callers
|
|
72
|
+
// (no snapshotCache) keep the disk-read fallback for tests/dev.
|
|
73
|
+
if (snapshotCache) return null;
|
|
74
|
+
return { run, agents: agentsFor(run) };
|
|
75
|
+
} catch {
|
|
76
|
+
if (snapshotCache) return null;
|
|
77
|
+
return { run, agents: agentsFor(run) };
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
.filter((item): item is WidgetRun => item !== null && isDisplayActiveRun(item.run, item.agents));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Build a status summary string for the status bar.
|
|
85
|
+
*/
|
|
86
|
+
export function statusSummary(runs: WidgetRun[]): string {
|
|
87
|
+
const agents = runs.flatMap((item) => item.agents);
|
|
88
|
+
const runningAgents = agents.filter((a) => a.status === "running").length;
|
|
89
|
+
const queuedAgents = agents.filter((a) => a.status === "queued" || a.status === "waiting").length;
|
|
90
|
+
const completedAgents = agents.filter((a) => a.status === "completed").length;
|
|
91
|
+
const totalAgents = agents.length;
|
|
92
|
+
const totalRuns = runs.length;
|
|
93
|
+
const model = agents
|
|
94
|
+
.find((a) => a.model)
|
|
95
|
+
?.model?.split("/")
|
|
96
|
+
.at(-1);
|
|
97
|
+
const parts = [`⚙ ${runningAgents}r`];
|
|
98
|
+
if (queuedAgents > 0) parts.push(`${queuedAgents}q`);
|
|
99
|
+
if (completedAgents > 0) parts.push(`${completedAgents}/${totalAgents}done`);
|
|
100
|
+
if (totalRuns > 1) parts.push(`${totalRuns}runs`);
|
|
101
|
+
if (model) parts.push(model);
|
|
102
|
+
return parts.join(" · ");
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Build the short run label (team/workflow).
|
|
107
|
+
*/
|
|
108
|
+
export function shortRunLabel(run: TeamRunManifest): string {
|
|
109
|
+
return `${run.team}/${run.workflow ?? "none"}`;
|
|
110
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Widget rendering — builds and colorizes widget lines.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from crew-widget.ts.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { listLiveAgents } from "../../runtime/live-agent-manager.ts";
|
|
8
|
+
import { isFinishedRunStatus } from "../../runtime/process-status.ts";
|
|
9
|
+
import { truncate } from "../../utils/visual.ts";
|
|
10
|
+
import { Box, Text } from "../layout-primitives.ts";
|
|
11
|
+
import { spinnerFrame } from "../spinner.ts";
|
|
12
|
+
import { colorizeStatusGlyphs, iconForStatus } from "../status-colors.ts";
|
|
13
|
+
import type { CrewTheme } from "../theme-adapter.ts";
|
|
14
|
+
import { agentActivity, agentStats, notificationBadge } from "./widget-formatters.ts";
|
|
15
|
+
import { activeWidgetRuns, shortRunLabel } from "./widget-model.ts";
|
|
16
|
+
import type { WidgetRun } from "./widget-types.ts";
|
|
17
|
+
|
|
18
|
+
const MAX_AGENTS_DISPLAY = 3;
|
|
19
|
+
const FINISHED_LINGER_MAX_AGE = 1;
|
|
20
|
+
/** Default terminal width when caller doesn't pass one explicitly. Keep <= 116
|
|
21
|
+
* (the same default used elsewhere in pi-crew tool renderers) so we never paint
|
|
22
|
+
* a line wider than the smallest expected TUI. Callers SHOULD pass the real
|
|
23
|
+
* width when known (via ctx.width || process.stdout.columns). */
|
|
24
|
+
export const DEFAULT_WIDGET_WIDTH = 100;
|
|
25
|
+
/** Cap per-component text so a single field cannot blow past width on its own. */
|
|
26
|
+
export const TASK_DESC_MAX = 60;
|
|
27
|
+
const ERROR_LINGER_MAX_AGE = 2;
|
|
28
|
+
const ERROR_STATUSES = new Set(["failed", "cancelled", "stopped", "needs_attention"]);
|
|
29
|
+
|
|
30
|
+
// ── Header ────────────────────────────────────────────────────────────
|
|
31
|
+
|
|
32
|
+
export function widgetHeader(runs: WidgetRun[], runningGlyph: string, maxLines = 20, notificationCount = 0): string {
|
|
33
|
+
const agents = runs.flatMap((item) => item.agents);
|
|
34
|
+
const runningAgents = agents.filter((a) => a.status === "running").length;
|
|
35
|
+
const queuedAgents = agents.filter((a) => a.status === "queued").length;
|
|
36
|
+
const waitingAgents = agents.filter((a) => a.status === "waiting").length;
|
|
37
|
+
const completedAgents = agents.filter((a) => a.status === "completed").length;
|
|
38
|
+
const parts = [`${runningAgents} running`];
|
|
39
|
+
if (queuedAgents) parts.push(`${queuedAgents} queued`);
|
|
40
|
+
if (waitingAgents) parts.push(`${waitingAgents} waiting`);
|
|
41
|
+
if (completedAgents) parts.push(`${completedAgents}/${agents.length} done`);
|
|
42
|
+
return `${runningGlyph} Crew agents${notificationBadge(notificationCount)} · ${parts.join(" · ")} · /team-dashboard`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ── Line builder ──────────────────────────────────────────────────────
|
|
46
|
+
|
|
47
|
+
export function buildWidgetLines(
|
|
48
|
+
cwd: string,
|
|
49
|
+
frame = 0,
|
|
50
|
+
maxLines = 8,
|
|
51
|
+
providedRuns?: WidgetRun[],
|
|
52
|
+
notificationCount = 0,
|
|
53
|
+
width = DEFAULT_WIDGET_WIDTH,
|
|
54
|
+
): string[] {
|
|
55
|
+
// Match the legacy `buildCrewWidgetLines` API: when no runs are supplied,
|
|
56
|
+
// auto-fetch via activeWidgetRuns(cwd). Otherwise widgets calling with
|
|
57
|
+
// only `(cwd, frame)` would render an empty line set (regression vs. the
|
|
58
|
+
// pre-refactor implementation that called activeWidgetRuns here).
|
|
59
|
+
const runs = providedRuns ?? activeWidgetRuns(cwd);
|
|
60
|
+
if (!runs.length) return [];
|
|
61
|
+
|
|
62
|
+
const runningGlyph = spinnerFrame("widget-header");
|
|
63
|
+
const lines: string[] = [widgetHeader(runs, runningGlyph, maxLines, notificationCount)];
|
|
64
|
+
|
|
65
|
+
for (const { run, agents, snapshot } of runs) {
|
|
66
|
+
const activeAgents = agents.filter((a) => a.status === "running" || a.status === "queued" || a.status === "waiting");
|
|
67
|
+
const now = Date.now();
|
|
68
|
+
const finishedAgents = agents.filter((item) => {
|
|
69
|
+
if (item.status === "running" || item.status === "queued" || item.status === "waiting") return false;
|
|
70
|
+
if (!item.completedAt) return false;
|
|
71
|
+
const maxAgeMs = (ERROR_STATUSES.has(item.status) ? ERROR_LINGER_MAX_AGE : FINISHED_LINGER_MAX_AGE) * 60_000;
|
|
72
|
+
const age = now - new Date(item.completedAt).getTime();
|
|
73
|
+
return Number.isFinite(age) && age < maxAgeMs;
|
|
74
|
+
});
|
|
75
|
+
const completed = agents.filter((a) => a.status === "completed").length;
|
|
76
|
+
const runGlyph = iconForStatus(run.status, { runningGlyph });
|
|
77
|
+
const isTerminal = isFinishedRunStatus(run.status);
|
|
78
|
+
// Run progress line. v1–v3 flickered on snapshot.tasks state, v4 was
|
|
79
|
+
// too minimal (`0/1 agents` only), v5 duplicated the worker activity
|
|
80
|
+
// line (tools/tokens/duration already shown one row below). v6 (this)
|
|
81
|
+
// shows only data that is RUN-level (not already in the per-agent
|
|
82
|
+
// activity line) and is GUARANTEED stable across ticks:
|
|
83
|
+
// - agents count — from `agents` array, always populated, never empty.
|
|
84
|
+
// - run elapsed — from `run.createdAt`, always set on manifest.
|
|
85
|
+
// Both come from sources with no race window — `agents` is read from
|
|
86
|
+
// snapshot.agents OR agentsFor(run) (both always return same length
|
|
87
|
+
// for a healthy run), and `run.createdAt` is immutable. The format
|
|
88
|
+
// shape `"X/Y agents · Ns"` is therefore truly invariant: same number
|
|
89
|
+
// of `·`-separated fields, same field meanings, every render tick.
|
|
90
|
+
//
|
|
91
|
+
// Bug 022 (timer-fix + label): for TERMINAL runs (failed/cancelled/
|
|
92
|
+
// completed) the elapsed counter previously kept ticking up forever
|
|
93
|
+
// from createdAt (a failed run showed `2028s` and climbing, read as
|
|
94
|
+
// "still running"). Now it FREEZES at updatedAt (when the run
|
|
95
|
+
// reached its terminal status). The status label is also surfaced
|
|
96
|
+
// explicitly so the row cannot be misread as an active run.
|
|
97
|
+
const agentCountText = `${completed}/${agents.length} agents`;
|
|
98
|
+
const runEndMs = isTerminal ? new Date(run.updatedAt).getTime() : now;
|
|
99
|
+
const runElapsedMs = Math.max(0, Number.isFinite(runEndMs) ? runEndMs - new Date(run.createdAt).getTime() : 0);
|
|
100
|
+
const runElapsedText = `${Math.floor(runElapsedMs / 1000)}s`;
|
|
101
|
+
const statusLabel = isTerminal ? ` · ${run.status}` : "";
|
|
102
|
+
const progressPart = `${agentCountText} · ${runElapsedText}${statusLabel}`;
|
|
103
|
+
lines.push(truncate(`├─ ${runGlyph} ${shortRunLabel(run)} · ${progressPart} · ${run.runId.slice(-8)}`, width));
|
|
104
|
+
|
|
105
|
+
const liveForRun = listLiveAgents().filter((a) => a.runId === run.runId);
|
|
106
|
+
|
|
107
|
+
// L-4: prioritize RUNNING > QUEUED > WAITING within the visible window so the
|
|
108
|
+
// most relevant live workers are always shown. Finished rows fill only the
|
|
109
|
+
// leftover budget and never steal slots from running agents.
|
|
110
|
+
const ACTIVE_PRIORITY: Record<string, number> = {
|
|
111
|
+
running: 0,
|
|
112
|
+
queued: 1,
|
|
113
|
+
waiting: 2,
|
|
114
|
+
};
|
|
115
|
+
const prioritizedActive = [...activeAgents].sort((a, b) => (ACTIVE_PRIORITY[a.status] ?? 9) - (ACTIVE_PRIORITY[b.status] ?? 9));
|
|
116
|
+
// Finished rows only appear in slots not used by active agents (max 2). When
|
|
117
|
+
// there are >= MAX_AGENTS_DISPLAY live workers, finished rows are suppressed
|
|
118
|
+
// entirely so they cannot push a live agent's activity line off-screen.
|
|
119
|
+
const finishedSlots = Math.max(0, Math.min(2, MAX_AGENTS_DISPLAY - activeAgents.length));
|
|
120
|
+
|
|
121
|
+
const visibleAgents = prioritizedActive.slice(0, MAX_AGENTS_DISPLAY);
|
|
122
|
+
for (const [index, agent] of visibleAgents.entries()) {
|
|
123
|
+
const last = index === visibleAgents.length - 1 && activeAgents.length <= MAX_AGENTS_DISPLAY && finishedSlots === 0;
|
|
124
|
+
const branch = last ? "└─" : "├─";
|
|
125
|
+
const agentGlyph = iconForStatus(agent.status, { runningGlyph });
|
|
126
|
+
const liveHandle = liveForRun.find((h) => h.taskId === agent.taskId);
|
|
127
|
+
const stats = agentStats(agent, liveHandle);
|
|
128
|
+
const name = liveHandle?.agent ?? agent.agent;
|
|
129
|
+
const desc = truncate(liveHandle?.description ?? agent.role ?? "", TASK_DESC_MAX);
|
|
130
|
+
const _activeMain = truncate(`│ ${branch} ${agentGlyph} ${name}${desc ? ` · ${desc}` : ` · ${agent.role}`}`, width);
|
|
131
|
+
lines.push(_activeMain);
|
|
132
|
+
const _activity = truncate(`│ ⊶ ${agentActivity(agent, liveHandle)}${stats ? ` · ${stats}` : ""}`, width);
|
|
133
|
+
lines.push(_activity);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (activeAgents.length > MAX_AGENTS_DISPLAY) {
|
|
137
|
+
lines.push(truncate(`│ └─ … +${activeAgents.length - MAX_AGENTS_DISPLAY} more agents`, width));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
for (const [index, agent] of finishedAgents.slice(0, finishedSlots).entries()) {
|
|
141
|
+
const liveHandle = liveForRun.find((h) => h.taskId === agent.taskId);
|
|
142
|
+
const name = liveHandle?.agent ?? agent.agent;
|
|
143
|
+
const icon =
|
|
144
|
+
agent.status === "completed" ? "✓" : agent.status === "failed" ? "✗" : agent.status === "needs_attention" ? "⚠" : "▪";
|
|
145
|
+
const stats = agentStats(agent, liveHandle);
|
|
146
|
+
const desc = truncate(liveHandle?.description ?? agent.role ?? "", TASK_DESC_MAX);
|
|
147
|
+
const isLastFinished = index === Math.min(finishedAgents.length, finishedSlots) - 1;
|
|
148
|
+
const branch = isLastFinished ? "└─" : "├─";
|
|
149
|
+
const _finished = truncate(`│ ${branch} ${icon} ${name} · ${desc}${stats ? ` · ${stats}` : ""}`, width);
|
|
150
|
+
lines.push(_finished);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (lines.length >= maxLines) break;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return lines.slice(0, maxLines);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// ── Colorization ──────────────────────────────────────────────────────
|
|
160
|
+
|
|
161
|
+
export function colorWidgetLine(line: string, index: number, theme: CrewTheme): string {
|
|
162
|
+
let result = line;
|
|
163
|
+
if (index === 0) {
|
|
164
|
+
result = result.replace("Crew agents", theme.bold(theme.fg("accent", "Crew agents")));
|
|
165
|
+
}
|
|
166
|
+
// Shared glyph colorizer covers ALL status glyphs — including ⏳ (waiting),
|
|
167
|
+
// ⚠ (needs_attention), and the braille spinner range ⠁-⣿ (running) — which the
|
|
168
|
+
// previous local statusGlyphColor map + regex omitted (F-1, V-3).
|
|
169
|
+
result = colorizeStatusGlyphs(result, theme);
|
|
170
|
+
if (index === 0) {
|
|
171
|
+
result = theme.fg("accent", result);
|
|
172
|
+
}
|
|
173
|
+
return result;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function renderLines(lines: string[], width: number): string[] {
|
|
177
|
+
const box = new Box(0, 0);
|
|
178
|
+
for (const line of lines) {
|
|
179
|
+
box.addChild(new Text(line));
|
|
180
|
+
}
|
|
181
|
+
return box.render(width);
|
|
182
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Widget type definitions.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { CrewAgentRecord } from "../../runtime/crew-agent-runtime.ts";
|
|
6
|
+
import type { ManifestCache } from "../../runtime/manifest-cache.ts";
|
|
7
|
+
import type { TeamRunManifest } from "../../state/types.ts";
|
|
8
|
+
import type { RunSnapshotCache, RunUiSnapshot } from "../snapshot-types.ts";
|
|
9
|
+
|
|
10
|
+
export interface WidgetRun {
|
|
11
|
+
run: TeamRunManifest;
|
|
12
|
+
agents: CrewAgentRecord[];
|
|
13
|
+
snapshot?: RunUiSnapshot;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface CrewWidgetModel {
|
|
17
|
+
cwd: string;
|
|
18
|
+
frame: number;
|
|
19
|
+
maxLines: number;
|
|
20
|
+
notificationCount?: number;
|
|
21
|
+
manifestCache?: ManifestCache;
|
|
22
|
+
snapshotCache?: RunSnapshotCache;
|
|
23
|
+
preloadManifests?: TeamRunManifest[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface CrewWidgetState {
|
|
27
|
+
frame: number;
|
|
28
|
+
lastPlacement?: string;
|
|
29
|
+
lastVisibility?: "hidden" | "visible";
|
|
30
|
+
lastKey?: string;
|
|
31
|
+
lastMaxLines?: number;
|
|
32
|
+
lastCwd?: string;
|
|
33
|
+
legacyCleared?: boolean;
|
|
34
|
+
model?: CrewWidgetModel;
|
|
35
|
+
notificationCount?: number;
|
|
36
|
+
}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import type { AgentConfig } from "../agents/agent-config.ts";
|
|
2
|
+
import type { TeamConfig } from "../teams/team-config.ts";
|
|
3
|
+
|
|
4
|
+
interface SearchDocument {
|
|
5
|
+
id: string;
|
|
6
|
+
fields: Record<string, string>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface SearchResult<T> {
|
|
10
|
+
item: T;
|
|
11
|
+
score: number;
|
|
12
|
+
matchedOn: string[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface BM25Config {
|
|
16
|
+
k1?: number;
|
|
17
|
+
b?: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class BM25Search<T extends SearchDocument> {
|
|
21
|
+
private readonly documents: T[];
|
|
22
|
+
private readonly fieldWeights: Record<string, number>;
|
|
23
|
+
private readonly avgDocLen: number;
|
|
24
|
+
private readonly k1: number;
|
|
25
|
+
private readonly b: number;
|
|
26
|
+
private readonly docLenMap: Map<string, number>;
|
|
27
|
+
private readonly N: number;
|
|
28
|
+
/**
|
|
29
|
+
* Precomputed document frequency per term. Cached at construction time
|
|
30
|
+
* to avoid O(N) recomputation on every search() call. The cache is
|
|
31
|
+
* immutable for a given document corpus, so it's safe to share across
|
|
32
|
+
* search() invocations.
|
|
33
|
+
*/
|
|
34
|
+
private readonly dfCache: Map<string, number>;
|
|
35
|
+
|
|
36
|
+
constructor(documents: T[], fieldWeights: Record<string, number> = {}, config: BM25Config = {}) {
|
|
37
|
+
this.documents = documents;
|
|
38
|
+
this.fieldWeights = fieldWeights;
|
|
39
|
+
this.k1 = config.k1 ?? 1.5;
|
|
40
|
+
this.b = config.b ?? 0.75;
|
|
41
|
+
this.N = documents.length;
|
|
42
|
+
|
|
43
|
+
this.docLenMap = new Map();
|
|
44
|
+
this.dfCache = new Map();
|
|
45
|
+
|
|
46
|
+
for (const doc of documents) {
|
|
47
|
+
const fieldValues = Object.values(doc.fields).join(" ");
|
|
48
|
+
const len = fieldValues.split(/\s+/).filter(Boolean).length;
|
|
49
|
+
this.docLenMap.set(doc.id, len);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const totalLen = [...this.docLenMap.values()].reduce((a, b) => a + b, 0);
|
|
53
|
+
this.avgDocLen = totalLen / this.N || 1;
|
|
54
|
+
|
|
55
|
+
// Precompute df for all terms in the corpus. We do this once instead
|
|
56
|
+
// of on-demand to avoid the O(Q * N * field_count) cost per search call.
|
|
57
|
+
this.precomputeDocumentFrequencies();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Build a map of term -> document frequency. O(N * avg_terms * field_count).
|
|
62
|
+
* Called once in the constructor.
|
|
63
|
+
*/
|
|
64
|
+
private precomputeDocumentFrequencies(): void {
|
|
65
|
+
for (const doc of this.documents) {
|
|
66
|
+
for (const field of Object.keys(this.fieldWeights)) {
|
|
67
|
+
const text = (doc.fields[field] ?? "").toLowerCase();
|
|
68
|
+
// Extract unique terms via split on whitespace
|
|
69
|
+
const terms = new Set(text.split(/\s+/).filter(Boolean));
|
|
70
|
+
for (const term of terms) {
|
|
71
|
+
if (term.length === 0) continue;
|
|
72
|
+
this.dfCache.set(term, (this.dfCache.get(term) ?? 0) + 1);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get document frequency for a term. Returns the precomputed value.
|
|
80
|
+
* O(1) lookup.
|
|
81
|
+
*/
|
|
82
|
+
private df(term: string): number {
|
|
83
|
+
return this.dfCache.get(term.toLowerCase()) ?? 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
search(query: string, options?: { limit?: number; minScore?: number }): SearchResult<T>[] {
|
|
87
|
+
const queryTerms = query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
88
|
+
if (queryTerms.length === 0) return [];
|
|
89
|
+
|
|
90
|
+
const results: SearchResult<T>[] = [];
|
|
91
|
+
|
|
92
|
+
for (const doc of this.documents) {
|
|
93
|
+
let totalScore = 0;
|
|
94
|
+
const matchedOn: string[] = [];
|
|
95
|
+
|
|
96
|
+
for (const [field, weight] of Object.entries(this.fieldWeights)) {
|
|
97
|
+
const text = doc.fields[field] ?? "";
|
|
98
|
+
const textLower = text.toLowerCase();
|
|
99
|
+
let fieldScore = 0;
|
|
100
|
+
|
|
101
|
+
for (const term of queryTerms) {
|
|
102
|
+
// Use indexOf for linear-time substring counting instead of regex
|
|
103
|
+
const termLower = term.toLowerCase();
|
|
104
|
+
let tf = 0;
|
|
105
|
+
let pos = 0;
|
|
106
|
+
while ((pos = textLower.indexOf(termLower, pos)) !== -1) {
|
|
107
|
+
tf++;
|
|
108
|
+
pos += termLower.length;
|
|
109
|
+
// Cap tf to prevent runaway on repeated patterns
|
|
110
|
+
if (tf > 100) break;
|
|
111
|
+
}
|
|
112
|
+
if (tf === 0) continue;
|
|
113
|
+
|
|
114
|
+
const df = this.df(termLower);
|
|
115
|
+
if (df === 0) continue;
|
|
116
|
+
|
|
117
|
+
const idf = Math.log((this.N - df + 0.5) / (df + 0.5) + 1);
|
|
118
|
+
const docLen = this.docLenMap.get(doc.id) ?? this.avgDocLen;
|
|
119
|
+
const numerator = tf * (this.k1 + 1);
|
|
120
|
+
const denominator = tf + this.k1 * (1 - this.b + (this.b * docLen) / this.avgDocLen);
|
|
121
|
+
fieldScore += idf * (numerator / denominator);
|
|
122
|
+
|
|
123
|
+
matchedOn.push(field);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
totalScore += fieldScore * (weight || 1);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (totalScore > 0) {
|
|
130
|
+
results.push({
|
|
131
|
+
item: doc,
|
|
132
|
+
score: totalScore,
|
|
133
|
+
matchedOn: [...new Set(matchedOn)],
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
results.sort((a, b) => b.score - a.score);
|
|
139
|
+
|
|
140
|
+
const limit = options?.limit ?? 10;
|
|
141
|
+
const minScore = options?.minScore ?? 0.01;
|
|
142
|
+
|
|
143
|
+
return results.filter((r) => r.score >= minScore).slice(0, limit);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Agent search interface
|
|
148
|
+
interface AgentSearchResult {
|
|
149
|
+
agent: AgentConfig;
|
|
150
|
+
score: number;
|
|
151
|
+
matchedOn: string[];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Search agents using BM25 ranking.
|
|
156
|
+
* Uses dynamic import to avoid ESM/CJS issues at module load time.
|
|
157
|
+
*/
|
|
158
|
+
export async function searchAgents(query: string, options?: { limit?: number }): Promise<AgentSearchResult[]> {
|
|
159
|
+
// LAZY: defer dynamic import of ../agents/discover-agents.ts to its call site.
|
|
160
|
+
const { discoverAgents, allAgents } = await import("../agents/discover-agents.ts");
|
|
161
|
+
const discovery = discoverAgents(process.cwd());
|
|
162
|
+
const all = allAgents(discovery);
|
|
163
|
+
|
|
164
|
+
const docs: (SearchDocument & { agent: AgentConfig })[] = all.map((agent: AgentConfig) => ({
|
|
165
|
+
id: agent.name,
|
|
166
|
+
fields: {
|
|
167
|
+
name: agent.name,
|
|
168
|
+
description: agent.description ?? "",
|
|
169
|
+
skills: (agent.skills ?? []).join(" "),
|
|
170
|
+
},
|
|
171
|
+
agent,
|
|
172
|
+
}));
|
|
173
|
+
|
|
174
|
+
const engine = new BM25Search(docs, {
|
|
175
|
+
name: 3.0,
|
|
176
|
+
description: 1.5,
|
|
177
|
+
skills: 1.0,
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
const results = engine.search(query, {
|
|
181
|
+
limit: options?.limit ?? 10,
|
|
182
|
+
minScore: 0.1,
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
return results.map((r) => ({
|
|
186
|
+
agent: r.item.agent,
|
|
187
|
+
score: r.score,
|
|
188
|
+
matchedOn: r.matchedOn,
|
|
189
|
+
}));
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Team search interface
|
|
193
|
+
interface TeamSearchResult {
|
|
194
|
+
team: TeamConfig;
|
|
195
|
+
score: number;
|
|
196
|
+
matchedOn: string[];
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Search teams using BM25 ranking.
|
|
201
|
+
* Uses dynamic import to avoid ESM/CJS issues at module load time.
|
|
202
|
+
*/
|
|
203
|
+
export async function searchTeams(query: string, options?: { limit?: number }): Promise<TeamSearchResult[]> {
|
|
204
|
+
// LAZY: defer dynamic import of ../teams/discover-teams.ts to its call site.
|
|
205
|
+
const { discoverTeams, allTeams } = await import("../teams/discover-teams.ts");
|
|
206
|
+
const discovery = discoverTeams(process.cwd());
|
|
207
|
+
const all = allTeams(discovery);
|
|
208
|
+
|
|
209
|
+
const docs: (SearchDocument & { team: TeamConfig })[] = all.map((team: TeamConfig) => ({
|
|
210
|
+
id: team.name,
|
|
211
|
+
fields: {
|
|
212
|
+
name: team.name,
|
|
213
|
+
description: team.description ?? "",
|
|
214
|
+
roles: (team.roles ?? []).map((r: { name: string }) => r.name).join(" "),
|
|
215
|
+
},
|
|
216
|
+
team,
|
|
217
|
+
}));
|
|
218
|
+
|
|
219
|
+
const engine = new BM25Search(docs, {
|
|
220
|
+
name: 2.0,
|
|
221
|
+
description: 1.5,
|
|
222
|
+
roles: 1.0,
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
const results = engine.search(query, {
|
|
226
|
+
limit: options?.limit ?? 5,
|
|
227
|
+
minScore: 0.1,
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
return results.map((r) => ({
|
|
231
|
+
team: r.item.team,
|
|
232
|
+
score: r.score,
|
|
233
|
+
matchedOn: r.matchedOn,
|
|
234
|
+
}));
|
|
235
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
interface CompletionDataLike {
|
|
2
|
+
id?: unknown;
|
|
3
|
+
agent?: unknown;
|
|
4
|
+
timestamp?: unknown;
|
|
5
|
+
sessionId?: unknown;
|
|
6
|
+
taskIndex?: unknown;
|
|
7
|
+
totalTasks?: unknown;
|
|
8
|
+
success?: unknown;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function asNonEmptyString(value: unknown): string | undefined {
|
|
12
|
+
if (typeof value !== "string") return undefined;
|
|
13
|
+
const trimmed = value.trim();
|
|
14
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function asFiniteNumber(value: unknown): number | undefined {
|
|
18
|
+
if (typeof value !== "number") return undefined;
|
|
19
|
+
return Number.isFinite(value) ? value : undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function buildCompletionKey(data: CompletionDataLike, fallback: string): string {
|
|
23
|
+
const id = asNonEmptyString(data.id);
|
|
24
|
+
if (id) return `id:${id}`;
|
|
25
|
+
const sessionId = asNonEmptyString(data.sessionId) ?? "no-session";
|
|
26
|
+
const agent = asNonEmptyString(data.agent) ?? "unknown";
|
|
27
|
+
const timestamp = asFiniteNumber(data.timestamp);
|
|
28
|
+
const taskIndex = asFiniteNumber(data.taskIndex);
|
|
29
|
+
const totalTasks = asFiniteNumber(data.totalTasks);
|
|
30
|
+
const success = typeof data.success === "boolean" ? (data.success ? "1" : "0") : "?";
|
|
31
|
+
return [
|
|
32
|
+
"meta",
|
|
33
|
+
sessionId,
|
|
34
|
+
agent,
|
|
35
|
+
timestamp !== undefined ? String(timestamp) : "no-ts",
|
|
36
|
+
taskIndex !== undefined ? String(taskIndex) : "-",
|
|
37
|
+
totalTasks !== undefined ? String(totalTasks) : "-",
|
|
38
|
+
success,
|
|
39
|
+
fallback,
|
|
40
|
+
].join(":");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function pruneSeenMap(seen: Map<string, number>, now: number, ttlMs: number): void {
|
|
44
|
+
for (const [key, ts] of seen.entries()) {
|
|
45
|
+
if (now - ts > ttlMs) seen.delete(key);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function markSeenWithTtl(seen: Map<string, number>, key: string, now: number, ttlMs: number): boolean {
|
|
50
|
+
pruneSeenMap(seen, now, ttlMs);
|
|
51
|
+
if (seen.has(key)) return true;
|
|
52
|
+
seen.set(key, now);
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function getGlobalSeenMap(storeKey: string): Map<string, number> {
|
|
57
|
+
const globalStore = globalThis as Record<string, unknown>;
|
|
58
|
+
const existing = globalStore[storeKey];
|
|
59
|
+
if (existing instanceof Map) return existing as Map<string, number>;
|
|
60
|
+
const map = new Map<string, number>();
|
|
61
|
+
globalStore[storeKey] = map;
|
|
62
|
+
return map;
|
|
63
|
+
}
|