mixdog 1.1.1 → 1.2.0
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 +1 -0
- package/package.json +2 -2
- package/scripts/lib/run-node-tests.mjs +9 -0
- package/scripts/prune-desktop-runtime.mjs +3 -0
- package/scripts/release-paths.mjs +39 -2
- package/scripts/test-direct.mjs +4 -2
- package/src/defaults/shipped-history.json +6 -0
- package/src/defaults/skills/setup/references/actions.md +5 -2
- package/src/defaults/skills/visualize/SKILL.md +157 -0
- package/src/defaults/skills/visualize/references/craft.md +88 -0
- package/src/headless-command.mjs +56 -3
- package/src/headless-exec.mjs +17 -1
- package/src/headless-role.mjs +2 -2
- package/src/help.mjs +2 -0
- package/src/lib/rules-builder.cjs +0 -23
- package/src/rules/lead/LEAD.md +2 -2
- package/src/rules/shared/70-delivery.md +2 -2
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +1 -0
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +2 -0
- package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
- package/src/runtime/agent/orchestrator/config-providers-merge.mjs +17 -11
- package/src/runtime/agent/orchestrator/config-storage.mjs +1 -0
- package/src/runtime/agent/orchestrator/config.mjs +9 -1
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +47 -7
- package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +51 -8
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +25 -5
- package/src/runtime/agent/orchestrator/mcp/client.mjs +348 -122
- package/src/runtime/agent/orchestrator/mcp/reconnect-singleflight.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +15 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +13 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/cursor-wire-normalization.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +12 -4
- package/src/runtime/agent/orchestrator/providers/effort-rejection.mjs +244 -0
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +8 -40
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-tokens.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +51 -12
- package/src/runtime/agent/orchestrator/providers/model-cache.mjs +37 -2
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +67 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +521 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +251 -0
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth-tokens.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +69 -102
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +6 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog-store.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/registry.mjs +15 -1
- package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +10 -0
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +36 -3
- package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +12 -11
- package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +16 -1
- package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +11 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +11 -8
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.mjs +9 -5
- package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +18 -8
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +10 -3
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +18 -11
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +13 -5
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +362 -0
- package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +253 -0
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +12 -14
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/continuation.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/diagnostic.mjs +1 -7
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/refusal.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +17 -7
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +12 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +5 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +37 -16
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +90 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +22 -12
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +32 -3
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +27 -0
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -1
- package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +1 -5
- package/src/runtime/agent/orchestrator/session/message-ids.mjs +123 -0
- package/src/runtime/agent/orchestrator/session/message-ids.test-support.mjs +29 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +29 -19
- package/src/runtime/agent/orchestrator/session/read-dedup.mjs +0 -1
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +10 -3
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +11 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +29 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +23 -4
- package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +20 -3
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +28 -8
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +140 -0
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +52 -2
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +32 -22
- package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +10 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-cache-policy.mjs +8 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +31 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-fast-paths.mjs +32 -35
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +11 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +9 -6
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +80 -66
- package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +8 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +5 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +16 -7
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +137 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +11 -10
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +21 -11
- package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +12 -1
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +56 -13
- package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +58 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/trusted-roots.mjs +25 -1
- package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +78 -5
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +0 -10
- package/src/runtime/attachments/store.mjs +38 -0
- package/src/runtime/channels/index.mjs +1 -5
- package/src/runtime/channels/lib/runtime-paths.mjs +8 -23
- package/src/runtime/channels/lib/tool-dispatch.mjs +1 -13
- package/src/runtime/channels/lib/worker-ipc.mjs +2 -2
- package/src/runtime/channels/lib/worker-main.mjs +4 -34
- package/src/runtime/shared/atomic-file.mjs +8 -2
- package/src/runtime/shared/best-effort-stderr.mjs +8 -0
- package/src/runtime/shared/code-graph-state.mjs +12 -0
- package/src/runtime/shared/defaults-separation.mjs +2 -0
- package/src/runtime/shared/git-runner-worker.mjs +3 -2
- package/src/runtime/shared/git-runner.mjs +4 -3
- package/src/runtime/shared/llm/default-context-window.mjs +6 -0
- package/src/runtime/shared/llm/model-catalog-projection.mjs +5 -4
- package/src/runtime/shared/llm/model-catalog.mjs +240 -118
- package/src/runtime/shared/llm/provider-catalog-cache.mjs +36 -28
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +156 -0
- package/src/runtime/shared/llm/provider-seed-rosters.mjs +130 -0
- package/src/runtime/shared/model-proxy-mode.d.mts +3 -0
- package/src/runtime/shared/model-proxy-mode.mjs +19 -0
- package/src/runtime/shared/provider-accounts.mjs +2 -2
- package/src/runtime/shared/provider-api-key.mjs +21 -1
- package/src/runtime/shared/schedule-model-ref.mjs +11 -2
- package/src/runtime/shared/semver.d.mts +1 -0
- package/src/runtime/shared/semver.mjs +57 -0
- package/src/runtime/shared/session-usage-totals.mjs +19 -0
- package/src/runtime/shared/sharp-electron-linux.mjs +25 -0
- package/src/runtime/shared/singleton-owner.mjs +36 -6
- package/src/runtime/shared/statusline/statusline-segments.mjs +68 -14
- package/src/runtime/shared/tool-surface.mjs +9 -2
- package/src/runtime/shared/tool-work-units.mjs +14 -0
- package/src/runtime/shared/transcript-metadata.mjs +17 -1
- package/src/runtime/shared/turn-changes.mjs +791 -0
- package/src/runtime/shared/turn-snapshot-store.mjs +346 -12
- package/src/runtime/shared/turn-snapshot.mjs +690 -81
- package/src/runtime/shared/turn-worktree-snapshot.mjs +161 -11
- package/src/runtime/shared/update-checker.mjs +2 -31
- package/src/runtime/shared/worktrees/cache-cleanups.mjs +52 -0
- package/src/runtime/shared/worktrees/contract.mjs +551 -0
- package/src/runtime/shared/worktrees/disk.mjs +57 -0
- package/src/runtime/shared/worktrees/git.mjs +247 -0
- package/src/runtime/shared/worktrees/include.mjs +480 -0
- package/src/runtime/shared/worktrees/lock.mjs +46 -0
- package/src/runtime/shared/worktrees/maintenance.mjs +96 -0
- package/src/runtime/shared/worktrees/manager.mjs +1215 -0
- package/src/runtime/shared/worktrees/merge.mjs +182 -0
- package/src/runtime/shared/worktrees/owner.mjs +46 -0
- package/src/runtime/shared/worktrees/paths.mjs +62 -0
- package/src/runtime/shared/worktrees/registry.mjs +110 -0
- package/src/runtime/shared/worktrees/settings.mjs +84 -0
- package/src/runtime/shared/worktrees/slug.mjs +62 -0
- package/src/runtime/shared/worktrees/test-support.mjs +96 -0
- package/src/runtime/visualize-bridge/client.mjs +181 -0
- package/src/runtime/visualize-bridge/tool-defs.mjs +97 -0
- package/src/session-runtime/boot/apis.mjs +35 -0
- package/src/session-runtime/boot/begin.mjs +0 -2
- package/src/session-runtime/boot/config.mjs +2 -0
- package/src/session-runtime/boot/facade.mjs +20 -0
- package/src/session-runtime/boot/infrastructure.mjs +1 -0
- package/src/session-runtime/boot/session.mjs +1 -0
- package/src/session-runtime/boot/tools.mjs +9 -4
- package/src/session-runtime/config-lifecycle.mjs +10 -1
- package/src/session-runtime/cwd-plugins/cwd-apply.mjs +11 -1
- package/src/session-runtime/global-extensions.mjs +2 -2
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +27 -2
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +32 -1
- package/src/session-runtime/internal-tool-executor.mjs +9 -1
- package/src/session-runtime/lifecycle/session-catalog.mjs +8 -1
- package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +5 -0
- package/src/session-runtime/lifecycle/session-switch/resume.mjs +21 -3
- package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +16 -0
- package/src/session-runtime/mcp-glue/connect.mjs +11 -6
- package/src/session-runtime/mcp-glue/server-catalog.mjs +7 -3
- package/src/session-runtime/mcp-glue/server-input.mjs +29 -0
- package/src/session-runtime/model-route/route-persist.mjs +3 -0
- package/src/session-runtime/model-route/set-route.mjs +15 -2
- package/src/session-runtime/notification-bus.mjs +9 -1
- package/src/session-runtime/provider-models/row-hydration.mjs +2 -0
- package/src/session-runtime/resource-extension-sync.mjs +30 -7
- package/src/session-runtime/resource-mcp-api.mjs +27 -10
- package/src/session-runtime/route-resolution.mjs +10 -1
- package/src/session-runtime/route-state.mjs +16 -2
- package/src/session-runtime/runtime-bootstrap.mjs +0 -4
- package/src/session-runtime/runtime-core.mjs +5 -0
- package/src/session-runtime/runtime-facade.mjs +8 -0
- package/src/session-runtime/runtime-paths.mjs +0 -1
- package/src/session-runtime/runtime-review-api.mjs +9 -0
- package/src/session-runtime/services/agent-tool/helpers.mjs +5 -0
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +3 -0
- package/src/session-runtime/services/agent-tool/job-views/job-lookup.mjs +1 -0
- package/src/session-runtime/services/agent-tool/job-views/spawn-meta.mjs +1 -0
- package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +15 -0
- package/src/session-runtime/services/agent-tool/send-flow.mjs +1 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +10 -2
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -7
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +2 -1
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -0
- package/src/session-runtime/services/agent-tool/worker-rows.mjs +1 -0
- package/src/session-runtime/services/agent-tool.mjs +1 -0
- package/src/session-runtime/services/channel-worker.mjs +1 -1
- package/src/session-runtime/services/daemon-candidate.mjs +3 -2
- package/src/session-runtime/services/daemon-crash-capture/spawn-capture.mjs +55 -0
- package/src/session-runtime/session-create/session-options.mjs +10 -1
- package/src/session-runtime/session-turn-api.mjs +1 -0
- package/src/session-runtime/settings-api.mjs +4 -2
- package/src/session-runtime/settings-builtin-tools-api.mjs +9 -2
- package/src/session-runtime/settings-profile-api.mjs +27 -2
- package/src/session-runtime/settings-worktree-api.mjs +17 -0
- package/src/session-runtime/setup-tool/executor.mjs +11 -4
- package/src/session-runtime/setup-tool/settings-contract.mjs +3 -1
- package/src/session-runtime/setup-tool/tool-defs.mjs +31 -3
- package/src/session-runtime/starter-guide-state.mjs +62 -0
- package/src/session-runtime/turn/agent-ops.mjs +12 -1
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +13 -3
- package/src/session-runtime/turn/turn-run/snapshot-tracker.mjs +20 -15
- package/src/session-runtime/turn/turn-run/turn-open.mjs +4 -5
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +29 -1
- package/src/session-runtime/turn/turn-run/turn-settle.mjs +6 -1
- package/src/session-runtime/turn/turn-run.mjs +6 -7
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +15 -3
- package/src/session-runtime/workflow-agents-api/onboarding.mjs +3 -2
- package/src/session-runtime/workspace/admission-gate.mjs +197 -0
- package/src/session-runtime/workspace/project-branches.mjs +136 -0
- package/src/session-runtime/workspace/transition-steps.mjs +364 -0
- package/src/session-runtime/workspace/transitions.mjs +651 -0
- package/src/session-runtime/workspace/workspace-state.mjs +112 -0
- package/src/standalone/channel-binding.mjs +1 -2
- package/src/standalone/channel-transport/call-dispatch.mjs +4 -10
- package/src/standalone/channel-transport/http-routes.mjs +17 -0
- package/src/standalone/channel-transport.mjs +13 -1
- package/src/standalone/daemon-channels-loader.mjs +2 -3
- package/src/standalone/daemon-desktop-runtime.mjs +1 -0
- package/src/standalone/daemon-owner.mjs +372 -0
- package/src/standalone/daemon-stored-session-views.mjs +4 -1
- package/src/standalone/daemon.mjs +139 -5
- package/src/standalone/desktop-service-registry.mjs +20 -0
- package/src/standalone/local-session-runtime.mjs +13 -78
- package/src/standalone/session-client/attachment-calls.mjs +3 -1
- package/src/standalone/session-client/daemon-unavailable.mjs +62 -0
- package/src/standalone/session-client/lease-heartbeat.mjs +47 -0
- package/src/standalone/session-client.mjs +104 -13
- package/src/standalone/session-protocol.mjs +17 -0
- package/src/standalone/session-proxy.mjs +3 -0
- package/src/standalone/session-service/agent-tree/agent-child.mjs +4 -0
- package/src/standalone/session-service/agent-tree/agent-rehydrate.mjs +1 -0
- package/src/standalone/session-service/entries/lifecycle.mjs +6 -0
- package/src/standalone/session-service/projection/revisions.mjs +2 -0
- package/src/standalone/session-service/projection/transcript-window.mjs +149 -19
- package/src/standalone/session-service/projection/workspace.mjs +14 -0
- package/src/standalone/session-service/session-calls/session-action.mjs +11 -3
- package/src/standalone/session-transport/call-route.mjs +13 -0
- package/src/standalone/session-transport/client-registry/client-grace.mjs +45 -3
- package/src/standalone/session-transport/client-registry/registration-replays.mjs +1 -0
- package/src/standalone/session-transport/client-registry.mjs +20 -3
- package/src/standalone/session-transport/routes.mjs +79 -2
- package/src/standalone/session-transport/stack.mjs +2 -0
- package/src/standalone/session-transport.mjs +24 -1
- package/src/tui/app/message-selector.mjs +2 -1
- package/src/tui/app/model-options.mjs +35 -5
- package/src/tui/app/model-picker/provider-models-list.mjs +2 -2
- package/src/tui/app/model-picker.mjs +4 -2
- package/src/tui/dist/index.mjs +332 -36
- package/src/tui/index.jsx +10 -2
- package/src/tui/session/compaction-view.mjs +147 -0
- package/src/tui/session/context-state.mjs +6 -0
- package/src/tui/session/initial-state.mjs +3 -0
- package/src/tui/session/quota-resume.mjs +2 -1
- package/src/tui/session/session-api/commands.mjs +10 -2
- package/src/tui/session/session-api/controls.mjs +4 -0
- package/src/tui/session/session-api/extensions.mjs +12 -8
- package/src/tui/session/session-api/intake/rewind.mjs +2 -1
- package/src/tui/session/session-api/integrations.mjs +18 -0
- package/src/tui/session/session-api/lifecycle/dispose.mjs +6 -1
- package/src/tui/session/session-api/lifecycle/inheritance.mjs +2 -0
- package/src/tui/session/session-api/lifecycle/resume.mjs +3 -0
- package/src/tui/session/session-api/routes.mjs +10 -1
- package/src/tui/session/session-api/settings.mjs +2 -0
- package/src/tui/session/session-api/shared.mjs +10 -6
- package/src/tui/session/session-api/worktree.mjs +60 -0
- package/src/tui/session/session-api.mjs +2 -0
- package/src/tui/session/session-flow/auto-clear.mjs +31 -12
- package/src/tui/session/session-flow/drain.mjs +15 -1
- package/src/tui/session/session-flow/session-reset.mjs +4 -3
- package/src/tui/session/session-flow.mjs +2 -0
- package/src/tui/session/transcript-intake.mjs +14 -5
- package/src/tui/session/turn-stream.mjs +32 -4
- package/src/tui/session/turn-tool-cards.mjs +10 -2
- package/src/tui/session/turn.mjs +39 -10
- package/src/runtime/channels/tool-defs.mjs +0 -17
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/tui/session/compaction-view.mjs - the visible transcript across a
|
|
3
|
+
* compaction. The rows the compaction took out of the model context stay in
|
|
4
|
+
* view, marked `archived` (display-only: greyed, no model-state actions), and
|
|
5
|
+
* the completion row becomes the "compacted" divider at the boundary.
|
|
6
|
+
*
|
|
7
|
+
* The model transcript itself belongs to runtime.compact / the pre-send pass;
|
|
8
|
+
* the durable copy of the dropped rows is the runtime's compaction archive.
|
|
9
|
+
*/
|
|
10
|
+
import { COMPACTION_DIVIDER_LABEL } from '../../runtime/agent/orchestrator/session/compaction-archive.mjs';
|
|
11
|
+
|
|
12
|
+
function isCompactionDivider(item) {
|
|
13
|
+
return item?.kind === 'statusdone' && item.status === 'compacted';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function archivedItem(item) {
|
|
17
|
+
if (!item || typeof item !== 'object' || item.archived === true || isCompactionDivider(item)) return item;
|
|
18
|
+
return { ...item, archived: true };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** `divider` (id, detail) as the compaction boundary row. Every path — manual,
|
|
22
|
+
* auto-clear, mid-turn — and the persisted archive carry the one compaction
|
|
23
|
+
* label; the stats stay in `detail`. */
|
|
24
|
+
function compactionDividerItem(item) {
|
|
25
|
+
return {
|
|
26
|
+
...item,
|
|
27
|
+
kind: 'statusdone',
|
|
28
|
+
status: 'compacted',
|
|
29
|
+
label: COMPACTION_DIVIDER_LABEL,
|
|
30
|
+
at: item?.at ?? Date.now(),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Row kinds a transcript message backs (prompt, reply, tool card). */
|
|
35
|
+
const MESSAGE_ROW_KINDS = new Set(['user', 'assistant', 'tool']);
|
|
36
|
+
|
|
37
|
+
const idSet = (values) => new Set(Array.isArray(values) ? values.filter((value) => value != null) : []);
|
|
38
|
+
|
|
39
|
+
/** The tool calls a tool row shows: its own call, a restored aggregate's
|
|
40
|
+
* calls, a live aggregate's members (whose ids are their call ids). */
|
|
41
|
+
function toolCallIdsOfItem(item) {
|
|
42
|
+
if (item?.kind !== 'tool') return [];
|
|
43
|
+
if (item.callId) return [String(item.callId)];
|
|
44
|
+
if (Array.isArray(item.callIds) && item.callIds.length) return item.callIds.filter(Boolean).map(String);
|
|
45
|
+
if (item.aggregate === true && Array.isArray(item.toolMembers)) {
|
|
46
|
+
return item.toolMembers
|
|
47
|
+
.map((member) => member?.id)
|
|
48
|
+
.filter((id) => id != null)
|
|
49
|
+
.map(String);
|
|
50
|
+
}
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Which rows a compaction took out of the model context, from the result or
|
|
56
|
+
* event it reported:
|
|
57
|
+
* - `droppedIdentities` ({ messageIds, callIds }) — whenever supplied,
|
|
58
|
+
* whatever `droppedMessages` says — by id membership only:
|
|
59
|
+
* a tool row whose calls all left (or, without call ids, whose message
|
|
60
|
+
* id left); any other row with a message of its own (prompt, reply,
|
|
61
|
+
* notification, restored marker) whose message id left — a prompt,
|
|
62
|
+
* reply or tool row without an id stays live. Only a row with no
|
|
63
|
+
* message of its own (a live completion, notice or status row) follows
|
|
64
|
+
* its turn's prompt;
|
|
65
|
+
* - no identities and `droppedMessages: 0` (a rewrite-only pass): none;
|
|
66
|
+
* - neither (a source that reports nothing): every row.
|
|
67
|
+
* Returns a predicate over the rows before the boundary, in order.
|
|
68
|
+
*/
|
|
69
|
+
export function compactionArchivedRows(result) {
|
|
70
|
+
const identities = result?.droppedIdentities;
|
|
71
|
+
// Identities decide when supplied: a kept message can still have lost
|
|
72
|
+
// part of itself (its text, some calls) with no message fully dropped.
|
|
73
|
+
// The count is only the fallback for a source without identities.
|
|
74
|
+
if (!identities || typeof identities !== 'object') {
|
|
75
|
+
const count = result?.droppedMessages;
|
|
76
|
+
return count !== undefined && count !== null && !(Number(count) > 0) ? () => false : () => true;
|
|
77
|
+
}
|
|
78
|
+
const messageIds = idSet(identities.messageIds);
|
|
79
|
+
const callIds = idSet(identities.callIds);
|
|
80
|
+
let promptDropped = false;
|
|
81
|
+
const predicate = (item) => {
|
|
82
|
+
if (!item || typeof item !== 'object') return false;
|
|
83
|
+
const calls = toolCallIdsOfItem(item);
|
|
84
|
+
let dropped;
|
|
85
|
+
if (calls.length) dropped = calls.every((id) => callIds.has(id));
|
|
86
|
+
// A message-backed row is decided by its own id alone: one without an id
|
|
87
|
+
// has no display identity in the result and stays live.
|
|
88
|
+
else if (item.messageId || MESSAGE_ROW_KINDS.has(item.kind)) {
|
|
89
|
+
dropped = Boolean(item.messageId) && messageIds.has(item.messageId);
|
|
90
|
+
}
|
|
91
|
+
// Only an auxiliary row (no message of its own) follows its turn.
|
|
92
|
+
else return promptDropped;
|
|
93
|
+
if (item.kind === 'user') promptDropped = dropped;
|
|
94
|
+
return dropped;
|
|
95
|
+
};
|
|
96
|
+
// An aggregate row some of whose calls survive stays live, with its dropped
|
|
97
|
+
// members marked archived (the restart path archives exactly those calls).
|
|
98
|
+
predicate.markDroppedMembers = (item) => {
|
|
99
|
+
if (item?.kind !== 'tool' || item.aggregate !== true || !Array.isArray(item.toolMembers)) return item;
|
|
100
|
+
if (!item.toolMembers.some((member) => member?.id != null && callIds.has(String(member.id)))) return item;
|
|
101
|
+
return {
|
|
102
|
+
...item,
|
|
103
|
+
toolMembers: item.toolMembers.map((member) =>
|
|
104
|
+
member?.id != null && callIds.has(String(member.id)) && member.archived !== true
|
|
105
|
+
? { ...member, archived: true }
|
|
106
|
+
: member
|
|
107
|
+
),
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
return predicate;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function classifiedRow(item, archived) {
|
|
114
|
+
if (archived(item)) return archivedItem(item);
|
|
115
|
+
return typeof archived.markDroppedMembers === 'function' ? archived.markDroppedMembers(item) : item;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Items with the rows before `boundary` (default: all) that `archived`
|
|
119
|
+
* selects marked archived, and the divider inserted at the boundary.
|
|
120
|
+
* Returns the next list and the divider's index. */
|
|
121
|
+
export function archiveItemsForCompaction(
|
|
122
|
+
items,
|
|
123
|
+
divider,
|
|
124
|
+
boundary = null,
|
|
125
|
+
{ archived = () => true, archiveTail = false } = {}
|
|
126
|
+
) {
|
|
127
|
+
const list = Array.isArray(items) ? items : [];
|
|
128
|
+
const at = Number.isInteger(boundary) ? Math.max(0, Math.min(list.length, boundary)) : list.length;
|
|
129
|
+
const next = list.slice(0, at).map((item) => classifiedRow(item, archived));
|
|
130
|
+
next.push(compactionDividerItem(divider));
|
|
131
|
+
// The current turn's rows after the boundary stay in place but are still
|
|
132
|
+
// classified by the same result: what compaction explicitly dropped from
|
|
133
|
+
// this turn (its tool calls) is archived, the rest stays live.
|
|
134
|
+
for (let index = at; index < list.length; index += 1) {
|
|
135
|
+
next.push(archiveTail ? classifiedRow(list[index], archived) : list[index]);
|
|
136
|
+
}
|
|
137
|
+
return { items: next, dividerIndex: at };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** The runtime archive range a resumed session exposes to paged views
|
|
141
|
+
* (`transcriptArchive` state), or null. */
|
|
142
|
+
export function resumedTranscriptArchive(range) {
|
|
143
|
+
const after = Number(range?.after);
|
|
144
|
+
const before = Number(range?.before);
|
|
145
|
+
if (!Number.isInteger(after) || !Number.isInteger(before) || before - 1 <= after) return null;
|
|
146
|
+
return { after, before };
|
|
147
|
+
}
|
|
@@ -61,12 +61,18 @@ export function createContextState({
|
|
|
61
61
|
effortOptions: runtime.effortOptions,
|
|
62
62
|
fast: runtime.fast,
|
|
63
63
|
fastCapable: runtime.fastCapable,
|
|
64
|
+
autoEffort: runtime.autoEffort !== false,
|
|
64
65
|
modelParameters: runtime.modelParameters || {},
|
|
65
66
|
contextPercent: runtime.contextPercent,
|
|
66
67
|
contextWindow: runtime.contextWindow,
|
|
67
68
|
rawContextWindow: runtime.rawContextWindow,
|
|
68
69
|
effectiveContextWindowPercent: runtime.effectiveContextWindowPercent,
|
|
69
70
|
cwd: runtime.cwd || process.cwd(),
|
|
71
|
+
// Lead workspace record (worktrees/contract.mjs SessionWorkspace): the
|
|
72
|
+
// registered Project, the execution root, the worktree binding and its
|
|
73
|
+
// revision. Null while the session has never left its project folder.
|
|
74
|
+
// Identity-stable until a transition commits.
|
|
75
|
+
workspace: runtime.getWorkspace?.() ?? null,
|
|
70
76
|
systemShell: runtime.systemShell || { source: 'auto', command: '', effective: '' },
|
|
71
77
|
webSearchRoute: runtime.getWebSearchRoute?.() || runtime.webSearchRoute || null,
|
|
72
78
|
autoClear: autoClearState(),
|
|
@@ -12,6 +12,9 @@ export function createInitialSessionState({ runtime, runtimeCwd, baseRouteState
|
|
|
12
12
|
transcriptViewRevision: 0,
|
|
13
13
|
transcriptHistoryBefore: false,
|
|
14
14
|
transcriptHistoryAfter: false,
|
|
15
|
+
// Compaction-archive segments a paged view may load above the rows held
|
|
16
|
+
// here ({ after, before } segment numbers), set on resume.
|
|
17
|
+
transcriptArchive: null,
|
|
15
18
|
structureRevision: 0,
|
|
16
19
|
streamingTail: null,
|
|
17
20
|
toasts: [],
|
|
@@ -52,7 +52,8 @@ export function latestQuotaFailure(items) {
|
|
|
52
52
|
const transcript = Array.isArray(items) ? items : [];
|
|
53
53
|
for (let index = transcript.length - 1; index >= 0; index -= 1) {
|
|
54
54
|
const item = transcript[index];
|
|
55
|
-
|
|
55
|
+
// A turn a compaction archived is no longer the model's to resume.
|
|
56
|
+
if (item?.kind === 'user' || item?.archived === true) return null;
|
|
56
57
|
if (item?.kind !== 'turndone') continue;
|
|
57
58
|
const quota = item.quota;
|
|
58
59
|
if (String(item.status || '').toLowerCase() !== 'failed' || !quota || typeof quota.provider !== 'string') {
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* a turn is running). Each shows a command status while it holds the lock.
|
|
5
5
|
*/
|
|
6
6
|
import { compactEventDetail } from '../labels.mjs';
|
|
7
|
+
import { archiveItemsForCompaction, compactionArchivedRows } from '../compaction-view.mjs';
|
|
7
8
|
|
|
8
9
|
export function createSessionCommandsApi(bag) {
|
|
9
10
|
const {
|
|
@@ -108,8 +109,15 @@ export function createSessionCommandsApi(bag) {
|
|
|
108
109
|
invalidateExact: compactChanged,
|
|
109
110
|
});
|
|
110
111
|
set({ ...routeState(), stats: { ...getState().stats } });
|
|
111
|
-
if (compactChanged)
|
|
112
|
-
|
|
112
|
+
if (compactChanged) {
|
|
113
|
+
// The compacted rows stay visible (archived) above the divider.
|
|
114
|
+
const { items } = archiveItemsForCompaction(getState().items, compactDoneItem(result, startedAt), null, {
|
|
115
|
+
archived: compactionArchivedRows(result),
|
|
116
|
+
});
|
|
117
|
+
set({ items: replaceItems(items, { preserveSpill: true }) });
|
|
118
|
+
} else {
|
|
119
|
+
pushItem(compactDoneItem(result, startedAt));
|
|
120
|
+
}
|
|
113
121
|
return result;
|
|
114
122
|
});
|
|
115
123
|
} finally {
|
|
@@ -63,6 +63,10 @@ export function createSessionControlsApi(bag) {
|
|
|
63
63
|
taskControl: (args = {}) => {
|
|
64
64
|
return runtime.taskControl?.(args) ?? null;
|
|
65
65
|
},
|
|
66
|
+
// Structured stop of one background shell job: { stopped, error? }.
|
|
67
|
+
stopShellJob: async (taskId) => {
|
|
68
|
+
return (await runtime.stopShellJob?.(taskId)) ?? { stopped: false, error: 'shell job control is unavailable' };
|
|
69
|
+
},
|
|
66
70
|
goalControl: async (args = {}) => {
|
|
67
71
|
const result = await runtime.goalControl?.(args);
|
|
68
72
|
if (['pause', 'stop'].includes(result?.action)) {
|
|
@@ -14,15 +14,19 @@ export function createSessionExtensionsApi(bag) {
|
|
|
14
14
|
resetStatsAndSyncContext,
|
|
15
15
|
routeState,
|
|
16
16
|
});
|
|
17
|
-
// One locked runtime mutation, then republish and announce it.
|
|
17
|
+
// One locked runtime mutation, then republish and announce it. A refused
|
|
18
|
+
// change throws so a caller never reports a skipped write as saved.
|
|
18
19
|
const lockedChange = (call, notice) =>
|
|
19
|
-
withCommandLock(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
withCommandLock(
|
|
21
|
+
async (...args) => {
|
|
22
|
+
const result = await call(...args);
|
|
23
|
+
refreshRouteStats();
|
|
24
|
+
const [text, level = 'info'] = notice(result, ...args);
|
|
25
|
+
pushNotice(text, level);
|
|
26
|
+
return result;
|
|
27
|
+
},
|
|
28
|
+
{ busyError: 'Another command is still running; try again when it finishes.' }
|
|
29
|
+
);
|
|
26
30
|
const pluginLabel = (result, plugin) => result?.plugin?.title || result?.plugin?.name || plugin?.name || plugin;
|
|
27
31
|
|
|
28
32
|
return {
|
|
@@ -13,7 +13,8 @@ export function createRewindAction(bag) {
|
|
|
13
13
|
if (getState().busy || getState().commandBusy) return null;
|
|
14
14
|
const items = getState().items || [];
|
|
15
15
|
const index = items.findIndex((item) => item?.kind === 'user' && String(item?.id) === target);
|
|
16
|
-
|
|
16
|
+
// An archived prompt left the model context: there is nothing to rewind.
|
|
17
|
+
if (index < 0 || items[index]?.archived === true) return null;
|
|
17
18
|
const text = String(items[index]?.text || '').trim();
|
|
18
19
|
if (!text) return null;
|
|
19
20
|
set({ commandBusy: true });
|
|
@@ -61,6 +61,23 @@ export function createSessionIntegrationsApi(bag, { oauthFlows }) {
|
|
|
61
61
|
checkpointId
|
|
62
62
|
);
|
|
63
63
|
},
|
|
64
|
+
getTurnChanges: async (options = {}) => {
|
|
65
|
+
return await requireRuntimeMethod('getTurnChanges', 'Turn changes are unavailable')(options);
|
|
66
|
+
},
|
|
67
|
+
revertTurnChanges: async (checkpointId, file, revision) => {
|
|
68
|
+
return await requireRuntimeMethod('revertTurnChanges', 'Turn changes undo is unavailable')(
|
|
69
|
+
checkpointId,
|
|
70
|
+
file,
|
|
71
|
+
revision
|
|
72
|
+
);
|
|
73
|
+
},
|
|
74
|
+
reapplyTurnChanges: async (checkpointId, file, revision) => {
|
|
75
|
+
return await requireRuntimeMethod('reapplyTurnChanges', 'Turn changes reapply is unavailable')(
|
|
76
|
+
checkpointId,
|
|
77
|
+
file,
|
|
78
|
+
revision
|
|
79
|
+
);
|
|
80
|
+
},
|
|
64
81
|
getOnboardingStatus: () => {
|
|
65
82
|
return runtime.getOnboardingStatus?.() || { completed: true, workflowRoutes: {} };
|
|
66
83
|
},
|
|
@@ -68,6 +85,7 @@ export function createSessionIntegrationsApi(bag, { oauthFlows }) {
|
|
|
68
85
|
// Completed-marking only; no route/agent/provider writes.
|
|
69
86
|
return runtime.skipOnboarding?.() || null;
|
|
70
87
|
},
|
|
88
|
+
saveStarterGuideState: (state) => runtime.saveStarterGuideState?.(state) || null,
|
|
71
89
|
completeOnboarding: withCommandLock(async (payload = {}) => {
|
|
72
90
|
const result = await runtime.completeOnboarding?.(payload);
|
|
73
91
|
refreshRouteStats();
|
|
@@ -35,7 +35,12 @@ export function createDisposeAction(bag, { oauthFlows }) {
|
|
|
35
35
|
try {
|
|
36
36
|
clearInterval(lifecycle.runtimePulseTimer);
|
|
37
37
|
} catch {}
|
|
38
|
-
for (const key of [
|
|
38
|
+
for (const key of [
|
|
39
|
+
'unsubscribeRuntimeNotifications',
|
|
40
|
+
'unsubscribeAgentStatus',
|
|
41
|
+
'unsubscribeRemoteState',
|
|
42
|
+
'unsubscribeCompletionWakeGate',
|
|
43
|
+
]) {
|
|
39
44
|
try {
|
|
40
45
|
lifecycle[key]?.();
|
|
41
46
|
} catch {}
|
|
@@ -25,6 +25,8 @@ export function createInheritanceActions(bag, { restoreTranscriptItems }) {
|
|
|
25
25
|
set({
|
|
26
26
|
sessionId,
|
|
27
27
|
items: replaceItems(items),
|
|
28
|
+
// An heir carries the conversation, never the source's archive.
|
|
29
|
+
transcriptArchive: null,
|
|
28
30
|
toasts: [],
|
|
29
31
|
queued: [],
|
|
30
32
|
thinking: null,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Resume: reopen a stored session, rebuild the visible transcript from its
|
|
2
2
|
// messages and reconcile live-share and steering at the same boundary.
|
|
3
3
|
import { primeContextEstimates } from '../../../../runtime/agent/orchestrator/session/context-utils.mjs';
|
|
4
|
+
import { resumedTranscriptArchive } from '../../compaction-view.mjs';
|
|
4
5
|
|
|
5
6
|
export function createResumeAction(bag, { restoreTranscriptItems }) {
|
|
6
7
|
const {
|
|
@@ -52,6 +53,8 @@ export function createResumeAction(bag, { restoreTranscriptItems }) {
|
|
|
52
53
|
});
|
|
53
54
|
set({
|
|
54
55
|
items: replaceItems(items),
|
|
56
|
+
// Paged views continue into the compaction archive past these rows.
|
|
57
|
+
transcriptArchive: resumedTranscriptArchive(r.transcriptArchive),
|
|
55
58
|
toasts: [],
|
|
56
59
|
queued: [],
|
|
57
60
|
thinking: null,
|
|
@@ -9,7 +9,16 @@ import { createApiHelpers } from './shared.mjs';
|
|
|
9
9
|
// published before the runtime write settles. What is NOT previewed about the
|
|
10
10
|
// route (effort options, Fast capability, context window) is provider
|
|
11
11
|
// metadata the runtime resolves while the preview is already on screen.
|
|
12
|
-
const ROUTE_PREVIEW_KEYS = [
|
|
12
|
+
const ROUTE_PREVIEW_KEYS = [
|
|
13
|
+
'provider',
|
|
14
|
+
'model',
|
|
15
|
+
'effort',
|
|
16
|
+
'fast',
|
|
17
|
+
'autoEffort',
|
|
18
|
+
'modelParameters',
|
|
19
|
+
'contextPercent',
|
|
20
|
+
'contextTokens',
|
|
21
|
+
];
|
|
13
22
|
|
|
14
23
|
/**
|
|
15
24
|
* The patch that publishes a requested route before the runtime write settles.
|
|
@@ -129,6 +129,8 @@ export function createSessionSettingsApi(bag) {
|
|
|
129
129
|
getTidyInstallStatus: () => runtime.getTidyInstallStatus?.(),
|
|
130
130
|
getDeveloperSettings: () => runtime.getDeveloperSettings?.(),
|
|
131
131
|
setDeveloperOption: lockedRuntimeCall((id, enabled) => runtime.setDeveloperOption?.(id, enabled)),
|
|
132
|
+
getWorktreeSettings: () => runtime.getWorktreeSettings(),
|
|
133
|
+
setWorktreeSettings: lockedRuntimeCall((patch) => runtime.setWorktreeSettings(patch)),
|
|
132
134
|
setWebSearchEnabled: lockedRuntimeCall((enabled) => runtime.setWebSearchEnabled?.(enabled)),
|
|
133
135
|
setInstructionFiles: lockedRuntimeCall((mode) => runtime.setInstructionFiles?.(mode)),
|
|
134
136
|
setMemoryToolsEnabled: lockedRuntimeCall((enabled) => runtime.setMemoryToolsEnabled?.(enabled)),
|
|
@@ -5,15 +5,19 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export function createApiHelpers({ getState, set, resetStatsAndSyncContext, routeState, syncContextStats }) {
|
|
7
7
|
/**
|
|
8
|
-
* Wrap a runtime call in the command lock: refused (→ `busyResult
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* Wrap a runtime call in the command lock: refused (→ `busyResult`, or a
|
|
9
|
+
* thrown `busyError` for callers that must not read a refusal as success)
|
|
10
|
+
* while another command holds commandBusy, otherwise held for the call's
|
|
11
|
+
* duration. `onRelease` runs after the lock drops (RPC replies read the
|
|
12
|
+
* published snapshot, not the mutable draft, so some callers flush there).
|
|
12
13
|
*/
|
|
13
14
|
const withCommandLock =
|
|
14
|
-
(run, { busyResult = null, onRelease = null } = {}) =>
|
|
15
|
+
(run, { busyResult = null, busyError = '', onRelease = null } = {}) =>
|
|
15
16
|
async (...args) => {
|
|
16
|
-
if (getState().commandBusy)
|
|
17
|
+
if (getState().commandBusy) {
|
|
18
|
+
if (busyError) throw new Error(busyError);
|
|
19
|
+
return busyResult;
|
|
20
|
+
}
|
|
17
21
|
set({ commandBusy: true });
|
|
18
22
|
try {
|
|
19
23
|
return await run(...args);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* worktree.mjs — the session object's Lead worktree surface. The daemon
|
|
3
|
+
* resolves these advertised actions by name (session-protocol.mjs) and each
|
|
4
|
+
* delegates to the runtime's workspace transition authority
|
|
5
|
+
* (session-runtime/workspace/transitions.mjs), then republishes the route
|
|
6
|
+
* state so the new `workspace` reaches every viewer. Failures are typed
|
|
7
|
+
* WorktreeErrors whose `code` crosses the daemon wire; a runtime without the
|
|
8
|
+
* authority rejects with WORKTREE_NOT_IMPLEMENTED.
|
|
9
|
+
*
|
|
10
|
+
* getBranchMenu() → { workspace, pendingWorktree, branches, occupancy, retainedWorktree }
|
|
11
|
+
* getProjectBranchMenu({ projectPath }) → { workspace, branches, occupancy, retainedWorktree: null }
|
|
12
|
+
* (no session: a New Task draft or the source-control dock)
|
|
13
|
+
* selectBranch({ branch, create?, expectedRevision?, confirmLarge? }) → { revision, workspace }
|
|
14
|
+
* selectProjectBranch({ projectPath, branch, create?, remote?, startPoint? }) → { branch, changed, commit? }
|
|
15
|
+
* selectProjectBranch({ projectPath, detach: commitId }) → { branch: null, changed, commit, detached: true }
|
|
16
|
+
* (no session: the guarded project-folder checkout)
|
|
17
|
+
* mergeProjectBranch({ projectPath, branch, target }) → backend merge result
|
|
18
|
+
* (no session: the source-control dock's merge into the confirmed target)
|
|
19
|
+
* requestWorktree({ name?, confirmLarge?, provision?, prompt?, txId?, expectedRevision? }) → { revision, workspace, pending, warnings? }
|
|
20
|
+
* (provision: a New Task's first send creates and enters it now)
|
|
21
|
+
* mergeWorkspace({ confirmed: true, target, cleanup?, expectedRevision? }) → backend merge result (+ cleanup)
|
|
22
|
+
* removeWorktree({ force?, expectedRevision? }) → { revision, workspace, removed }
|
|
23
|
+
* (expectedRevision: WORKTREE_REVISION_CONFLICT when the session moved on)
|
|
24
|
+
* (WORKTREE_REMOVAL_INCOMPLETE: partly removed; call again to finish)
|
|
25
|
+
* listWorktrees() → every managed worktree with its retention
|
|
26
|
+
* pruneWorktrees() → reconcile report (never a retained worktree)
|
|
27
|
+
*/
|
|
28
|
+
import { worktreeError } from '../../../runtime/shared/worktrees/contract.mjs';
|
|
29
|
+
|
|
30
|
+
/** Session actions of the Lead worktree feature (settings live in settings.mjs). */
|
|
31
|
+
export const SESSION_WORKTREE_ACTIONS = Object.freeze([
|
|
32
|
+
'getBranchMenu',
|
|
33
|
+
'getProjectBranchMenu',
|
|
34
|
+
'selectBranch',
|
|
35
|
+
'selectProjectBranch',
|
|
36
|
+
'mergeProjectBranch',
|
|
37
|
+
'requestWorktree',
|
|
38
|
+
'mergeWorkspace',
|
|
39
|
+
'removeWorktree',
|
|
40
|
+
'listWorktrees',
|
|
41
|
+
'pruneWorktrees',
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
export function createSessionWorktreeApi({ runtime, set, routeState } = {}) {
|
|
45
|
+
return Object.fromEntries(
|
|
46
|
+
SESSION_WORKTREE_ACTIONS.map((action) => [
|
|
47
|
+
action,
|
|
48
|
+
async (input = {}) => {
|
|
49
|
+
if (typeof runtime?.[action] !== 'function') {
|
|
50
|
+
throw worktreeError('WORKTREE_NOT_IMPLEMENTED', `${action} is not implemented yet.`);
|
|
51
|
+
}
|
|
52
|
+
const value = await runtime[action](input ?? {});
|
|
53
|
+
if (!action.startsWith('get') && typeof set === 'function' && typeof routeState === 'function') {
|
|
54
|
+
set({ ...routeState() });
|
|
55
|
+
}
|
|
56
|
+
return value;
|
|
57
|
+
},
|
|
58
|
+
])
|
|
59
|
+
);
|
|
60
|
+
}
|
|
@@ -12,6 +12,7 @@ import { createSessionControlsApi } from './session-api/controls.mjs';
|
|
|
12
12
|
import { createSessionExtensionsApi } from './session-api/extensions.mjs';
|
|
13
13
|
import { createSessionCommandsApi } from './session-api/commands.mjs';
|
|
14
14
|
import { createQuotaResumeApi } from './session-api/quota-resume.mjs';
|
|
15
|
+
import { createSessionWorktreeApi } from './session-api/worktree.mjs';
|
|
15
16
|
|
|
16
17
|
export function createSessionApi(bag) {
|
|
17
18
|
const api = { ...createSessionApiA(bag), ...createSessionApiB(bag) };
|
|
@@ -59,5 +60,6 @@ export function createSessionApiA(bag) {
|
|
|
59
60
|
...createSessionExtensionsApi(bag),
|
|
60
61
|
...createSessionCommandsApi(bag),
|
|
61
62
|
...createQuotaResumeApi(bag),
|
|
63
|
+
...createSessionWorktreeApi(bag),
|
|
62
64
|
};
|
|
63
65
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { presentErrorText } from '../../../runtime/shared/err-text.mjs';
|
|
7
7
|
import { sessionActivityTimestamp } from '../queue-helpers.mjs';
|
|
8
|
+
import { archiveItemsForCompaction, compactionArchivedRows } from '../compaction-view.mjs';
|
|
8
9
|
|
|
9
10
|
// Upper bound on the awaited idle compaction. Without a bound a stalled
|
|
10
11
|
// compaction wedges autoClearRunning/commandBusy and suppresses input drain.
|
|
@@ -52,23 +53,26 @@ export function createAutoClearOps(bag, { reset, kickDrain }) {
|
|
|
52
53
|
autoClearState,
|
|
53
54
|
routeState,
|
|
54
55
|
syncContextStats,
|
|
56
|
+
replaceItems,
|
|
55
57
|
} = bag;
|
|
56
58
|
|
|
57
|
-
// Only an actual compaction resets the visible
|
|
58
|
-
// success keeps it. The
|
|
59
|
+
// Only an actual compaction resets the visible activity; an unchanged
|
|
60
|
+
// success keeps it. The compacted rows stay in view, archived above the
|
|
61
|
+
// divider. The model transcript always belongs to runtime.compact.
|
|
59
62
|
function applyAutoClearUi(result) {
|
|
60
63
|
if (result.changed === false) return false;
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
|
|
64
|
+
const kept = getState().items;
|
|
65
|
+
reset.resetStats();
|
|
66
|
+
reset.clearUiActivityBeforeContextSync({ keepTranscript: true });
|
|
67
|
+
syncContextStats({ allowEstimated: true, invalidateExact: true });
|
|
68
|
+
const { items } = archiveItemsForCompaction(kept, { id: nextId() }, null, {
|
|
69
|
+
archived: compactionArchivedRows(result),
|
|
70
|
+
});
|
|
67
71
|
set({
|
|
72
|
+
items: replaceItems(items, { preserveSpill: true }),
|
|
68
73
|
...routeState(),
|
|
69
74
|
stats: { ...getState().stats },
|
|
70
75
|
});
|
|
71
|
-
pushItem({ kind: 'statusdone', id: nextId(), label: 'Auto-clear complete' });
|
|
72
76
|
return true;
|
|
73
77
|
}
|
|
74
78
|
|
|
@@ -129,7 +133,9 @@ export function createAutoClearOps(bag, { reset, kickDrain }) {
|
|
|
129
133
|
}
|
|
130
134
|
}
|
|
131
135
|
|
|
132
|
-
|
|
136
|
+
// `ignorePending`: a completion-wake drain has already dequeued its own
|
|
137
|
+
// batch, so other queued entries must not veto the idle check.
|
|
138
|
+
async function autoClearBeforeSubmit({ ignorePending = false } = {}) {
|
|
133
139
|
flushDeferredClearedSessionUi();
|
|
134
140
|
const cfg = autoClearState();
|
|
135
141
|
const now = Date.now();
|
|
@@ -138,7 +144,7 @@ export function createAutoClearOps(bag, { reset, kickDrain }) {
|
|
|
138
144
|
const notIdle =
|
|
139
145
|
!cfg.enabled ||
|
|
140
146
|
getState().busy ||
|
|
141
|
-
pending.length > 0 ||
|
|
147
|
+
(!ignorePending && pending.length > 0) ||
|
|
142
148
|
flags.autoClearRunning ||
|
|
143
149
|
flags.autoClearInFlight ||
|
|
144
150
|
idleMs < cfg.idleMs;
|
|
@@ -188,5 +194,18 @@ export function createAutoClearOps(bag, { reset, kickDrain }) {
|
|
|
188
194
|
}
|
|
189
195
|
}
|
|
190
196
|
|
|
191
|
-
|
|
197
|
+
// Same eligibility as a user submit, run before a completion wake turn so a
|
|
198
|
+
// cold cache after a long idle is compacted first. Never throws: a skipped or
|
|
199
|
+
// failed auto-clear must still let the wake run. A viewer mirroring another
|
|
200
|
+
// surface's owner leaves compaction to that owner.
|
|
201
|
+
async function autoClearBeforeWake() {
|
|
202
|
+
if (bag.liveShareMirroring?.() === true) return false;
|
|
203
|
+
try {
|
|
204
|
+
return await autoClearBeforeSubmit({ ignorePending: true });
|
|
205
|
+
} catch {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return { autoClearBeforeSubmit, autoClearBeforeWake, performAutoClear, flushDeferredClearedSessionUi };
|
|
192
211
|
}
|
|
@@ -114,7 +114,12 @@ function turnOptionsForBatch(batch, steering) {
|
|
|
114
114
|
};
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
|
|
117
|
+
const COMPLETION_WAKE_MODES = new Set(['task-notification', 'pending-resume']);
|
|
118
|
+
|
|
119
|
+
export function createDrainLoop(
|
|
120
|
+
bag,
|
|
121
|
+
{ queue, steering, submissions, flushDeferredClearedSessionUi, autoClearBeforeWake }
|
|
122
|
+
) {
|
|
118
123
|
const {
|
|
119
124
|
tuiDebug,
|
|
120
125
|
flags,
|
|
@@ -248,6 +253,15 @@ export function createDrainLoop(bag, { queue, steering, submissions, flushDeferr
|
|
|
248
253
|
if (isGoalQueuedEntry(batch[0]) && bag.shouldRunGoalContinuation?.(batch[0]) !== true) {
|
|
249
254
|
continue;
|
|
250
255
|
}
|
|
256
|
+
// A completion wake calls the model like a user turn, so a cold cache
|
|
257
|
+
// after a long idle is compacted first; the wake runs regardless.
|
|
258
|
+
if (autoClearBeforeWake && batch.every((entry) => COMPLETION_WAKE_MODES.has(entry.mode))) {
|
|
259
|
+
await autoClearBeforeWake();
|
|
260
|
+
if (flags.drainEpoch !== drainEpoch || admission() !== 'open') {
|
|
261
|
+
queue.requeueEntriesFront(batch);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
251
265
|
tuiDebug(`busy-queue drain batch=${batch.length} remaining=${pending.length}`);
|
|
252
266
|
const merged = mergePromptContents(batch);
|
|
253
267
|
rewindFailedTurnRows(batch);
|
|
@@ -30,12 +30,13 @@ export function createSessionResetOps(bag) {
|
|
|
30
30
|
return stats;
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
// `keepTranscript`: a compaction keeps the visible rows (its caller archives
|
|
34
|
+
// them); a clear or session reset wipes them and the archive range with them.
|
|
35
|
+
const clearUiActivityBeforeContextSync = ({ keepTranscript = false } = {}) => {
|
|
34
36
|
clearToastTimers();
|
|
35
37
|
resetAllStreamingMarkdownStablePrefixes();
|
|
36
|
-
const items = replaceItems([]);
|
|
37
38
|
set({
|
|
38
|
-
items,
|
|
39
|
+
...(keepTranscript ? {} : { items: replaceItems([]), transcriptArchive: null }),
|
|
39
40
|
toasts: [],
|
|
40
41
|
queued: [],
|
|
41
42
|
thinking: null,
|
|
@@ -23,6 +23,7 @@ export function createSessionFlow(bag) {
|
|
|
23
23
|
steering,
|
|
24
24
|
submissions,
|
|
25
25
|
flushDeferredClearedSessionUi: autoClear.flushDeferredClearedSessionUi,
|
|
26
|
+
autoClearBeforeWake: autoClear.autoClearBeforeWake,
|
|
26
27
|
});
|
|
27
28
|
|
|
28
29
|
return {
|
|
@@ -41,6 +42,7 @@ export function createSessionFlow(bag) {
|
|
|
41
42
|
drainPendingSteering: steering.drainPendingSteering,
|
|
42
43
|
restoreLeadSteeringFromDisk: steering.restoreLeadSteeringFromDisk,
|
|
43
44
|
autoClearBeforeSubmit: autoClear.autoClearBeforeSubmit,
|
|
45
|
+
autoClearBeforeWake: autoClear.autoClearBeforeWake,
|
|
44
46
|
performAutoClear: autoClear.performAutoClear,
|
|
45
47
|
restoreQueued: queue.restoreQueued,
|
|
46
48
|
prioritizeQueued: queue.prioritizeQueued,
|