mixdog 1.4.0 → 1.4.2
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 +3 -2
- package/scripts/build-shipped-history.mjs +115 -33
- package/scripts/check-voice-runtime-inputs.mjs +25 -0
- package/scripts/gate-local.mjs +183 -63
- package/scripts/latest-guard.mjs +21 -9
- package/scripts/lib/gate-scheduler.mjs +138 -32
- package/scripts/lib/gate-timing-reporter.mjs +16 -0
- package/scripts/lib/isolated-test-env.mjs +10 -5
- package/scripts/lib/run-node-tests.mjs +91 -66
- package/scripts/lib/scoped-temp.d.mts +16 -0
- package/scripts/lib/scoped-temp.mjs +124 -0
- package/scripts/lib/stale-temp.mjs +44 -0
- package/scripts/lib/test-failure-records.mjs +14 -1
- package/scripts/lib/test-failure-summary.mjs +16 -4
- package/scripts/lib/test-spawn-ledger.mjs +12 -3
- package/scripts/post-release-check.mjs +1 -6
- package/scripts/pptx-kit-index.mjs +17 -5
- package/scripts/suite-health.mjs +115 -24
- package/scripts/test-data-dir.mjs +10 -7
- package/scripts/test.mjs +9 -14
- package/src/agents/advisor/AGENT.md +4 -4
- package/src/agents/advisor/agent.json +1 -1
- package/src/agents/explore/AGENT.md +22 -0
- package/src/agents/explore/agent.json +6 -0
- package/src/app.mjs +4 -0
- package/src/cli.mjs +7 -0
- package/src/defaults/agents.json +7 -0
- package/src/defaults/shipped-history.json +23 -2
- package/src/defaults/skills/browser-use/SKILL.md +10 -5
- package/src/defaults/skills/code-tidy/SKILL.md +71 -102
- package/src/defaults/skills/code-tidy/references/agent-cleanup.md +66 -114
- package/src/defaults/skills/code-tidy/references/cleanup-report.md +19 -35
- package/src/defaults/skills/code-tidy/references/dead-code.md +3 -9
- package/src/defaults/skills/code-tidy/references/test-suite-slop.md +16 -27
- package/src/defaults/skills/computer-use/SKILL.md +16 -4
- package/src/defaults/skills/goal-management/SKILL.md +1 -1
- package/src/defaults/skills/setup/references/actions.md +12 -6
- package/src/defaults/skills/setup/references/surfaces.md +2 -2
- package/src/defaults/skills/setup-guide/SKILL.md +5 -2
- package/src/defaults/skills/setup-guide/model-recommendations.json +13 -0
- package/src/defaults/skills/skill-creator/SKILL.md +85 -190
- package/src/defaults/skills/skill-creator/references/design.md +70 -162
- package/src/defaults/skills/skill-creator/references/evaluation.md +33 -92
- package/src/defaults/skills/test-suite/SKILL.md +194 -0
- package/src/defaults/skills/test-suite/references/case-management.md +51 -0
- package/src/defaults/skills/test-suite/references/flaky-policy.md +39 -0
- package/src/defaults/skills/test-suite/references/reliability.md +49 -0
- package/src/defaults/skills/test-suite/references/suite-design.md +78 -0
- package/src/defaults/skills/test-suite/scripts/inventory.mjs +335 -0
- package/src/defaults/skills/visualize/SKILL.md +6 -2
- package/src/lib/rules-builder.cjs +35 -42
- package/src/output-styles/common.md +2 -2
- package/src/output-styles/simple.md +1 -1
- package/src/rules/agent/AGENT.md +5 -4
- package/src/rules/lead/LEAD.md +12 -7
- package/src/rules/shared/10-tool-workflow.md +3 -1
- package/src/rules/shared/20-research.md +3 -6
- package/src/rules/shared/40-editing.md +1 -0
- package/src/rules/shared/45-destructive.md +0 -2
- package/src/rules/shared/50-execution.md +2 -0
- package/src/rules/shared/60-verification.md +10 -9
- package/src/rules/shared/70-delivery.md +8 -9
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/abort-link.mjs +5 -1
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +10 -1
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +156 -24
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +13 -0
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +4 -1
- package/src/runtime/agent/orchestrator/cache-break-trace.mjs +2 -0
- package/src/runtime/agent/orchestrator/config.mjs +12 -7
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +8 -8
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +5 -26
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +3 -1
- package/src/runtime/agent/orchestrator/internal-agents.mjs +3 -14
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +122 -12
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +5 -3
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +13 -2
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +152 -58
- package/src/runtime/agent/orchestrator/mcp/client.mjs +51 -18
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +88 -54
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +42 -26
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +54 -8
- package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +37 -31
- package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +8 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +31 -21
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +14 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +6 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +40 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider-keys.mjs +34 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +14 -7
- package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/devin.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +248 -41
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -11
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +45 -6
- package/src/runtime/agent/orchestrator/providers/lib/first-output-window.mjs +58 -0
- package/src/runtime/agent/orchestrator/providers/lib/listen-on.mjs +14 -0
- package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +0 -18
- package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +138 -6
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/model-cache.mjs +100 -33
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/oauth-secret-fields.fixtures.mjs +45 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +14 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +4 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +5 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +16 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +13 -3
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +13 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +81 -42
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +160 -31
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +22 -12
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +49 -22
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/registry.mjs +45 -2
- package/src/runtime/agent/orchestrator/providers/vertex-ai-auth.mjs +622 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai-maas.mjs +185 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai-models.mjs +445 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai.mjs +567 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +41 -13
- package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -6
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +7 -3
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +6 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +14 -5
- package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -0
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -5
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +171 -37
- package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +1 -3
- package/src/runtime/agent/orchestrator/session/cache-warm.mjs +102 -12
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -8
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +23 -0
- package/src/runtime/agent/orchestrator/session/compact/observation-supersession.mjs +103 -23
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +160 -36
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +164 -23
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +139 -19
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +38 -7
- package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +100 -22
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -3
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -6
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +33 -3
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +9 -2
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +13 -5
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +23 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +23 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +39 -21
- package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +13 -8
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +50 -28
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +30 -13
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +63 -6
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +35 -13
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +24 -14
- package/src/runtime/agent/orchestrator/session/manager/session-scratch-environment.mjs +70 -0
- package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +0 -3
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +10 -6
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +56 -29
- package/src/runtime/agent/orchestrator/session/manager/turn-reap.mjs +125 -0
- package/src/runtime/agent/orchestrator/session/mixy-name.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +30 -7
- package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +154 -0
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +37 -8
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +252 -39
- package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +163 -64
- package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +164 -4
- package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +142 -18
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +61 -2
- package/src/runtime/agent/orchestrator/stall-policy.mjs +23 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +46 -20
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +67 -31
- package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +25 -13
- package/src/runtime/agent/orchestrator/tools/builtin/lib/scoped-search-flight.mjs +9 -5
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +58 -20
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +23 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +1 -8
- package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +20 -15
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +96 -20
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +59 -10
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/federation.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/lib/isolated-test-env.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs +99 -2
- package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +103 -13
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +49 -15
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +45 -27
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +34 -10
- package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +28 -4
- package/src/runtime/agent/orchestrator/tools/lib/wait-until-fixture.mjs +26 -0
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -2
- package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
- package/src/runtime/channels/lib/webhook/signature.mjs +4 -1
- package/src/runtime/channels/lib/whisper-port.mjs +29 -11
- package/src/runtime/channels/lib/whisper-server.mjs +10 -1
- package/src/runtime/computer-bridge/action-schema.mjs +2 -2
- package/src/runtime/computer-bridge/core-actions.mjs +2 -2
- package/src/runtime/computer-bridge/error-recovery.mjs +5 -4
- package/src/runtime/computer-bridge/linux-action-capabilities.mjs +24 -5
- package/src/runtime/computer-bridge/linux-readiness.d.mts +7 -2
- package/src/runtime/connectors/connector-accounts-mcp.mjs +236 -103
- package/src/runtime/connectors/gmail-app-password.mjs +3 -3
- package/src/runtime/explore/explorer.mjs +93 -0
- package/src/runtime/explore/tool-defs.mjs +35 -0
- package/src/runtime/explore/tool.mjs +123 -0
- package/src/runtime/local-provider/server-process.mjs +2 -1
- package/src/runtime/media/adapters/gemini-video.mjs +4 -1
- package/src/runtime/media/adapters/xai-media.mjs +2 -1
- package/src/runtime/memory/index.mjs +4 -0
- package/src/runtime/memory/lib/embedding-provider.mjs +4 -1
- package/src/runtime/memory/lib/embedding-worker.mjs +10 -3
- package/src/runtime/memory/lib/memory-action-handlers/cycle-backfill-action.mjs +1 -7
- package/src/runtime/memory/lib/memory-chunk-quality.mjs +1 -6
- package/src/runtime/office/authoring/pdf-author-action.mjs +1 -6
- package/src/runtime/office/design/design-art-direction.mjs +29 -27
- package/src/runtime/office/pdf/pdf-writer.mjs +6 -1
- package/src/runtime/office/portable/portable-snapshot-docx.mjs +7 -1
- package/src/runtime/office/portable/portable-snapshot-shared.mjs +6 -1
- package/src/runtime/office/quality/assurance-rendered.mjs +9 -2
- package/src/runtime/office/quality/assurance-structure-docx.mjs +4 -2
- package/src/runtime/office/quality/design-review.mjs +1 -5
- package/src/runtime/office/quality/document-brief.mjs +1 -5
- package/src/runtime/office/quality/forced-break-pages.mjs +9 -6
- package/src/runtime/office/quality/quality-pipeline.mjs +1 -1
- package/src/runtime/shared/agent-route-config.mjs +17 -2
- package/src/runtime/shared/atomic-file.mjs +103 -2
- package/src/runtime/shared/background-tasks.mjs +15 -6
- package/src/runtime/shared/bot-owned-work.mjs +56 -0
- package/src/runtime/shared/connector-accounts.mjs +5 -5
- package/src/runtime/shared/connector-catalog.d.mts +11 -4
- package/src/runtime/shared/connector-catalog.mjs +60 -52
- package/src/runtime/shared/custom-provider-keys.mjs +20 -0
- package/src/runtime/shared/defaults-separation.mjs +1 -4
- package/src/runtime/shared/fetch-safe-listen.d.mts +16 -0
- package/src/runtime/shared/fetch-safe-listen.mjs +50 -0
- package/src/runtime/shared/file-has-data.mjs +26 -2
- package/src/runtime/shared/file-lock.mjs +13 -15
- package/src/runtime/shared/git-launch.d.mts +9 -0
- package/src/runtime/shared/git-launch.mjs +213 -0
- package/src/runtime/shared/git-runner-worker.mjs +2 -1
- package/src/runtime/shared/handoff-artifacts.d.mts +2 -1
- package/src/runtime/shared/handoff-artifacts.mjs +18 -8
- package/src/runtime/shared/idle-auto-clear-gate.mjs +29 -7
- package/src/runtime/shared/llm/cost.mjs +11 -2
- package/src/runtime/shared/llm/http-agent.mjs +313 -29
- package/src/runtime/shared/llm/model-catalog-projection.mjs +3 -2
- package/src/runtime/shared/llm/model-catalog.mjs +46 -6
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +3 -0
- package/src/runtime/shared/llm/system-proxy.mjs +452 -0
- package/src/runtime/shared/loopback-listener.mjs +25 -2
- package/src/runtime/shared/model-route-chain.d.mts +7 -2
- package/src/runtime/shared/model-route-chain.mjs +22 -4
- package/src/runtime/shared/open-url.mjs +10 -0
- package/src/runtime/shared/provider-accounts.mjs +52 -2
- package/src/runtime/shared/session-activity-signal.mjs +14 -0
- package/src/runtime/shared/session-scratch.mjs +37 -0
- package/src/runtime/shared/staged-install-worker.mjs +5 -0
- package/src/runtime/shared/staged-update.mjs +47 -2
- package/src/runtime/shared/tool-card-model/agent-surface.mjs +1 -3
- package/src/runtime/shared/tool-card-model/card-status.mjs +15 -2
- package/src/runtime/shared/tool-result-summary.mjs +1 -1
- package/src/runtime/shared/tool-surface.mjs +113 -36
- package/src/runtime/shared/tool-work-units.mjs +6 -0
- package/src/runtime/shared/turn-snapshot-store.mjs +13 -6
- package/src/runtime/shared/turn-worktree-snapshot.mjs +414 -54
- package/src/runtime/shared/worktrees/activity-gate.mjs +215 -318
- package/src/runtime/shared/worktrees/activity-ledger-worker.mjs +56 -0
- package/src/runtime/shared/worktrees/activity-ledger.mjs +391 -0
- package/src/runtime/shared/worktrees/branch-management.mjs +9 -3
- package/src/runtime/shared/worktrees/contract.mjs +4 -1
- package/src/runtime/shared/worktrees/git.mjs +72 -0
- package/src/runtime/shared/worktrees/manager.mjs +285 -168
- package/src/runtime/shared/worktrees/test-support.mjs +6 -10
- package/src/runtime/tidy/install.mjs +95 -15
- package/src/runtime/tidy/languages.mjs +17 -15
- package/src/runtime/tidy/process.mjs +7 -4
- package/src/runtime/tidy/resolve.mjs +19 -16
- package/src/runtime/tidy/runners/biome.mjs +3 -3
- package/src/runtime/tidy/tool.mjs +1 -1
- package/src/runtime/tidy/worktree.mjs +10 -6
- package/src/runtime/visualize-bridge/client.mjs +6 -1
- package/src/runtime/visualize-bridge/tool-defs.mjs +7 -2
- package/src/runtime/web-search/index.mjs +1 -1
- package/src/session-runtime/agent-home-delivery.mjs +41 -0
- package/src/session-runtime/agent-task-sessions.mjs +458 -312
- package/src/session-runtime/agent-tool-routing.mjs +8 -41
- package/src/session-runtime/boot/tools.mjs +7 -1
- package/src/session-runtime/bot-status.mjs +107 -101
- package/src/session-runtime/bot-target.mjs +38 -0
- package/src/session-runtime/channel-config-api.mjs +6 -1
- package/src/session-runtime/connector-merge-migration.mjs +18 -15
- package/src/session-runtime/conversation-import/codex-titles.mjs +88 -0
- package/src/session-runtime/conversation-import/discovery.mjs +401 -36
- package/src/session-runtime/conversation-import/service.mjs +35 -8
- package/src/session-runtime/handoff-attachments.mjs +82 -31
- package/src/session-runtime/held-requests.mjs +3 -1
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +12 -13
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +1 -0
- package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -0
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +8 -0
- package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +4 -1
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +145 -112
- package/src/session-runtime/lifecycle/cold-heir.mjs +11 -6
- package/src/session-runtime/lifecycle/session-catalog.mjs +9 -1
- package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -1
- package/src/session-runtime/lifecycle/teardown.mjs +1 -1
- package/src/session-runtime/mcp-glue/server-catalog.mjs +16 -10
- package/src/session-runtime/mcp-glue/server-input.mjs +4 -1
- package/src/session-runtime/mixy-heartbeat.mjs +1 -1
- package/src/session-runtime/model-route/set-route.mjs +11 -2
- package/src/session-runtime/provider-auth/login.mjs +2 -2
- package/src/session-runtime/provider-catalog-cache.mjs +82 -36
- package/src/session-runtime/provider-models/catalog-load.mjs +23 -6
- package/src/session-runtime/provider-models.mjs +4 -2
- package/src/session-runtime/resource-mcp-api.mjs +98 -35
- package/src/session-runtime/resource-mcp-connector-accounts.mjs +44 -31
- package/src/session-runtime/resource-mcp-secrets.mjs +28 -11
- package/src/session-runtime/resource-mcp-servers.mjs +5 -4
- package/src/session-runtime/resource-recall-api.mjs +6 -1
- package/src/session-runtime/runtime-feature-gates.mjs +5 -1
- package/src/session-runtime/services/agent-tool/execute.mjs +14 -9
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +20 -4
- package/src/session-runtime/services/agent-tool/model-select.mjs +48 -7
- package/src/session-runtime/services/agent-tool/render.mjs +71 -17
- package/src/session-runtime/services/agent-tool/send-flow.mjs +10 -2
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +8 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +4 -1
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +6 -2
- package/src/session-runtime/services/agent-tool/tool-def.mjs +9 -9
- package/src/session-runtime/services/agent-watchdog-registry.mjs +32 -4
- package/src/session-runtime/services/channel-worker/daemon-spawn.mjs +2 -0
- package/src/session-runtime/services/daemon-candidate.mjs +4 -1
- package/src/session-runtime/services/memory-runtime-proxy/daemon-spawn.mjs +4 -0
- package/src/session-runtime/services/plugin-admin.mjs +10 -6
- package/src/session-runtime/services/provider-admin.mjs +283 -11
- package/src/session-runtime/session-turn-api.mjs +2 -0
- package/src/session-runtime/settings-builtin-tools-api.mjs +4 -1
- package/src/session-runtime/settings-system-api.mjs +1 -1
- package/src/session-runtime/setup-tool/agent-settings-actions.mjs +13 -3
- package/src/session-runtime/setup-tool/connector-widen-approval.mjs +96 -0
- package/src/session-runtime/setup-tool/executor.mjs +6 -2
- package/src/session-runtime/setup-tool/tool-defs.mjs +2 -1
- package/src/session-runtime/tool-policy/policy-stage.mjs +1 -0
- package/src/session-runtime/turn/agent-ops.mjs +23 -0
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +49 -11
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +5 -1
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +25 -5
- package/src/session-runtime/workflow-agents-api/onboarding.mjs +3 -3
- package/src/session-runtime/workspace/activity-guards.mjs +176 -0
- package/src/session-runtime/workspace/session-view.mjs +149 -0
- package/src/session-runtime/workspace/side-checkouts.mjs +203 -0
- package/src/session-runtime/workspace/transition-runner.mjs +188 -0
- package/src/session-runtime/workspace/transitions.mjs +108 -1041
- package/src/session-runtime/workspace/workspace-merge.mjs +132 -0
- package/src/session-runtime/workspace/worktree-intents.mjs +242 -0
- package/src/session-runtime/workspace/worktree-maintenance.mjs +80 -0
- package/src/session-runtime/workspace/worktree-setup.mjs +85 -0
- package/src/session-runtime/workspace/worktree-tool.mjs +73 -56
- package/src/standalone/daemon-desktop-runtime.mjs +2 -0
- package/src/standalone/daemon-session-control.mjs +169 -138
- package/src/standalone/daemon.mjs +7 -0
- package/src/standalone/desktop-service-registry.mjs +9 -0
- package/src/standalone/local-session-runtime.mjs +5 -1
- package/src/standalone/session-client/daemon-unavailable.mjs +3 -0
- package/src/standalone/session-client.mjs +5 -1
- package/src/standalone/session-frame-stream.mjs +83 -11
- package/src/standalone/session-protocol.mjs +4 -0
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +16 -12
- package/src/standalone/session-service/agent-tree.mjs +45 -9
- package/src/standalone/session-service/projection/transcript-window.mjs +700 -64
- package/src/standalone/session-service/session-calls/session-action.mjs +10 -3
- package/src/standalone/session-service/session-calls/session-views.mjs +160 -104
- package/src/standalone/session-service/stored-reader.mjs +127 -40
- package/src/standalone/session-transport/client-registry/client-grace.mjs +12 -9
- package/src/tui/App.jsx +154 -164
- package/src/tui/app/app-view/floating-panel.jsx +10 -4
- package/src/tui/app/app-view/text-entry-labels.mjs +1 -0
- package/src/tui/app/clipboard.mjs +21 -10
- package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +1 -3
- package/src/tui/app/model-picker/route-selection.mjs +5 -6
- package/src/tui/app/prompt-handlers/use-prompt-history-nav.mjs +1 -1
- package/src/tui/app/prompt-handlers/use-prompt-interrupt.mjs +3 -0
- package/src/tui/app/prompt-submit/provider-prompts.mjs +3 -1
- package/src/tui/app/provider-setup/api-key-actions.mjs +31 -1
- package/src/tui/app/provider-setup/oauth-actions.mjs +58 -21
- package/src/tui/app/provider-setup/provider-items.mjs +8 -2
- package/src/tui/app/provider-setup-picker.mjs +29 -18
- package/src/tui/app/shell-layout/row-budgets.mjs +12 -10
- package/src/tui/app/slash-commands.mjs +1 -0
- package/src/tui/app/slash-dispatch/session-commands.mjs +46 -0
- package/src/tui/app/slash-dispatch.mjs +1 -1
- package/src/tui/app/use-btw-panel.mjs +29 -0
- package/src/tui/app/use-context-panel-refresh.mjs +31 -0
- package/src/tui/app/use-model-catalog-cache.mjs +13 -10
- package/src/tui/app/use-mouse-input.mjs +11 -0
- package/src/tui/app/use-onboarding-start.mjs +8 -3
- package/src/tui/app/use-panel-transition.mjs +10 -1
- package/src/tui/app/use-pasted-buffers.mjs +28 -20
- package/src/tui/app/use-prompt-draft-flow.mjs +7 -0
- package/src/tui/app/use-prompt-layout-rows.mjs +3 -3
- package/src/tui/app/use-prompt-queue-history.mjs +3 -2
- package/src/tui/app/use-selection-focus.mjs +11 -2
- package/src/tui/app/use-selection-geometry.mjs +18 -9
- package/src/tui/app/use-selection-paint.mjs +4 -4
- package/src/tui/app/use-selection-stitch.mjs +3 -3
- package/src/tui/app/use-slash-palette.mjs +62 -0
- package/src/tui/app/use-terminal-chrome.mjs +2 -2
- package/src/tui/app/use-transcript-activity.mjs +47 -32
- package/src/tui/app/use-transcript-follow.mjs +12 -4
- package/src/tui/app/use-transcript-scroll.mjs +46 -17
- package/src/tui/app/use-transcript-swap-reset.mjs +27 -0
- package/src/tui/app/use-transcript-window/geometry.mjs +19 -5
- package/src/tui/app/use-transcript-window/instance-state.mjs +4 -0
- package/src/tui/app/use-transcript-window/selection-shift.mjs +5 -1
- package/src/tui/app/use-transcript-window.mjs +21 -11
- package/src/tui/app/use-tui-ready.mjs +18 -0
- package/src/tui/app/use-welcome-prompt-hint.mjs +5 -0
- package/src/tui/app/use-workflow-tab-cycle.mjs +5 -3
- package/src/tui/components/Picker.jsx +27 -3
- package/src/tui/components/QuestionPanel.jsx +13 -4
- package/src/tui/components/SignInUrl.jsx +68 -0
- package/src/tui/components/TextEntryPanel.jsx +76 -46
- package/src/tui/components/sign-in-url-layout.mjs +24 -0
- package/src/tui/dist/index.mjs +1963 -1361
- package/src/tui/session/goal-turn-state.mjs +6 -2
- package/src/tui/session/session-api/controls.mjs +4 -0
- package/src/tui/session/session-api/extensions.mjs +8 -0
- package/src/tui/session/session-api/intake/abort.mjs +2 -1
- package/src/tui/session/session-api/intake.mjs +2 -0
- package/src/tui/session/session-api/integrations.mjs +2 -2
- package/src/tui/session/session-api/routes-agent-definitions.mjs +1 -0
- package/src/tui/session/session-api/settings.mjs +2 -2
- package/src/tui/session/session-flow/queue/take-entries.mjs +11 -0
- package/src/tui/session/transcript-spill/spill-writer.mjs +15 -0
- package/src/tui/session/transcript-spill.mjs +92 -4
- package/src/tui/session/transcript-store.mjs +2 -0
- package/src/ui/statusline-agents.mjs +1 -3
- package/src/defaults/skills/skill-creator/references/source-review.md +0 -94
|
@@ -9,11 +9,12 @@ import { withBuiltinPathLocks } from './path-locks.mjs';
|
|
|
9
9
|
import { withAdvisoryLocks } from './advisory-lock.mjs';
|
|
10
10
|
import { gitRepoLockKey, withGitWorktreeWriteLock } from './git-repo-rw-lock.mjs';
|
|
11
11
|
import { invalidateBuiltinResultCache } from './cache-layers.mjs';
|
|
12
|
-
import {
|
|
12
|
+
import { tryAdmitWorkspaceActivityAsync } from '../../../../shared/worktrees/activity-gate.mjs';
|
|
13
13
|
import { WORKTREE_SNAPSHOT_KIND } from '../../../../shared/worktrees/contract.mjs';
|
|
14
14
|
import { isWithin } from '../../../../shared/worktrees/paths.mjs';
|
|
15
15
|
import { readRegistrySync } from '../../../../shared/worktrees/registry.mjs';
|
|
16
16
|
import { runAbortable } from '../../../../shared/abort-race.mjs';
|
|
17
|
+
import { startGit } from '../../../../shared/git-launch.mjs';
|
|
17
18
|
import { sleep } from '../../../../shared/sleep.mjs';
|
|
18
19
|
import { capMarker } from '../../../../shared/tool-output-marker.mjs';
|
|
19
20
|
import { drainCodeGraphCache } from '../code-graph-state.mjs';
|
|
@@ -83,6 +84,9 @@ const SERVER_OPERATIONS = new Set(['daemon', 'instaweb']);
|
|
|
83
84
|
// probe into `git rev-parse exited 128` inside a plain directory.
|
|
84
85
|
const REPO_FREE_OPERATIONS = new Set(['version', 'help']);
|
|
85
86
|
|
|
87
|
+
const GIT_DESCRIPTION_HEAD =
|
|
88
|
+
'Run Git here, never through shell. An array runs in order and stops on failure; batch read-only commands in one. diff for known changes, status to discover them; history only when needed. git diff or git diff -- <paths> includes untracked files. Set include_stage_ids:true to select changes, then action:stage with diff_id/change_ids. Staging rejects stale or cross-Project diffs and returns per-file staged counts.';
|
|
89
|
+
|
|
86
90
|
export const GIT_TOOL_DEF = {
|
|
87
91
|
name: 'git',
|
|
88
92
|
title: 'Git',
|
|
@@ -94,8 +98,7 @@ export const GIT_TOOL_DEF = {
|
|
|
94
98
|
openWorldHint: true,
|
|
95
99
|
compressible: true,
|
|
96
100
|
},
|
|
97
|
-
description:
|
|
98
|
-
'Run Git here, never through shell. An array (max 10) runs in order and stops on failure; batch read-only commands in one. diff for known changes, status to discover them; history only when needed. git diff or git diff -- <paths> includes untracked files. Set include_stage_ids:true to select changes, then action:stage with diff_id/change_ids. Staging rejects stale or cross-Project diffs and returns per-file staged counts. Worktrees are managed only: action:worktree (Lead only) moves a session into/out of its managed worktree, merges, removes, lists, prunes; git worktree add/remove/list/prune map to managed operations (add -b keeps the session in place; add --detach makes a read-only snapshot worktree, removed when its turn ends; list --porcelain stays raw git; move/lock/unlock/repair are refused). Merge or remove only when the user asks; carry and large-size answers come from the user; force only on explicit request.',
|
|
101
|
+
description: `${GIT_DESCRIPTION_HEAD} Worktrees are managed only: action:worktree; git worktree add/remove/list/prune map to managed operations (add -b keeps the session in place; add --detach makes a read-only snapshot worktree, removed when its turn ends; list --porcelain stays raw git; move/lock/unlock/repair are refused). Merge or remove only when the user asks.`,
|
|
99
102
|
inputSchema: {
|
|
100
103
|
type: 'object',
|
|
101
104
|
properties: {
|
|
@@ -118,14 +121,14 @@ export const GIT_TOOL_DEF = {
|
|
|
118
121
|
minimum: 1,
|
|
119
122
|
maximum: GIT_OUTPUT_LIMIT_MAX,
|
|
120
123
|
description:
|
|
121
|
-
'Body line cap
|
|
124
|
+
'Body line cap; staging IDs are not capped. Default 500; git log defaults to 100. A cut ends with [output capped …] naming how to continue.',
|
|
122
125
|
},
|
|
123
126
|
include_stage_ids: {
|
|
124
127
|
type: 'boolean',
|
|
125
128
|
description:
|
|
126
129
|
'Include staging IDs outside the body cap for git diff or git diff -- <paths> only. Default false.',
|
|
127
130
|
},
|
|
128
|
-
diff_id: { type: 'string', description: 'stage: exact diff_id from git diff
|
|
131
|
+
diff_id: { type: 'string', description: 'stage: exact diff_id from git diff.' },
|
|
129
132
|
change_ids: {
|
|
130
133
|
anyOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' }, minItems: 1, maxItems: 50 }],
|
|
131
134
|
description: 'stage: exact change ID or IDs to stage, including new files.',
|
|
@@ -158,6 +161,29 @@ export const GIT_TOOL_DEF = {
|
|
|
158
161
|
},
|
|
159
162
|
};
|
|
160
163
|
|
|
164
|
+
// Only the Lead host runs enter/return/merge/remove/prune (git-worktree-tool.mjs
|
|
165
|
+
// leadHost); an agent keeps `list`, so its schema omits every field the other
|
|
166
|
+
// operations take.
|
|
167
|
+
const LEAD_ONLY_WORKTREE_FIELDS = ['session_id', 'name', 'branch', 'create', 'carry', 'confirm_large', 'force'];
|
|
168
|
+
|
|
169
|
+
function buildGitAgentToolDef(base) {
|
|
170
|
+
const properties = { ...base.inputSchema.properties };
|
|
171
|
+
for (const field of LEAD_ONLY_WORKTREE_FIELDS) delete properties[field];
|
|
172
|
+
properties.action = {
|
|
173
|
+
...properties.action,
|
|
174
|
+
description: 'Default command. stage uses diff_id/change_ids instead of command. worktree uses worktree_action.',
|
|
175
|
+
};
|
|
176
|
+
properties.worktree_action = { type: 'string', enum: ['list'], description: 'list only.' };
|
|
177
|
+
return {
|
|
178
|
+
...base,
|
|
179
|
+
description: `${GIT_DESCRIPTION_HEAD} Worktrees are Lead-managed: only worktree_action:list and git worktree list work; every other worktree operation is refused.`,
|
|
180
|
+
inputSchema: { ...base.inputSchema, properties },
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** The git tool as a delegated agent sees it (see bindAgentOwner). */
|
|
185
|
+
export const GIT_AGENT_TOOL_DEF = buildGitAgentToolDef(GIT_TOOL_DEF);
|
|
186
|
+
|
|
161
187
|
function cleanText(value) {
|
|
162
188
|
return String(value || '')
|
|
163
189
|
.replace(/\r\n/g, '\n')
|
|
@@ -412,7 +438,24 @@ function parseCommand(rawCommand, workDir) {
|
|
|
412
438
|
return { command: String(command), cwd, globalArgs, operation, args };
|
|
413
439
|
}
|
|
414
440
|
|
|
415
|
-
|
|
441
|
+
function gitToolEnvironment(optionalLocks) {
|
|
442
|
+
return {
|
|
443
|
+
...process.env,
|
|
444
|
+
GIT_TERMINAL_PROMPT: '0',
|
|
445
|
+
GIT_PAGER: 'cat',
|
|
446
|
+
GIT_EDITOR: 'true',
|
|
447
|
+
GIT_SEQUENCE_EDITOR: 'true',
|
|
448
|
+
LC_ALL: 'C',
|
|
449
|
+
// Reads run beside writes without a lock (git-repo-rw-lock.mjs).
|
|
450
|
+
// With optional locks off `git status` never takes index.lock to
|
|
451
|
+
// write back a refreshed index, so it cannot fail a concurrent
|
|
452
|
+
// write on that lock. (`git diff` ignores the setting and may still
|
|
453
|
+
// refresh the index briefly; the write retry absorbs that.)
|
|
454
|
+
...(optionalLocks ? {} : { GIT_OPTIONAL_LOCKS: '0' }),
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
async function runProcess(program, argv, { cwd, signal, maxBytes = MAX_CAPTURE_BYTES, env } = {}) {
|
|
416
459
|
let child;
|
|
417
460
|
try {
|
|
418
461
|
await ensureNativeSpawnServer();
|
|
@@ -421,20 +464,7 @@ async function runProcess(program, argv, { cwd, signal, maxBytes = MAX_CAPTURE_B
|
|
|
421
464
|
argv,
|
|
422
465
|
spawnOptions: {
|
|
423
466
|
cwd,
|
|
424
|
-
env
|
|
425
|
-
...process.env,
|
|
426
|
-
GIT_TERMINAL_PROMPT: '0',
|
|
427
|
-
GIT_PAGER: 'cat',
|
|
428
|
-
GIT_EDITOR: 'true',
|
|
429
|
-
GIT_SEQUENCE_EDITOR: 'true',
|
|
430
|
-
LC_ALL: 'C',
|
|
431
|
-
// Reads run beside writes without a lock (git-repo-rw-lock.mjs).
|
|
432
|
-
// With optional locks off `git status` never takes index.lock to
|
|
433
|
-
// write back a refreshed index, so it cannot fail a concurrent
|
|
434
|
-
// write on that lock. (`git diff` ignores the setting and may still
|
|
435
|
-
// refresh the index briefly; the write retry absorbs that.)
|
|
436
|
-
...(optionalLocks ? {} : { GIT_OPTIONAL_LOCKS: '0' }),
|
|
437
|
-
},
|
|
467
|
+
env,
|
|
438
468
|
outputLimit: maxBytes,
|
|
439
469
|
// Bytes as git wrote them, decoded once by the caller: a multibyte
|
|
440
470
|
// character split across two pipe reads must not become U+FFFD.
|
|
@@ -548,11 +578,11 @@ function commandFailure(plan, result, limit = GIT_OUTPUT_LINES_DEFAULT) {
|
|
|
548
578
|
}
|
|
549
579
|
|
|
550
580
|
function runGit(plan, argv, options = {}) {
|
|
551
|
-
return
|
|
552
|
-
|
|
553
|
-
signal: options.signal,
|
|
554
|
-
|
|
555
|
-
|
|
581
|
+
return startGit(
|
|
582
|
+
gitToolEnvironment(!options.readOnly),
|
|
583
|
+
(command, env) => runProcess(command, [...plan.globalArgs, ...argv], { cwd: plan.cwd, signal: options.signal, env }),
|
|
584
|
+
(result) => result.error
|
|
585
|
+
);
|
|
556
586
|
}
|
|
557
587
|
|
|
558
588
|
// Another process (an editor, a terminal, an IDE) holding one of git's lock
|
|
@@ -560,6 +590,10 @@ function runGit(plan, argv, options = {}) {
|
|
|
560
590
|
// config.lock. Commands take that lock before changing anything, so a brief
|
|
561
591
|
// retry with backoff turns the collision into a short wait; a command that had
|
|
562
592
|
// already done part of its work reports its own state on the retry.
|
|
593
|
+
// Git reports lock contention only as text: lockfile.c's "Unable to create
|
|
594
|
+
// '<path>.lock': File exists" (and config.c's "could not lock config file"),
|
|
595
|
+
// stable English because runProcess pins LC_ALL=C. The delays are a bounded
|
|
596
|
+
// backoff (3.1 s in all), a policy choice rather than anything git reports.
|
|
563
597
|
const GIT_LOCK_CONTENTION_RE =
|
|
564
598
|
/Unable to create '[^'\n]*\.lock': File exists|could not lock config file [^\n]*: File exists/;
|
|
565
599
|
const GIT_LOCK_RETRY_DELAYS_MS = [100, 200, 400, 800, 1600];
|
|
@@ -849,7 +883,8 @@ function snapshotContaining(repo) {
|
|
|
849
883
|
}
|
|
850
884
|
return (
|
|
851
885
|
Object.values(entries).find(
|
|
852
|
-
(record) =>
|
|
886
|
+
(record) =>
|
|
887
|
+
record?.kind === WORKTREE_SNAPSHOT_KIND && typeof record.path === 'string' && isWithin(record.path, repo)
|
|
853
888
|
) ?? null
|
|
854
889
|
);
|
|
855
890
|
}
|
|
@@ -858,12 +893,13 @@ function snapshotContaining(repo) {
|
|
|
858
893
|
// lease it holds (activity-gate, the same as a background shell's) keeps the
|
|
859
894
|
// snapshot from being removed in any process until it ends, and a snapshot
|
|
860
895
|
// whose removal is under way refuses it. Returns the release.
|
|
861
|
-
function admitSnapshotCommand(repo, sessionId) {
|
|
896
|
+
async function admitSnapshotCommand(repo, sessionId) {
|
|
862
897
|
const snapshot = snapshotContaining(repo);
|
|
863
898
|
if (!snapshot) return () => {};
|
|
864
|
-
const leave =
|
|
899
|
+
const leave = await tryAdmitWorkspaceActivityAsync(sessionId || 'git-tool', repo, { kind: 'command' });
|
|
865
900
|
if (!leave) throw new Error(`the snapshot worktree ${snapshot.path} is being removed; nothing ran`);
|
|
866
|
-
|
|
901
|
+
// Fails only when workspace admission stopped (reported there), which keeps the snapshot held.
|
|
902
|
+
return () => leave().catch(() => {});
|
|
867
903
|
}
|
|
868
904
|
|
|
869
905
|
function invalidateAfterGitMutation() {
|
|
@@ -1031,14 +1067,14 @@ async function executeSingleGitTool(input, workDir, options = {}) {
|
|
|
1031
1067
|
// under it, and a snapshot being removed refuses it.
|
|
1032
1068
|
let leaveSnapshot;
|
|
1033
1069
|
try {
|
|
1034
|
-
leaveSnapshot = admitSnapshotCommand(repo, options.sessionId);
|
|
1070
|
+
leaveSnapshot = await admitSnapshotCommand(repo, options.sessionId);
|
|
1035
1071
|
} catch (error) {
|
|
1036
1072
|
return rejected(error.message);
|
|
1037
1073
|
}
|
|
1038
1074
|
try {
|
|
1039
1075
|
return await runInRepository(input, plan, { repo, lockKey, limit, signal, workDir });
|
|
1040
1076
|
} finally {
|
|
1041
|
-
leaveSnapshot();
|
|
1077
|
+
await leaveSnapshot();
|
|
1042
1078
|
}
|
|
1043
1079
|
}
|
|
1044
1080
|
|
|
@@ -101,6 +101,8 @@ function worktreeFailureText(code, message, details) {
|
|
|
101
101
|
return typeof details.path === 'string' && details.path
|
|
102
102
|
? `This branch is already checked out in ${details.path}.`
|
|
103
103
|
: 'This branch is already checked out in another worktree.';
|
|
104
|
+
case 'WORKTREE_DEFAULT_BRANCH':
|
|
105
|
+
return "The repository's default branch can't be opened in a worktree: the project folder could not switch to it while the worktree exists. Check it out in the project folder, or create a new branch for the worktree.";
|
|
104
106
|
case 'WORKTREE_REMOVAL_INCOMPLETE':
|
|
105
107
|
return 'The worktree could not be removed completely because a file is still in use. Close it and remove the worktree again.';
|
|
106
108
|
case 'WORKTREE_PATH_UNSAFE':
|
|
@@ -162,6 +164,8 @@ function nextStep(code, details, { raw }) {
|
|
|
162
164
|
return 'The workspace changed meanwhile; call again (the workspace is read afresh).';
|
|
163
165
|
case 'WORKTREE_BUSY_JOBS':
|
|
164
166
|
return 'Nothing was changed; try again once the session and its workers are idle.';
|
|
167
|
+
case 'WORKTREE_DEFAULT_BRANCH':
|
|
168
|
+
return 'Nothing was created. Work on a new branch instead (worktree_action:"enter" with branch and create:true), or ask the user to check the default branch out in the project folder.';
|
|
165
169
|
case 'MERGE_CONFLICT':
|
|
166
170
|
return 'Nothing was merged or forced. Resolve the conflict in the worktree (merge the target branch into it there), or ask the user.';
|
|
167
171
|
case 'WORKTREE_DIRTY':
|
|
@@ -316,7 +320,8 @@ async function rawAdd(plan, input, options) {
|
|
|
316
320
|
throw new Error(`git worktree add: ${value} is not supported for managed worktrees`);
|
|
317
321
|
}
|
|
318
322
|
if (ADD_BARE_FLAGS.has(value)) continue;
|
|
319
|
-
if (value.startsWith('-'))
|
|
323
|
+
if (value.startsWith('-'))
|
|
324
|
+
throw new Error(`git worktree add: option ${value} is not supported for managed worktrees`);
|
|
320
325
|
positional.push(value);
|
|
321
326
|
}
|
|
322
327
|
const [path, commitish = null] = positional;
|
|
@@ -329,11 +334,9 @@ async function rawAdd(plan, input, options) {
|
|
|
329
334
|
const txId = txIdOf(options, plan.command);
|
|
330
335
|
const mapped = { mapped: plan.command, requestedPath: resolve(plan.cwd, path) };
|
|
331
336
|
// A detached checkout, or a commit-ish that names no local branch: a snapshot.
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
? commitish
|
|
336
|
-
: null;
|
|
337
|
+
let snapshotCommit = null;
|
|
338
|
+
if (detach) snapshotCommit = commitish ?? 'HEAD';
|
|
339
|
+
else if (!branch && commitish && !(await localBranchExists(plan.cwd, commitish))) snapshotCommit = commitish;
|
|
337
340
|
if (snapshotCommit) {
|
|
338
341
|
const commit = await commitIn(plan.cwd, snapshotCommit);
|
|
339
342
|
if (!commit) throw new Error(`git worktree add: ${snapshotCommit} is not a commit`);
|
|
@@ -436,8 +439,9 @@ async function rawPrune(plan, options) {
|
|
|
436
439
|
const WORKTREE_HELP = Object.freeze({
|
|
437
440
|
add: 'git worktree add [-b <branch>] [--detach] <path> [<commit-ish>]: a managed worktree for the branch (the session stays put), or a read-only snapshot for a detached commit.',
|
|
438
441
|
remove: 'git worktree remove [-f] <path>: the managed removal of that worktree.',
|
|
439
|
-
list:
|
|
440
|
-
prune:
|
|
442
|
+
list: "git worktree list [-v]: managed worktrees plus the repository's other worktrees. --porcelain stays raw git.",
|
|
443
|
+
prune:
|
|
444
|
+
'git worktree prune [-n|--dry-run] [-v]: the managed prune of this repository (clean, merged worktrees no session retains); -n only lists what it would remove.',
|
|
441
445
|
});
|
|
442
446
|
|
|
443
447
|
/** -h/--help before any `--` (the help answers instead of the operation running). */
|
|
@@ -450,7 +454,9 @@ function wantsHelp(args) {
|
|
|
450
454
|
function checkListArgs(args) {
|
|
451
455
|
for (const value of args) {
|
|
452
456
|
if (value === '-v' || value === '--verbose') continue;
|
|
453
|
-
throw new Error(
|
|
457
|
+
throw new Error(
|
|
458
|
+
`git worktree list: ${value.startsWith('-') ? `option ${value} is not supported` : `unexpected argument ${value}`}`
|
|
459
|
+
);
|
|
454
460
|
}
|
|
455
461
|
}
|
|
456
462
|
|
|
@@ -466,7 +472,8 @@ export async function executeRawWorktree(plan, input, options = {}) {
|
|
|
466
472
|
if (sub === 'list' && plan.args.includes('--porcelain')) return null;
|
|
467
473
|
try {
|
|
468
474
|
if (sub === 'list') checkListArgs(plan.args.slice(1));
|
|
469
|
-
if (sub === 'list')
|
|
475
|
+
if (sub === 'list')
|
|
476
|
+
return { text: okJson({ mapped: plan.command, ...(await listRows(options, plan.cwd)) }), failed: false };
|
|
470
477
|
if (sub === 'add') return { text: await rawAdd(plan, input, options), failed: false };
|
|
471
478
|
if (sub === 'remove') return { text: await rawRemove(plan, options), failed: false };
|
|
472
479
|
if (sub === 'prune') return { text: await rawPrune(plan, options), failed: false };
|
|
@@ -479,7 +486,9 @@ export async function executeRawWorktree(plan, input, options = {}) {
|
|
|
479
486
|
};
|
|
480
487
|
}
|
|
481
488
|
return {
|
|
482
|
-
text: fail(
|
|
489
|
+
text: fail(
|
|
490
|
+
`git worktree ${sub || '(no subcommand)'} is not supported; use add, remove, list, prune or action:"worktree"`
|
|
491
|
+
),
|
|
483
492
|
failed: true,
|
|
484
493
|
};
|
|
485
494
|
} catch (error) {
|
|
@@ -529,7 +538,8 @@ export async function executeWorktreeAction(input, workDir, options = {}) {
|
|
|
529
538
|
if (problem) return fail(problem);
|
|
530
539
|
const action = input.worktree_action;
|
|
531
540
|
try {
|
|
532
|
-
if (action === 'list')
|
|
541
|
+
if (action === 'list')
|
|
542
|
+
return okJson({ worktree_action: action, ...(await listRows(options, resolve(workDir || process.cwd()))) });
|
|
533
543
|
const host = leadHost(options, `git worktree_action ${action}`);
|
|
534
544
|
const sessionId = input.session_id?.trim() || null;
|
|
535
545
|
const request = {
|
|
@@ -545,7 +555,9 @@ export async function executeWorktreeAction(input, workDir, options = {}) {
|
|
|
545
555
|
}
|
|
546
556
|
: {}),
|
|
547
557
|
...(action === 'remove' ? { force: input.force === true } : {}),
|
|
548
|
-
...(action === 'prune'
|
|
558
|
+
...(action === 'prune'
|
|
559
|
+
? { repoCommonDir: (await repositoryAt(resolve(workDir || process.cwd())))?.repoCommonDir ?? null }
|
|
560
|
+
: {}),
|
|
549
561
|
txId: txIdOf(options, action),
|
|
550
562
|
};
|
|
551
563
|
const result = await runOn(host, request, options);
|
|
@@ -8,11 +8,15 @@ import {
|
|
|
8
8
|
// A shared scan's outcome belongs to every subscriber, not only the caller
|
|
9
9
|
// whose computation won admission. Persisted cache hits contain safe text.
|
|
10
10
|
export async function runScopedSearchInFlight(key, compute, options, outcome) {
|
|
11
|
-
const settled = await runResultCacheInFlight(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
const settled = await runResultCacheInFlight(
|
|
12
|
+
key,
|
|
13
|
+
async ({ signal }) => {
|
|
14
|
+
const scopedCacheOutcome = createScopedCacheOutcome();
|
|
15
|
+
const result = await compute({ signal, scopedCacheOutcome });
|
|
16
|
+
return { result, scopedCacheOutcome };
|
|
17
|
+
},
|
|
18
|
+
options
|
|
19
|
+
);
|
|
16
20
|
if (typeof settled === 'string') return settled;
|
|
17
21
|
if (settled.scopedCacheOutcome.complete === false) markScopedCacheIncomplete(outcome);
|
|
18
22
|
if (settled.scopedCacheOutcome.cacheSafe === false) markScopedCacheUnsafe(outcome);
|
|
@@ -27,24 +27,40 @@ import { join } from 'node:path';
|
|
|
27
27
|
import { holdsNoData, writeJsonAtomicAsync } from '../../../../../shared/atomic-file.mjs';
|
|
28
28
|
import { isPidAlive } from '../../../../../shared/pid-liveness.mjs';
|
|
29
29
|
import { displayShellCommand } from '../../../../../shared/shell-display.mjs';
|
|
30
|
-
import {
|
|
30
|
+
import { tryAdmitWorkspaceActivityAsync } from '../../../../../shared/worktrees/activity-gate.mjs';
|
|
31
31
|
import { worktreeError } from '../../../../../shared/worktrees/contract.mjs';
|
|
32
32
|
import { workspaceSees } from '../../../../../shared/worktrees/workspace-visibility.mjs';
|
|
33
33
|
|
|
34
34
|
const workspaceLeases = new Map();
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Calls both releases in order; settles once both did. Never goes unhandled
|
|
38
|
+
* (an asynchronous release rejects only when workspace admission stopped).
|
|
39
|
+
*/
|
|
40
|
+
export function bothReleased(first, second) {
|
|
41
|
+
const both = Promise.all([first(), second()]);
|
|
42
|
+
both.catch(() => {});
|
|
43
|
+
return both;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* A workspace grant requested now, for a release handle needed before it is
|
|
48
|
+
* answered: the release, whenever called, follows the grant (and releases
|
|
49
|
+
* nothing if it was refused or failed).
|
|
50
|
+
*/
|
|
51
|
+
export function pendingWorkspaceAdmission(granting) {
|
|
52
|
+
granting.catch(() => {});
|
|
53
|
+
return () =>
|
|
54
|
+
granting.then(
|
|
55
|
+
(leave) => leave?.(),
|
|
56
|
+
() => {}
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
36
60
|
/** Transfer a foreground reader to a surviving-descendant task without a lease gap. */
|
|
37
61
|
export function adoptShellWorkspaceAdmission(jobId, leave) {
|
|
38
62
|
const prior = workspaceLeases.get(jobId);
|
|
39
|
-
workspaceLeases.set(
|
|
40
|
-
jobId,
|
|
41
|
-
prior
|
|
42
|
-
? () => {
|
|
43
|
-
prior();
|
|
44
|
-
leave();
|
|
45
|
-
}
|
|
46
|
-
: leave
|
|
47
|
-
);
|
|
63
|
+
workspaceLeases.set(jobId, prior ? () => bothReleased(prior, leave) : leave);
|
|
48
64
|
}
|
|
49
65
|
|
|
50
66
|
// A record whose owner process is gone is garbage. Age alone never deletes a
|
|
@@ -88,8 +104,13 @@ function validJobId(jobId) {
|
|
|
88
104
|
|
|
89
105
|
function terminalRecord(base, detail) {
|
|
90
106
|
const finishedAt = detail?.finishedAt || new Date().toISOString();
|
|
107
|
+
// A completed record no longer claims an unconfirmed termination: it is
|
|
108
|
+
// written once the processes are confirmed gone, or explicitly released.
|
|
109
|
+
// A completed record no longer claims an unconfirmed termination: it is
|
|
110
|
+
// written once the processes are confirmed gone, or explicitly released.
|
|
111
|
+
const { terminationUnconfirmed: _held, ...open } = base || {};
|
|
91
112
|
return {
|
|
92
|
-
...
|
|
113
|
+
...open,
|
|
93
114
|
jobId: String(detail?.jobId || base?.jobId || ''),
|
|
94
115
|
kind: 'bash',
|
|
95
116
|
status: String(detail?.status || 'failed'),
|
|
@@ -172,7 +193,14 @@ async function sweepOrphanRecords(dir) {
|
|
|
172
193
|
}
|
|
173
194
|
}
|
|
174
195
|
|
|
175
|
-
/**
|
|
196
|
+
/**
|
|
197
|
+
* Publish the record for a job that has just started or been promoted. Its
|
|
198
|
+
* workspace lease (under the job's pid) is requested at the call and adopted
|
|
199
|
+
* under the job id at once, so a later release of the job — or of a
|
|
200
|
+
* predecessor's lease — is ordered after it. Resolves once the lease is in
|
|
201
|
+
* both ledger copies; rejects (and writes no record) when it is refused or
|
|
202
|
+
* cannot be written. The returned promise never goes unhandled.
|
|
203
|
+
*/
|
|
176
204
|
export function publishShellJobRecord(
|
|
177
205
|
task,
|
|
178
206
|
{
|
|
@@ -184,16 +212,20 @@ export function publishShellJobRecord(
|
|
|
184
212
|
} = {}
|
|
185
213
|
) {
|
|
186
214
|
const jobId = String(task?.jobId || '').trim();
|
|
187
|
-
if (!jobId) return;
|
|
215
|
+
if (!jobId) return Promise.resolve();
|
|
216
|
+
let admitted = Promise.resolve();
|
|
188
217
|
if (task?.cwd) {
|
|
189
|
-
const
|
|
218
|
+
const granting = tryAdmitWorkspaceActivityAsync(ownerSessionId || jobId, task.cwd, {
|
|
190
219
|
pid: Number(task.pid) || process.pid,
|
|
191
220
|
kind: 'command',
|
|
192
221
|
});
|
|
193
|
-
|
|
222
|
+
admitted = granting.then((leave) => {
|
|
223
|
+
if (!leave) throw worktreeError('WORKTREE_BUSY_JOBS', 'The command folder is being managed.');
|
|
224
|
+
});
|
|
225
|
+
admitted.catch(() => {});
|
|
194
226
|
// A descendant handoff can reuse the job id with a different live pid.
|
|
195
|
-
//
|
|
196
|
-
adoptShellWorkspaceAdmission(jobId,
|
|
227
|
+
// Its reader is requested before any predecessor's admission is released.
|
|
228
|
+
adoptShellWorkspaceAdmission(jobId, pendingWorkspaceAdmission(granting));
|
|
197
229
|
}
|
|
198
230
|
const ownerPid = Number(clientHostPid ?? task?.clientHostPid) || process.pid;
|
|
199
231
|
const dir = jobsDir();
|
|
@@ -202,6 +234,8 @@ export function publishShellJobRecord(
|
|
|
202
234
|
paths.set(jobId, [jsonPath, ownerPath]);
|
|
203
235
|
void enqueue(jobId, async () => {
|
|
204
236
|
try {
|
|
237
|
+
// No record for a job whose workspace lease was not granted.
|
|
238
|
+
await admitted;
|
|
205
239
|
await mkdir(dir, { recursive: true });
|
|
206
240
|
if (!sweepStarted) {
|
|
207
241
|
sweepStarted = true;
|
|
@@ -244,6 +278,7 @@ export function publishShellJobRecord(
|
|
|
244
278
|
/* the record is presentation only; never fail a job for it */
|
|
245
279
|
}
|
|
246
280
|
});
|
|
281
|
+
return admitted;
|
|
247
282
|
}
|
|
248
283
|
|
|
249
284
|
/** Preserve a bounded terminal snapshot for manual recovery after restart. */
|
|
@@ -335,8 +370,9 @@ export function releaseShellJobWorkspace(jobId) {
|
|
|
335
370
|
const key = String(jobId || '').trim();
|
|
336
371
|
const leave = workspaceLeases.get(key);
|
|
337
372
|
if (!leave) return;
|
|
338
|
-
leave();
|
|
373
|
+
const released = leave();
|
|
339
374
|
if (workspaceLeases.get(key) === leave) workspaceLeases.delete(key);
|
|
375
|
+
return released;
|
|
340
376
|
}
|
|
341
377
|
|
|
342
378
|
/** Flag a still-open job record as "termination unconfirmed" for the readouts. */
|
|
@@ -390,8 +426,10 @@ export function completeShellJobRecord(jobId, detail) {
|
|
|
390
426
|
// Callers complete a record only once its processes are confirmed gone
|
|
391
427
|
// (or explicitly released): the workspace admission follows that, not
|
|
392
428
|
// the record write, so a failed write cannot strand it with no handle.
|
|
393
|
-
leaveWorkspace?.();
|
|
429
|
+
const released = leaveWorkspace?.();
|
|
394
430
|
if (workspaceLeases.get(key) === leaveWorkspace) workspaceLeases.delete(key);
|
|
431
|
+
// Fails only when workspace admission stopped (reported there), which keeps the folder held.
|
|
432
|
+
await Promise.resolve(released).catch(() => {});
|
|
395
433
|
}
|
|
396
434
|
await removePaths(ownerPaths);
|
|
397
435
|
paths.set(key, [jsonPath, donePath]);
|
|
@@ -486,6 +524,6 @@ export function retireShellJobRecord(jobId) {
|
|
|
486
524
|
records.delete(key);
|
|
487
525
|
incarnations.delete(key);
|
|
488
526
|
await removePaths(list);
|
|
489
|
-
leaveWorkspace?.();
|
|
527
|
+
await leaveWorkspace?.();
|
|
490
528
|
});
|
|
491
529
|
}
|
|
@@ -53,7 +53,13 @@ export async function streamRangeResult(ctx, { source, fileHandle, prefixBuffer
|
|
|
53
53
|
res.firstEmitted && res.lastEmitted ? [{ startLine: res.firstEmitted, endLine: res.lastEmitted }] : [];
|
|
54
54
|
const snapshotMeta = { source, ranges, rangeHashes: _rangeHashesFromRenderedReadText(res.text, ranges) };
|
|
55
55
|
if (!res.readSnapshotStat) return res.text;
|
|
56
|
-
return await commitStreamResult(
|
|
56
|
+
return await commitStreamResult(
|
|
57
|
+
{ ...ctx, st: res.readSnapshotStat },
|
|
58
|
+
res.text,
|
|
59
|
+
snapshotMeta,
|
|
60
|
+
res.prefixHash,
|
|
61
|
+
helpers
|
|
62
|
+
);
|
|
57
63
|
} catch (err) {
|
|
58
64
|
return `Error: ${normalizeErrorMessage(err instanceof Error ? err.message : String(err))}`;
|
|
59
65
|
}
|
|
@@ -137,9 +137,12 @@ async function readRangeFromHandle(fh, fullPath, offset, limit, stHint, hooks) {
|
|
|
137
137
|
}
|
|
138
138
|
if (!stop) lines.finishTail();
|
|
139
139
|
let readSnapshotStat = null;
|
|
140
|
-
if (
|
|
141
|
-
|
|
142
|
-
|
|
140
|
+
if (
|
|
141
|
+
!(await publishReadRangeIndex(rangeIndex, fh, null, checkDeadline, (version) => {
|
|
142
|
+
readSnapshotStat = version;
|
|
143
|
+
}))
|
|
144
|
+
)
|
|
145
|
+
checkDeadline();
|
|
143
146
|
|
|
144
147
|
ioTraceDone('read_range_stream', traceStart, {
|
|
145
148
|
pathHash: hashText(fullPath).slice(0, 12),
|
|
@@ -41,7 +41,7 @@ async function estimateTaskBytes(entry, workDir) {
|
|
|
41
41
|
const st = await stat(resolvePath(workDir || '.', String(entry?.path || ''))).catch(() => null);
|
|
42
42
|
if (!st?.isFile()) return Infinity;
|
|
43
43
|
const lines = Math.max(1, st.size / AVG_LINE_BYTES);
|
|
44
|
-
let need = st.size + st.size / MIN_LINE_BYTES * LINE_PREFIX_BYTES;
|
|
44
|
+
let need = st.size + (st.size / MIN_LINE_BYTES) * LINE_PREFIX_BYTES;
|
|
45
45
|
// A coalesced entry reads its whole union window, not only its own slot.
|
|
46
46
|
const limit = Number(readEntryCoalescedDiskWindow(entry)?.limit ?? entry?.limit);
|
|
47
47
|
if (Number.isFinite(limit) && limit > 0) need *= Math.min(1, limit / lines);
|
|
@@ -85,10 +85,14 @@ export async function runBatchReadSnapshotPublication(executeChildBuiltinTool, h
|
|
|
85
85
|
// A numbered row may end halfway through its content at the byte cap.
|
|
86
86
|
// Only this slot's producer can certify complete lines; another read of
|
|
87
87
|
// the same path must not authorize hashing this slot's partial text.
|
|
88
|
-
return mergeReadRanges(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
return mergeReadRanges(
|
|
89
|
+
ranges.flatMap((range) =>
|
|
90
|
+
(observation?.ranges ?? []).map((complete) => ({
|
|
91
|
+
startLine: Math.max(range.startLine, complete.startLine),
|
|
92
|
+
endLine: Math.min(range.endLine, complete.endLine),
|
|
93
|
+
}))
|
|
94
|
+
)
|
|
95
|
+
);
|
|
92
96
|
},
|
|
93
97
|
_recordReadSnapshot: (fullPath, _st, scope, meta) => {
|
|
94
98
|
corrections.set(fullPath, { scope: scope ?? null, meta });
|
|
@@ -104,22 +108,29 @@ export async function runBatchReadSnapshotPublication(executeChildBuiltinTool, h
|
|
|
104
108
|
}
|
|
105
109
|
for (const [fullPath, correction] of corrections) {
|
|
106
110
|
const delivered = tasks.filter((task) => task.fullPath === fullPath && hasRenderedLines(task.body));
|
|
107
|
-
const observations = delivered.map((task) =>
|
|
108
|
-
(record) => record.fullPath === fullPath && record.scope === correction.scope
|
|
109
|
-
)
|
|
111
|
+
const observations = delivered.map((task) =>
|
|
112
|
+
task.records.findLast((record) => record.fullPath === fullPath && record.scope === correction.scope)
|
|
113
|
+
);
|
|
110
114
|
// Never combine different versions or bless stale/missing observations.
|
|
111
115
|
// The eventual recorder rechecks the retained lease after all awaits.
|
|
112
|
-
if (
|
|
113
|
-
|
|
114
|
-
|
|
116
|
+
if (
|
|
117
|
+
observations.length &&
|
|
118
|
+
observations.every(
|
|
119
|
+
(record) => record?.isCurrent() && sameFileVersion(record.identity, observations[0].identity)
|
|
120
|
+
)
|
|
121
|
+
) {
|
|
115
122
|
observations[0].publish(correction.meta);
|
|
116
123
|
}
|
|
117
124
|
}
|
|
118
125
|
// Rich media/binary results have no line slices. Preserve their original
|
|
119
126
|
// evidence, still under the producer's lease rather than the batch's.
|
|
120
127
|
for (const task of tasks) {
|
|
121
|
-
if (
|
|
122
|
-
|
|
128
|
+
if (
|
|
129
|
+
hasRenderedLines(task.body) ||
|
|
130
|
+
task.body?.isError === true ||
|
|
131
|
+
(typeof task.body === 'string' && helpers.classifyResultKind(task.body) === 'error')
|
|
132
|
+
)
|
|
133
|
+
continue;
|
|
123
134
|
for (const record of task.records) {
|
|
124
135
|
if (!corrections.has(record.fullPath)) record.publish();
|
|
125
136
|
}
|
|
@@ -69,7 +69,12 @@ async function rawRangeHashes(fullPath, mergedRanges, { _hashText }) {
|
|
|
69
69
|
|
|
70
70
|
export async function recordSlicedBatchSnapshots(orderedResults, workDir, readStateScope, helpers) {
|
|
71
71
|
const { _mergeReadRanges, _recordReadSnapshot } = helpers;
|
|
72
|
-
const { exactRangesByPath, rangeHashesByPath } = deliveredRangesByPath(
|
|
72
|
+
const { exactRangesByPath, rangeHashesByPath } = deliveredRangesByPath(
|
|
73
|
+
orderedResults,
|
|
74
|
+
workDir,
|
|
75
|
+
readStateScope,
|
|
76
|
+
helpers
|
|
77
|
+
);
|
|
73
78
|
for (const [fullPath, ranges] of exactRangesByPath) {
|
|
74
79
|
const mergedRanges = _mergeReadRanges(ranges);
|
|
75
80
|
let rangeHashes = rangeHashesByPath.get(fullPath) || [];
|
|
@@ -112,14 +112,7 @@ export async function executeReadTool(args, ...rest) {
|
|
|
112
112
|
return `${out}\n[skipped ${skipped.length} more file(s) over the per-call limit: ${skipped.join(', ')} — read them in another call]`;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
async function executeReadToolBody(
|
|
116
|
-
args,
|
|
117
|
-
workDir,
|
|
118
|
-
readStateScope,
|
|
119
|
-
executeChildBuiltinTool,
|
|
120
|
-
options = {},
|
|
121
|
-
helpers = {}
|
|
122
|
-
) {
|
|
115
|
+
async function executeReadToolBody(args, workDir, readStateScope, executeChildBuiltinTool, options = {}, helpers = {}) {
|
|
123
116
|
const { normalizeInputPath, normaliseReadLineWindowArgs } = helpers;
|
|
124
117
|
applyFilePathAlias(args);
|
|
125
118
|
args.path = coerceReadFamilyPathArg(args.path);
|