mixdog 1.2.3 → 1.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/scripts/gate-local.mjs +6 -4
- package/scripts/lib/gate-scheduler.mjs +29 -11
- package/scripts/mobile-release.mjs +5 -4
- package/scripts/probe-provider-catalog.mjs +31 -0
- package/scripts/provider-pingpong-live.mjs +128 -38
- package/scripts/session-sweep.mjs +5 -25
- package/src/agents/maintainer/AGENT.md +1 -1
- package/src/agents/maintainer/agent.json +1 -1
- package/src/agents/reviewer/AGENT.md +2 -4
- package/src/agents/security/AGENT.md +1 -2
- package/src/agents/writer/AGENT.md +2 -3
- package/src/defaults/shipped-history.json +7 -1
- package/src/defaults/skills/image/SKILL.md +21 -23
- package/src/lib/keychain-cjs.cjs +13 -11
- package/src/output-styles/common.md +2 -1
- package/src/rules/agent/AGENT.md +7 -5
- package/src/rules/lead/LEAD.md +13 -13
- package/src/rules/shared/45-destructive.md +4 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +28 -7
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -11
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +101 -23
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-api-key-fetch.mjs +36 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +26 -44
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +2 -5
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +41 -12
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +13 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +81 -10
- package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +109 -5
- package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +107 -37
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor-native-context.mjs +48 -0
- package/src/runtime/agent/orchestrator/providers/cursor-wire-exec.mjs +144 -34
- package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +28 -4
- package/src/runtime/agent/orchestrator/providers/cursor-wire-request.mjs +8 -4
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +41 -11
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +67 -5
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +14 -4
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +14 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +9 -6
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -2
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +26 -4
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +12 -6
- package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +14 -6
- package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/gemini-rest-stream/watchdogs.mjs +16 -5
- package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +6 -1
- package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +22 -10
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -2
- package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +33 -7
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +11 -2
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +9 -5
- package/src/runtime/agent/orchestrator/providers/lib/request-compression.mjs +86 -0
- package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +4 -2
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -5
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +60 -16
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +11 -13
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +30 -19
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +5 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +42 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +13 -9
- package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +1 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +18 -7
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +36 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +51 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +11 -1
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +64 -52
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +1 -4
- package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +0 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +7 -6
- package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +13 -2
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/openrouter.mjs +1 -2
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +5 -4
- package/src/runtime/agent/orchestrator/providers/registry.mjs +9 -1
- package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +11 -4
- package/src/runtime/agent/orchestrator/providers/wire-route.mjs +14 -4
- package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +15 -3
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +6 -2
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +8 -6
- package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +4 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +30 -2
- package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +3 -2
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -3
- package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +3 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge-contract.mjs +6 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +10 -10
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +3 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +46 -8
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -8
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -2
- package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +24 -0
- package/src/runtime/agent/orchestrator/session/cache/tool-result-reuse.mjs +10 -2
- package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +2 -3
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +3 -11
- package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +6 -22
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +16 -2
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +28 -0
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +0 -6
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +0 -6
- package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/historical-session-closure.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +2 -5
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +2 -4
- package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +0 -27
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -10
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +2 -9
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +1 -4
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +76 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +8 -9
- package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +1 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +3 -4
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +33 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-support.mjs +0 -4
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +21 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +38 -13
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-failure.mjs +33 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +19 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +57 -13
- package/src/runtime/agent/orchestrator/session/manager/failed-turn-rewind.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +6 -120
- package/src/runtime/agent/orchestrator/session/manager/pending-persist-queue.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +29 -8
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +42 -49
- package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +50 -0
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +32 -14
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +17 -33
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +29 -13
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-recovery.mjs +45 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +2 -9
- package/src/runtime/agent/orchestrator/session/send-instrumentation.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/side-question.mjs +12 -7
- package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +5 -12
- package/src/runtime/agent/orchestrator/session/store/lifecycle-read.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/listing.mjs +2 -6
- package/src/runtime/agent/orchestrator/session/store/live-cache-eviction.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/liveness-veto.mjs +46 -37
- package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/load-session.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +5 -11
- package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +59 -0
- package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +27 -32
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +0 -8
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +6 -18
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +33 -106
- package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store-agent-worker-pool.mjs +5 -8
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +160 -212
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +50 -116
- package/src/runtime/agent/orchestrator/session/store-summary-locations.mjs +3 -29
- package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +7 -8
- package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +9 -20
- package/src/runtime/agent/orchestrator/session/store.mjs +3 -16
- package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +11 -12
- package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +37 -13
- package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +15 -4
- package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +4 -2
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +72 -15
- package/src/runtime/agent/orchestrator/session/turn-failure.mjs +45 -0
- package/src/runtime/agent/orchestrator/stall-policy.mjs +50 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +5 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +204 -10
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +160 -39
- package/src/runtime/agent/orchestrator/tools/builtin/git-partial-stage.mjs +7 -5
- package/src/runtime/agent/orchestrator/tools/builtin/grep-formatting.mjs +14 -5
- package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-context-expander.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-output.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-path-fanout.mjs +48 -44
- package/src/runtime/agent/orchestrator/tools/builtin/lib/search-input-helpers.mjs +10 -3
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +200 -17
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +5 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +20 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +101 -2
- package/src/runtime/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +67 -0
- package/src/runtime/agent/orchestrator/tools/lib/process-table-fixture.mjs +50 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +303 -63
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +108 -18
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +77 -11
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +81 -5
- package/src/runtime/attachments/store.d.mts +9 -0
- package/src/runtime/attachments/store.mjs +80 -9
- package/src/runtime/browser-bridge/browser-action-contract.d.mts +0 -1
- package/src/runtime/browser-bridge/browser-action-contract.mjs +0 -2
- package/src/runtime/computer-bridge/action-schema.mjs +178 -178
- package/src/runtime/computer-bridge/linux-readiness.d.mts +0 -2
- package/src/runtime/computer-bridge/linux-readiness.mjs +0 -16
- package/src/runtime/effort-judge/judge-client.mjs +21 -4
- package/src/runtime/effort-judge/judge-worker.mjs +4 -1
- package/src/runtime/github/tool.mjs +118 -17
- package/src/runtime/media/adapters/codex-image.mjs +140 -21
- package/src/runtime/media/catalog.mjs +4 -4
- package/src/runtime/media/chatgpt-usage.mjs +55 -0
- package/src/runtime/media/defaults.mjs +37 -0
- package/src/runtime/media/jobs.mjs +12 -2
- package/src/runtime/media/lanes.mjs +12 -0
- package/src/runtime/media/tool-defs.mjs +15 -4
- package/src/runtime/media/tool.mjs +41 -12
- package/src/runtime/media/upstream-error.mjs +72 -6
- package/src/runtime/memory/lib/ingest/transcript-rows.mjs +1 -0
- package/src/runtime/memory/lib/pg/process.mjs +5 -7
- package/src/runtime/memory/lib/pg/supervisor.mjs +4 -1
- package/src/runtime/office/authoring/docx-html-runner.mjs +1 -1
- package/src/runtime/office/authoring/html-browser.mjs +18 -8
- package/src/runtime/office/authoring/pdf-html-runner.mjs +1 -1
- package/src/runtime/office/authoring/pptx-html-measure.mjs +1 -1
- package/src/runtime/office/authoring/xlsx-html-runner.mjs +1 -1
- package/src/runtime/office/core/office-write-ledger.mjs +1 -5
- package/src/runtime/office/index.mjs +2 -3
- package/src/runtime/office/pdf/pdf-analysis.mjs +0 -68
- package/src/runtime/session-search/session-search-ingest.mjs +1 -1
- package/src/runtime/shared/agent-reap-state.mjs +13 -0
- package/src/runtime/shared/atomic-file.d.mts +1 -1
- package/src/runtime/shared/background-tasks.mjs +6 -1
- package/src/runtime/shared/bounded-line-diff.mjs +11 -2
- package/src/runtime/shared/browser-launch.mjs +15 -0
- package/src/runtime/shared/err-text.mjs +42 -4
- package/src/runtime/shared/file-lock.mjs +6 -5
- package/src/runtime/shared/llm/anthropic-betas.mjs +1 -2
- package/src/runtime/shared/llm/provider-model-identities.mjs +1 -0
- package/src/runtime/shared/model-route-chain.d.mts +8 -0
- package/src/runtime/shared/model-route-chain.mjs +48 -0
- package/src/runtime/shared/model-route-fallback.mjs +22 -0
- package/src/runtime/shared/pid-liveness.mjs +12 -0
- package/src/runtime/shared/provider-api-key.mjs +6 -0
- package/src/runtime/shared/provider-timeout-phase.mjs +17 -0
- package/src/runtime/shared/quiet-progress.d.mts +35 -0
- package/src/runtime/shared/quiet-progress.mjs +101 -0
- package/src/runtime/shared/quota-resume-store.mjs +32 -1
- package/src/runtime/shared/read-row-numbers.mjs +44 -0
- package/src/runtime/shared/remote-intent.mjs +2 -42
- package/src/runtime/shared/slow-span.mjs +8 -1
- package/src/runtime/shared/statusline/statusline-segments.mjs +24 -2
- package/src/runtime/shared/tool-card-model/card-header.mjs +2 -1
- package/src/runtime/shared/tool-output-budget.mjs +2 -0
- package/src/runtime/shared/tool-result-summary.mjs +16 -2
- package/src/runtime/shared/tool-status.mjs +3 -2
- package/src/runtime/shared/tool-surface.mjs +2 -3
- package/src/runtime/shared/tool-work-units.mjs +22 -15
- package/src/runtime/shared/transcript-metadata.mjs +49 -1
- package/src/runtime/shared/transcript-turn-keys.mjs +33 -0
- package/src/runtime/shared/transcript-writer/transcript-file.mjs +10 -1
- package/src/runtime/shared/transcript-writer.mjs +14 -4
- package/src/runtime/shared/turn-changes.mjs +2 -1
- package/src/runtime/shared/turn-snapshot.mjs +11 -3
- package/src/runtime/shared/worktrees/activity-gate.mjs +175 -0
- package/src/runtime/shared/worktrees/branch-management.mjs +179 -0
- package/src/runtime/shared/worktrees/carry.mjs +6 -4
- package/src/runtime/shared/worktrees/contract.mjs +27 -1
- package/src/runtime/shared/worktrees/dependencies.mjs +456 -0
- package/src/runtime/shared/worktrees/file-recovery.mjs +29 -13
- package/src/runtime/shared/worktrees/git-head.mjs +22 -13
- package/src/runtime/shared/worktrees/include.mjs +125 -7
- package/src/runtime/shared/worktrees/lock.mjs +1 -1
- package/src/runtime/shared/worktrees/maintenance.mjs +20 -2
- package/src/runtime/shared/worktrees/manager.mjs +378 -32
- package/src/runtime/shared/worktrees/owner.mjs +2 -1
- package/src/runtime/shared/worktrees/preparation-report.mjs +79 -0
- package/src/runtime/shared/worktrees/setup-commands.mjs +232 -0
- package/src/runtime/shared/worktrees/workspace-visibility.mjs +17 -0
- package/src/runtime/terminal-bridge/client.mjs +14 -10
- package/src/session-runtime/boot/apis.mjs +7 -1
- package/src/session-runtime/boot/config.mjs +2 -0
- package/src/session-runtime/boot/facade.mjs +3 -0
- package/src/session-runtime/boot/session.mjs +3 -2
- package/src/session-runtime/boot/tools.mjs +3 -0
- package/src/session-runtime/conversation-import/service.mjs +1 -1
- package/src/session-runtime/goal-facade-api.mjs +2 -2
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +44 -18
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +4 -1
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +22 -8
- package/src/session-runtime/internal-tool-executor.mjs +2 -0
- package/src/session-runtime/lifecycle/cold-heir.mjs +0 -1
- package/src/session-runtime/lifecycle/session-catalog.mjs +14 -16
- package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +18 -53
- package/src/session-runtime/lifecycle/session-switch.mjs +1 -1
- package/src/session-runtime/lifecycle/shared.mjs +5 -6
- package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -5
- package/src/session-runtime/lifecycle/teardown.mjs +7 -16
- package/src/session-runtime/media-api.mjs +8 -0
- package/src/session-runtime/model-route/route-ownership.mjs +60 -0
- package/src/session-runtime/model-route/route-persist.mjs +3 -2
- package/src/session-runtime/model-route/set-route.mjs +114 -34
- package/src/session-runtime/model-route/web-search-route.mjs +7 -2
- package/src/session-runtime/model-route-api.mjs +4 -2
- package/src/session-runtime/native-web-search/routes.mjs +37 -24
- package/src/session-runtime/native-web-search.mjs +9 -8
- package/src/session-runtime/provider-auth/setup.mjs +4 -0
- package/src/session-runtime/provider-models/catalog-load.mjs +9 -0
- package/src/session-runtime/provider-models/web-search-catalog.mjs +23 -3
- package/src/session-runtime/provider-models.mjs +1 -0
- package/src/session-runtime/provider-usage.mjs +4 -0
- package/src/session-runtime/route-resolution.mjs +3 -1
- package/src/session-runtime/runtime-core.mjs +4 -0
- package/src/session-runtime/runtime-facade.mjs +6 -0
- package/src/session-runtime/services/agent-task-status.mjs +2 -0
- package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +0 -3
- package/src/session-runtime/services/agent-tool/close-flow.mjs +6 -7
- package/src/session-runtime/services/agent-tool/execute-send.mjs +2 -2
- package/src/session-runtime/services/agent-tool/execute-spawn.mjs +36 -3
- package/src/session-runtime/services/agent-tool/execute.mjs +9 -1
- package/src/session-runtime/services/agent-tool/helpers.mjs +30 -7
- package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +7 -2
- package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +6 -3
- package/src/session-runtime/services/agent-tool/lead-worker-index/lead-rows.mjs +3 -4
- package/src/session-runtime/services/agent-tool/lead-worker-index/reap-timers.mjs +9 -3
- package/src/session-runtime/services/agent-tool/lead-worker-index/row-settlement.mjs +7 -18
- package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +9 -6
- package/src/session-runtime/services/agent-tool/model-select.mjs +82 -0
- package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -6
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +3 -1
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -5
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -4
- package/src/session-runtime/services/agent-tool/spawn-flow.mjs +2 -1
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
- package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +1 -3
- package/src/session-runtime/services/agent-tool/tag-registry/tag-refresh.mjs +1 -3
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -9
- package/src/session-runtime/services/agent-tool/terminal-reaper/scan-admission.mjs +8 -41
- package/src/session-runtime/services/agent-tool/terminal-reaper/stale-rows.mjs +3 -3
- package/src/session-runtime/services/agent-tool/terminal-reaper.mjs +6 -23
- package/src/session-runtime/services/agent-tool/terminal-trace.mjs +0 -1
- package/src/session-runtime/services/agent-tool/tool-def.mjs +7 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +32 -20
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -2
- package/src/session-runtime/services/agent-tool/worker-index.mjs +28 -8
- package/src/session-runtime/services/agent-tool.mjs +4 -0
- package/src/session-runtime/services/agent-watchdog-registry.mjs +2 -0
- package/src/session-runtime/services/provider-admin.mjs +77 -0
- package/src/session-runtime/session-create/session-options.mjs +7 -5
- package/src/session-runtime/session-create/session-start-hook.mjs +2 -1
- package/src/session-runtime/session-transcript.mjs +4 -5
- package/src/session-runtime/session-turn-api.mjs +3 -9
- package/src/session-runtime/settings-builtin-tools-api.mjs +9 -6
- package/src/session-runtime/setup-tool/executor.mjs +23 -5
- package/src/session-runtime/setup-tool/extended-actions.mjs +6 -6
- package/src/session-runtime/setup-tool/settings-contract.mjs +7 -2
- package/src/session-runtime/setup-tool/tool-defs.mjs +13 -1
- package/src/session-runtime/tool-policy-refresh.mjs +83 -32
- package/src/session-runtime/turn/agent-ops.mjs +49 -2
- package/src/session-runtime/turn/side-question-ops.mjs +1 -4
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +2 -0
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +4 -0
- package/src/session-runtime/turn/turn-run/turn-settle.mjs +8 -2
- package/src/session-runtime/turn/turn-run.mjs +1 -36
- package/src/session-runtime/usage-stats-api.mjs +4 -1
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +16 -1
- package/src/session-runtime/workspace/admission-gate.mjs +44 -15
- package/src/session-runtime/workspace/project-branches.mjs +28 -36
- package/src/session-runtime/workspace/transition-steps.mjs +96 -95
- package/src/session-runtime/workspace/transitions.mjs +248 -68
- package/src/standalone/channel-transport.mjs +3 -4
- package/src/standalone/daemon-desktop-runtime.mjs +32 -1
- package/src/standalone/daemon-pg-stop.mjs +1 -3
- package/src/standalone/daemon-session-control.mjs +88 -0
- package/src/standalone/daemon-stored-session-views.mjs +23 -3
- package/src/standalone/daemon.mjs +2 -0
- package/src/standalone/desktop-service-registry.mjs +32 -5
- package/src/standalone/local-session-runtime.mjs +11 -12
- package/src/standalone/session-protocol.mjs +7 -0
- package/src/standalone/session-runtime-inline-host.mjs +2 -0
- package/src/standalone/session-service/agent-tree/agent-cancel.mjs +91 -49
- package/src/standalone/session-service/agent-tree/agent-child.mjs +19 -1
- package/src/standalone/session-service/agent-tree/agent-registry.mjs +25 -0
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +9 -1
- package/src/standalone/session-service/agent-tree.mjs +28 -2
- package/src/standalone/session-service/entries/session-loads.mjs +16 -5
- package/src/standalone/session-service/entries.mjs +1 -0
- package/src/standalone/session-service/projection/transcript-window.mjs +39 -0
- package/src/standalone/session-service/quota-resume.mjs +28 -13
- package/src/standalone/session-service/session-calls/session-turns.mjs +17 -6
- package/src/standalone/session-service/session-calls/session-views.mjs +6 -0
- package/src/standalone/session-tool-output.mjs +82 -0
- package/src/tui/app/app-view.jsx +2 -1
- package/src/tui/app/provider-setup/provider-items.mjs +8 -0
- package/src/tui/app/provider-setup-picker.mjs +15 -3
- package/src/tui/app/slash-commands.mjs +6 -0
- package/src/tui/app/slash-dispatch/session-commands.mjs +49 -0
- package/src/tui/components/Spinner.jsx +4 -0
- package/src/tui/components/SpinnerByline.jsx +21 -2
- package/src/tui/components/status-line/local-line.mjs +10 -2
- package/src/tui/dist/index.mjs +529 -270
- package/src/tui/session/active-tool-summary.mjs +1 -1
- package/src/tui/session/context-state.mjs +0 -3
- package/src/tui/session/goal-continuation/continuation-queue.mjs +2 -3
- package/src/tui/session/goal-continuation/deadline-delivery.mjs +4 -2
- package/src/tui/session/goal-continuation/session-boundary.mjs +21 -0
- package/src/tui/session/quota-resume.mjs +140 -61
- package/src/tui/session/session-api/commands.mjs +4 -10
- package/src/tui/session/session-api/controls.mjs +12 -0
- package/src/tui/session/session-api/lifecycle/dispose.mjs +2 -9
- package/src/tui/session/session-api/lifecycle/resume.mjs +2 -7
- package/src/tui/session/session-api/lifecycle.mjs +13 -11
- package/src/tui/session/session-api/media.mjs +2 -0
- package/src/tui/session/session-api/routes.mjs +81 -57
- package/src/tui/session/session-api/settings.mjs +3 -3
- package/src/tui/session/session-api/worktree.mjs +3 -2
- package/src/tui/session/session-flow/auto-clear.mjs +1 -3
- package/src/tui/session/session-flow/drain.mjs +6 -4
- package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -0
- package/src/tui/session/session-flow/queue/take-entries.mjs +2 -1
- package/src/tui/session/session-flow/queue.mjs +1 -1
- package/src/tui/session/tool-approval.mjs +17 -8
- package/src/tui/session/transcript-store/streaming-tail.mjs +1 -1
- package/src/tui/session/tui-steering-persist.mjs +3 -5
- package/src/tui/session/turn-quiet.mjs +53 -0
- package/src/tui/session/turn-stream.mjs +5 -1
- package/src/tui/session/turn.mjs +38 -31
- package/src/tui/session/worktree-setup-notice.mjs +38 -0
- package/src/tui/spinner-meta.mjs +10 -0
- package/src/tui/spinner-verbs.mjs +3 -0
- package/src/ui/statusline.mjs +13 -3
- package/src/ui/streaming-markdown-heal.mjs +70 -18
- package/src/runtime/agent/orchestrator/providers/model-pricing-rates.mjs +0 -1
- package/src/runtime/agent/orchestrator/session/manager/foreign-pending-messages.mjs +0 -346
- package/src/runtime/agent/orchestrator/session/manager/session-owner-liveness.mjs +0 -117
- package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +0 -302
- package/src/session-runtime/services/agent-tool/terminal-reaper/reap-timers.mjs +0 -142
- package/src/session-runtime/turn/share-ops.mjs +0 -77
- package/src/tui/session/cross-surface-share.mjs +0 -406
- package/src/tui/session/live-share/delta.mjs +0 -153
- package/src/tui/session/live-share/mirror.mjs +0 -106
- package/src/tui/session/live-share/owner.mjs +0 -254
- package/src/tui/session/live-share/retry.mjs +0 -54
- package/src/tui/session/live-share/viewer/frame-router.mjs +0 -32
- package/src/tui/session/live-share/viewer/pipe-client.mjs +0 -108
- package/src/tui/session/live-share/viewer/submit-acks.mjs +0 -65
- package/src/tui/session/live-share/viewer/sync-waiters.mjs +0 -53
- package/src/tui/session/live-share/viewer.mjs +0 -99
- package/src/tui/session/live-share/wire.mjs +0 -44
- package/src/tui/session/live-share.mjs +0 -154
- package/src/tui/session/shared-dir-watch.mjs +0 -69
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The Lead session workspace transition authority. Every workspace change of
|
|
3
3
|
* the Lead this runtime hosts — entering its retained worktree (created lazily
|
|
4
|
-
* on the first message of a worktree task),
|
|
5
|
-
* branch
|
|
4
|
+
* on the first message of a worktree task), selecting a branch (it runs where
|
|
5
|
+
* that branch is checked out — the project folder, a linked checkout, or a
|
|
6
|
+
* managed worktree made for it — and no existing folder is switched),
|
|
7
|
+
* removing the worktree — goes through applyWorkspaceTransition: one
|
|
6
8
|
* serialized, revisioned commit that retargets the runtime cwd (and the turn's
|
|
7
9
|
* cwd override), stores the durable `workspace` record, re-roots the prompt
|
|
8
|
-
* context of the Lead and its idle workers, and persists
|
|
9
|
-
* WorktreeErrors and leave the
|
|
10
|
+
* context of the Lead and its idle workers, and persists, awaiting each save
|
|
11
|
+
* before it reports success. Failures are typed WorktreeErrors and leave the
|
|
12
|
+
* previous workspace intact.
|
|
10
13
|
*
|
|
11
14
|
* Git and registry work is delegated to the managed-worktree backend
|
|
12
15
|
* (runtime/shared/worktrees/manager.mjs), loaded on first use.
|
|
@@ -21,12 +24,24 @@ import {
|
|
|
21
24
|
normalizeSessionWorkspace,
|
|
22
25
|
worktreeError,
|
|
23
26
|
worktreeNameError,
|
|
27
|
+
worktreeRefusal,
|
|
24
28
|
} from '../../runtime/shared/worktrees/contract.mjs';
|
|
25
29
|
import { normalizeWorktreeSettings } from '../../runtime/shared/worktrees/settings.mjs';
|
|
26
30
|
import * as maintenance from '../../runtime/shared/worktrees/maintenance.mjs';
|
|
27
31
|
import { inspectRepo, throwIfAborted } from '../../runtime/shared/worktrees/git.mjs';
|
|
32
|
+
import { worktreePreparationNote } from '../../runtime/shared/worktrees/preparation-report.mjs';
|
|
28
33
|
import { isWithin, samePath } from '../../runtime/shared/worktrees/paths.mjs';
|
|
29
34
|
import { readGitHead } from '../../runtime/shared/worktrees/git-head.mjs';
|
|
35
|
+
import {
|
|
36
|
+
holdWorkspaceActivity,
|
|
37
|
+
isExternalCheckout,
|
|
38
|
+
releaseAll,
|
|
39
|
+
} from '../../runtime/shared/worktrees/activity-gate.mjs';
|
|
40
|
+
import { mergeConfirmedTarget } from '../../runtime/shared/worktrees/branch-management.mjs';
|
|
41
|
+
import {
|
|
42
|
+
clearReadDedupSession,
|
|
43
|
+
resetReadStateAfterCompaction,
|
|
44
|
+
} from '../../runtime/agent/orchestrator/session/cache/read-cache.mjs';
|
|
30
45
|
import { sessionHasConversationMessages } from '../../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
31
46
|
import { buildWorkspacePromptContext } from '../../runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs';
|
|
32
47
|
import {
|
|
@@ -36,7 +51,7 @@ import {
|
|
|
36
51
|
import { AGENT_OWNER } from '../../runtime/agent/orchestrator/agent-owner.mjs';
|
|
37
52
|
import { _liveSessions } from '../../runtime/agent/orchestrator/session/store/live-state.mjs';
|
|
38
53
|
import { admitTurn, beginWorkspaceTransition, holdCheckoutFolder } from './admission-gate.mjs';
|
|
39
|
-
import {
|
|
54
|
+
import { createProjectBranchOps } from './project-branches.mjs';
|
|
40
55
|
import { assertRetainedFits, createTransitionSteps, undoAll } from './transition-steps.mjs';
|
|
41
56
|
import { readSessionWorkspace } from './workspace-state.mjs';
|
|
42
57
|
|
|
@@ -65,6 +80,17 @@ async function defaultRegisteredProject(path) {
|
|
|
65
80
|
return listProjectsStrict().find((entry) => samePath(entry.path, path))?.path ?? null;
|
|
66
81
|
}
|
|
67
82
|
|
|
83
|
+
/** The dependency installs a new worktree folder still needs (dependencies.mjs). */
|
|
84
|
+
async function defaultPlanWorktreeSetup(input) {
|
|
85
|
+
const { planDependencySetup } = await import('../../runtime/shared/worktrees/dependencies.mjs');
|
|
86
|
+
return planDependencySetup(input);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function defaultRunWorktreeSetup(input) {
|
|
90
|
+
const { runWorktreeSetupCommands } = await import('../../runtime/shared/worktrees/setup-commands.mjs');
|
|
91
|
+
return runWorktreeSetupCommands(input);
|
|
92
|
+
}
|
|
93
|
+
|
|
68
94
|
/**
|
|
69
95
|
* Re-root one session's prompt at `cwd`: environment facts and instruction
|
|
70
96
|
* files for every session, project memory for the Lead only (workers never
|
|
@@ -74,6 +100,10 @@ async function defaultRegisteredProject(path) {
|
|
|
74
100
|
* a worktree) adds the uncommitted-changes and path lines to that notice.
|
|
75
101
|
*/
|
|
76
102
|
export async function refreshWorkspacePrompt(session, cwd, { loadCoreMemoryContext, move = null } = {}) {
|
|
103
|
+
// A new checkout invalidates observed-file snapshots as well as read/search
|
|
104
|
+
// results. Conversation text remains historical evidence, not a file cache.
|
|
105
|
+
clearReadDedupSession(session?.id);
|
|
106
|
+
resetReadStateAfterCompaction(session?.id);
|
|
77
107
|
const { environmentContext, instructionFilesContext } = buildWorkspacePromptContext(session, cwd);
|
|
78
108
|
const coreMemoryContext =
|
|
79
109
|
session?.owner === AGENT_OWNER || typeof loadCoreMemoryContext !== 'function'
|
|
@@ -149,7 +179,7 @@ const TRANSITION_STATE = { worktree: 'provisioning', branch: 'switching', 'remov
|
|
|
149
179
|
* @param {() => string} deps.getCurrentCwd
|
|
150
180
|
* @param {(cwd: string, options?: { persistProjectSelection?: boolean }) => unknown} deps.applyResolvedCwd Retargets rt cwd, session.cwd and the cwd override (and, persisting, the Project selection).
|
|
151
181
|
* @param {(desktopSession: any) => unknown} [deps.setDesktopSession] Restores the runtime's desktop metadata on a rollback.
|
|
152
|
-
* @param {(session: any) => unknown} deps.persistSession
|
|
182
|
+
* @param {(session: any) => Promise<unknown>|unknown} deps.persistSession Durable save: resolves once the session is on disk, rejects (throws) when it is not.
|
|
153
183
|
* @param {(session: any, cwd: string, move?: { from: string, changes: 'carried'|'left'|null }|null) => Promise<unknown>} deps.refreshWorkspaceContext
|
|
154
184
|
* @param {() => number} deps.getActiveTurnCount
|
|
155
185
|
* @param {() => { agentWorkers?: any[], agentJobs?: any[] }} deps.agentStatusState
|
|
@@ -179,11 +209,24 @@ export function createWorkspaceTransitions({
|
|
|
179
209
|
inspectProject = inspectRepo,
|
|
180
210
|
findRegisteredProject = defaultRegisteredProject,
|
|
181
211
|
listStoredSessionIds = maintenance.storedSessionIds,
|
|
212
|
+
listWorkspaceConsumers = maintenance.storedWorkspaceConsumers,
|
|
213
|
+
listWorkspaceJobs = async () => {
|
|
214
|
+
const { listShellJobRecords } = await import(
|
|
215
|
+
'../../runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs'
|
|
216
|
+
);
|
|
217
|
+
return listShellJobRecords({ strict: true });
|
|
218
|
+
},
|
|
182
219
|
runtimeToken = randomUUID(),
|
|
183
220
|
newTxId = randomUUID,
|
|
221
|
+
planWorktreeSetup = defaultPlanWorktreeSetup,
|
|
222
|
+
runWorktreeSetup = defaultRunWorktreeSetup,
|
|
184
223
|
}) {
|
|
185
224
|
const worktreeSettings = () => normalizeWorktreeSettings(getConfig?.()?.worktree);
|
|
186
225
|
let pendingIntent = creationIntent(initialIntent, worktreeSettings());
|
|
226
|
+
// The new worktree whose dependencies have not been prepared yet, bound to
|
|
227
|
+
// that worktree (worktreeId + cwd): it runs only while the session is there.
|
|
228
|
+
let pendingSetup = null;
|
|
229
|
+
const setupListeners = new Set();
|
|
187
230
|
let managerPromise = null;
|
|
188
231
|
const backend = () => {
|
|
189
232
|
if (manager) return Promise.resolve(manager);
|
|
@@ -300,25 +343,19 @@ export function createWorkspaceTransitions({
|
|
|
300
343
|
* wait (admission gate). `sessionId` null: a session-less (draft) change.
|
|
301
344
|
* @returns {() => void}
|
|
302
345
|
*/
|
|
303
|
-
function holdProjectFolder(sessionId, folder) {
|
|
346
|
+
function holdProjectFolder(sessionId, folder, { hold = true } = {}) {
|
|
304
347
|
const users = listLiveSessions().filter(
|
|
305
348
|
(candidate) =>
|
|
306
349
|
candidate?.id &&
|
|
307
350
|
candidate.id !== sessionId &&
|
|
308
351
|
candidate.closed !== true &&
|
|
309
|
-
candidate.remoteAttached !== true &&
|
|
310
352
|
(!sessionId || (candidate.ownerSessionId !== sessionId && candidate.parentSessionId !== sessionId)) &&
|
|
311
353
|
typeof candidate.cwd === 'string' &&
|
|
312
354
|
isWithin(folder, candidate.cwd) &&
|
|
313
355
|
isSessionActive(candidate)
|
|
314
356
|
);
|
|
315
|
-
if (users.length) {
|
|
316
|
-
|
|
317
|
-
reason: 'folder-in-use',
|
|
318
|
-
sessions: users.map((candidate) => candidate.id),
|
|
319
|
-
});
|
|
320
|
-
}
|
|
321
|
-
return holdCheckoutFolder(sessionId, folder);
|
|
357
|
+
if (users.length) throw worktreeRefusal('folder-in-use', { sessions: users.map((candidate) => candidate.id) });
|
|
358
|
+
return holdCheckoutFolder(sessionId, folder, { hold });
|
|
322
359
|
}
|
|
323
360
|
|
|
324
361
|
/** Run `fn` holding the checkout `folder` (holdProjectFolder); released when it settles. */
|
|
@@ -352,12 +389,49 @@ export function createWorkspaceTransitions({
|
|
|
352
389
|
.map((candidate) => candidate.id);
|
|
353
390
|
if (!sharing.length) return;
|
|
354
391
|
const shellJobs = await countOwnShellJobs(sharing);
|
|
355
|
-
if (shellJobs > 0) {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
392
|
+
if (shellJobs > 0) throw worktreeRefusal('folder-shell-jobs', { shellJobs });
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* The shared admission of every merge and folder cleanup (manageProjectBranch):
|
|
397
|
+
* refuses while a session or worker runs in an affected folder, or a
|
|
398
|
+
* background command does; `removing` refuses while any session still uses
|
|
399
|
+
* one. Then holds the folders — Mixdog checkouts only; an external checkout
|
|
400
|
+
* is never lock-blocked — so new Mixdog work there waits until `run`
|
|
401
|
+
* settles. `actor`: the session acting on its own checkout, whose own turn
|
|
402
|
+
* and workers its caller already checked (assertLeadIdle).
|
|
403
|
+
*/
|
|
404
|
+
async function withManagementFolders(folders, removing, run, { actor = null } = {}) {
|
|
405
|
+
const release = [];
|
|
406
|
+
try {
|
|
407
|
+
for (const folder of [...new Set(folders)].sort()) {
|
|
408
|
+
release.push(holdProjectFolder(actor, folder, { hold: !isExternalCheckout(folder) }));
|
|
409
|
+
}
|
|
410
|
+
release.push(holdWorkspaceActivity(folders, { sessionId: actor }));
|
|
411
|
+
const stored = await listWorkspaceConsumers();
|
|
412
|
+
const consumers = new Map(stored.map((session) => [session.id, session]));
|
|
413
|
+
for (const session of listLiveSessions()) if (session?.closed !== true) consumers.set(session.id, session);
|
|
414
|
+
const affected = [...consumers.values()].filter((session) =>
|
|
415
|
+
folders.some((folder) => session.cwd && isWithin(folder, session.cwd))
|
|
360
416
|
);
|
|
417
|
+
const blocking = removing
|
|
418
|
+
? affected
|
|
419
|
+
: affected.filter(
|
|
420
|
+
(session) =>
|
|
421
|
+
!(actor && [session.id, session.ownerSessionId, session.parentSessionId].includes(actor)) &&
|
|
422
|
+
isSessionActive(session)
|
|
423
|
+
);
|
|
424
|
+
if (blocking.length) throw worktreeRefusal('folder-in-use', { sessions: blocking.map((session) => session.id) });
|
|
425
|
+
const jobs = await listWorkspaceJobs();
|
|
426
|
+
if (jobs.some((job) => !job.terminal && folders.some((folder) => isWithin(folder, job.cwd)))) {
|
|
427
|
+
throw worktreeRefusal('folder-shell-jobs');
|
|
428
|
+
}
|
|
429
|
+
if ((await countOwnShellJobs(affected.map((session) => session.id))) > 0) {
|
|
430
|
+
throw worktreeRefusal('folder-shell-jobs');
|
|
431
|
+
}
|
|
432
|
+
return await run([...consumers.keys()]);
|
|
433
|
+
} finally {
|
|
434
|
+
releaseAll(release);
|
|
361
435
|
}
|
|
362
436
|
}
|
|
363
437
|
|
|
@@ -382,6 +456,7 @@ export function createWorkspaceTransitions({
|
|
|
382
456
|
inspectProject,
|
|
383
457
|
findRegisteredProject,
|
|
384
458
|
withProjectFolder,
|
|
459
|
+
withManagementFolders,
|
|
385
460
|
});
|
|
386
461
|
|
|
387
462
|
async function transition(session, target, options = {}) {
|
|
@@ -406,22 +481,48 @@ export function createWorkspaceTransitions({
|
|
|
406
481
|
await assertLeadIdle(session, { ownTurn: options.ownTurn === true });
|
|
407
482
|
const run = { signal: options.signal, txId, journal };
|
|
408
483
|
if (target.kind === 'worktree') {
|
|
409
|
-
|
|
484
|
+
const { created, ...entered } = await steps.enterWorktree(session, previous, {
|
|
410
485
|
...run,
|
|
411
486
|
name: target.name,
|
|
412
487
|
nameHint: options.nameHint,
|
|
413
488
|
confirmLarge: options.confirmLarge,
|
|
414
489
|
changes: options.changes,
|
|
415
490
|
});
|
|
491
|
+
// A new checkout gets its dependencies prepared at the start of the
|
|
492
|
+
// session's next turn there (prepareTurnWorkspace).
|
|
493
|
+
if (created) {
|
|
494
|
+
pendingSetup = {
|
|
495
|
+
...created,
|
|
496
|
+
sessionId: session.id,
|
|
497
|
+
worktreeId: entered.workspace.worktreeId,
|
|
498
|
+
cwd: entered.workspace.cwd,
|
|
499
|
+
mainDir: previous.projectPath,
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
return entered;
|
|
416
503
|
}
|
|
417
504
|
if (target.kind === 'branch') {
|
|
418
|
-
|
|
505
|
+
const { created, ...entered } = await steps.enterProjectBranch(session, previous, {
|
|
419
506
|
...run,
|
|
420
507
|
branch: target.branch,
|
|
421
508
|
create: target.create,
|
|
509
|
+
confirmLarge: options.confirmLarge,
|
|
422
510
|
});
|
|
511
|
+
if (created && entered.workspace?.worktreeId) {
|
|
512
|
+
pendingSetup = {
|
|
513
|
+
...created,
|
|
514
|
+
sessionId: session.id,
|
|
515
|
+
worktreeId: entered.workspace.worktreeId,
|
|
516
|
+
cwd: entered.workspace.cwd,
|
|
517
|
+
mainDir: previous.projectPath,
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
return entered;
|
|
423
521
|
}
|
|
424
|
-
|
|
522
|
+
const removed = await steps.removeRetainedWorktree(session, previous, { ...run, force: target.force });
|
|
523
|
+
// The session's retained worktree is gone: its pending setup goes with it.
|
|
524
|
+
if (pendingSetup?.sessionId === session.id) pendingSetup = null;
|
|
525
|
+
return removed;
|
|
425
526
|
} catch (error) {
|
|
426
527
|
// Whatever already moved (cwd, record, prompts, worker roots, lease)
|
|
427
528
|
// goes back exactly; the previous workspace stays authoritative.
|
|
@@ -495,21 +596,77 @@ export function createWorkspaceTransitions({
|
|
|
495
596
|
);
|
|
496
597
|
}
|
|
497
598
|
const intent = intentFor(session);
|
|
498
|
-
|
|
599
|
+
let result = null;
|
|
600
|
+
if (intent) {
|
|
601
|
+
try {
|
|
602
|
+
result = await provisionIntent(session, intent, submissionId, prompt, {
|
|
603
|
+
confirmLarge: intent.confirmLarge || confirmLarge === true,
|
|
604
|
+
signal,
|
|
605
|
+
ownTurn: true,
|
|
606
|
+
});
|
|
607
|
+
} catch (error) {
|
|
608
|
+
// The settings default never blocks a task outside a git repository.
|
|
609
|
+
if (!intent.explicit && isWorktreeError(error, 'WORKTREE_UNSUPPORTED_REPO')) {
|
|
610
|
+
if (pendingIntent === intent) pendingIntent = null;
|
|
611
|
+
return null;
|
|
612
|
+
}
|
|
613
|
+
throw error;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
await runPendingSetup(session, signal);
|
|
617
|
+
return result;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* Prepare the session's new worktree, once, under the turn (its admission
|
|
622
|
+
* keeps the folder from being merged or removed; its signal — the Stop
|
|
623
|
+
* button — cancels): the frozen installs the links made at creation did
|
|
624
|
+
* not cover. While an install runs, every onWorktreeSetup listener gets its
|
|
625
|
+
* one-line progress; nothing else reaches the user. The agent gets one
|
|
626
|
+
* compact note with this turn (`session.pendingSetupNotice`): the main
|
|
627
|
+
* checkout, what was copied, linked and installed, what failed (with the
|
|
628
|
+
* output tail) and what was skipped. A failure or timeout is in the note
|
|
629
|
+
* and the turn goes on; a cancel aborts the turn like any other stop. The
|
|
630
|
+
* worktree stays either way. The setup belongs to the worktree it was made
|
|
631
|
+
* for: while the session works elsewhere (it returned to a project-folder
|
|
632
|
+
* branch before its first turn there) it is deferred, never run in another
|
|
633
|
+
* folder, and runs on the first turn after the session re-enters it.
|
|
634
|
+
*/
|
|
635
|
+
async function runPendingSetup(session, signal) {
|
|
636
|
+
const pending = pendingSetup;
|
|
637
|
+
if (!pending || pending.sessionId !== session.id) return;
|
|
638
|
+
const here = readSessionWorkspace(session);
|
|
639
|
+
if (!isWorktreeBound(here) || here.worktreeId !== pending.worktreeId || !samePath(here.cwd, pending.cwd)) return;
|
|
640
|
+
pendingSetup = null;
|
|
641
|
+
const id = newTxId();
|
|
642
|
+
const report = { root: pending.root, prepared: pending.prepared, dependencyNotes: [], installs: null, notes: [] };
|
|
643
|
+
const emit = (event) => {
|
|
644
|
+
for (const listener of setupListeners) {
|
|
645
|
+
try {
|
|
646
|
+
listener({ ...event, id, sessionId: session.id, cwd: pending.cwd });
|
|
647
|
+
} catch {
|
|
648
|
+
/* a viewer's failure never stops the setup */
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
};
|
|
499
652
|
try {
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
});
|
|
505
|
-
} catch (error) {
|
|
506
|
-
// The settings default never blocks a task outside a git repository.
|
|
507
|
-
if (!intent.explicit && isWorktreeError(error, 'WORKTREE_UNSUPPORTED_REPO')) {
|
|
508
|
-
if (pendingIntent === intent) pendingIntent = null;
|
|
509
|
-
return null;
|
|
653
|
+
const plan = await planWorktreeSetup({ worktreeDir: pending.cwd, mainDir: pending.mainDir, signal });
|
|
654
|
+
report.dependencyNotes = plan.notes;
|
|
655
|
+
if (plan.commands.length) {
|
|
656
|
+
report.installs = await runWorktreeSetup({ commands: plan.commands, signal, onProgress: emit });
|
|
510
657
|
}
|
|
511
|
-
|
|
658
|
+
} catch (error) {
|
|
659
|
+
if (!signal?.aborted) report.notes.push(`Dependencies could not be prepared: ${error?.message || error}`);
|
|
512
660
|
}
|
|
661
|
+
session.pendingSetupNotice = { revision: Date.now(), content: worktreePreparationNote(report) };
|
|
662
|
+
throwIfAborted(signal);
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/** Subscribe to worktree setup progress; returns the unsubscribe. */
|
|
666
|
+
function onWorktreeSetup(listener) {
|
|
667
|
+
if (typeof listener !== 'function') return () => {};
|
|
668
|
+
setupListeners.add(listener);
|
|
669
|
+
return () => setupListeners.delete(listener);
|
|
513
670
|
}
|
|
514
671
|
|
|
515
672
|
async function getBranchMenu() {
|
|
@@ -521,14 +678,16 @@ export function createWorkspaceTransitions({
|
|
|
521
678
|
projectPath: workspace.projectPath,
|
|
522
679
|
sessionId: session?.id || null,
|
|
523
680
|
});
|
|
524
|
-
|
|
681
|
+
const selectedEntry = workspace.worktreeId ? await (await backend()).findWorktreeContaining(workspace.cwd) : null;
|
|
682
|
+
// A session outside a managed worktree (the project folder — never moved,
|
|
683
|
+
// or back from a worktree — or a linked checkout of the selected branch)
|
|
525
684
|
// is on whatever that folder has checked out now.
|
|
526
685
|
// Its repository is the project's (a never-moved session has no stored
|
|
527
686
|
// record), and a detached checkout shows branch null with the commit in
|
|
528
687
|
// baseCommit — never mistaken for "not a repository".
|
|
529
688
|
let view = workspace;
|
|
530
689
|
if (!isWorktreeBound(workspace)) {
|
|
531
|
-
const project = await inspectProject(workspace.
|
|
690
|
+
const project = await inspectProject(workspace.cwd);
|
|
532
691
|
const checkedOut = project.currentBranch ?? null;
|
|
533
692
|
view = {
|
|
534
693
|
...workspace,
|
|
@@ -542,7 +701,7 @@ export function createWorkspaceTransitions({
|
|
|
542
701
|
pendingWorktree: pendingIntent ? { name: pendingIntent.name } : null,
|
|
543
702
|
branches: branchMenuEntries(menu.branches, menu.occupancy),
|
|
544
703
|
occupancy: menu.occupancy,
|
|
545
|
-
retainedWorktree: menu.retainedWorktree ?? null,
|
|
704
|
+
retainedWorktree: selectedEntry ?? menu.retainedWorktree ?? null,
|
|
546
705
|
// Creation notes of the retained worktree (submodules, include entries).
|
|
547
706
|
warnings: Array.isArray(menu.retainedWorktree?.warnings) ? [...menu.retainedWorktree.warnings] : [],
|
|
548
707
|
};
|
|
@@ -581,11 +740,13 @@ export function createWorkspaceTransitions({
|
|
|
581
740
|
|
|
582
741
|
async function selectBranch({ branch, create = false, expectedRevision, confirmLarge = false } = {}) {
|
|
583
742
|
const session = await ensureSession();
|
|
584
|
-
const
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
743
|
+
const current = currentWorkspace(session);
|
|
744
|
+
if (current.branch === branch && current.worktreeId) {
|
|
745
|
+
assertRevision(current.revision, validRevision(expectedRevision));
|
|
746
|
+
pendingIntent = null;
|
|
747
|
+
return { revision: current.revision, workspace: current };
|
|
748
|
+
}
|
|
749
|
+
const target = { kind: 'branch', branch, create: create === true };
|
|
589
750
|
const result = await applyWorkspaceTransition({ sessionId: session.id }, target, {
|
|
590
751
|
expectedRevision,
|
|
591
752
|
confirmLarge,
|
|
@@ -695,14 +856,24 @@ export function createWorkspaceTransitions({
|
|
|
695
856
|
cleanup: { removed: false, reason: 'auto-cleanup-off', message: 'Auto cleanup is off; the worktree is kept.' },
|
|
696
857
|
};
|
|
697
858
|
}
|
|
859
|
+
// The cleanup never moves a session: while this session still works in the
|
|
860
|
+
// merged folder (or any other session uses it) the removal is refused.
|
|
698
861
|
try {
|
|
699
|
-
|
|
862
|
+
if (isWorktreeBound(currentWorkspace(session))) {
|
|
863
|
+
throw worktreeRefusal('folder-in-use', { sessions: [session.id] });
|
|
864
|
+
}
|
|
865
|
+
const entry = await (await backend()).getSessionWorktree(session.id);
|
|
866
|
+
const removed = await withManagementFolders(
|
|
867
|
+
entry ? [entry.path] : [],
|
|
868
|
+
true,
|
|
869
|
+
() => removeWorktree({ force: false }, { ownTurn }),
|
|
870
|
+
{ actor: session.id }
|
|
871
|
+
);
|
|
700
872
|
return { ...merged, cleanup: removed.removed, revision: removed.revision, workspace: removed.workspace };
|
|
701
873
|
} catch (error) {
|
|
702
|
-
// The merge stands: a refused or incomplete cleanup (
|
|
703
|
-
// retained file recovery data, partly removed, …) is
|
|
704
|
-
// thrown, with the workspace as it is now
|
|
705
|
-
// returned to the project folder).
|
|
874
|
+
// The merge stands: a refused or incomplete cleanup (in use, dirty,
|
|
875
|
+
// unmerged, retained file recovery data, partly removed, …) is
|
|
876
|
+
// reported, never thrown, with the workspace as it is now.
|
|
706
877
|
const workspace = currentWorkspace(session);
|
|
707
878
|
const code = typeof error?.code === 'string' ? error.code : '';
|
|
708
879
|
return {
|
|
@@ -722,8 +893,9 @@ export function createWorkspaceTransitions({
|
|
|
722
893
|
/**
|
|
723
894
|
* The merge itself. The retained worktree must belong to this session's
|
|
724
895
|
* Project (same repository and Project folder — a Project switch may have
|
|
725
|
-
* left it behind)
|
|
726
|
-
*
|
|
896
|
+
* left it behind); its branch, or the branch of the linked checkout the
|
|
897
|
+
* session works in, is merged into the project folder through the shared
|
|
898
|
+
* guarded path (mergeConfirmedTarget): both folders validated and held.
|
|
727
899
|
*/
|
|
728
900
|
async function mergeRetainedWorktree(session, { target, ownTurn, expectedRevision }) {
|
|
729
901
|
const workspace = currentWorkspace(session);
|
|
@@ -731,26 +903,31 @@ export function createWorkspaceTransitions({
|
|
|
731
903
|
const leave = beginWorkspaceTransition(session.id, `merge:${newTxId()}`);
|
|
732
904
|
try {
|
|
733
905
|
await assertLeadIdle(session, { ownTurn: ownTurn === true });
|
|
734
|
-
const backendApi = await backend();
|
|
735
|
-
const entry = await backendApi.getSessionWorktree(session.id);
|
|
736
|
-
if (!entry) throw worktreeError('WORKTREE_MISSING', 'This session has no worktree to merge.');
|
|
737
906
|
const project = await inspectProject(workspace.projectPath);
|
|
738
|
-
|
|
739
|
-
if (!samePath(
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
907
|
+
let branch;
|
|
908
|
+
if (!workspace.worktreeId && !samePath(workspace.cwd, workspace.projectPath)) {
|
|
909
|
+
const source = await inspectProject(workspace.cwd);
|
|
910
|
+
if (!samePath(source.repoCommonDir, project.repoCommonDir)) throw worktreeError('WORKTREE_PROJECT_MISMATCH');
|
|
911
|
+
branch = source.currentBranch;
|
|
912
|
+
} else {
|
|
913
|
+
const backendApi = await backend();
|
|
914
|
+
const entry = workspace.worktreeId
|
|
915
|
+
? await backendApi.findWorktreeContaining(workspace.cwd)
|
|
916
|
+
: await backendApi.getSessionWorktree(session.id);
|
|
917
|
+
if (!entry) throw worktreeError('WORKTREE_MISSING', 'This session has no worktree to merge.');
|
|
918
|
+
assertRetainedFits(entry, project, workspace.projectPath);
|
|
919
|
+
if (!samePath(entry.projectPath, workspace.projectPath)) {
|
|
920
|
+
throw worktreeError('WORKTREE_PROJECT_MISMATCH', undefined, {
|
|
921
|
+
worktreeId: entry.id,
|
|
922
|
+
worktreeProject: entry.projectPath,
|
|
923
|
+
projectPath: workspace.projectPath,
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
branch = entry.branch;
|
|
745
927
|
}
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
entryId: entry.id,
|
|
750
|
-
target: project.currentBranch,
|
|
751
|
-
confirmed: true,
|
|
752
|
-
projectPath: entry.projectPath,
|
|
753
|
-
})
|
|
928
|
+
return await mergeConfirmedTarget(
|
|
929
|
+
{ projectPath: workspace.projectPath, branch, target },
|
|
930
|
+
(folders, removing, run) => withManagementFolders(folders, removing, run, { actor: session.id })
|
|
754
931
|
);
|
|
755
932
|
} finally {
|
|
756
933
|
leave();
|
|
@@ -815,6 +992,8 @@ export function createWorkspaceTransitions({
|
|
|
815
992
|
selectBranch,
|
|
816
993
|
selectProjectBranch: projectBranches.selectProjectBranch,
|
|
817
994
|
mergeProjectBranch: projectBranches.mergeProjectBranch,
|
|
995
|
+
inspectProjectBranch: projectBranches.inspectProjectBranch,
|
|
996
|
+
manageProjectBranch: projectBranches.manageProjectBranch,
|
|
818
997
|
requestWorktree,
|
|
819
998
|
mergeWorkspace,
|
|
820
999
|
removeWorktree,
|
|
@@ -822,5 +1001,6 @@ export function createWorkspaceTransitions({
|
|
|
822
1001
|
listWorktrees,
|
|
823
1002
|
pruneWorktrees,
|
|
824
1003
|
cleanupDeletedSession,
|
|
1004
|
+
onWorktreeSetup,
|
|
825
1005
|
};
|
|
826
1006
|
}
|
|
@@ -8,10 +8,9 @@
|
|
|
8
8
|
// (targeted routing, never broadcast — see channel-transport/remote-notify.mjs).
|
|
9
9
|
//
|
|
10
10
|
// This module owns ONLY the transport (sockets, client registry, notify
|
|
11
|
-
// routing and lifecycle). The channels runtime
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// (stub runtime, no Discord token).
|
|
11
|
+
// routing and lifecycle). The channels runtime is injected via `handleCall`
|
|
12
|
+
// so the same transport is exercised by the real daemon entry AND the smoke
|
|
13
|
+
// harness (stub runtime, no Discord token).
|
|
15
14
|
//
|
|
16
15
|
// Composition root: the shared transport state below is read and written by
|
|
17
16
|
// the sub-services in channel-transport/ (remote binding, client registry,
|
|
@@ -8,7 +8,31 @@
|
|
|
8
8
|
// created after this surface is handed to the session service).
|
|
9
9
|
// Output: the desktopRuntime object consumed by session-service.
|
|
10
10
|
|
|
11
|
+
/** The stored-session reader, with the Agents pool's running state taken from
|
|
12
|
+
* this daemon's in-memory turn activity (every session runs inline here, so
|
|
13
|
+
* it is the single source of truth; worker index files only declare work). */
|
|
14
|
+
async function loadSessionStoreWithRuntimeActivity() {
|
|
15
|
+
const [store, runtime, progress] = await Promise.all([
|
|
16
|
+
import('../runtime/agent/orchestrator/session/store-summary-reader.mjs'),
|
|
17
|
+
// The import-free leaf holding the runtime map: no session manager graph.
|
|
18
|
+
import('../runtime/agent/orchestrator/session/manager/runtime-state.mjs'),
|
|
19
|
+
import('../runtime/agent/orchestrator/session/agent-pool-progress.mjs'),
|
|
20
|
+
]);
|
|
21
|
+
return {
|
|
22
|
+
...store,
|
|
23
|
+
// Running rows also carry their turn's progress stamp and stage (the
|
|
24
|
+
// quiet-time cue), read from the same runtime map.
|
|
25
|
+
listStoredAgentWorkers: () =>
|
|
26
|
+
progress.withTurnProgress(
|
|
27
|
+
store.listStoredAgentWorkers({ runningSessionIds: runtime.inFlightSessionActivity().working }),
|
|
28
|
+
(sessionId) => runtime.runtimeState.get(sessionId),
|
|
29
|
+
runtime.isTurnInFlight
|
|
30
|
+
),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
11
34
|
export function createDesktopRuntime({ getLocalSessionBridge }) {
|
|
35
|
+
let sessionStore = null;
|
|
12
36
|
return {
|
|
13
37
|
async attachSessionClient(options = {}) {
|
|
14
38
|
const bridge = getLocalSessionBridge();
|
|
@@ -17,7 +41,14 @@ export function createDesktopRuntime({ getLocalSessionBridge }) {
|
|
|
17
41
|
},
|
|
18
42
|
loadProjects: () => import('../runtime/shared/projects.mjs'),
|
|
19
43
|
loadWorktrees: () => import('../runtime/shared/worktrees/manager.mjs'),
|
|
20
|
-
loadSessionStore
|
|
44
|
+
loadSessionStore() {
|
|
45
|
+
// A failed import is forgotten so the next caller retries.
|
|
46
|
+
sessionStore ??= loadSessionStoreWithRuntimeActivity().catch((error) => {
|
|
47
|
+
sessionStore = null;
|
|
48
|
+
throw error;
|
|
49
|
+
});
|
|
50
|
+
return sessionStore;
|
|
51
|
+
},
|
|
21
52
|
loadSessionSearch: () => import('../runtime/session-search/session-search-db.mjs'),
|
|
22
53
|
loadStatuslineSegments: () => import('../runtime/shared/statusline/statusline-segments.mjs'),
|
|
23
54
|
loadConfig: () => import('../runtime/shared/config.mjs'),
|
|
@@ -25,9 +25,7 @@ export function createDaemonPgStop({
|
|
|
25
25
|
const drainBudget = () => Math.max(0, startedAt + forcedStopAtMs - Date.now());
|
|
26
26
|
const run = (drain) => {
|
|
27
27
|
stopping ??= loadAdapter()
|
|
28
|
-
.then(({ shutdownOwnedPg }) =>
|
|
29
|
-
shutdownOwnedPg({ timeoutMs: stopTimeoutMs, drainMs: drain ? drainBudget() : 0 })
|
|
30
|
-
)
|
|
28
|
+
.then(({ shutdownOwnedPg }) => shutdownOwnedPg({ timeoutMs: stopTimeoutMs, drainMs: drain ? drainBudget() : 0 }))
|
|
31
29
|
.then(
|
|
32
30
|
(stopped) => {
|
|
33
31
|
if (stopped) log('postgres stopped');
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { SESSION_ID_PATTERN } from '../runtime/agent/orchestrator/runtime-core/session-id.mjs';
|
|
2
|
+
import { sessionListOutput, sessionReadOutput, SESSION_TOOL_OUTPUT_BYTES } from './session-tool-output.mjs';
|
|
3
|
+
|
|
4
|
+
const TARGET_ACTIONS = new Set(['status', 'read', 'send', 'cancel', 'delete']);
|
|
5
|
+
const MUTATING_ACTIONS = new Set(['send', 'cancel', 'delete']);
|
|
6
|
+
|
|
7
|
+
/** Model-facing session operations over the same service used by desktop and TUI. */
|
|
8
|
+
export function createSessionControl({ getSessionService }) {
|
|
9
|
+
return async function executeSessionControl(args = {}, context = {}) {
|
|
10
|
+
const action = args.action;
|
|
11
|
+
if (action !== 'list' && !TARGET_ACTIONS.has(action)) {
|
|
12
|
+
throw new Error(`session: unsupported remote action "${action}"`);
|
|
13
|
+
}
|
|
14
|
+
const caller = context.callerSessionId;
|
|
15
|
+
if (typeof caller !== 'string' || !SESSION_ID_PATTERN.test(caller)) {
|
|
16
|
+
throw new Error('session: caller session is required');
|
|
17
|
+
}
|
|
18
|
+
const sessionId = typeof args.session_id === 'string' ? args.session_id.trim() : '';
|
|
19
|
+
if (TARGET_ACTIONS.has(action) && (typeof sessionId !== 'string' || !SESSION_ID_PATTERN.test(sessionId))) {
|
|
20
|
+
throw new Error(`session: session_id is required for action=${action}`);
|
|
21
|
+
}
|
|
22
|
+
if (MUTATING_ACTIONS.has(action) && sessionId === caller) {
|
|
23
|
+
throw new Error(`session: ${action} must target another session`);
|
|
24
|
+
}
|
|
25
|
+
const limit = args.limit ?? 25;
|
|
26
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
|
|
27
|
+
throw new Error('session: limit must be an integer from 1 to 100');
|
|
28
|
+
}
|
|
29
|
+
const offset = args.offset ?? 0;
|
|
30
|
+
const textOffset = args.text_offset ?? 0;
|
|
31
|
+
if (!Number.isSafeInteger(offset) || offset < 0 || !Number.isSafeInteger(offset + limit)) {
|
|
32
|
+
throw new Error('session: offset must be a nonnegative safe integer');
|
|
33
|
+
}
|
|
34
|
+
if (!Number.isSafeInteger(textOffset) || textOffset < 0) throw new Error('session: invalid text_offset');
|
|
35
|
+
if (args.text_offset !== undefined && (args.offset === undefined || limit !== 1 || !args.item_id)) {
|
|
36
|
+
throw new Error('session: text_offset requires offset, limit:1 and item_id from read');
|
|
37
|
+
}
|
|
38
|
+
const service = getSessionService();
|
|
39
|
+
if (!service) throw new Error('session: session service is unavailable');
|
|
40
|
+
if (action === 'list') {
|
|
41
|
+
const page = await service.listSessionCatalog({ page: { limit, cursor: args.cursor || null } });
|
|
42
|
+
return sessionListOutput(page, limit);
|
|
43
|
+
}
|
|
44
|
+
if (action === 'send') {
|
|
45
|
+
if (typeof args.prompt !== 'string' || !args.prompt.trim()) {
|
|
46
|
+
throw new Error('session: prompt is required for action=send');
|
|
47
|
+
}
|
|
48
|
+
const result = await service.submitSession({
|
|
49
|
+
sessionId,
|
|
50
|
+
prompt: args.prompt,
|
|
51
|
+
options: { mode: 'prompt', transcriptMeta: { sender: 'lead' } },
|
|
52
|
+
});
|
|
53
|
+
return { sessionId, accepted: result.accepted === true };
|
|
54
|
+
}
|
|
55
|
+
if (action === 'cancel') {
|
|
56
|
+
const result = await service.abortSession({ sessionId });
|
|
57
|
+
return { sessionId, aborted: result.aborted === true };
|
|
58
|
+
}
|
|
59
|
+
if (action === 'delete') {
|
|
60
|
+
const result = await service.configureSession(
|
|
61
|
+
{ sessionId, action: 'deleteSession', args: [sessionId] },
|
|
62
|
+
{ revision: 1 }
|
|
63
|
+
);
|
|
64
|
+
return { sessionId, deleted: result.value === true };
|
|
65
|
+
}
|
|
66
|
+
if (action === 'read') {
|
|
67
|
+
const result = await service.readSession({ sessionId, transcriptRange: { offset, limit } });
|
|
68
|
+
return sessionReadOutput(sessionId, result.range, { textOffset, itemId: args.item_id });
|
|
69
|
+
}
|
|
70
|
+
const result = await service.readSession({
|
|
71
|
+
sessionId,
|
|
72
|
+
transcriptItemLimit: action === 'status' ? 1 : limit,
|
|
73
|
+
transcriptByteBudget: SESSION_TOOL_OUTPUT_BYTES,
|
|
74
|
+
});
|
|
75
|
+
const snapshot = result.full;
|
|
76
|
+
if (!snapshot) throw new Error(`session: ${sessionId} is unavailable`);
|
|
77
|
+
const status = {
|
|
78
|
+
sessionId,
|
|
79
|
+
title: snapshot.title ?? null,
|
|
80
|
+
cwd: snapshot.cwd ?? null,
|
|
81
|
+
provider: snapshot.provider ?? null,
|
|
82
|
+
model: snapshot.model ?? null,
|
|
83
|
+
busy: snapshot.busy === true,
|
|
84
|
+
quotaResume: snapshot.quotaResume ?? null,
|
|
85
|
+
};
|
|
86
|
+
return status;
|
|
87
|
+
};
|
|
88
|
+
}
|