mixdog 0.9.2 → 0.9.4
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/package.json +8 -3
- package/scripts/anthropic-maxtokens-test.mjs +119 -0
- package/scripts/bench/lead-review-tasks-r3.json +20 -0
- package/scripts/bench/lead-review-tasks.json +20 -0
- package/scripts/bench/r4-mixed-tasks.json +20 -0
- package/scripts/bench/review-tasks.json +20 -0
- package/scripts/bench/round-codex.json +114 -0
- package/scripts/bench/round-mixdog-lead-r3.json +269 -0
- package/scripts/bench/round-mixdog-lead.json +269 -0
- package/scripts/bench/round-mixdog.json +126 -0
- package/scripts/bench/round-r10-bigsample.json +679 -0
- package/scripts/bench/round-r11-codexalign.json +257 -0
- package/scripts/bench/round-r4-codex.json +114 -0
- package/scripts/bench/round-r4-mixed.json +225 -0
- package/scripts/bench/round-r5-gpt-lead.json +259 -0
- package/scripts/bench/round-r6-codex.json +114 -0
- package/scripts/bench/round-r6-solo.json +257 -0
- package/scripts/bench/round-r7-full.json +254 -0
- package/scripts/bench/round-r8-fulldefault.json +255 -0
- package/scripts/bench-run.mjs +215 -29
- package/scripts/build-tui.mjs +13 -1
- package/scripts/explore-bench.mjs +124 -0
- package/scripts/freevar-smoke.mjs +95 -0
- package/scripts/hook-bus-test.mjs +191 -0
- package/scripts/internal-comms-bench.mjs +1 -0
- package/scripts/internal-comms-smoke.mjs +10 -9
- package/scripts/mouse-probe.mjs +45 -0
- package/scripts/output-style-bench.mjs +13 -6
- package/scripts/output-style-smoke.mjs +4 -4
- package/scripts/path-suffix-test.mjs +57 -0
- package/scripts/provider-toolcall-test.mjs +7 -3
- package/scripts/recall-bench.mjs +207 -0
- package/scripts/recall-usecase-cases.json +18 -0
- package/scripts/recall-usecase-probe.json +6 -0
- package/scripts/session-bench.mjs +152 -6
- package/scripts/tool-smoke.mjs +30 -67
- package/scripts/tui-render-smoke.mjs +90 -0
- package/scripts/webhook-smoke.mjs +208 -0
- package/src/agents/debugger/AGENT.md +5 -2
- package/src/agents/heavy-worker/AGENT.md +21 -11
- package/src/agents/maintainer/AGENT.md +4 -0
- package/src/agents/reviewer/AGENT.md +3 -2
- package/src/agents/worker/AGENT.md +21 -11
- package/src/lib/rules-builder.cjs +4 -0
- package/src/mixdog-session-runtime.mjs +933 -3731
- package/src/output-styles/default.md +34 -9
- package/src/output-styles/{oneline.md → extreme-minimal.md} +5 -4
- package/src/output-styles/minimal.md +4 -1
- package/src/output-styles/simple.md +22 -7
- package/src/repl.mjs +5 -5
- package/src/rules/agent/00-common.md +2 -0
- package/src/rules/agent/30-explorer.md +8 -11
- package/src/rules/lead/lead-brief.md +12 -0
- package/src/rules/lead/lead-tool.md +2 -9
- package/src/rules/shared/01-tool.md +11 -5
- package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +25 -0
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +100 -23
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +6 -15
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +362 -0
- package/src/runtime/agent/orchestrator/agent-trace-io.mjs +410 -0
- package/src/runtime/agent/orchestrator/agent-trace.mjs +16 -735
- package/src/runtime/agent/orchestrator/config.mjs +69 -2
- package/src/runtime/agent/orchestrator/context/collect.mjs +51 -0
- package/src/runtime/agent/orchestrator/mcp/client.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +63 -21
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +93 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +209 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +489 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +97 -1343
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +607 -0
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +78 -10
- package/src/runtime/agent/orchestrator/providers/api-usage.mjs +1 -13
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +81 -0
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +248 -0
- package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +303 -0
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +505 -0
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +44 -1014
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +18 -4
- package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +32 -0
- package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +86 -11
- package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +348 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +54 -20
- package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +108 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +19 -12
- package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +58 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +368 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +760 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +41 -1142
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +732 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +193 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +303 -2119
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +140 -995
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +227 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-events.mjs +67 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +436 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +1105 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +38 -12
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +7 -8
- package/src/runtime/agent/orchestrator/session/compact/budget.mjs +288 -0
- package/src/runtime/agent/orchestrator/session/compact/constants.mjs +85 -0
- package/src/runtime/agent/orchestrator/session/compact/engine.mjs +749 -0
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +82 -0
- package/src/runtime/agent/orchestrator/session/compact/summary-schema.mjs +315 -0
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +643 -0
- package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +326 -0
- package/src/runtime/agent/orchestrator/session/compact.mjs +40 -2282
- package/src/runtime/agent/orchestrator/session/loop/compact-debug.mjs +28 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +274 -0
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +61 -0
- package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +38 -0
- package/src/runtime/agent/orchestrator/session/loop/env.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/loop/hidden-agents.mjs +21 -0
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +47 -0
- package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +182 -0
- package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +173 -0
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +63 -0
- package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +100 -0
- package/src/runtime/agent/orchestrator/session/loop/termination.mjs +58 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +52 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +239 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +218 -0
- package/src/runtime/agent/orchestrator/session/loop/transcript-repair.mjs +101 -0
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +35 -0
- package/src/runtime/agent/orchestrator/session/loop.mjs +409 -1304
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +471 -0
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +230 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +235 -0
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +149 -0
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +155 -0
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +406 -0
- package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +80 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +303 -0
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +210 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +226 -2114
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +189 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +74 -179
- package/src/runtime/agent/orchestrator/stall-policy.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +70 -20
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +22 -2
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +33 -42
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +241 -0
- package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +40 -0
- package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +42 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +11 -4
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +29 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +8 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +126 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +81 -87
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +161 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +108 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +78 -304
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +11 -6
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +303 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +43 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +382 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +551 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +295 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-model.mjs +158 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/keyword-match.mjs +82 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/lang-predicates.mjs +128 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.mjs +66 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/project-root.mjs +44 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1080 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/source-access.mjs +81 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/span.mjs +19 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +280 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/text-columns.mjs +45 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +347 -0
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +6 -6
- package/src/runtime/agent/orchestrator/tools/code-graph.mjs +36 -4277
- package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/patch/constants.mjs +9 -0
- package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +171 -0
- package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +471 -0
- package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +436 -0
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +342 -0
- package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +359 -0
- package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +340 -0
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +643 -0
- package/src/runtime/agent/orchestrator/tools/patch.mjs +36 -2959
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +1 -23
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +10 -74
- package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +77 -0
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +2 -4
- package/src/runtime/agent/orchestrator/tools/shell-state.mjs +154 -0
- package/src/runtime/channels/backends/discord-access.mjs +32 -0
- package/src/runtime/channels/backends/discord-attachments.mjs +65 -0
- package/src/runtime/channels/backends/discord-gateway.mjs +233 -0
- package/src/runtime/channels/backends/discord.mjs +12 -292
- package/src/runtime/channels/index.mjs +241 -894
- package/src/runtime/channels/lib/backend-dispatch.mjs +44 -0
- package/src/runtime/channels/lib/boot-profile.mjs +23 -0
- package/src/runtime/channels/lib/crash-log.mjs +106 -0
- package/src/runtime/channels/lib/event-pipeline.mjs +18 -1
- package/src/runtime/channels/lib/event-queue.mjs +63 -4
- package/src/runtime/channels/lib/inbound-routing.mjs +111 -0
- package/src/runtime/channels/lib/index-drop-trace.mjs +72 -0
- package/src/runtime/channels/lib/output-forwarder.mjs +9 -1
- package/src/runtime/channels/lib/owner-heartbeat.mjs +75 -0
- package/src/runtime/channels/lib/parent-bridge.mjs +88 -0
- package/src/runtime/channels/lib/runtime-paths.mjs +14 -4
- package/src/runtime/channels/lib/session-discovery.mjs +56 -4
- package/src/runtime/channels/lib/telegram-format.mjs +19 -22
- package/src/runtime/channels/lib/tool-dispatch.mjs +158 -0
- package/src/runtime/channels/lib/tool-format.mjs +1 -1
- package/src/runtime/channels/lib/transcript-discovery.mjs +4 -4
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +6 -3
- package/src/runtime/channels/lib/voice-transcription.mjs +179 -0
- package/src/runtime/channels/lib/webhook/deliveries.mjs +312 -0
- package/src/runtime/channels/lib/webhook/log.mjs +42 -0
- package/src/runtime/channels/lib/webhook/ngrok.mjs +181 -0
- package/src/runtime/channels/lib/webhook/signature.mjs +60 -0
- package/src/runtime/channels/lib/webhook.mjs +36 -570
- package/src/runtime/channels/lib/whisper-language.mjs +42 -0
- package/src/runtime/channels/tool-defs.mjs +11 -130
- package/src/runtime/memory/index.mjs +258 -2050
- package/src/runtime/memory/lib/core-memory-store.mjs +351 -1
- package/src/runtime/memory/lib/cycle-llm-adapters.mjs +58 -0
- package/src/runtime/memory/lib/cycle-scheduler.mjs +497 -0
- package/src/runtime/memory/lib/cycle-signatures.mjs +34 -0
- package/src/runtime/memory/lib/embedding-warmup.mjs +58 -0
- package/src/runtime/memory/lib/http-wire.mjs +57 -0
- package/src/runtime/memory/lib/memory-config-flags.mjs +91 -0
- package/src/runtime/memory/lib/memory-cycle.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle2-gate.mjs +515 -0
- package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +324 -0
- package/src/runtime/memory/lib/memory-cycle2-shared.mjs +18 -0
- package/src/runtime/memory/lib/memory-cycle2.mjs +72 -837
- package/src/runtime/memory/lib/memory-embed.mjs +149 -0
- package/src/runtime/memory/lib/memory-process-lock.mjs +162 -0
- package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +24 -0
- package/src/runtime/memory/lib/memory-recall-store.mjs +22 -2
- package/src/runtime/memory/lib/memory-retrievers.mjs +8 -0
- package/src/runtime/memory/lib/memory.mjs +20 -0
- package/src/runtime/memory/lib/pg/supervisor.mjs +1 -1
- package/src/runtime/memory/lib/promotion-fingerprint.mjs +50 -0
- package/src/runtime/memory/lib/query-handlers.mjs +780 -0
- package/src/runtime/memory/lib/recall-format.mjs +238 -0
- package/src/runtime/memory/lib/runtime-fetcher.mjs +8 -3
- package/src/runtime/memory/lib/transcript-ingest.mjs +425 -0
- package/src/runtime/memory/tool-defs.mjs +6 -14
- package/src/runtime/search/lib/http-fetch.mjs +274 -0
- package/src/runtime/search/lib/ssrf-guard.mjs +333 -0
- package/src/runtime/search/lib/web-tools.mjs +24 -602
- package/src/runtime/shared/abort-controller.mjs +1 -1
- package/src/runtime/shared/atomic-file.mjs +26 -1
- package/src/runtime/shared/background-tasks.mjs +2 -3
- package/src/runtime/shared/buffered-appender.mjs +149 -0
- package/src/runtime/shared/launcher-control.mjs +2 -2
- package/src/runtime/shared/task-notification-envelope.mjs +98 -0
- package/src/runtime/shared/tool-execution-contract.mjs +2 -2
- package/src/runtime/shared/tool-primitives.mjs +308 -0
- package/src/runtime/shared/tool-result-summary.mjs +515 -0
- package/src/runtime/shared/tool-surface.mjs +80 -898
- package/src/runtime/shared/transcript-writer.mjs +52 -2
- package/src/runtime/shared/update-checker.mjs +7 -4
- package/src/session-runtime/config-helpers.mjs +291 -0
- package/src/session-runtime/config-lifecycle.mjs +232 -0
- package/src/session-runtime/cwd-plugins.mjs +226 -0
- package/src/session-runtime/effort.mjs +128 -0
- package/src/session-runtime/fs-utils.mjs +10 -0
- package/src/session-runtime/mcp-glue.mjs +177 -0
- package/src/session-runtime/model-capabilities.mjs +130 -0
- package/src/session-runtime/model-recency.mjs +111 -0
- package/src/session-runtime/native-search.mjs +247 -0
- package/src/session-runtime/output-styles.mjs +126 -0
- package/src/session-runtime/plugin-mcp.mjs +114 -0
- package/src/session-runtime/prewarm.mjs +142 -0
- package/src/session-runtime/provider-models.mjs +278 -0
- package/src/session-runtime/provider-usage.mjs +120 -0
- package/src/session-runtime/quick-model-rows.mjs +170 -0
- package/src/session-runtime/quick-search-models.mjs +46 -0
- package/src/session-runtime/session-hooks.mjs +93 -0
- package/src/session-runtime/session-text.mjs +100 -0
- package/src/session-runtime/settings-api.mjs +319 -0
- package/src/session-runtime/statusline-route.mjs +35 -0
- package/src/session-runtime/tool-catalog.mjs +720 -0
- package/src/session-runtime/tool-defs.mjs +84 -0
- package/src/session-runtime/warmup-schedulers.mjs +201 -0
- package/src/session-runtime/workflow.mjs +358 -0
- package/src/standalone/agent-tool/helpers.mjs +237 -0
- package/src/standalone/agent-tool/notify.mjs +107 -0
- package/src/standalone/agent-tool/provider-init.mjs +143 -0
- package/src/standalone/agent-tool/render.mjs +152 -0
- package/src/standalone/agent-tool/tool-def.mjs +55 -0
- package/src/standalone/agent-tool.mjs +155 -677
- package/src/standalone/channel-worker.mjs +7 -9
- package/src/standalone/explore-tool.mjs +40 -12
- package/src/standalone/hook-bus/config.mjs +207 -0
- package/src/standalone/hook-bus/constants.mjs +90 -0
- package/src/standalone/hook-bus/handlers.mjs +481 -0
- package/src/standalone/hook-bus/payload.mjs +31 -0
- package/src/standalone/hook-bus/rules.mjs +77 -0
- package/src/standalone/hook-bus.mjs +110 -746
- package/src/standalone/memory-runtime-proxy.mjs +7 -0
- package/src/standalone/opencode-go-login.mjs +125 -0
- package/src/standalone/provider-admin.mjs +15 -19
- package/src/standalone/usage-dashboard.mjs +3 -1
- package/src/tui/App.jsx +1163 -7571
- package/src/tui/app/app-format.mjs +206 -0
- package/src/tui/app/channel-pickers.mjs +510 -0
- package/src/tui/app/clipboard.mjs +67 -0
- package/src/tui/app/core-memory-picker.mjs +210 -0
- package/src/tui/app/extension-pickers.mjs +506 -0
- package/src/tui/app/input-parsers.mjs +193 -0
- package/src/tui/app/maintenance-pickers.mjs +324 -0
- package/src/tui/app/model-options.mjs +330 -0
- package/src/tui/app/model-picker.mjs +365 -0
- package/src/tui/app/onboarding-steps.mjs +400 -0
- package/src/tui/app/project-picker.mjs +247 -0
- package/src/tui/app/provider-setup-picker.mjs +580 -0
- package/src/tui/app/resume-picker.mjs +55 -0
- package/src/tui/app/route-pickers.mjs +419 -0
- package/src/tui/app/settings-picker.mjs +490 -0
- package/src/tui/app/slash-commands.mjs +101 -0
- package/src/tui/app/slash-dispatch.mjs +427 -0
- package/src/tui/app/text-layout.mjs +46 -0
- package/src/tui/app/theme-effort-pickers.mjs +154 -0
- package/src/tui/app/transcript-window.mjs +671 -0
- package/src/tui/app/use-mouse-input.mjs +460 -0
- package/src/tui/app/use-prompt-handlers.mjs +310 -0
- package/src/tui/app/use-transcript-scroll.mjs +510 -0
- package/src/tui/app/use-transcript-window.mjs +589 -0
- package/src/tui/components/ConfirmBar.jsx +1 -1
- package/src/tui/components/Picker.jsx +32 -4
- package/src/tui/components/PromptInput.jsx +259 -80
- package/src/tui/components/SlashCommandPalette.jsx +8 -1
- package/src/tui/components/StatusLine.jsx +63 -12
- package/src/tui/components/TextEntryPanel.jsx +11 -0
- package/src/tui/components/ToolExecution.jsx +56 -588
- package/src/tui/components/TranscriptItem.jsx +105 -0
- package/src/tui/components/UsagePanel.jsx +18 -4
- package/src/tui/components/prompt-input/edit-helpers.mjs +72 -0
- package/src/tui/components/prompt-input/voice-indicator.mjs +39 -0
- package/src/tui/components/tool-execution/ResultBody.jsx +56 -0
- package/src/tui/components/tool-execution/surface-detail.mjs +405 -0
- package/src/tui/components/tool-execution/text-format.mjs +161 -0
- package/src/tui/components/tool-output-format.mjs +2 -2
- package/src/tui/display-width.mjs +20 -3
- package/src/tui/dist/index.mjs +18034 -17188
- package/src/tui/engine/agent-envelope.mjs +296 -0
- package/src/tui/engine/agent-job-feed.mjs +133 -0
- package/src/tui/engine/boot-profile.mjs +21 -0
- package/src/tui/engine/labels.mjs +67 -0
- package/src/tui/engine/notice-text.mjs +112 -0
- package/src/tui/engine/notification-plan.mjs +76 -0
- package/src/tui/engine/queue-helpers.mjs +161 -0
- package/src/tui/engine/render-timing.mjs +17 -0
- package/src/tui/engine/session-stats.mjs +46 -0
- package/src/tui/engine/tool-approval.mjs +94 -0
- package/src/tui/engine/tool-call-fields.mjs +23 -0
- package/src/tui/engine/tool-card-results.mjs +234 -0
- package/src/tui/engine/tool-result-status.mjs +135 -0
- package/src/tui/engine/tool-result-text.mjs +126 -0
- package/src/tui/engine.mjs +405 -1385
- package/src/tui/figures.mjs +5 -0
- package/src/tui/index.jsx +105 -0
- package/src/tui/input-editing.mjs +60 -10
- package/src/tui/keyboard-protocol.mjs +2 -2
- package/src/tui/lib/voice-recorder.mjs +35 -19
- package/src/tui/markdown/format-token.mjs +11 -9
- package/src/tui/paste-attachments.mjs +38 -0
- package/src/tui/statusline-ansi-bridge.mjs +11 -3
- package/src/tui/theme.mjs +6 -0
- package/src/tui/themes/base.mjs +2 -2
- package/src/tui/themes/kanagawa.mjs +4 -4
- package/src/tui/themes/teal.mjs +4 -5
- package/src/tui/themes/utils.mjs +1 -1
- package/src/ui/statusline-agents.mjs +213 -0
- package/src/ui/statusline-format.mjs +146 -0
- package/src/ui/statusline-segments.mjs +148 -0
- package/src/ui/statusline.mjs +77 -462
- package/src/ui/tool-card.mjs +0 -1
- package/src/vendor/statusline/bin/statusline-route.mjs +15 -2
- package/src/workflows/default/WORKFLOW.md +16 -9
- package/src/workflows/sequential/WORKFLOW.md +16 -11
- package/src/workflows/solo/WORKFLOW.md +5 -1
- package/vendor/ink/build/display-width.js +19 -3
- package/vendor/ink/build/ink.js +103 -6
- package/vendor/ink/build/log-update.js +17 -3
- package/vendor/ink/build/wrap-text.js +125 -0
- package/scripts/_test-folder-dialog.mjs +0 -30
- package/scripts/fix-brief-fn.mjs +0 -35
- package/scripts/fix-format-tool-surface.mjs +0 -24
- package/scripts/fix-tool-exec-visible.mjs +0 -42
- package/scripts/patch-agent-brief.mjs +0 -48
- package/scripts/patch-app.mjs +0 -21
- package/scripts/patch-app2.mjs +0 -18
- package/scripts/patch-dist-brief.mjs +0 -96
- package/scripts/patch-tool-exec.mjs +0 -70
- package/src/examples/schedules/SCHEDULE.example.md +0 -32
- package/src/examples/webhooks/WEBHOOK.example.md +0 -40
- package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +0 -107
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +0 -143
- package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -285
- package/src/runtime/agent/orchestrator/tools/builtin/open-config-tool.mjs +0 -26
- package/src/runtime/shared/channel-notification-routing.test.mjs +0 -45
- package/src/runtime/shared/tool-execution-contract.test.mjs +0 -183
- package/src/standalone/agent-task-status.test.mjs +0 -76
- package/src/tui/components/tool-output-format.test.mjs +0 -399
- package/src/tui/display-width.test.mjs +0 -35
- package/src/tui/engine-runtime-notification.test.mjs +0 -115
- package/src/tui/engine-tool-result-text.test.mjs +0 -75
- package/src/tui/markdown/format-token.test.mjs +0 -354
- package/src/tui/markdown/render-ansi.test.mjs +0 -108
- package/src/tui/markdown/stream-fence.test.mjs +0 -26
- package/src/tui/markdown/streaming-markdown.test.mjs +0 -70
- package/src/tui/prompt-history-store.test.mjs +0 -52
- package/src/tui/statusline-ansi-bridge.test.mjs +0 -159
- package/src/tui/transcript-tool-failures.test.mjs +0 -111
- package/src/ui/markdown.test.mjs +0 -70
- package/src/ui/statusline-context-label.test.mjs +0 -15
- package/src/vendor/statusline/bin/statusline-lib.mjs +0 -186
- package/src/vendor/statusline/bin/statusline-route.test.mjs +0 -80
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// Standalone session tool definitions (wrapper tools surfaced by the runtime).
|
|
2
|
+
// Pure, self-contained schemas + the agent-hidden default helper. Extracted
|
|
3
|
+
// from mixdog-session-runtime.mjs; no runtime closure dependencies.
|
|
4
|
+
|
|
5
|
+
export const TOOL_SEARCH_TOOL = {
|
|
6
|
+
name: 'tool_search',
|
|
7
|
+
title: 'Tool Search',
|
|
8
|
+
annotations: {
|
|
9
|
+
title: 'Tool Search',
|
|
10
|
+
readOnlyHint: true,
|
|
11
|
+
destructiveHint: false,
|
|
12
|
+
idempotentHint: true,
|
|
13
|
+
openWorldHint: false,
|
|
14
|
+
agentHidden: true,
|
|
15
|
+
},
|
|
16
|
+
description: 'Search deferred tools; confident queries load matches.',
|
|
17
|
+
inputSchema: {
|
|
18
|
+
type: 'object',
|
|
19
|
+
properties: {
|
|
20
|
+
query: { type: 'string', description: 'Search text; confident hits load. select:a,b forces exact names.' },
|
|
21
|
+
select: { anyOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }], description: 'Force exact tool names.' },
|
|
22
|
+
limit: { type: 'number', description: 'Max matches.' },
|
|
23
|
+
},
|
|
24
|
+
additionalProperties: false,
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const CWD_TOOL = {
|
|
29
|
+
name: 'cwd',
|
|
30
|
+
title: 'Work Project',
|
|
31
|
+
annotations: {
|
|
32
|
+
title: 'Work Project',
|
|
33
|
+
readOnlyHint: false,
|
|
34
|
+
destructiveHint: false,
|
|
35
|
+
idempotentHint: false,
|
|
36
|
+
openWorldHint: false,
|
|
37
|
+
agentHidden: true,
|
|
38
|
+
},
|
|
39
|
+
description: 'Show or set the session work project for tool execution.',
|
|
40
|
+
inputSchema: {
|
|
41
|
+
type: 'object',
|
|
42
|
+
properties: {
|
|
43
|
+
action: { type: 'string', enum: ['get', 'set'], description: 'Default get.' },
|
|
44
|
+
path: { type: 'string', description: 'Project directory for set.' },
|
|
45
|
+
},
|
|
46
|
+
additionalProperties: false,
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const SKILL_TOOL = {
|
|
51
|
+
name: 'Skill',
|
|
52
|
+
title: 'Skill',
|
|
53
|
+
annotations: {
|
|
54
|
+
title: 'Skill',
|
|
55
|
+
readOnlyHint: true,
|
|
56
|
+
destructiveHint: false,
|
|
57
|
+
idempotentHint: true,
|
|
58
|
+
openWorldHint: false,
|
|
59
|
+
agentHidden: false,
|
|
60
|
+
},
|
|
61
|
+
description: 'Load a named SKILL.md into context.',
|
|
62
|
+
inputSchema: {
|
|
63
|
+
type: 'object',
|
|
64
|
+
properties: {
|
|
65
|
+
name: { type: 'string', description: 'Skill name.' },
|
|
66
|
+
},
|
|
67
|
+
required: ['name'],
|
|
68
|
+
additionalProperties: false,
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const LEAD_DISALLOWED_TOOLS = Object.freeze([]);
|
|
73
|
+
export const AGENT_HIDDEN_WRAPPER_TOOLS = new Set([]);
|
|
74
|
+
|
|
75
|
+
export function applyStandaloneToolDefaults(tool) {
|
|
76
|
+
if (!tool || !AGENT_HIDDEN_WRAPPER_TOOLS.has(tool.name)) return tool;
|
|
77
|
+
return {
|
|
78
|
+
...tool,
|
|
79
|
+
annotations: {
|
|
80
|
+
...(tool.annotations || {}),
|
|
81
|
+
agentHidden: true,
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
// Background warmup/refresh schedulers, extracted from
|
|
2
|
+
// mixdog-session-runtime.mjs. Dependency-injected factory: the timer handles
|
|
3
|
+
// live in a caller-owned `timers` object (so the facade's clearTimeout teardown
|
|
4
|
+
// still sees them) and all route/config/state reads go through supplied
|
|
5
|
+
// accessors. Returns the schedule* functions plus a clearAll() teardown helper.
|
|
6
|
+
import { performance } from 'node:perf_hooks';
|
|
7
|
+
import { clean } from './session-text.mjs';
|
|
8
|
+
|
|
9
|
+
export function createWarmupSchedulers({
|
|
10
|
+
timers,
|
|
11
|
+
bootProfile,
|
|
12
|
+
getRoute,
|
|
13
|
+
getConfig,
|
|
14
|
+
isCloseRequested,
|
|
15
|
+
getActiveTurnCount,
|
|
16
|
+
getSessionCreatePromise,
|
|
17
|
+
getProviderModelsCache,
|
|
18
|
+
getProviderModelsPromise,
|
|
19
|
+
reloadFullConfig,
|
|
20
|
+
ensureConfigForRouteProvider,
|
|
21
|
+
ensureProvidersReady,
|
|
22
|
+
ensureProviderEnabled,
|
|
23
|
+
refreshStatuslineUsageSnapshot,
|
|
24
|
+
warmProviderModelCache,
|
|
25
|
+
cachedProviderSetup,
|
|
26
|
+
warmCatalogsInBackground,
|
|
27
|
+
isFirstTurnCompleted,
|
|
28
|
+
envFlag,
|
|
29
|
+
delays,
|
|
30
|
+
flags,
|
|
31
|
+
}) {
|
|
32
|
+
const {
|
|
33
|
+
providerWarmupDelayMs,
|
|
34
|
+
providerSetupWarmupDelayMs,
|
|
35
|
+
providerModelWarmupDelayMs,
|
|
36
|
+
modelCatalogWarmupDelayMs,
|
|
37
|
+
statuslineUsageWarmupDelayMs,
|
|
38
|
+
statuslineUsageRefreshDelayMs,
|
|
39
|
+
backgroundBusyRetryMs,
|
|
40
|
+
} = delays;
|
|
41
|
+
const {
|
|
42
|
+
providerWarmupEnabled,
|
|
43
|
+
modelPrefetchEnabled,
|
|
44
|
+
modelCatalogWarmupEnabled,
|
|
45
|
+
} = flags;
|
|
46
|
+
|
|
47
|
+
function scheduleProviderWarmup(delayMs = providerWarmupDelayMs) {
|
|
48
|
+
if (!providerWarmupEnabled) {
|
|
49
|
+
bootProfile('providers:warm-skipped');
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (timers.providerWarmupTimer || isCloseRequested()) return;
|
|
53
|
+
timers.providerWarmupTimer = setTimeout(() => {
|
|
54
|
+
timers.providerWarmupTimer = null;
|
|
55
|
+
if (isCloseRequested()) return;
|
|
56
|
+
if (!isFirstTurnCompleted() && !envFlag('MIXDOG_PROVIDER_WARMUP_BEFORE_FIRST_TURN')) {
|
|
57
|
+
bootProfile('providers:warm-deferred', { reason: 'first-turn-pending' });
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (getActiveTurnCount() > 0 || getSessionCreatePromise()) {
|
|
61
|
+
bootProfile('providers:warm-deferred', { reason: getActiveTurnCount() > 0 ? 'turn-active' : 'session-create' });
|
|
62
|
+
scheduleProviderWarmup(backgroundBusyRetryMs);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const providersStartedAt = performance.now();
|
|
66
|
+
try {
|
|
67
|
+
reloadFullConfig();
|
|
68
|
+
} catch (error) {
|
|
69
|
+
bootProfile('config:full-failed', { error: error?.message || String(error) });
|
|
70
|
+
}
|
|
71
|
+
void ensureProvidersReady(getConfig().providers || {})
|
|
72
|
+
.then(() => {
|
|
73
|
+
bootProfile('providers:init:ready', { ms: (performance.now() - providersStartedAt).toFixed(1) });
|
|
74
|
+
if (isCloseRequested()) return null;
|
|
75
|
+
return true;
|
|
76
|
+
})
|
|
77
|
+
.catch((error) => bootProfile('providers:warm-failed', { error: error?.message || String(error) }));
|
|
78
|
+
}, delayMs);
|
|
79
|
+
timers.providerWarmupTimer.unref?.();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function scheduleProviderSetupWarmup(delayMs = providerSetupWarmupDelayMs) {
|
|
83
|
+
if (timers.providerSetupWarmupTimer || isCloseRequested()) return;
|
|
84
|
+
timers.providerSetupWarmupTimer = setTimeout(() => {
|
|
85
|
+
timers.providerSetupWarmupTimer = null;
|
|
86
|
+
if (isCloseRequested()) return;
|
|
87
|
+
void cachedProviderSetup()
|
|
88
|
+
.then(() => bootProfile('provider-setup:warm-ready'))
|
|
89
|
+
.catch((error) => bootProfile('provider-setup:warm-failed', { error: error?.message || String(error) }));
|
|
90
|
+
}, delayMs);
|
|
91
|
+
timers.providerSetupWarmupTimer.unref?.();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function scheduleProviderModelWarmup(delayMs = providerModelWarmupDelayMs) {
|
|
95
|
+
if (!modelPrefetchEnabled) return;
|
|
96
|
+
if (timers.providerModelWarmupTimer || isCloseRequested()) return;
|
|
97
|
+
timers.providerModelWarmupTimer = setTimeout(() => {
|
|
98
|
+
timers.providerModelWarmupTimer = null;
|
|
99
|
+
if (isCloseRequested() || Array.isArray(getProviderModelsCache().models) || getProviderModelsPromise()) return;
|
|
100
|
+
if (getActiveTurnCount() > 0 || getSessionCreatePromise()) {
|
|
101
|
+
bootProfile('provider-models:warm-deferred', { reason: getActiveTurnCount() > 0 ? 'turn-active' : 'session-create' });
|
|
102
|
+
scheduleProviderModelWarmup(backgroundBusyRetryMs);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
warmProviderModelCache();
|
|
106
|
+
}, delayMs);
|
|
107
|
+
timers.providerModelWarmupTimer.unref?.();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function scheduleModelCatalogWarmup(delayMs = modelCatalogWarmupDelayMs) {
|
|
111
|
+
if (!modelCatalogWarmupEnabled) {
|
|
112
|
+
bootProfile('model-catalog:warm-skipped', { reason: 'disabled' });
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (timers.modelCatalogWarmupTimer || isCloseRequested()) return;
|
|
116
|
+
timers.modelCatalogWarmupTimer = setTimeout(() => {
|
|
117
|
+
timers.modelCatalogWarmupTimer = null;
|
|
118
|
+
if (isCloseRequested()) return;
|
|
119
|
+
if (getActiveTurnCount() > 0 || getSessionCreatePromise()) {
|
|
120
|
+
bootProfile('model-catalog:warm-deferred', { reason: getActiveTurnCount() > 0 ? 'turn-active' : 'session-create' });
|
|
121
|
+
scheduleModelCatalogWarmup(backgroundBusyRetryMs);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
void warmCatalogsInBackground()
|
|
125
|
+
.then(() => bootProfile('model-catalog:warm-ready'))
|
|
126
|
+
.catch((error) => bootProfile('model-catalog:warm-failed', { error: error?.message || String(error) }));
|
|
127
|
+
}, delayMs);
|
|
128
|
+
timers.modelCatalogWarmupTimer.unref?.();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function scheduleStatuslineUsageWarmup(delayMs = statuslineUsageWarmupDelayMs) {
|
|
132
|
+
const route = getRoute();
|
|
133
|
+
const providerId = clean(route?.provider);
|
|
134
|
+
if (!providerId || !providerId.includes('oauth')) {
|
|
135
|
+
bootProfile('statusline-usage:warm-skipped', { provider: providerId || null });
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (timers.statuslineUsageWarmupTimer || isCloseRequested()) return;
|
|
139
|
+
timers.statuslineUsageWarmupTimer = setTimeout(async () => {
|
|
140
|
+
timers.statuslineUsageWarmupTimer = null;
|
|
141
|
+
if (isCloseRequested()) return;
|
|
142
|
+
if (getActiveTurnCount() > 0 || getSessionCreatePromise()) {
|
|
143
|
+
bootProfile('statusline-usage:warm-deferred', { reason: getActiveTurnCount() > 0 ? 'turn-active' : 'session-create' });
|
|
144
|
+
scheduleStatuslineUsageWarmup(backgroundBusyRetryMs);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
ensureConfigForRouteProvider();
|
|
149
|
+
await ensureProvidersReady(ensureProviderEnabled(getConfig(), getRoute().provider));
|
|
150
|
+
if (isCloseRequested()) return;
|
|
151
|
+
refreshStatuslineUsageSnapshot(getRoute());
|
|
152
|
+
bootProfile('statusline-usage:warm-ready', { provider: clean(getRoute()?.provider) });
|
|
153
|
+
} catch (error) {
|
|
154
|
+
bootProfile('statusline-usage:warm-failed', { error: error?.message || String(error) });
|
|
155
|
+
} finally {
|
|
156
|
+
scheduleStatuslineUsageRefresh();
|
|
157
|
+
}
|
|
158
|
+
}, delayMs);
|
|
159
|
+
timers.statuslineUsageWarmupTimer.unref?.();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Idle keep-alive loop: periodically re-fetch the OAuth usage snapshot so its
|
|
163
|
+
// cachedAt stays "live-fresh" and the statusline usage segment does not vanish
|
|
164
|
+
// after LIVE_USAGE_SNAPSHOT_MAX_AGE_MS while the session is idle. Turn-driven
|
|
165
|
+
// refreshes (recordStandaloneStatusTelemetry) already cover active sessions.
|
|
166
|
+
function scheduleStatuslineUsageRefresh(delayMs = statuslineUsageRefreshDelayMs) {
|
|
167
|
+
const route = getRoute();
|
|
168
|
+
const providerId = clean(route?.provider);
|
|
169
|
+
if (!providerId || !providerId.includes('oauth')) return;
|
|
170
|
+
if (timers.statuslineUsageRefreshTimer || isCloseRequested()) return;
|
|
171
|
+
timers.statuslineUsageRefreshTimer = setTimeout(async () => {
|
|
172
|
+
timers.statuslineUsageRefreshTimer = null;
|
|
173
|
+
if (isCloseRequested()) return;
|
|
174
|
+
if (getActiveTurnCount() > 0 || getSessionCreatePromise()) {
|
|
175
|
+
// Active turns refresh usage on their own; just re-arm the idle loop.
|
|
176
|
+
scheduleStatuslineUsageRefresh();
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
try {
|
|
180
|
+
ensureConfigForRouteProvider();
|
|
181
|
+
await ensureProvidersReady(ensureProviderEnabled(getConfig(), getRoute().provider));
|
|
182
|
+
if (isCloseRequested()) return;
|
|
183
|
+
refreshStatuslineUsageSnapshot(getRoute());
|
|
184
|
+
} catch {
|
|
185
|
+
// Usage display must never affect the session runtime.
|
|
186
|
+
} finally {
|
|
187
|
+
scheduleStatuslineUsageRefresh();
|
|
188
|
+
}
|
|
189
|
+
}, delayMs);
|
|
190
|
+
timers.statuslineUsageRefreshTimer.unref?.();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
scheduleProviderWarmup,
|
|
195
|
+
scheduleProviderSetupWarmup,
|
|
196
|
+
scheduleProviderModelWarmup,
|
|
197
|
+
scheduleModelCatalogWarmup,
|
|
198
|
+
scheduleStatuslineUsageWarmup,
|
|
199
|
+
scheduleStatuslineUsageRefresh,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
// Workflow/agent pack loading + route resolution, and search-route
|
|
2
|
+
// normalization. Roots/dataDir and config-dependent helpers are injected to
|
|
3
|
+
// keep this module free of the runtime's path/provider constants.
|
|
4
|
+
import { basename, join } from 'node:path';
|
|
5
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
6
|
+
import { clean } from './session-text.mjs';
|
|
7
|
+
import { normalizeEffortInput } from './effort.mjs';
|
|
8
|
+
import { isLikelyRawModelId } from './config-helpers.mjs';
|
|
9
|
+
import { readTextSafe, readJsonSafe } from './fs-utils.mjs';
|
|
10
|
+
|
|
11
|
+
export const WORKFLOW_ROUTE_SLOTS = ['lead', 'agent', 'explorer', 'memory'];
|
|
12
|
+
export const FIXED_AGENT_SLOTS = Object.freeze([
|
|
13
|
+
{ id: 'explore', label: 'Explore', description: 'Broad repository exploration', workflowSlot: 'explorer' },
|
|
14
|
+
{ id: 'maintainer', label: 'Maintainer', description: 'Background memory and upkeep', workflowSlot: 'memory' },
|
|
15
|
+
{ id: 'worker', label: 'Worker', description: 'Scoped implementation' },
|
|
16
|
+
{ id: 'heavy-worker', label: 'Heavy Worker', description: 'Broad or multi-file implementation' },
|
|
17
|
+
{ id: 'reviewer', label: 'Reviewer', description: 'Diff review and risk checks' },
|
|
18
|
+
{ id: 'debugger', label: 'Debugger', description: 'Root-cause analysis and failure tracing' },
|
|
19
|
+
]);
|
|
20
|
+
const AGENT_ROLE_IDS = new Set(FIXED_AGENT_SLOTS.map((agent) => agent.id));
|
|
21
|
+
const DEFAULT_WORKFLOW_ID = 'default';
|
|
22
|
+
|
|
23
|
+
const SEARCH_CAPABLE_PROVIDERS = new Set([
|
|
24
|
+
'openai-oauth', 'openai', 'grok-oauth', 'xai', 'gemini', 'anthropic', 'anthropic-oauth',
|
|
25
|
+
]);
|
|
26
|
+
export const SEARCH_DEFAULT_PROVIDER = 'default';
|
|
27
|
+
export const SEARCH_DEFAULT_MODEL = 'default';
|
|
28
|
+
const SEARCH_PROVIDER_ALIASES = Object.freeze({
|
|
29
|
+
'openai-api': 'openai',
|
|
30
|
+
'xai-api': 'xai',
|
|
31
|
+
'gemini-api': 'gemini',
|
|
32
|
+
'anthropic-api': 'anthropic',
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const agentDefinitionCache = new Map();
|
|
36
|
+
const AGENT_DEFINITION_CACHE_LIMIT = 64;
|
|
37
|
+
function setAgentDefinitionCache(key, value) {
|
|
38
|
+
if (!agentDefinitionCache.has(key) && agentDefinitionCache.size >= AGENT_DEFINITION_CACHE_LIMIT) {
|
|
39
|
+
const oldestKey = agentDefinitionCache.keys().next().value;
|
|
40
|
+
agentDefinitionCache.delete(oldestKey);
|
|
41
|
+
}
|
|
42
|
+
agentDefinitionCache.set(key, value);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function workflowPresetId(slot) {
|
|
46
|
+
return `workflow-${slot}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function workflowPresetName(slot) {
|
|
50
|
+
return `WORKFLOW ${String(slot || '').toUpperCase()}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function agentPresetSlot(agentId) {
|
|
54
|
+
return `agent-${String(agentId || '').replace(/[^a-z0-9_.-]+/gi, '-').toLowerCase()}`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function normalizeAgentId(value) {
|
|
58
|
+
const id = clean(value).toLowerCase().replace(/[\s_]+/g, '-');
|
|
59
|
+
if (id === 'explorer') return 'explore';
|
|
60
|
+
if (id === 'maint' || id === 'maintenance' || id === 'memory') return 'maintainer';
|
|
61
|
+
if (id === 'heavy' || id === 'heavyworker') return 'heavy-worker';
|
|
62
|
+
if (id === 'review') return 'reviewer';
|
|
63
|
+
if (id === 'debug') return 'debugger';
|
|
64
|
+
return AGENT_ROLE_IDS.has(id) ? id : '';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function normalizeWorkflowId(value, fallback = '') {
|
|
68
|
+
const id = clean(value).toLowerCase().replace(/[\s_]+/g, '-');
|
|
69
|
+
return /^[a-z0-9][a-z0-9_.-]*$/.test(id) ? id : fallback;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// A workflow/agent pack loader is created per data/root layout via
|
|
73
|
+
// createWorkflowHelpers, and the config-aware route helpers via
|
|
74
|
+
// createWorkflowRouteHelpers.
|
|
75
|
+
export function createWorkflowHelpers({ rootDir, dataDir, readMarkdownDocument, normalizeAgentPermissionOrNone }) {
|
|
76
|
+
function workflowSourceDirs(dir) {
|
|
77
|
+
return [
|
|
78
|
+
{ root: join(rootDir, 'workflows'), source: 'built-in' },
|
|
79
|
+
{ root: join(dir || dataDir, 'workflows'), source: 'user' },
|
|
80
|
+
];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function agentSourceDirs(dir, id) {
|
|
84
|
+
return [
|
|
85
|
+
join(dir || dataDir, 'agents', id),
|
|
86
|
+
join(rootDir, 'agents', id),
|
|
87
|
+
];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function readWorkflowPackFromDir(dir, source = 'built-in', dirName = '') {
|
|
91
|
+
const entry = 'WORKFLOW.md';
|
|
92
|
+
const doc = readMarkdownDocument(readTextSafe(join(dir, entry)));
|
|
93
|
+
const body = doc.body;
|
|
94
|
+
if (!body) return null;
|
|
95
|
+
const fm = doc.frontmatter || {};
|
|
96
|
+
const id = normalizeWorkflowId(clean(fm.id) || dirName || basename(dir));
|
|
97
|
+
if (!id) return null;
|
|
98
|
+
const agentsConfigured = Object.prototype.hasOwnProperty.call(fm, 'agents');
|
|
99
|
+
return {
|
|
100
|
+
id,
|
|
101
|
+
name: clean(fm.name) || id,
|
|
102
|
+
description: clean(fm.description),
|
|
103
|
+
entry,
|
|
104
|
+
agentsConfigured,
|
|
105
|
+
agents: agentsConfigured
|
|
106
|
+
? String(fm.agents || '')
|
|
107
|
+
.split(',')
|
|
108
|
+
.map((agent) => normalizeAgentId(agent) || normalizeWorkflowId(agent))
|
|
109
|
+
.filter(Boolean)
|
|
110
|
+
: [],
|
|
111
|
+
body,
|
|
112
|
+
source,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function listWorkflowPacks(dir) {
|
|
117
|
+
const byId = new Map();
|
|
118
|
+
for (const { root, source } of workflowSourceDirs(dir)) {
|
|
119
|
+
if (!existsSync(root)) continue;
|
|
120
|
+
let entries = [];
|
|
121
|
+
try { entries = readdirSync(root, { withFileTypes: true }); } catch { entries = []; }
|
|
122
|
+
for (const entry of entries) {
|
|
123
|
+
if (!entry.isDirectory()) continue;
|
|
124
|
+
const d = join(root, entry.name);
|
|
125
|
+
if (!existsSync(join(d, 'WORKFLOW.md'))) continue;
|
|
126
|
+
const pack = readWorkflowPackFromDir(d, source, entry.name);
|
|
127
|
+
if (pack) byId.set(pack.id, pack);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return [...byId.values()].sort((a, b) => {
|
|
131
|
+
if (a.id === DEFAULT_WORKFLOW_ID) return -1;
|
|
132
|
+
if (b.id === DEFAULT_WORKFLOW_ID) return 1;
|
|
133
|
+
return a.name.localeCompare(b.name);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function activeWorkflowId(config) {
|
|
138
|
+
return normalizeWorkflowId(config?.workflow?.active, DEFAULT_WORKFLOW_ID);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function loadWorkflowPack(dir, id) {
|
|
142
|
+
const wanted = normalizeWorkflowId(id, DEFAULT_WORKFLOW_ID);
|
|
143
|
+
for (const { root, source } of workflowSourceDirs(dir).reverse()) {
|
|
144
|
+
const pack = readWorkflowPackFromDir(join(root, wanted), source, wanted);
|
|
145
|
+
if (pack) return pack;
|
|
146
|
+
}
|
|
147
|
+
return readWorkflowPackFromDir(join(rootDir, 'workflows', DEFAULT_WORKFLOW_ID), 'built-in', DEFAULT_WORKFLOW_ID);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function workflowSummary(pack) {
|
|
151
|
+
const id = normalizeWorkflowId(pack?.id, DEFAULT_WORKFLOW_ID);
|
|
152
|
+
return {
|
|
153
|
+
id,
|
|
154
|
+
name: clean(pack?.name) || (id === DEFAULT_WORKFLOW_ID ? 'Default' : id),
|
|
155
|
+
description: clean(pack?.description),
|
|
156
|
+
source: clean(pack?.source),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function activeWorkflowSummary(config, dir) {
|
|
161
|
+
return workflowSummary(loadWorkflowPack(dir, activeWorkflowId(config)));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function loadAgentDefinition(dir, id) {
|
|
165
|
+
const agentId = normalizeAgentId(id) || normalizeWorkflowId(id);
|
|
166
|
+
if (!agentId) return null;
|
|
167
|
+
const cacheKey = `${dir || dataDir}\n${agentId}`;
|
|
168
|
+
if (agentDefinitionCache.has(cacheKey)) return agentDefinitionCache.get(cacheKey);
|
|
169
|
+
for (const d of agentSourceDirs(dir, agentId)) {
|
|
170
|
+
const manifest = readJsonSafe(join(d, 'agent.json')) || {};
|
|
171
|
+
const entry = clean(manifest.entry) || 'AGENT.md';
|
|
172
|
+
const doc = readMarkdownDocument(readTextSafe(join(d, entry)));
|
|
173
|
+
const body = doc.body;
|
|
174
|
+
if (!body) continue;
|
|
175
|
+
const definition = {
|
|
176
|
+
id: agentId,
|
|
177
|
+
name: clean(manifest.name) || FIXED_AGENT_SLOTS.find((agent) => agent.id === agentId)?.label || agentId,
|
|
178
|
+
description: clean(manifest.description) || FIXED_AGENT_SLOTS.find((agent) => agent.id === agentId)?.description || '',
|
|
179
|
+
permission: normalizeAgentPermissionOrNone(doc.frontmatter.permission),
|
|
180
|
+
frontmatter: doc.frontmatter,
|
|
181
|
+
body,
|
|
182
|
+
};
|
|
183
|
+
setAgentDefinitionCache(cacheKey, definition);
|
|
184
|
+
return definition;
|
|
185
|
+
}
|
|
186
|
+
const legacyDoc = readMarkdownDocument(readTextSafe(join(rootDir, 'agents', `${agentId}.md`)));
|
|
187
|
+
if (!legacyDoc.body) {
|
|
188
|
+
setAgentDefinitionCache(cacheKey, null);
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
const definition = {
|
|
192
|
+
id: agentId,
|
|
193
|
+
name: FIXED_AGENT_SLOTS.find((agent) => agent.id === agentId)?.label || agentId,
|
|
194
|
+
description: '',
|
|
195
|
+
permission: normalizeAgentPermissionOrNone(legacyDoc.frontmatter.permission),
|
|
196
|
+
frontmatter: legacyDoc.frontmatter,
|
|
197
|
+
body: legacyDoc.body,
|
|
198
|
+
};
|
|
199
|
+
setAgentDefinitionCache(cacheKey, definition);
|
|
200
|
+
return definition;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function workflowContextBlock(config, dir) {
|
|
204
|
+
const pack = loadWorkflowPack(dir, activeWorkflowId(config));
|
|
205
|
+
if (!pack) return '';
|
|
206
|
+
const lines = [`# Active Workflow: ${pack.name}`];
|
|
207
|
+
if (pack.description) lines.push(pack.description);
|
|
208
|
+
lines.push(pack.body);
|
|
209
|
+
const agentIds = pack.agentsConfigured ? pack.agents : FIXED_AGENT_SLOTS.map((agent) => agent.id);
|
|
210
|
+
const agentBlocks = agentIds.map((id) => loadAgentDefinition(dir, id)).filter(Boolean);
|
|
211
|
+
if (agentBlocks.length) {
|
|
212
|
+
lines.push('# Available Agents');
|
|
213
|
+
for (const agent of agentBlocks) {
|
|
214
|
+
lines.push(`## ${agent.name} (${agent.id})`);
|
|
215
|
+
if (agent.description) lines.push(agent.description);
|
|
216
|
+
lines.push(agent.body);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return lines.join('\n\n');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
listWorkflowPacks,
|
|
224
|
+
activeWorkflowId,
|
|
225
|
+
loadWorkflowPack,
|
|
226
|
+
workflowSummary,
|
|
227
|
+
activeWorkflowSummary,
|
|
228
|
+
loadAgentDefinition,
|
|
229
|
+
workflowContextBlock,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export function normalizeSearchProviderId(provider) {
|
|
234
|
+
const id = clean(provider);
|
|
235
|
+
return SEARCH_PROVIDER_ALIASES[id] || id;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export function isDefaultSearchRouteConfig(routeLike = {}) {
|
|
239
|
+
return normalizeSearchProviderId(routeLike?.provider) === SEARCH_DEFAULT_PROVIDER
|
|
240
|
+
&& clean(routeLike?.model).toLowerCase() === SEARCH_DEFAULT_MODEL;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export function isSearchCapableProvider(provider) {
|
|
244
|
+
return SEARCH_CAPABLE_PROVIDERS.has(normalizeSearchProviderId(provider));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export function normalizeSearchRouteConfig(routeLike, fallback = {}) {
|
|
248
|
+
const provider = normalizeSearchProviderId(routeLike?.provider || fallback.provider);
|
|
249
|
+
const model = clean(routeLike?.model || fallback.model);
|
|
250
|
+
if (!provider || !model) return null;
|
|
251
|
+
let effort = null;
|
|
252
|
+
try {
|
|
253
|
+
effort = normalizeEffortInput(routeLike?.effort ?? fallback.effort);
|
|
254
|
+
} catch {
|
|
255
|
+
effort = null;
|
|
256
|
+
}
|
|
257
|
+
const fast = routeLike?.fast ?? fallback.fast;
|
|
258
|
+
const toolType = clean(routeLike?.toolType || fallback.toolType);
|
|
259
|
+
return {
|
|
260
|
+
provider,
|
|
261
|
+
model,
|
|
262
|
+
...(effort ? { effort } : {}),
|
|
263
|
+
...(fast === true ? { fast: true } : {}),
|
|
264
|
+
...(toolType ? { toolType } : {}),
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export function normalizeWorkflowRoute(routeLike, fallback = {}) {
|
|
269
|
+
const provider = clean(routeLike?.provider) || clean(fallback.provider);
|
|
270
|
+
const model = clean(routeLike?.model) || clean(fallback.model);
|
|
271
|
+
if (!provider || !model) return null;
|
|
272
|
+
// Defensive: a workflow/agent route must carry a real model id. Reject values
|
|
273
|
+
// that are obviously free-form text (whitespace, prose) so a bad string can
|
|
274
|
+
// never be persisted as a preset/workflow route.
|
|
275
|
+
if (!isLikelyRawModelId(model)) return null;
|
|
276
|
+
const effort = normalizeEffortInput(routeLike?.effort ?? fallback.effort);
|
|
277
|
+
const fast = routeLike?.fast ?? fallback.fast;
|
|
278
|
+
return {
|
|
279
|
+
provider,
|
|
280
|
+
model,
|
|
281
|
+
...(effort ? { effort } : {}),
|
|
282
|
+
...(fast === true ? { fast: true } : {}),
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export function upsertWorkflowPreset(presets, slot, routeLike) {
|
|
287
|
+
const route = normalizeWorkflowRoute(routeLike);
|
|
288
|
+
if (!route) return presets;
|
|
289
|
+
const id = workflowPresetId(slot);
|
|
290
|
+
const preset = {
|
|
291
|
+
id,
|
|
292
|
+
name: workflowPresetName(slot),
|
|
293
|
+
type: 'agent',
|
|
294
|
+
provider: route.provider,
|
|
295
|
+
model: route.model,
|
|
296
|
+
...(route.effort ? { effort: route.effort } : {}),
|
|
297
|
+
...(route.fast === true ? { fast: true } : {}),
|
|
298
|
+
tools: 'full',
|
|
299
|
+
};
|
|
300
|
+
const next = (Array.isArray(presets) ? presets : []).filter((p) => clean(p?.id) !== id && clean(p?.name) !== preset.name);
|
|
301
|
+
next.push(preset);
|
|
302
|
+
return next;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Config-aware route resolvers need resolveDefaultProvider + findPreset from
|
|
306
|
+
// the runtime; created via this factory.
|
|
307
|
+
export function createWorkflowRouteHelpers({ resolveDefaultProvider, findPreset }) {
|
|
308
|
+
function summarizeWorkflowRoutes(config) {
|
|
309
|
+
const routes = config?.workflowRoutes && typeof config.workflowRoutes === 'object' ? config.workflowRoutes : {};
|
|
310
|
+
const fallbackProvider = resolveDefaultProvider(config);
|
|
311
|
+
const out = {};
|
|
312
|
+
for (const slot of WORKFLOW_ROUTE_SLOTS) {
|
|
313
|
+
const route = routes[slot];
|
|
314
|
+
// Read/interpret path: a route with a model but no provider falls back to
|
|
315
|
+
// config.defaultProvider (then DEFAULT_PROVIDER).
|
|
316
|
+
if (route?.model && (route?.provider || fallbackProvider)) {
|
|
317
|
+
out[slot] = normalizeWorkflowRoute(route, { provider: fallbackProvider });
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return out;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function routeFromPreset(config, slotValue) {
|
|
324
|
+
// Maintenance slots now store a direct {provider, model} route. Accept that
|
|
325
|
+
// shape first; fall back to the legacy preset-NAME string lookup so configs
|
|
326
|
+
// written before the route migration still resolve.
|
|
327
|
+
if (slotValue && typeof slotValue === 'object' && !Array.isArray(slotValue)) {
|
|
328
|
+
const direct = normalizeWorkflowRoute(slotValue);
|
|
329
|
+
if (direct) return direct;
|
|
330
|
+
}
|
|
331
|
+
const preset = findPreset(config, slotValue);
|
|
332
|
+
return preset ? normalizeWorkflowRoute(preset) : null;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function agentRouteFromConfig(config, agentId, _dataDir) {
|
|
336
|
+
const id = normalizeAgentId(agentId);
|
|
337
|
+
if (!id) return null;
|
|
338
|
+
// Read/interpret path: inject config.defaultProvider (then DEFAULT_PROVIDER)
|
|
339
|
+
// when a stored route omits its provider.
|
|
340
|
+
const fallback = { provider: resolveDefaultProvider(config) };
|
|
341
|
+
const explicit = normalizeWorkflowRoute(config?.agents?.[id], fallback)
|
|
342
|
+
|| (id === 'maintainer' ? normalizeWorkflowRoute(config?.agents?.maintenance, fallback) : null);
|
|
343
|
+
if (explicit) return explicit;
|
|
344
|
+
|
|
345
|
+
const agent = FIXED_AGENT_SLOTS.find((item) => item.id === id);
|
|
346
|
+
if (agent?.workflowSlot) {
|
|
347
|
+
const workflowRoute = normalizeWorkflowRoute(config?.workflowRoutes?.[agent.workflowSlot], fallback);
|
|
348
|
+
if (workflowRoute) return workflowRoute;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (id === 'explore') return routeFromPreset(config, config?.maintenance?.explore);
|
|
352
|
+
if (id === 'maintainer') return routeFromPreset(config, config?.maintenance?.memory);
|
|
353
|
+
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return { summarizeWorkflowRoutes, routeFromPreset, agentRouteFromConfig };
|
|
358
|
+
}
|