mixdog 1.0.12 → 1.1.1
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/README.md +83 -182
- package/package.json +4 -2
- package/scripts/build-shipped-history.mjs +131 -0
- package/scripts/latest-guard.mjs +63 -0
- package/scripts/lib/run-node-tests.mjs +330 -32
- package/scripts/lib/test-failure-records.mjs +5 -0
- package/scripts/lib/test-failure-summary.mjs +14 -3
- package/scripts/lib/test-spawn-ledger.mjs +19 -0
- package/scripts/merge-mac-update-feed.mjs +107 -0
- package/scripts/mobile-release.mjs +210 -0
- package/scripts/post-release-check.mjs +353 -0
- package/scripts/prune-embedding-runtime.mjs +9 -5
- package/scripts/publish-asset-release.mjs +43 -0
- package/scripts/release-guard.mjs +63 -0
- package/scripts/test-direct.mjs +16 -1
- package/scripts/test.mjs +29 -7
- package/src/agents/advisor/AGENT.md +38 -0
- package/src/agents/advisor/agent.json +6 -0
- package/src/agents/reviewer/AGENT.md +5 -2
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +383 -0
- package/src/defaults/skills/computer-use/SKILL.md +1 -1
- package/src/defaults/skills/goal-management/SKILL.md +11 -5
- package/src/defaults/skills/setup/SKILL.md +5 -8
- package/src/defaults/skills/setup/references/actions.md +62 -31
- package/src/defaults/skills/setup/references/surfaces.md +12 -10
- package/src/lib/keychain-cjs.cjs +582 -17
- package/src/lib/rules-builder.cjs +1 -1
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +3 -1
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +4 -0
- package/src/runtime/agent/orchestrator/config-presets.d.mts +1 -0
- package/src/runtime/agent/orchestrator/config-presets.mjs +44 -0
- package/src/runtime/agent/orchestrator/config-providers-merge.mjs +9 -1
- package/src/runtime/agent/orchestrator/config-storage.mjs +32 -4
- package/src/runtime/agent/orchestrator/config.mjs +120 -21
- package/src/runtime/agent/orchestrator/context/instruction-files.mjs +130 -0
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +77 -26
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +44 -14
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +11 -2
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +3 -3
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +388 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +92 -109
- package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +107 -0
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +51 -9
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +11 -0
- package/src/runtime/agent/orchestrator/providers/lib/open-login-url.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-login.mjs +254 -0
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +218 -0
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-tokens.mjs +239 -0
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +233 -0
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth-login.mjs +247 -0
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth-tokens.mjs +225 -0
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +542 -0
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +25 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +18 -10
- package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +13 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +51 -11
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +6 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +7 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +12 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +37 -9
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +12 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +6 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog-store.mjs +99 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog.mjs +4 -8
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +3 -7
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/quota-reading.mjs +70 -0
- package/src/runtime/agent/orchestrator/providers/registry.mjs +42 -3
- package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +19 -35
- package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +7 -0
- package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +0 -17
- package/src/runtime/agent/orchestrator/runtime-core/goal-state.mjs +0 -3
- package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +0 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-text.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-tool-defs.mjs +16 -2
- package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +1 -2
- package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +18 -4
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +7 -1
- package/src/runtime/agent/orchestrator/runtime-core/session-route-policy.mjs +16 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +2 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +2 -2
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +7 -7
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +11 -1
- package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +28 -3
- package/src/runtime/agent/orchestrator/session/loop/tool-call-ids.mjs +90 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +19 -11
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +24 -11
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +2 -6
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +28 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +63 -3
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +4 -4
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-status.mjs +23 -0
- package/src/runtime/agent/orchestrator/session/turn-effort.mjs +18 -0
- package/src/runtime/agent/orchestrator/stall-policy.mjs +0 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +11 -8
- package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +27 -12
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/bashism-rewrite.mjs +245 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +13 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +49 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +9 -7
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +19 -20
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +67 -19
- package/src/runtime/agent/orchestrator/tools/builtin/file-version-test-helpers.mjs +11 -0
- package/src/runtime/agent/orchestrator/tools/builtin/file-version.mjs +13 -0
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +28 -3
- package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-single-file-rescue.mjs +8 -5
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +25 -12
- package/src/runtime/agent/orchestrator/tools/builtin/path-utils.mjs +73 -1
- package/src/runtime/agent/orchestrator/tools/builtin/raw-content-publication.mjs +17 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +136 -76
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-guards.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +15 -17
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +11 -10
- package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +5 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +30 -16
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +17 -6
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +23 -5
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +93 -43
- package/src/runtime/agent/orchestrator/tools/builtin/snapshot-helpers.mjs +4 -11
- package/src/runtime/agent/orchestrator/tools/builtin/snapshot-store.mjs +7 -3
- package/src/runtime/agent/orchestrator/tools/builtin/snapshot-validation.mjs +16 -19
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +32 -6
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +9 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +12 -15
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +14 -4
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/patch/apply-patch/codex-batch.mjs +58 -8
- package/src/runtime/agent/orchestrator/tools/patch/content-guard.mjs +47 -0
- package/src/runtime/agent/orchestrator/tools/patch/delete-quarantine.mjs +155 -0
- package/src/runtime/agent/orchestrator/tools/patch/dispatch/native-proofs.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/patch/dispatch/native-snapshots.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +19 -16
- package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +13 -44
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/patch/post-patch-excerpts.mjs +5 -2
- package/src/runtime/agent/orchestrator/tools/patch/replay-capture.mjs +47 -7
- package/src/runtime/agent/orchestrator/tools/patch/rollback-state.mjs +72 -8
- package/src/runtime/agent/orchestrator/tools/patch/section-coalesce.mjs +3 -2
- package/src/runtime/agent/orchestrator/tools/patch/sequence/run.mjs +9 -1
- package/src/runtime/agent/orchestrator/tools/patch/sequence/units.mjs +9 -1
- package/src/runtime/agent/orchestrator/tools/patch/sequence.mjs +6 -6
- package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +16 -4
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +35 -14
- package/src/runtime/agent/orchestrator/tools/patch/wave.mjs +42 -4
- package/src/runtime/agent/orchestrator/tools/shell-codepage.mjs +296 -0
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +124 -81
- package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +75 -24
- package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +19 -4
- package/src/runtime/channels/lib/config.mjs +3 -8
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +7 -3
- package/src/{tui → runtime/channels}/lib/voice-setup.mjs +38 -22
- package/src/runtime/channels/lib/webhook/request-handler.mjs +42 -8
- package/src/runtime/computer-bridge/actions.mjs +2 -0
- package/src/runtime/computer-bridge/client.mjs +25 -1
- package/src/runtime/computer-bridge/linux-action-capabilities.mjs +84 -0
- package/src/runtime/computer-bridge/linux-readiness.d.mts +52 -0
- package/src/runtime/computer-bridge/linux-readiness.mjs +411 -0
- package/src/runtime/computer-bridge/test-linux-display.mjs +5 -0
- package/src/runtime/effort-judge/compact-tokenizer.mjs +13 -8
- package/src/runtime/effort-judge/judge-client.mjs +12 -3
- package/src/runtime/effort-judge/judge-input.mjs +5 -2
- package/src/runtime/effort-judge/model-install.mjs +9 -3
- package/src/runtime/effort-judge/model-manifest.json +8 -8
- package/src/runtime/effort-judge/previous-human-request.mjs +162 -0
- package/src/runtime/effort-judge/verified-context-input.mjs +10 -0
- package/src/runtime/memory/lib/embedding-provider.mjs +12 -0
- package/src/runtime/memory/lib/embedding-worker.mjs +9 -3
- package/src/runtime/memory/lib/http-router/session-routes.mjs +2 -1
- package/src/runtime/memory/lib/memory-config-flags.mjs +3 -2
- package/src/runtime/memory/lib/memory-embed.mjs +5 -0
- package/src/runtime/memory/lib/pg/supervisor.mjs +3 -0
- package/src/runtime/shared/agent-route-config.mjs +50 -2
- package/src/runtime/shared/bounded-file-read.mjs +166 -0
- package/src/runtime/shared/builtin-grandfathering.mjs +37 -0
- package/src/runtime/shared/config.mjs +74 -6
- package/src/runtime/shared/defaults-separation.mjs +263 -0
- package/src/runtime/shared/developer-options.mjs +7 -0
- package/src/runtime/shared/instruction-files-mode.mjs +9 -0
- package/src/runtime/shared/llm/anthropic-effort.mjs +4 -0
- package/src/runtime/shared/llm/model-catalog.mjs +25 -1
- package/src/runtime/shared/llm/openai-daybreak.mjs +79 -0
- package/src/runtime/shared/llm/usage-ledger-rollup.mjs +105 -1
- package/src/runtime/shared/llm/usage-ledger-worker.mjs +2 -1
- package/src/runtime/shared/llm/usage-ledger.mjs +72 -5
- package/src/runtime/shared/onnx-runtime-support.mjs +6 -0
- package/src/runtime/shared/orchestration.mjs +14 -6
- package/src/runtime/shared/pristine-execution-contract.json +9 -0
- package/src/runtime/shared/pristine-execution.mjs +1 -1
- package/src/runtime/shared/projects.mjs +65 -48
- package/src/runtime/shared/provider-accounts.mjs +49 -6
- package/src/runtime/shared/quota-resume-store.mjs +255 -0
- package/src/runtime/shared/resource-admission.mjs +10 -3
- package/src/runtime/shared/schedule-model-ref.mjs +11 -0
- package/src/runtime/shared/session-approval-wait.mjs +35 -0
- package/src/runtime/shared/shell-display.mjs +4 -2
- package/src/runtime/shared/shipped-definitions.mjs +275 -0
- package/src/runtime/shared/tool-card-model.golden.json +3 -3
- package/src/runtime/shared/tool-result-summary.mjs +86 -15
- package/src/runtime/shared/transcript-metadata.mjs +2 -0
- package/src/runtime/shared/turn-review-reply.mjs +2 -0
- package/src/runtime/shared/turn-snapshot.mjs +65 -6
- package/src/runtime/shared/turn-worktree-snapshot.mjs +208 -27
- package/src/session-runtime/boot/apis.mjs +24 -0
- package/src/session-runtime/boot/config.mjs +4 -0
- package/src/session-runtime/boot/facade.mjs +4 -1
- package/src/session-runtime/boot/infrastructure.mjs +21 -2
- package/src/session-runtime/boot/session.mjs +3 -0
- package/src/session-runtime/channel-config-api.mjs +5 -0
- package/src/session-runtime/config-lifecycle/config-writers.mjs +3 -0
- package/src/session-runtime/config-lifecycle.mjs +31 -6
- package/src/session-runtime/goal-facade-api.mjs +4 -0
- package/src/session-runtime/lifecycle/inheritance.mjs +28 -6
- package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +3 -0
- package/src/session-runtime/lifecycle/session-switch/resume.mjs +7 -1
- package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +6 -0
- package/src/session-runtime/lifecycle/teardown/session-close.mjs +14 -2
- package/src/session-runtime/media-api.mjs +32 -22
- package/src/session-runtime/model-recency.mjs +17 -0
- package/src/session-runtime/model-route/route-tuning.mjs +3 -5
- package/src/session-runtime/model-route/set-route.mjs +49 -21
- package/src/session-runtime/model-route-api.mjs +2 -1
- package/src/session-runtime/notification-bus.mjs +31 -6
- package/src/session-runtime/provider-auth/login.mjs +16 -10
- package/src/session-runtime/provider-auth/setup.mjs +22 -2
- package/src/session-runtime/provider-models/catalog-load.mjs +3 -1
- package/src/session-runtime/provider-models/row-hydration.mjs +26 -17
- package/src/session-runtime/provider-readiness.mjs +4 -0
- package/src/session-runtime/quick-model-rows/model-meta.mjs +26 -0
- package/src/session-runtime/quick-model-rows/provider-rows.mjs +40 -14
- package/src/session-runtime/resource-api.mjs +8 -1
- package/src/session-runtime/runtime-core.mjs +4 -0
- package/src/session-runtime/runtime-facade.mjs +25 -1
- package/src/session-runtime/runtime-review-api.mjs +12 -1
- package/src/session-runtime/schedule-session-run.mjs +3 -1
- package/src/session-runtime/services/agent-tool/helpers.mjs +4 -0
- package/src/session-runtime/services/agent-tool/index-write-queue.mjs +63 -27
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +15 -3
- package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +2 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +11 -3
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +2 -0
- package/src/session-runtime/services/agent-tool/worker-index/approval-wait.mjs +97 -0
- package/src/session-runtime/services/agent-tool/worker-index/mutation-batch.mjs +4 -2
- package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -2
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +3 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +58 -2
- package/src/session-runtime/services/agent-tool/worker-index.mjs +69 -15
- package/src/session-runtime/services/agent-tool/worker-rows.mjs +2 -0
- package/src/session-runtime/services/channel-admin.mjs +91 -15
- package/src/session-runtime/services/provider-admin.mjs +336 -80
- package/src/session-runtime/services/seeds.mjs +80 -152
- package/src/session-runtime/services/usage-dashboard-model.mjs +35 -0
- package/src/session-runtime/services/usage-dashboard.mjs +7 -0
- package/src/session-runtime/session-address.mjs +125 -0
- package/src/session-runtime/session-create.mjs +57 -2
- package/src/session-runtime/settings-builtin-tools-api.mjs +23 -0
- package/src/session-runtime/settings-compaction-api.mjs +13 -0
- package/src/session-runtime/setup-tool/executor.mjs +97 -40
- package/src/session-runtime/setup-tool/extended-actions.mjs +64 -5
- package/src/session-runtime/setup-tool/settings-contract.mjs +44 -1
- package/src/session-runtime/setup-tool/tool-defs.mjs +20 -7
- package/src/session-runtime/tool-policy-refresh.mjs +3 -0
- package/src/session-runtime/tool-surface.mjs +16 -9
- package/src/session-runtime/turn/session-ops.mjs +3 -0
- package/src/session-runtime/turn/share-ops.mjs +4 -1
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +6 -0
- package/src/session-runtime/usage-stats-api.mjs +15 -0
- package/src/session-runtime/webhook-session-run.mjs +3 -1
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +31 -5
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +4 -0
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +27 -7
- package/src/standalone/daemon-boot-coordinator.mjs +10 -0
- package/src/standalone/daemon-drain-policy.mjs +9 -0
- package/src/standalone/daemon-stored-session-views.mjs +7 -8
- package/src/standalone/daemon.mjs +21 -5
- package/src/standalone/local-session-runtime.mjs +11 -0
- package/src/standalone/session-client.mjs +52 -7
- package/src/standalone/session-protocol.mjs +9 -0
- package/src/standalone/session-service/agent-tree/agent-child.mjs +2 -0
- package/src/standalone/session-service/entries/lifecycle.mjs +2 -0
- package/src/standalone/session-service/entries/session-loads.mjs +9 -0
- package/src/standalone/session-service/projection/revisions.mjs +28 -4
- package/src/standalone/session-service/projection.mjs +1 -0
- package/src/standalone/session-service/quota-resume.mjs +140 -0
- package/src/standalone/session-service/session-calls/session-action.mjs +2 -2
- package/src/standalone/session-service/session-calls.mjs +10 -2
- package/src/standalone/session-service/stored-reader.mjs +26 -1
- package/src/standalone/session-service.mjs +21 -0
- package/src/standalone/session-transport/routes.mjs +2 -0
- package/src/tui/app/doctor.mjs +7 -11
- package/src/tui/app/maintenance-pickers/auto-clear-picker.mjs +3 -5
- package/src/tui/app/model-options.mjs +13 -1
- package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +10 -4
- package/src/tui/app/provider-setup/oauth-actions.mjs +5 -0
- package/src/tui/app/settings-picker/settings-rows.mjs +4 -6
- package/src/tui/app/settings-picker/settings-toggles/store-toggles.mjs +1 -1
- package/src/tui/app/slash-dispatch/route-commands.mjs +3 -2
- package/src/tui/components/ContextPanel.jsx +5 -1
- package/src/tui/components/Spinner.jsx +34 -319
- package/src/tui/components/SpinnerByline.jsx +256 -0
- package/src/tui/components/use-spinner-progress.mjs +113 -0
- package/src/tui/dist/index.mjs +15421 -14283
- package/src/tui/session/agent-job-feed/execution-delivery.mjs +13 -1
- package/src/tui/session/agent-job-feed/notification-router.mjs +3 -0
- package/src/tui/session/agent-job-feed/pending-resume.mjs +14 -1
- package/src/tui/session/agent-job-feed.mjs +4 -0
- package/src/tui/session/context-state.mjs +15 -1
- package/src/tui/session/initial-state.mjs +6 -0
- package/src/tui/session/live-share/owner.mjs +17 -0
- package/src/tui/session/oauth-flows.mjs +2 -0
- package/src/tui/session/quota-resume.mjs +263 -0
- package/src/tui/session/session-api/intake/abort.mjs +39 -35
- package/src/tui/session/session-api/intake/submission.mjs +13 -21
- package/src/tui/session/session-api/intake.mjs +3 -3
- package/src/tui/session/session-api/integrations.mjs +13 -9
- package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
- package/src/tui/session/session-api/lifecycle/inheritance.mjs +2 -2
- package/src/tui/session/session-api/lifecycle/session-reset.mjs +4 -0
- package/src/tui/session/session-api/lifecycle.mjs +71 -2
- package/src/tui/session/session-api/media.mjs +2 -2
- package/src/tui/session/session-api/quota-resume.mjs +21 -0
- package/src/tui/session/session-api/routes.mjs +4 -2
- package/src/tui/session/session-api/settings.mjs +2 -0
- package/src/tui/session/session-api.mjs +2 -0
- package/src/tui/session/session-flow/auto-clear.mjs +14 -6
- package/src/tui/session/session-flow/drain.mjs +52 -5
- package/src/tui/session/session-flow/queue/take-entries.mjs +2 -3
- package/src/tui/session/session-flow/queue.mjs +3 -0
- package/src/tui/session/session-flow/steering.mjs +11 -0
- package/src/tui/session/session-flow.mjs +1 -0
- package/src/tui/session/tool-approval.mjs +7 -2
- package/src/tui/session/tool-card-results/grouped-result.mjs +11 -2
- package/src/tui/session/transcript-intake.mjs +1 -0
- package/src/tui/session/transcript-spill/spill-dir.mjs +22 -6
- package/src/tui/session/turn.mjs +40 -3
- package/src/tui/spinner-meta.mjs +26 -10
- package/src/vendor/statusline/bin/statusline-route.mjs +3 -2
|
@@ -30,7 +30,9 @@
|
|
|
30
30
|
* Non-breakpoint providers:
|
|
31
31
|
* - OpenAI (public): prompt_cache_key plus model-specific retention when
|
|
32
32
|
* response storage is enabled (30m cache options or 24h retention).
|
|
33
|
-
* - OpenAI OAuth: prompt_cache_key only
|
|
33
|
+
* - OpenAI OAuth: prompt_cache_key only; the Codex backend keeps the
|
|
34
|
+
* prompt cache at least 30 minutes on GPT-5.6+ models, refreshed on use
|
|
35
|
+
* (the openai-oauth auto-clear window matches it)
|
|
34
36
|
* - Gemini: provider-managed explicit cachedContents with 5m default TTL, plus
|
|
35
37
|
* implicit caching as a fallback when the prefix is below cache minimums.
|
|
36
38
|
* - xAI: conversation routing for chat; Responses omits prompt_cache_key
|
|
@@ -76,6 +76,8 @@ export function prepareAgentSession({
|
|
|
76
76
|
schemaAllowedTools,
|
|
77
77
|
sessionId,
|
|
78
78
|
mcpScopeId,
|
|
79
|
+
contextPercent,
|
|
80
|
+
selectedContextWindow,
|
|
79
81
|
}) {
|
|
80
82
|
const effectivePermission = resolveAgentSessionPermission(agent, permission);
|
|
81
83
|
// Pass cwd through verbatim — null is the fixed agent sentinel meaning
|
|
@@ -112,6 +114,8 @@ export function prepareAgentSession({
|
|
|
112
114
|
compaction: compaction || undefined,
|
|
113
115
|
mcpScopeId: mcpScopeId || null,
|
|
114
116
|
};
|
|
117
|
+
if (contextPercent) sessionOpts.contextPercent = contextPercent;
|
|
118
|
+
if (selectedContextWindow) sessionOpts.selectedContextWindow = selectedContextWindow;
|
|
115
119
|
if (agentTag) sessionOpts.agentTag = agentTag;
|
|
116
120
|
if (effectivePermission) sessionOpts.permission = effectivePermission;
|
|
117
121
|
if (permissionMode) sessionOpts.permissionMode = permissionMode;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function withDefaultPresets(stored: unknown): unknown[];
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
// Preset normalization and identity are independent of config storage.
|
|
2
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
3
|
+
|
|
2
4
|
const ANTHROPIC_FAMILY_MODEL = Object.freeze({
|
|
3
5
|
opus: 'claude-opus-4-8',
|
|
4
6
|
sonnet: 'claude-sonnet-4-6',
|
|
@@ -64,6 +66,48 @@ export const DEFAULT_PRESETS = Object.freeze([
|
|
|
64
66
|
}),
|
|
65
67
|
]);
|
|
66
68
|
|
|
69
|
+
const DEFAULT_PRESET_BY_ID = new Map(DEFAULT_PRESETS.map((preset) => [preset.id, preset]));
|
|
70
|
+
|
|
71
|
+
/** Effective presets: the stored entries in their stored order, then the
|
|
72
|
+
* shipped presets missing from storage in shipped order. */
|
|
73
|
+
export function withDefaultPresets(stored) {
|
|
74
|
+
const list = Array.isArray(stored) ? stored : [];
|
|
75
|
+
const present = new Set(list.map(presetKey));
|
|
76
|
+
return [...list, ...DEFAULT_PRESETS.filter((preset) => !present.has(preset.id)).map((preset) => ({ ...preset }))];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Stored form of `presets`: only entries that differ from the shipped default of the same id. */
|
|
80
|
+
export function presetsDelta(presets) {
|
|
81
|
+
return (Array.isArray(presets) ? presets : []).filter((preset) => {
|
|
82
|
+
const shipped = DEFAULT_PRESET_BY_ID.get(presetKey(preset));
|
|
83
|
+
return !shipped || !isDeepStrictEqual(normalizePreset(preset), { ...shipped });
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Stored form of `maintenance`: only slots that differ from the shipped route. */
|
|
88
|
+
export function maintenanceDelta(maintenance) {
|
|
89
|
+
const source = maintenance && typeof maintenance === 'object' ? maintenance : {};
|
|
90
|
+
return Object.fromEntries(
|
|
91
|
+
Object.entries(source).filter(([slot, route]) => !isDeepStrictEqual(route, DEFAULT_MAINTENANCE[slot]))
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Drop shipped presets and maintenance routes that equal their default; loadConfig restores them. */
|
|
96
|
+
export function stripStoredRouteDefaults(agent) {
|
|
97
|
+
const next = { ...agent };
|
|
98
|
+
if (Object.hasOwn(next, 'presets')) {
|
|
99
|
+
const presets = presetsDelta(next.presets);
|
|
100
|
+
if (presets.length) next.presets = presets;
|
|
101
|
+
else delete next.presets;
|
|
102
|
+
}
|
|
103
|
+
if (Object.hasOwn(next, 'maintenance')) {
|
|
104
|
+
const maintenance = maintenanceDelta(next.maintenance);
|
|
105
|
+
if (Object.keys(maintenance).length) next.maintenance = maintenance;
|
|
106
|
+
else delete next.maintenance;
|
|
107
|
+
}
|
|
108
|
+
return next;
|
|
109
|
+
}
|
|
110
|
+
|
|
67
111
|
const AGENT_PROVIDER_ALIASES = Object.freeze({
|
|
68
112
|
'openai-api': 'openai',
|
|
69
113
|
'gemini-api': 'gemini',
|
|
@@ -50,9 +50,17 @@ export function mergeStoredProviders({ raw, defaults, includeSecrets }) {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
// Custom providers: the keychain account is the generated custom-<uuid> id.
|
|
53
|
+
// A keyless (auth 'none') custom provider never carries a key, not even a
|
|
54
|
+
// hand-edited plaintext one.
|
|
55
|
+
for (const [name, val] of Object.entries(mergedProviders)) {
|
|
56
|
+
if (val?.type === 'custom' && val.auth === 'none' && Object.hasOwn(val, 'apiKey')) {
|
|
57
|
+
const { apiKey: _dropped, ...rest } = val;
|
|
58
|
+
mergedProviders[name] = rest;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
53
61
|
if (includeSecrets) {
|
|
54
62
|
for (const [name, val] of Object.entries(mergedProviders)) {
|
|
55
|
-
if (val?.type !== 'custom' || !name.startsWith('custom-')) continue;
|
|
63
|
+
if (val?.type !== 'custom' || !name.startsWith('custom-') || val.auth === 'none') continue;
|
|
56
64
|
const kc = getAgentApiKey(name);
|
|
57
65
|
if (kc) mergedProviders[name] = { ...val, apiKey: kc, enabled: raw.providers?.[name]?.enabled !== false };
|
|
58
66
|
}
|
|
@@ -2,6 +2,11 @@ import { hasExtensionScopes, normalizeExtensionScopes } from '../../shared/exten
|
|
|
2
2
|
import { agentRouteStorageNeedsMigration, canonicalizeAgentRouteStorage } from '../../shared/agent-route-config.mjs';
|
|
3
3
|
import profileConfig from '../../shared/profile-config.cjs';
|
|
4
4
|
import { normalizeAgentProviderId, normalizePreset } from './config-presets.mjs';
|
|
5
|
+
import {
|
|
6
|
+
loadSavedCodexCatalog,
|
|
7
|
+
migrateCodexRoute,
|
|
8
|
+
supersededCodexSettingsKey,
|
|
9
|
+
} from './providers/openai-oauth-catalog-store.mjs';
|
|
5
10
|
|
|
6
11
|
const { normalizeProfileConfig } = profileConfig;
|
|
7
12
|
const RETIRED_LOCAL_PROVIDER_IDS = new Set(['ollama', 'lmstudio']);
|
|
@@ -205,7 +210,20 @@ function retiredLocalProviderStoragePresent(value = {}) {
|
|
|
205
210
|
);
|
|
206
211
|
}
|
|
207
212
|
|
|
213
|
+
// Saved routes on a model the provider catalog has superseded (see
|
|
214
|
+
// openai-oauth-catalog-store.mjs) — read from the last fetched catalog.
|
|
215
|
+
function supersededRouteStoragePresent(value = {}, catalog = loadSavedCodexCatalog()) {
|
|
216
|
+
const superseded = (route) => migrateCodexRoute(route, catalog) !== route;
|
|
217
|
+
return (
|
|
218
|
+
(Array.isArray(value?.presets) && value.presets.some(superseded)) ||
|
|
219
|
+
Object.values(configObject(value?.agents)).some(superseded) ||
|
|
220
|
+
Object.values(configObject(value?.maintenance)).some(superseded) ||
|
|
221
|
+
Object.keys(configObject(value?.modelSettings)).some((key) => supersededCodexSettingsKey(key, catalog))
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
208
225
|
export function canonicalizeAgentStorage(value = {}) {
|
|
226
|
+
const catalog = loadSavedCodexCatalog();
|
|
209
227
|
const next = canonicalizeAgentRouteStorage(value);
|
|
210
228
|
const removedPresetIds = new Set(
|
|
211
229
|
(Array.isArray(next.presets) ? next.presets : [])
|
|
@@ -216,17 +234,26 @@ export function canonicalizeAgentStorage(value = {}) {
|
|
|
216
234
|
next.providers = configObject(next.providers);
|
|
217
235
|
for (const id of RETIRED_LOCAL_PROVIDER_IDS) delete next.providers[id];
|
|
218
236
|
next.presets = Array.isArray(next.presets)
|
|
219
|
-
? next.presets
|
|
237
|
+
? next.presets
|
|
238
|
+
.map((preset) => normalizePreset(migrateCodexRoute(preset, catalog)))
|
|
239
|
+
.filter((preset) => preset && !isRetiredLocalRoute(preset))
|
|
220
240
|
: [];
|
|
221
241
|
if (removedPresetIds.has(String(next.default || '').trim())) next.default = null;
|
|
222
242
|
next.agents = Object.fromEntries(
|
|
223
|
-
Object.entries(configObject(next.agents))
|
|
243
|
+
Object.entries(configObject(next.agents))
|
|
244
|
+
.filter(([, route]) => !isRetiredLocalRoute(route))
|
|
245
|
+
.map(([id, route]) => [id, migrateCodexRoute(route, catalog)])
|
|
224
246
|
);
|
|
225
247
|
next.maintenance = Object.fromEntries(
|
|
226
|
-
Object.entries(configObject(next.maintenance))
|
|
248
|
+
Object.entries(configObject(next.maintenance))
|
|
249
|
+
.filter(([, route]) => !isRetiredLocalRoute(route))
|
|
250
|
+
.map(([slot, route]) => [slot, migrateCodexRoute(route, catalog)])
|
|
227
251
|
);
|
|
252
|
+
// A superseded model's own settings have no model left to apply to.
|
|
228
253
|
next.modelSettings = Object.fromEntries(
|
|
229
|
-
Object.entries(normalizedModelSettings(value)).filter(
|
|
254
|
+
Object.entries(normalizedModelSettings(value)).filter(
|
|
255
|
+
([key]) => !isRetiredLocalModelKey(key) && !supersededCodexSettingsKey(key, catalog)
|
|
256
|
+
)
|
|
230
257
|
);
|
|
231
258
|
setOrDelete(next, 'autoClear', canonicalizeAutoClearStorage(next.autoClear));
|
|
232
259
|
setOrDelete(next, 'compaction', canonicalizeCompactionStorage(next.compaction));
|
|
@@ -266,6 +293,7 @@ export function agentConfigStorageNeedsMigration(value = {}) {
|
|
|
266
293
|
return (
|
|
267
294
|
agentRouteStorageNeedsMigration(value) ||
|
|
268
295
|
retiredLocalProviderStoragePresent(value) ||
|
|
296
|
+
supersededRouteStoragePresent(value) ||
|
|
269
297
|
RETIRED_AGENT_FIELDS.some((key) => key !== 'guide' && Object.hasOwn(value || {}, key)) ||
|
|
270
298
|
presets.some((preset) => !normalizePreset(preset)) ||
|
|
271
299
|
(modules && typeof modules === 'object' && Object.hasOwn(modules, 'memory')) ||
|
|
@@ -4,9 +4,33 @@ import { mergeStoredProviders } from './config-providers-merge.mjs';
|
|
|
4
4
|
import { normalizeExtensionScopes } from '../../shared/extension-scopes.mjs';
|
|
5
5
|
import { applyConfigPatch, diffConfig } from '../../shared/config-patch.mjs';
|
|
6
6
|
import { normalizeWorkflowSelection } from '../../shared/orchestration.mjs';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
DEFAULT_INSTRUCTION_FILES_MODE,
|
|
9
|
+
normalizeInstructionFilesMode,
|
|
10
|
+
} from '../../shared/instruction-files-mode.mjs';
|
|
11
|
+
import {
|
|
12
|
+
DEFAULT_DISABLED_AGENT_ROSTER,
|
|
13
|
+
canonicalizeAgentRouteStorage,
|
|
14
|
+
disabledAgentDelta,
|
|
15
|
+
disabledAgentIds,
|
|
16
|
+
effectiveDisabledAgents,
|
|
17
|
+
withEffectiveDisabledAgents,
|
|
18
|
+
withStoredDisabledAgents,
|
|
19
|
+
} from '../../shared/agent-route-config.mjs';
|
|
20
|
+
import {
|
|
21
|
+
DEFAULTS_VERSION,
|
|
22
|
+
ensureDefaultsSeparated,
|
|
23
|
+
storedDefaultsVersion,
|
|
24
|
+
stripAgentSectionDefaults,
|
|
25
|
+
} from '../../shared/defaults-separation.mjs';
|
|
8
26
|
import profileConfig from '../../shared/profile-config.cjs';
|
|
9
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
DEFAULT_MAINTENANCE,
|
|
29
|
+
DEFAULT_PRESETS,
|
|
30
|
+
normalizePreset,
|
|
31
|
+
stripStoredRouteDefaults,
|
|
32
|
+
withDefaultPresets,
|
|
33
|
+
} from './config-presets.mjs';
|
|
10
34
|
import {
|
|
11
35
|
agentConfigStorageNeedsMigration,
|
|
12
36
|
canonicalizeAgentStorage,
|
|
@@ -87,9 +111,13 @@ export function buildDefaultConfig(options = {}) {
|
|
|
87
111
|
// stored in mixdog-config.json — enabled at runtime from the presence of
|
|
88
112
|
// Mixdog-owned credentials.
|
|
89
113
|
providers['grok-oauth'] = oauthEntry('grok-oauth');
|
|
114
|
+
// Muse Code subscription (Meta Muse Spark), enabled from its stored key.
|
|
115
|
+
providers['muse-code-oauth'] = oauthEntry('muse-code-oauth');
|
|
90
116
|
// Dev-only providers (Settings → Developer → Providers, one option each):
|
|
91
117
|
// omitted entirely from the default config while their option is off so
|
|
92
118
|
// they never surface in settings.
|
|
119
|
+
// Experimental MiMo subscription: enabled from a stored platform API key.
|
|
120
|
+
if (isOAuthProviderAvailable('mimo-oauth')) providers['mimo-oauth'] = oauthEntry('mimo-oauth');
|
|
93
121
|
// Experimental direct Cursor wire provider. It remains disabled unless a
|
|
94
122
|
// Mixdog-owned login or CURSOR_ACCESS_TOKEN is present.
|
|
95
123
|
if (isOAuthProviderAvailable('cursor-oauth')) providers['cursor-oauth'] = oauthEntry('cursor-oauth');
|
|
@@ -100,11 +128,10 @@ export function buildDefaultConfig(options = {}) {
|
|
|
100
128
|
providers['mixdog-local'] = { enabled: false };
|
|
101
129
|
return {
|
|
102
130
|
providers,
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
disabledAgents: [...DEFAULT_DISABLED_AGENT_IDS, 'maintainer'],
|
|
131
|
+
// Effective roster; the file stores only the user's delta against it.
|
|
132
|
+
disabledAgents: [...DEFAULT_DISABLED_AGENT_ROSTER],
|
|
106
133
|
workflow: { active: 'default' },
|
|
107
|
-
orchestrationMode: '
|
|
134
|
+
orchestrationMode: 'balanced',
|
|
108
135
|
};
|
|
109
136
|
}
|
|
110
137
|
|
|
@@ -168,11 +195,26 @@ function normalizeRecapConfig(rawRecap) {
|
|
|
168
195
|
return recap;
|
|
169
196
|
}
|
|
170
197
|
|
|
198
|
+
// `instructionFiles` (instruction-files-mode.mjs): only a valid non-default
|
|
199
|
+
// mode is kept; absent means the default.
|
|
200
|
+
function storedInstructionFiles(agent) {
|
|
201
|
+
const mode = normalizeInstructionFilesMode(agent?.instructionFiles);
|
|
202
|
+
return mode === DEFAULT_INSTRUCTION_FILES_MODE ? {} : { instructionFiles: mode };
|
|
203
|
+
}
|
|
204
|
+
|
|
171
205
|
export function loadConfig(options = {}) {
|
|
172
206
|
const includeSecrets = options.secrets !== false;
|
|
207
|
+
try {
|
|
208
|
+
ensureDefaultsSeparated({ stripRouteDefaults: separateStoredAgent });
|
|
209
|
+
} catch (err) {
|
|
210
|
+
process.stderr.write(`[config] defaults separation failed: ${err?.message}\n`);
|
|
211
|
+
}
|
|
173
212
|
const sectionRaw = readSection('agent');
|
|
174
213
|
if (hasKeys(sectionRaw)) {
|
|
175
214
|
try {
|
|
215
|
+
// A file that could not be separated still holds the legacy form:
|
|
216
|
+
// before version 1 `disabledAgents` is the full list, not a delta.
|
|
217
|
+
const legacyDisabledAgents = storedDefaultsVersion() < 1;
|
|
176
218
|
let raw = sectionRaw;
|
|
177
219
|
const storageNeedsMigration = agentConfigStorageNeedsMigration(raw);
|
|
178
220
|
raw = canonicalizeAgentStorage(raw);
|
|
@@ -206,7 +248,7 @@ export function loadConfig(options = {}) {
|
|
|
206
248
|
const loaded = canonicalizeAgentRouteStorage({
|
|
207
249
|
providers: mergedProviders,
|
|
208
250
|
mcpServers,
|
|
209
|
-
presets: normalizedPresets,
|
|
251
|
+
presets: withDefaultPresets(normalizedPresets),
|
|
210
252
|
default: raw.default || null,
|
|
211
253
|
maintenance: { ...DEFAULT_MAINTENANCE, ...normalizedMaint },
|
|
212
254
|
workflowRoutes,
|
|
@@ -214,9 +256,11 @@ export function loadConfig(options = {}) {
|
|
|
214
256
|
modelSettings,
|
|
215
257
|
onboarding: raw.onboarding && typeof raw.onboarding === 'object' ? raw.onboarding : {},
|
|
216
258
|
agents: raw.agents && typeof raw.agents === 'object' ? raw.agents : {},
|
|
217
|
-
//
|
|
218
|
-
//
|
|
219
|
-
disabledAgents:
|
|
259
|
+
// Effective "off" roster = code defaults + the stored user delta.
|
|
260
|
+
// canonicalizeAgentRouteStorage drops it when empty.
|
|
261
|
+
disabledAgents: legacyDisabledAgents ? disabledAgentIds(raw) : effectiveDisabledAgents(raw),
|
|
262
|
+
...(raw.memoryTools && typeof raw.memoryTools === 'object' ? { memoryTools: { ...raw.memoryTools } } : {}),
|
|
263
|
+
...storedInstructionFiles(raw),
|
|
220
264
|
...normalizeWorkflowSelection(raw),
|
|
221
265
|
profile: normalizeProfileConfig(raw.profile),
|
|
222
266
|
skills: normalizeSkillsConfig(raw.skills),
|
|
@@ -241,7 +285,7 @@ export function loadConfig(options = {}) {
|
|
|
241
285
|
// Retired cross-section fields are no longer migrated by
|
|
242
286
|
// the shared config layer. Normalize only the locked
|
|
243
287
|
// current section; stale reads must not undo deletions.
|
|
244
|
-
persistAgentConfig(canonicalizeAgentStorage);
|
|
288
|
+
persistAgentConfig((current) => storedAgentForm(canonicalizeAgentStorage(current)));
|
|
245
289
|
} catch (err) {
|
|
246
290
|
process.stderr.write(`[config] persist canonical agent config failed: ${err?.message}\n`);
|
|
247
291
|
}
|
|
@@ -263,7 +307,7 @@ export function loadConfig(options = {}) {
|
|
|
263
307
|
onboarding: {},
|
|
264
308
|
agents: {},
|
|
265
309
|
workflow: { active: 'default' },
|
|
266
|
-
orchestrationMode: '
|
|
310
|
+
orchestrationMode: 'balanced',
|
|
267
311
|
profile: normalizeProfileConfig(null),
|
|
268
312
|
skills: normalizeSkillsConfig(null),
|
|
269
313
|
extensionScopes: normalizeExtensionScopes(null),
|
|
@@ -383,28 +427,83 @@ function buildAgentSaveBuilder(config) {
|
|
|
383
427
|
// Developer options (developer-options.mjs); an empty set stays absent.
|
|
384
428
|
if (Object.keys(developer).length) next.developer = developer;
|
|
385
429
|
else if (Object.hasOwn(config, 'developer')) delete next.developer;
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
430
|
+
// Only the user's delta against the default roster is stored.
|
|
431
|
+
delete next.disabledAgents;
|
|
432
|
+
delete next.enabledAgents;
|
|
433
|
+
// An unseparated file keeps the legacy full list until the pass succeeds.
|
|
434
|
+
if (storedDefaultsVersion() < 1) {
|
|
435
|
+
if (canonicalRoutes.disabledAgents?.length) next.disabledAgents = canonicalRoutes.disabledAgents;
|
|
436
|
+
} else Object.assign(next, disabledAgentDelta(canonicalRoutes.disabledAgents));
|
|
437
|
+
if (config.memoryTools && typeof config.memoryTools === 'object') next.memoryTools = { ...config.memoryTools };
|
|
438
|
+
else delete next.memoryTools;
|
|
439
|
+
delete next.instructionFiles;
|
|
440
|
+
Object.assign(next, storedInstructionFiles(config));
|
|
391
441
|
delete next.workflowRoutes;
|
|
392
|
-
|
|
442
|
+
// Defaults live in code: values equal to the current default are not stored.
|
|
443
|
+
return storedAgentForm(removeRetiredAgentFields(next));
|
|
393
444
|
};
|
|
394
445
|
}
|
|
446
|
+
|
|
447
|
+
/** A numeric `default` is a preset index; store the preset id it points at (index into the effective list). */
|
|
448
|
+
function resolveNumericDefault(agent) {
|
|
449
|
+
const value = agent?.default;
|
|
450
|
+
// The loader reads a falsy default (including 0) as "none".
|
|
451
|
+
if (!value || !(typeof value === 'number' || /^\d+$/.test(String(value)))) return agent;
|
|
452
|
+
const stored = (Array.isArray(agent.presets) ? agent.presets : [])
|
|
453
|
+
.map((preset) => normalizePreset(preset))
|
|
454
|
+
.filter(Boolean)
|
|
455
|
+
.filter((preset) => preset.id !== 'workflow-search');
|
|
456
|
+
const { presets } = canonicalizeAgentRouteStorage({ presets: withDefaultPresets(stored) });
|
|
457
|
+
const preset = presets[Number(value)];
|
|
458
|
+
return preset ? { ...agent, default: preset.id } : agent;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/** The agent section as stored: defaults dropped. Route defaults go only once the file is separated. */
|
|
462
|
+
function storedAgentForm(agent) {
|
|
463
|
+
const stripped = stripAgentSectionDefaults(resolveNumericDefault(agent));
|
|
464
|
+
return storedDefaultsVersion() >= DEFAULTS_VERSION ? stripStoredRouteDefaults(stripped) : stripped;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/** Separation pass: normalize the compared sections first, then drop every default. */
|
|
468
|
+
function separateStoredAgent(agent) {
|
|
469
|
+
const full = canonicalizeAgentStorage(agent);
|
|
470
|
+
const next = { ...agent };
|
|
471
|
+
for (const key of ['autoClear', 'compaction', 'modules']) {
|
|
472
|
+
if (!Object.hasOwn(agent, key)) continue;
|
|
473
|
+
if (full[key] === undefined) delete next[key];
|
|
474
|
+
else next[key] = full[key];
|
|
475
|
+
}
|
|
476
|
+
return stripStoredRouteDefaults(stripAgentSectionDefaults(resolveNumericDefault(next)));
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/** Patch the stored section; unseparated data keeps its form, a numeric default becomes an id first. */
|
|
480
|
+
function applyStoredPatch(current, changes) {
|
|
481
|
+
const base = resolveNumericDefault(current);
|
|
482
|
+
if (storedDefaultsVersion() >= 1) return applyConfigPatch(base, changes);
|
|
483
|
+
const delta = withStoredDisabledAgents({ ...base, disabledAgents: disabledAgentIds(base) });
|
|
484
|
+
return withEffectiveDisabledAgents(applyConfigPatch(delta, changes));
|
|
485
|
+
}
|
|
395
486
|
// Diff the persisted schema, not runtime defaults, aliases, or secret overlays.
|
|
487
|
+
// Patches always speak the delta domain; an unseparated file's full list is
|
|
488
|
+
// converted here and back in applyStoredPatch.
|
|
489
|
+
function patchForm(agent) {
|
|
490
|
+
if (storedDefaultsVersion() >= 1) return agent;
|
|
491
|
+
const { disabledAgents, ...rest } = agent;
|
|
492
|
+
return { ...rest, ...disabledAgentDelta(disabledAgents || []) };
|
|
493
|
+
}
|
|
494
|
+
|
|
396
495
|
export function createConfigPatch(before, after) {
|
|
397
|
-
return diffConfig(buildAgentSaveBuilder(before)({}), buildAgentSaveBuilder(after)({}));
|
|
496
|
+
return diffConfig(patchForm(buildAgentSaveBuilder(before)({})), patchForm(buildAgentSaveBuilder(after)({})));
|
|
398
497
|
}
|
|
399
498
|
|
|
400
499
|
export function saveConfigPatch(changes) {
|
|
401
500
|
if (!changes.length) return;
|
|
402
|
-
persistAgentConfig((current) =>
|
|
501
|
+
persistAgentConfig((current) => applyStoredPatch(current, changes));
|
|
403
502
|
}
|
|
404
503
|
|
|
405
504
|
export async function saveConfigPatchAsync(changes) {
|
|
406
505
|
if (!changes.length) return;
|
|
407
|
-
await persistAgentConfigAsync((current) =>
|
|
506
|
+
await persistAgentConfigAsync((current) => applyStoredPatch(current, changes));
|
|
408
507
|
}
|
|
409
508
|
|
|
410
509
|
// Whole-section replacement is reserved for explicit full saves. Read/edit/save
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// The user's instruction files (AGENTS.md / CLAUDE.md), global then project,
|
|
2
|
+
// rendered as one `# Instruction Files` block for a new session's BP3 core.
|
|
3
|
+
import { closeSync, constants, fstatSync, openSync, readSync, realpathSync, statSync } from 'node:fs';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import { isAbsolute, join, relative, resolve } from 'node:path';
|
|
6
|
+
import { readSection } from '../../../shared/config.mjs';
|
|
7
|
+
import { normalizeInstructionFilesMode } from '../../../shared/instruction-files-mode.mjs';
|
|
8
|
+
import { featureEnvOverride } from '../runtime-core/config-helpers.mjs';
|
|
9
|
+
|
|
10
|
+
// Per-file budget in UTF-8 bytes (same byte-based cap as core memory).
|
|
11
|
+
const INSTRUCTION_FILE_MAX_BYTES = 32 * 1024;
|
|
12
|
+
const TRUNCATED_MARK = '\n\n[... truncated]';
|
|
13
|
+
const KINDS_BY_MODE = { all: ['agents', 'claude'], agents: ['agents'], claude: ['claude'], off: [] };
|
|
14
|
+
const GLOBAL_DIR = { agents: '.codex', claude: '.claude' };
|
|
15
|
+
const FILE_NAME = { agents: 'AGENTS.md', claude: 'CLAUDE.md' };
|
|
16
|
+
|
|
17
|
+
/** The configured mode, forced off by MIXDOG_BOOT_INSTRUCTION_FILES=0. */
|
|
18
|
+
export function effectiveInstructionFilesMode(mode) {
|
|
19
|
+
if (featureEnvOverride('MIXDOG_BOOT_INSTRUCTION_FILES') === false) return 'off';
|
|
20
|
+
return normalizeInstructionFilesMode(mode);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** The stored agent-config value; an unreadable config reads as the default. */
|
|
24
|
+
export function configuredInstructionFilesMode() {
|
|
25
|
+
try {
|
|
26
|
+
return normalizeInstructionFilesMode(readSection('agent')?.instructionFiles);
|
|
27
|
+
} catch {
|
|
28
|
+
return normalizeInstructionFilesMode(undefined);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const UTF8_BOM = Buffer.from([0xef, 0xbb, 0xbf]);
|
|
33
|
+
|
|
34
|
+
/** Candidate files in load order: global files first, then the project root's.
|
|
35
|
+
* Project files are confined to the real directory of their `root`; global
|
|
36
|
+
* files carry no root and may resolve anywhere. */
|
|
37
|
+
function instructionFileCandidates({ mode, cwd, homeDir = homedir() } = {}) {
|
|
38
|
+
const kinds = KINDS_BY_MODE[effectiveInstructionFilesMode(mode)];
|
|
39
|
+
const candidates = [];
|
|
40
|
+
if (homeDir) {
|
|
41
|
+
const root = resolve(homeDir);
|
|
42
|
+
// Global files may be symlinks into a dotfiles repo: no containment root.
|
|
43
|
+
for (const kind of kinds) candidates.push({ path: join(root, GLOBAL_DIR[kind], FILE_NAME[kind]) });
|
|
44
|
+
}
|
|
45
|
+
if (cwd) {
|
|
46
|
+
const root = resolve(cwd);
|
|
47
|
+
for (const kind of kinds) candidates.push({ path: join(root, FILE_NAME[kind]), root });
|
|
48
|
+
}
|
|
49
|
+
return candidates;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function isInside(root, path) {
|
|
53
|
+
const rel = relative(root, path);
|
|
54
|
+
return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function skipNote(path, reason) {
|
|
58
|
+
process.stderr.write(`[instruction-files] skipped ${path}: ${reason}\n`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** At most the file's first cap bytes (plus a BOM allowance and one probe byte)
|
|
62
|
+
* from an open fd, so a huge or endless file is never read whole. */
|
|
63
|
+
function readHead(fd) {
|
|
64
|
+
const buffer = Buffer.allocUnsafe(INSTRUCTION_FILE_MAX_BYTES + UTF8_BOM.length + 1);
|
|
65
|
+
let length = 0;
|
|
66
|
+
while (length < buffer.length) {
|
|
67
|
+
const count = readSync(fd, buffer, length, buffer.length - length, null);
|
|
68
|
+
if (count === 0) break;
|
|
69
|
+
length += count;
|
|
70
|
+
}
|
|
71
|
+
return buffer.subarray(0, length);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Decode a head that may end mid-character: the incomplete tail is dropped. */
|
|
75
|
+
function decodeHead(bytes) {
|
|
76
|
+
return new TextDecoder('utf-8').decode(bytes, { stream: true });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** The bounded, trimmed text of one instruction file; over the budget it is cut
|
|
80
|
+
* at a word boundary and ends with the truncation notice. */
|
|
81
|
+
function boundedText(head) {
|
|
82
|
+
const bytes = head.subarray(0, UTF8_BOM.length).equals(UTF8_BOM) ? head.subarray(UTF8_BOM.length) : head;
|
|
83
|
+
if (bytes.length <= INSTRUCTION_FILE_MAX_BYTES) return decodeHead(bytes).trim();
|
|
84
|
+
const budget = INSTRUCTION_FILE_MAX_BYTES - Buffer.byteLength(TRUNCATED_MARK, 'utf8');
|
|
85
|
+
const text = decodeHead(bytes.subarray(0, budget)).trim();
|
|
86
|
+
return `${text.replace(/\s+\S*$/, '')}${TRUNCATED_MARK}`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** The file's bounded content, or '' when it is absent, unreadable, not a
|
|
90
|
+
* regular file, or resolves (symlink/junction) outside `root` when one is set. */
|
|
91
|
+
function readInstructionFile({ path, root }) {
|
|
92
|
+
let fd;
|
|
93
|
+
try {
|
|
94
|
+
const realPath = realpathSync.native(path);
|
|
95
|
+
if (root && !isInside(realpathSync.native(root), realPath)) {
|
|
96
|
+
skipNote(path, 'resolves outside its root');
|
|
97
|
+
return '';
|
|
98
|
+
}
|
|
99
|
+
if (!statSync(realPath).isFile()) return '';
|
|
100
|
+
fd = openSync(realPath, constants.O_RDONLY | (constants.O_NONBLOCK ?? 0));
|
|
101
|
+
if (!fstatSync(fd).isFile()) return '';
|
|
102
|
+
return boundedText(readHead(fd));
|
|
103
|
+
} catch (error) {
|
|
104
|
+
if (error?.code !== 'ENOENT' && error?.code !== 'ENOTDIR' && error?.code !== 'EISDIR') {
|
|
105
|
+
skipNote(path, error?.code || error?.message || 'unreadable');
|
|
106
|
+
}
|
|
107
|
+
return '';
|
|
108
|
+
} finally {
|
|
109
|
+
if (fd !== undefined) closeSync(fd);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** The `# Instruction Files` block, or '' when no file has content. Files
|
|
114
|
+
* whose bounded content repeats an included one (symlinks, copies) are dropped. */
|
|
115
|
+
export function loadInstructionFilesContext({ mode, cwd, homeDir = homedir() } = {}) {
|
|
116
|
+
const seen = new Set();
|
|
117
|
+
const sections = [];
|
|
118
|
+
for (const candidate of instructionFileCandidates({ mode, cwd, homeDir })) {
|
|
119
|
+
const content = readInstructionFile(candidate);
|
|
120
|
+
if (!content || seen.has(content)) continue;
|
|
121
|
+
seen.add(content);
|
|
122
|
+
sections.push(`## ${candidate.path}\n\n${content}`);
|
|
123
|
+
}
|
|
124
|
+
if (!sections.length) return '';
|
|
125
|
+
return [
|
|
126
|
+
'# Instruction Files',
|
|
127
|
+
"The user's instruction files. Project files take precedence over global ones when they conflict.",
|
|
128
|
+
...sections,
|
|
129
|
+
].join('\n\n');
|
|
130
|
+
}
|
|
@@ -268,12 +268,16 @@ export function composeSystemPrompt(opts) {
|
|
|
268
268
|
// Keep the active workflow first within BP3 so it leads the role and
|
|
269
269
|
// environment material that varies with the session.
|
|
270
270
|
const coreMemory = skip.memory ? '' : trimmedPromptSlice(opts.coreMemoryContext);
|
|
271
|
+
// User AGENTS.md / CLAUDE.md block (context/instruction-files.mjs), already
|
|
272
|
+
// headed `# Instruction Files`; rides right after core memory.
|
|
273
|
+
const instructionFiles = skip.claudemd ? '' : trimmedPromptSlice(opts.instructionFilesContext);
|
|
271
274
|
const sessionMarkerCore = joinPromptSlices([
|
|
272
275
|
trimmedPromptSlice(opts.workflowContext),
|
|
273
276
|
opts.roleRules || '',
|
|
274
277
|
opts.userPrompt || '',
|
|
275
278
|
roleInstructionContext,
|
|
276
279
|
coreMemory ? `# Core Memory\n${coreMemory}` : '',
|
|
280
|
+
instructionFiles,
|
|
277
281
|
]);
|
|
278
282
|
// Response language is the LAST system text before the conversation. It
|
|
279
283
|
// rides the environment block (not the tier3 core) because the `# Session`
|