mixdog 1.2.3 → 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/scripts/gate-local.mjs +6 -4
- package/scripts/lib/gate-scheduler.mjs +29 -11
- 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 +6 -1
- package/src/defaults/skills/image/SKILL.md +21 -23
- package/src/lib/keychain-cjs.cjs +13 -11
- package/src/rules/agent/AGENT.md +7 -5
- package/src/rules/lead/LEAD.md +7 -9
- 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 +136 -196
- 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/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 +478 -251
- 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/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
|
@@ -12,9 +12,16 @@
|
|
|
12
12
|
// adapter expects — the caller (builtin.mjs default: case) falls back to
|
|
13
13
|
// the existing EXTERNAL_TOOL_REDIRECTS guidance message in that case.
|
|
14
14
|
import { readFileSync, mkdirSync, existsSync, lstatSync, realpathSync, statSync } from 'node:fs';
|
|
15
|
-
import { dirname } from 'node:path';
|
|
15
|
+
import { dirname, relative, resolve } from 'node:path';
|
|
16
16
|
import { atomicWrite, symlinkWriteTarget } from './atomic-write.mjs';
|
|
17
|
-
import { fileVersion } from './file-version.mjs';
|
|
17
|
+
import { fileVersion, sameFileVersion } from './file-version.mjs';
|
|
18
|
+
import { withBuiltinPathLocks } from './path-locks.mjs';
|
|
19
|
+
import { withAdvisoryLocks } from './advisory-lock.mjs';
|
|
20
|
+
import { canonicalCachePath } from './read-range-index.mjs';
|
|
21
|
+
import { readSourceWindows } from './read-source-windows.mjs';
|
|
22
|
+
import { isReadLineClipped } from './read-formatting.mjs';
|
|
23
|
+
import { readSourceWindow } from '../../../../shared/read-row-numbers.mjs';
|
|
24
|
+
import { cursorNativeCall, releaseCursorNativeCall } from '../../providers/cursor-native-context.mjs';
|
|
18
25
|
import { assertPathsReachable } from './fs-reachability.mjs';
|
|
19
26
|
import {
|
|
20
27
|
normalizeInputPath,
|
|
@@ -30,12 +37,12 @@ import {
|
|
|
30
37
|
isBlockedDevicePath,
|
|
31
38
|
isSpecialFileStat,
|
|
32
39
|
} from './device-paths.mjs';
|
|
33
|
-
import { recordReadSnapshot } from './read-snapshot-runtime.mjs';
|
|
40
|
+
import { recordReadSnapshot, getReadSnapshot } from './read-snapshot-runtime.mjs';
|
|
34
41
|
import { executeBashTool } from './bash-tool.mjs';
|
|
35
42
|
import { nativeEditSessionSatisfiesContract, runServerEdit } from '../patch/native-server.mjs';
|
|
36
43
|
import { decodeValidUtf8OrNull, detectPatchTargetCodec, nearestPatchLineMatch } from '../patch/matcher.mjs';
|
|
37
44
|
import { hashText } from './hash-utils.mjs';
|
|
38
|
-
import { invalidateBuiltinResultCache } from './cache-layers.mjs';
|
|
45
|
+
import { invalidateBuiltinResultCache, rawContentCacheGet } from './cache-layers.mjs';
|
|
39
46
|
import { markCodeGraphDirtyPaths } from '../code-graph-state.mjs';
|
|
40
47
|
import { reviewFileContent } from '../../../../shared/bounded-file-read.mjs';
|
|
41
48
|
|
|
@@ -515,13 +522,14 @@ function readEditTarget(fullPath) {
|
|
|
515
522
|
let statBefore = {};
|
|
516
523
|
let content;
|
|
517
524
|
let fileEnc;
|
|
525
|
+
let rawBuf;
|
|
518
526
|
try {
|
|
519
527
|
try {
|
|
520
528
|
statBefore = { ...fileVersion(statSync(fullPath)) };
|
|
521
529
|
} catch {
|
|
522
530
|
/* readFileSync below surfaces the real error */
|
|
523
531
|
}
|
|
524
|
-
|
|
532
|
+
rawBuf = readFileSync(fullPath);
|
|
525
533
|
fileEnc = detectPatchTargetCodec(rawBuf);
|
|
526
534
|
content = fileEnc.certain ? decodeEditBuffer(rawBuf, fileEnc) : null;
|
|
527
535
|
} catch (err) {
|
|
@@ -536,7 +544,7 @@ function readEditTarget(fullPath) {
|
|
|
536
544
|
' Convert the encoding first.',
|
|
537
545
|
};
|
|
538
546
|
}
|
|
539
|
-
return { content, fileEnc, statBefore };
|
|
547
|
+
return { content, fileEnc, statBefore, rawBuf };
|
|
540
548
|
}
|
|
541
549
|
|
|
542
550
|
/**
|
|
@@ -759,7 +767,7 @@ function resolveStrReplaceArgs(args) {
|
|
|
759
767
|
return out;
|
|
760
768
|
}
|
|
761
769
|
|
|
762
|
-
async function adaptStrReplace(args, workDir, options) {
|
|
770
|
+
async function adaptStrReplace(args, workDir, options, resolvedTarget = null) {
|
|
763
771
|
const resolved = resolveStrReplaceArgs(args);
|
|
764
772
|
if (resolved.error) return resolved.error;
|
|
765
773
|
let oldStr = resolved.old_string;
|
|
@@ -769,7 +777,16 @@ async function adaptStrReplace(args, workDir, options) {
|
|
|
769
777
|
}
|
|
770
778
|
if (oldStr === newStr) return SAME_STRINGS_ERROR;
|
|
771
779
|
const replaceAll = args?.replace_all === true || String(args?.replace_all || '').toLowerCase() === 'true';
|
|
772
|
-
|
|
780
|
+
if (!resolvedTarget) {
|
|
781
|
+
return withEditTargetLock(
|
|
782
|
+
args,
|
|
783
|
+
workDir,
|
|
784
|
+
options,
|
|
785
|
+
(target) => adaptStrReplace(args, workDir, options, target),
|
|
786
|
+
oldStr.length === 0
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
const target = resolvedTarget || (await resolveTargetPath(args, workDir));
|
|
773
790
|
if (!target) return null;
|
|
774
791
|
if (target.error) return target.error;
|
|
775
792
|
const fullPath = target.full;
|
|
@@ -822,10 +839,13 @@ async function adaptStrReplace(args, workDir, options) {
|
|
|
822
839
|
return applyEditNative(edit, oldStr, newStr, editPlan, replaceAll);
|
|
823
840
|
}
|
|
824
841
|
|
|
825
|
-
async function adaptWrite(args, workDir, options) {
|
|
842
|
+
async function adaptWrite(args, workDir, options, resolvedTarget = null) {
|
|
826
843
|
const contents = args?.contents ?? args?.content ?? args?.file_text;
|
|
827
844
|
if (typeof contents !== 'string') return null;
|
|
828
|
-
|
|
845
|
+
if (!resolvedTarget) {
|
|
846
|
+
return withEditTargetLock(args, workDir, options, (target) => adaptWrite(args, workDir, options, target));
|
|
847
|
+
}
|
|
848
|
+
const target = resolvedTarget || (await resolveTargetPath(args, workDir));
|
|
829
849
|
if (!target) return null;
|
|
830
850
|
if (target.error) return target.error;
|
|
831
851
|
const fullPath = target.full;
|
|
@@ -849,6 +869,180 @@ async function adaptBash(key, args, workDir, options) {
|
|
|
849
869
|
return executeBashTool(shellArgs, workDir, options);
|
|
850
870
|
}
|
|
851
871
|
|
|
872
|
+
async function withEditTargetLock(args, workDir, options, run, allowCreate = true) {
|
|
873
|
+
if (options?.signal?.aborted) throw options.signal.reason || new Error('Edit cancelled');
|
|
874
|
+
const target = await resolveTargetPath(args, workDir);
|
|
875
|
+
if (!target || target.error) return target?.error ?? null;
|
|
876
|
+
if (!allowCreate && !existsSync(target.full)) {
|
|
877
|
+
return `Error: cannot read ${target.full} (target is missing or inaccessible)`;
|
|
878
|
+
}
|
|
879
|
+
const resolveReal = () => {
|
|
880
|
+
const nearest = realpathNearestExisting(target.full);
|
|
881
|
+
return nearest ? resolve(nearest.real, relative(nearest.probe, target.full)) : null;
|
|
882
|
+
};
|
|
883
|
+
const real = resolveReal();
|
|
884
|
+
if (!real) return 'Error: cannot resolve edit target for locking';
|
|
885
|
+
return withBuiltinPathLocks([target.full, real], () =>
|
|
886
|
+
withAdvisoryLocks([real], async () => {
|
|
887
|
+
if (options?.signal?.aborted) throw options.signal.reason || new Error('Edit cancelled');
|
|
888
|
+
if (resolveReal() !== real) return 'Error: edit target changed while acquiring its lock';
|
|
889
|
+
return run(target);
|
|
890
|
+
})
|
|
891
|
+
);
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
const NATIVE_SNAPSHOT_MAX_BYTES = 1024 * 1024;
|
|
895
|
+
|
|
896
|
+
// Structured truncation report for a returned read window, taken from the raw
|
|
897
|
+
// source lines of that window with the read display's own clip predicate. A
|
|
898
|
+
// window that cannot be verified is reported clipped (fail closed).
|
|
899
|
+
async function nativeReadWindowReport(fullPath, source) {
|
|
900
|
+
if (source.startLine == null || source.endLine < source.startLine) return { lineClipped: false };
|
|
901
|
+
try {
|
|
902
|
+
const rows = await readSourceWindows(fullPath, [{ start: source.startLine, end: source.endLine }]);
|
|
903
|
+
return { lineClipped: [...rows.values()].some((row) => isReadLineClipped(row)) };
|
|
904
|
+
} catch {
|
|
905
|
+
return { lineClipped: true };
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
/** Clip report of an ordinary read result, for a Cursor read the daemon runs
|
|
910
|
+
* for a remote/proxied provider: `{ lineClipped: true }`, or null when the
|
|
911
|
+
* result is no source window or none of its lines were clipped. */
|
|
912
|
+
export async function remoteReadWindowReport(args, workDir, result) {
|
|
913
|
+
const source = readSourceWindow(typeof result === 'string' ? result : '');
|
|
914
|
+
if (!source) return null;
|
|
915
|
+
const target = await resolveTargetPath(args, workDir);
|
|
916
|
+
const report = !target || target.error ? { lineClipped: true } : await nativeReadWindowReport(target.full, source);
|
|
917
|
+
return report.lineClipped ? report : null;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
async function captureNativeRead(context, args, workDir, options, result) {
|
|
921
|
+
const pending = context.pending;
|
|
922
|
+
delete pending.nativeSnapshot;
|
|
923
|
+
delete pending.nativeReadReply;
|
|
924
|
+
delete pending.nativeReadWindow;
|
|
925
|
+
const target = await resolveTargetPath(args, workDir);
|
|
926
|
+
if (!target || target.error) return;
|
|
927
|
+
let stat;
|
|
928
|
+
try {
|
|
929
|
+
stat = statSync(target.full);
|
|
930
|
+
} catch (error) {
|
|
931
|
+
if (error.code === 'ENOENT') pending.nativeReadReply = { fileNotFound: { path: pending.native.args.path } };
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
934
|
+
const source = readSourceWindow(typeof result === 'string' ? result : '');
|
|
935
|
+
if (source) pending.nativeReadWindow = await nativeReadWindowReport(target.full, source);
|
|
936
|
+
if (
|
|
937
|
+
!source ||
|
|
938
|
+
source.truncated ||
|
|
939
|
+
source.startLine !== 1 ||
|
|
940
|
+
args.offset ||
|
|
941
|
+
args.limit ||
|
|
942
|
+
stat.size > NATIVE_SNAPSHOT_MAX_BYTES ||
|
|
943
|
+
!stat.isFile()
|
|
944
|
+
)
|
|
945
|
+
return;
|
|
946
|
+
const observed = getReadSnapshot(target.full, options?.readStateScope ?? options?.sessionId ?? null);
|
|
947
|
+
if (!observed?.bodyDelivered || !sameFileVersion(observed, stat)) return;
|
|
948
|
+
const cached = rawContentCacheGet(target.full, stat);
|
|
949
|
+
if (!cached) return;
|
|
950
|
+
const bytes = Buffer.from(cached);
|
|
951
|
+
const text = bytes.toString('utf8');
|
|
952
|
+
if (text.includes('\0') || !Buffer.from(text, 'utf8').equals(bytes)) return;
|
|
953
|
+
const displayed = text
|
|
954
|
+
.replace(/^\uFEFF/, '')
|
|
955
|
+
.replace(/\r\n/g, '\n')
|
|
956
|
+
.replace(/\n$/, '');
|
|
957
|
+
if (displayed !== source.content) return;
|
|
958
|
+
const realPath = canonicalCachePath(realpathSync(target.full));
|
|
959
|
+
if (!sameFileVersion(stat, statSync(target.full))) return;
|
|
960
|
+
pending.nativeSnapshot = {
|
|
961
|
+
bytes,
|
|
962
|
+
text,
|
|
963
|
+
version: fileVersion(stat),
|
|
964
|
+
realPath,
|
|
965
|
+
path: canonicalCachePath(target.full),
|
|
966
|
+
delivered: false,
|
|
967
|
+
};
|
|
968
|
+
pending.nativeReadReply = {
|
|
969
|
+
success: {
|
|
970
|
+
path: pending.native.args.path,
|
|
971
|
+
content: text,
|
|
972
|
+
totalLines: source.totalLines,
|
|
973
|
+
fileSize: bytes.length,
|
|
974
|
+
truncated: false,
|
|
975
|
+
rangeApplied: false,
|
|
976
|
+
},
|
|
977
|
+
};
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
async function replaceNativeSnapshot(context, args, workDir, options) {
|
|
981
|
+
return withEditTargetLock(args, workDir, options, async (target) => {
|
|
982
|
+
const parent = context.pending.native.args.toolCallId;
|
|
983
|
+
if (typeof parent !== 'string' || parent.length === 0) {
|
|
984
|
+
return adaptStrReplace(args, workDir, options, target);
|
|
985
|
+
}
|
|
986
|
+
const path = canonicalCachePath(target.full);
|
|
987
|
+
const reads = [...context.executions.values()].filter(
|
|
988
|
+
(entry) =>
|
|
989
|
+
entry.native?.resultType === 'readResult' &&
|
|
990
|
+
entry.native.args.toolCallId === parent &&
|
|
991
|
+
entry.nativeSnapshot?.path === path
|
|
992
|
+
);
|
|
993
|
+
// Creating a missing/empty file retains the normal create-only contract.
|
|
994
|
+
if (reads.length === 0) return adaptStrReplace(args, workDir, options, target);
|
|
995
|
+
if (reads.length !== 1 || !reads[0].nativeSnapshot.delivered) {
|
|
996
|
+
return 'Error: native edit has no unambiguous, delivered full-file snapshot; use MCP edit with explicit old_string';
|
|
997
|
+
}
|
|
998
|
+
const snapshot = reads[0].nativeSnapshot;
|
|
999
|
+
const read = readEditTarget(target.full);
|
|
1000
|
+
if (read.error) return read.error;
|
|
1001
|
+
if (
|
|
1002
|
+
canonicalCachePath(realpathSync(target.full)) !== snapshot.realPath ||
|
|
1003
|
+
!sameFileVersion(snapshot.version, read.statBefore) ||
|
|
1004
|
+
!read.rawBuf.equals(snapshot.bytes)
|
|
1005
|
+
) {
|
|
1006
|
+
return 'Error: native edit target changed since its read; no replacement was written';
|
|
1007
|
+
}
|
|
1008
|
+
let after = args.new_string;
|
|
1009
|
+
if (typeof after !== 'string') return 'Error: native replacement requires text';
|
|
1010
|
+
if (read.fileEnc.bomLen && after.startsWith('\uFEFF')) after = after.slice(1);
|
|
1011
|
+
const lineEndings = new Set(read.content.match(/\r\n|\r|\n/g) || []);
|
|
1012
|
+
if (lineEndings.size > 1) {
|
|
1013
|
+
return 'Error: native full-file replacement cannot preserve mixed line endings; use MCP edit with explicit old_string';
|
|
1014
|
+
}
|
|
1015
|
+
if (lineEndings.size === 1) after = convertTextEol(after, lineEndings.values().next().value);
|
|
1016
|
+
const edit = { fullPath: target.full, workDir, options, ...read };
|
|
1017
|
+
const bytes = encodeEditContent(after, read.fileEnc);
|
|
1018
|
+
const stale = await commitEdit(edit, {
|
|
1019
|
+
bytes,
|
|
1020
|
+
after,
|
|
1021
|
+
staleMessage: STALE_DURING_EDIT,
|
|
1022
|
+
});
|
|
1023
|
+
if (!stale) context.pending.nativeWrittenBytes = bytes.length;
|
|
1024
|
+
return stale ?? `Updated ${editDisplayPath(edit)} (conditional native replacement)`;
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
// Called only after normal runtime permission checks. The capability is tied to
|
|
1029
|
+
// the streamed execution, not to a flag supplied in model arguments.
|
|
1030
|
+
export async function executeCursorNativeBuiltin(name, args, workDir, options, execute) {
|
|
1031
|
+
const context = cursorNativeCall(options.sessionId, options.toolCallId, name, args);
|
|
1032
|
+
if (!context) return execute(name, args, workDir, options);
|
|
1033
|
+
if (name === 'read') {
|
|
1034
|
+
const result = await execute(name, args, workDir, { ...options, suppressReadUnchangedStub: true });
|
|
1035
|
+
await captureNativeRead(context, args, workDir, options, result);
|
|
1036
|
+
return result;
|
|
1037
|
+
}
|
|
1038
|
+
releaseCursorNativeCall(context.pending);
|
|
1039
|
+
try {
|
|
1040
|
+
return await replaceNativeSnapshot(context, args, workDir, options);
|
|
1041
|
+
} catch (error) {
|
|
1042
|
+
return `Error: native edit failed (${error?.message || error})`;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
|
|
852
1046
|
export async function tryExecuteExternalToolAdapter(name, args, workDir, options) {
|
|
853
1047
|
if (typeof name !== 'string' || !name) return null;
|
|
854
1048
|
if (!args || typeof args !== 'object' || Array.isArray(args)) return null;
|
|
@@ -74,7 +74,7 @@ export const GIT_TOOL_DEF = {
|
|
|
74
74
|
compressible: true,
|
|
75
75
|
},
|
|
76
76
|
description:
|
|
77
|
-
'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
|
|
77
|
+
'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.',
|
|
78
78
|
inputSchema: {
|
|
79
79
|
type: 'object',
|
|
80
80
|
properties: {
|
|
@@ -142,47 +142,149 @@ function outputLines(value) {
|
|
|
142
142
|
return String(value || '').match(/[^\n]*\n|[^\n]+$/g) || [];
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
|
|
145
|
+
// A line cap alone lets a few very long lines (minified files, lockfiles)
|
|
146
|
+
// through, so each command also gets a character budget, and a command array
|
|
147
|
+
// shares one. A cut always states what was omitted and how to page.
|
|
148
|
+
const COMMAND_CHAR_BUDGET = 12_000;
|
|
149
|
+
const ARRAY_CHAR_BUDGET = 24_000;
|
|
150
|
+
const MIN_COMMAND_CHARS = 1_000;
|
|
151
|
+
const LARGE_DIFF_LINES = 200;
|
|
152
|
+
const LARGE_DIFF_HINT =
|
|
153
|
+
'hint: large diff - run with --stat first for per-file sizes, add -U1 for less context, and page by file with -- <path>';
|
|
154
|
+
|
|
155
|
+
// Line-ending warnings are noise the model cannot act on; the content is unchanged.
|
|
156
|
+
const CRLF_WARNING_RE = /^warning: in the working copy of .* (?:CRLF|LF) will be replaced[^\n]*(?:\n|$)/gm;
|
|
157
|
+
// `index abc..def` carries abbreviated object ids the model never uses; mode
|
|
158
|
+
// changes keep their own `old mode`/`new mode`/`new file mode` lines.
|
|
159
|
+
const DIFF_INDEX_LINE_RE = /^index [0-9a-f,]+\.\.[0-9a-f]+(?: [0-7]+)?\r?(?:\n|$)/gm;
|
|
160
|
+
const PATCH_OPERATIONS = new Set(['diff', 'diff-files', 'diff-index', 'diff-tree', 'show', 'log']);
|
|
161
|
+
|
|
162
|
+
function visibleStderr(value) {
|
|
163
|
+
return String(value || '').replace(CRLF_WARNING_RE, '');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function presentStdout(plan, value) {
|
|
167
|
+
const stdout = String(value || '');
|
|
168
|
+
if (plan.operation === 'merge-tree') return stdout.replace(/^Auto-merging .*(?:\r?\n|$)/gm, '');
|
|
169
|
+
if (PATCH_OPERATIONS.has(plan.operation) && /^diff --git /m.test(stdout)) {
|
|
170
|
+
return stdout.replace(DIFF_INDEX_LINE_RE, '');
|
|
171
|
+
}
|
|
172
|
+
return stdout;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function normalizeCap(limit) {
|
|
176
|
+
return typeof limit === 'object' ? limit : { lines: limit, chars: COMMAND_CHAR_BUDGET };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function capOutput(text, cap) {
|
|
146
180
|
const lines = outputLines(text);
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
181
|
+
const lineCut = lines.length > cap.lines;
|
|
182
|
+
const kept = lineCut ? lines.slice(0, cap.lines).join('') : text;
|
|
183
|
+
if (kept.length <= cap.chars) {
|
|
184
|
+
return {
|
|
185
|
+
text: lineCut
|
|
186
|
+
? appendText(
|
|
187
|
+
kept,
|
|
188
|
+
`... [${lines.length - cap.lines} more lines omitted; raise output_limit or narrow the command]`
|
|
189
|
+
)
|
|
190
|
+
: text,
|
|
191
|
+
truncated: lineCut,
|
|
192
|
+
totalLines: lines.length,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
const newline = kept.lastIndexOf('\n', cap.chars - 1);
|
|
196
|
+
const cut = newline > 0 ? newline + 1 : cap.chars;
|
|
197
|
+
const shown = outputLines(kept.slice(0, cut)).length;
|
|
198
|
+
return {
|
|
199
|
+
text: appendText(
|
|
200
|
+
kept.slice(0, cut),
|
|
201
|
+
`... [${lines.length - shown} more lines (${text.length - cut} chars) omitted; output limited to ${cap.chars} chars - narrow the command (-- <path>, -n/--skip) to page]`
|
|
202
|
+
),
|
|
203
|
+
truncated: true,
|
|
204
|
+
totalLines: lines.length,
|
|
205
|
+
};
|
|
152
206
|
}
|
|
153
207
|
|
|
154
208
|
function commandResult(plan, result, limit) {
|
|
155
|
-
const
|
|
209
|
+
const stdout = presentStdout(plan, result.stdout);
|
|
210
|
+
const capped = capOutput(appendText(stdout, visibleStderr(result.stderr)), normalizeCap(limit));
|
|
211
|
+
let output = capped.text;
|
|
212
|
+
if ((capped.truncated || capped.totalLines > LARGE_DIFF_LINES) && /^diff --git /m.test(stdout)) {
|
|
213
|
+
output = appendText(output, LARGE_DIFF_HINT);
|
|
214
|
+
}
|
|
156
215
|
if (succeeded(result)) return { text: output, failed: false };
|
|
157
216
|
const processError = result.error || result.timedOut || result.aborted || result.overflow || result.exitCode == null;
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
217
|
+
if (processError) return { text: appendText(fail(gitFailureReason(plan, result)), output), failed: true };
|
|
218
|
+
const outcome = exitSignal(plan, result);
|
|
219
|
+
if (outcome === 'conflicts') {
|
|
220
|
+
// A conflicted merge-tree is its answer, not a failed command: the array continues.
|
|
221
|
+
return {
|
|
222
|
+
text: appendText(
|
|
223
|
+
`exit ${result.exitCode}\n[outcome: conflicts]\nmerge has conflicts (see the CONFLICT lines); this is a result, not a command failure`,
|
|
224
|
+
output
|
|
225
|
+
),
|
|
226
|
+
failed: false,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
// A no-match signal is still a non-zero exit, so a command array stops on
|
|
230
|
+
// it; the outcome line only keeps the card from reporting a failure.
|
|
163
231
|
return {
|
|
164
|
-
text: appendText(
|
|
232
|
+
text: appendText(outcome ? `exit ${result.exitCode}\n[outcome: ${outcome}]` : `exit ${result.exitCode}`, output),
|
|
165
233
|
failed: true,
|
|
166
234
|
};
|
|
167
235
|
}
|
|
168
236
|
|
|
237
|
+
// Paths come from git unquoted; only a name that would break the one-line
|
|
238
|
+
// listing (control characters, quotes) is JSON-quoted.
|
|
239
|
+
function listedPath(path) {
|
|
240
|
+
return [...path].some((char) => char.charCodeAt(0) < 0x20 || char === '"') ? JSON.stringify(path) : path;
|
|
241
|
+
}
|
|
242
|
+
|
|
169
243
|
function stageableDiffResult(plan, result, snapshot, limit) {
|
|
170
244
|
if (!snapshot.diffId) return commandResult(plan, result, limit);
|
|
171
245
|
const rendered = commandResult(plan, result, limit);
|
|
172
|
-
|
|
173
|
-
|
|
246
|
+
// The hunk headers are already in the body; one line per file names the id range.
|
|
247
|
+
const files = [];
|
|
174
248
|
for (const change of snapshot.changes) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
const location =
|
|
180
|
-
change.kind || `@@ -${change.old_start},${change.deletions} +${change.new_start},${change.additions} @@`;
|
|
181
|
-
rendered.text = appendText(rendered.text, `change:${change.id} ${location}`);
|
|
249
|
+
const last = files.at(-1);
|
|
250
|
+
if (last?.path === change.path && !change.kind && !last.kind) last.end = change.id;
|
|
251
|
+
else files.push({ path: change.path, start: change.id, end: change.id, kind: change.kind });
|
|
182
252
|
}
|
|
253
|
+
const listing = files.map(
|
|
254
|
+
({ path, start, end, kind }) =>
|
|
255
|
+
`${listedPath(path)}: ${start === end ? start : `${start}-${end}`}${kind ? ' [whole file]' : ''}`
|
|
256
|
+
);
|
|
257
|
+
rendered.text = appendText(
|
|
258
|
+
rendered.text,
|
|
259
|
+
[
|
|
260
|
+
`diff_id: ${snapshot.diffId} (ids number the +/- runs in diff order; [whole file] ids stage the entire file)`,
|
|
261
|
+
...listing,
|
|
262
|
+
].join('\n')
|
|
263
|
+
);
|
|
183
264
|
return rendered;
|
|
184
265
|
}
|
|
185
266
|
|
|
267
|
+
// Per-file staged counts; the paths and ranges the model already holds are not repeated per change.
|
|
268
|
+
function stagedSummary(changes) {
|
|
269
|
+
const files = new Map();
|
|
270
|
+
for (const { path, additions = 0, deletions = 0 } of changes) {
|
|
271
|
+
const entry = files.get(path) || { count: 0, additions: 0, deletions: 0 };
|
|
272
|
+
entry.count += 1;
|
|
273
|
+
entry.additions += additions;
|
|
274
|
+
entry.deletions += deletions;
|
|
275
|
+
files.set(path, entry);
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
changes: changes.length,
|
|
279
|
+
additions: [...files.values()].reduce((sum, entry) => sum + entry.additions, 0),
|
|
280
|
+
deletions: [...files.values()].reduce((sum, entry) => sum + entry.deletions, 0),
|
|
281
|
+
files: [...files].map(
|
|
282
|
+
([path, entry]) =>
|
|
283
|
+
`${path}: ${entry.count} ${entry.count === 1 ? 'change' : 'changes'} +${entry.additions} -${entry.deletions}`
|
|
284
|
+
),
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
186
288
|
// A provider sometimes delivers the whole command as one quoted scalar
|
|
187
289
|
// (`"git diff"`). That tokenizes to a single argument, so the git prefix check
|
|
188
290
|
// rejected it and the caller paid a failed call plus a retry for a command it
|
|
@@ -351,14 +453,16 @@ function succeeded(result) {
|
|
|
351
453
|
|
|
352
454
|
// `git grep` exits 1 for no match and `git diff --exit-code/--quiet/--check`
|
|
353
455
|
// exits 1 to report a difference; the shell tool marks the same exits as
|
|
354
|
-
// signals, so the git tool does too.
|
|
456
|
+
// signals, so the git tool does too. `git merge-tree` exits 1 with its report
|
|
457
|
+
// on stdout when the merge has conflicts. Returns the outcome name or null.
|
|
355
458
|
function exitSignal(plan, result) {
|
|
356
|
-
if (result.exitCode !== 1 ||
|
|
357
|
-
if (plan.operation === 'grep') return
|
|
358
|
-
if (plan.operation
|
|
459
|
+
if (result.exitCode !== 1 || visibleStderr(result.stderr).trim()) return null;
|
|
460
|
+
if (plan.operation === 'grep') return 'no-match';
|
|
461
|
+
if (plan.operation === 'merge-tree') return String(result.stdout || '').trim() ? 'conflicts' : null;
|
|
462
|
+
if (plan.operation !== 'diff') return null;
|
|
359
463
|
const separator = plan.args.indexOf('--');
|
|
360
464
|
const options = separator === -1 ? plan.args : plan.args.slice(0, separator);
|
|
361
|
-
return options.some((arg) => GIT_DIFF_EXIT_SIGNAL_FLAGS.has(arg));
|
|
465
|
+
return options.some((arg) => GIT_DIFF_EXIT_SIGNAL_FLAGS.has(arg)) ? 'no-match' : null;
|
|
362
466
|
}
|
|
363
467
|
|
|
364
468
|
// ENOENT from the spawn itself is a capability fact, not a git error: the
|
|
@@ -690,10 +794,7 @@ async function executeGitStage(input, workDir, options = {}) {
|
|
|
690
794
|
if (!succeeded(applied)) return commandFailure(applyPlan, applied, limit);
|
|
691
795
|
deleteDiffSnapshot(request.diffId);
|
|
692
796
|
invalidateAfterGitMutation();
|
|
693
|
-
return ok({
|
|
694
|
-
staged: true,
|
|
695
|
-
changes: built.changes.map(({ id, preview, ...change }) => change),
|
|
696
|
-
});
|
|
797
|
+
return ok({ staged: true, ...stagedSummary(built.changes) });
|
|
697
798
|
});
|
|
698
799
|
}),
|
|
699
800
|
{ signal }
|
|
@@ -703,7 +804,13 @@ async function executeGitStage(input, workDir, options = {}) {
|
|
|
703
804
|
async function executeSingleGitTool(input, workDir, options = {}) {
|
|
704
805
|
if (!input || typeof input !== 'object' || Array.isArray(input)) return rejected('git requires an arguments object');
|
|
705
806
|
const hasCommand = typeof input.command === 'string' && Boolean(input.command.trim());
|
|
706
|
-
if (!hasCommand)
|
|
807
|
+
if (!hasCommand) {
|
|
808
|
+
return rejected(
|
|
809
|
+
input.include_stage_ids === true
|
|
810
|
+
? 'git requires command; staging IDs come from command:"git diff" (or "git diff -- <paths>") with include_stage_ids:true'
|
|
811
|
+
: 'git requires command: a full command starting with git, e.g. command:"git status"'
|
|
812
|
+
);
|
|
813
|
+
}
|
|
707
814
|
let plan;
|
|
708
815
|
try {
|
|
709
816
|
plan = localizeConfigPlan(parseCommand(input.command, workDir));
|
|
@@ -717,7 +824,10 @@ async function executeSingleGitTool(input, workDir, options = {}) {
|
|
|
717
824
|
return rejected('git archive requires -o/--output; binary stdout is not returned');
|
|
718
825
|
}
|
|
719
826
|
const limitDefault = plan.operation === 'log' ? 10 : 50;
|
|
720
|
-
const limit =
|
|
827
|
+
const limit = {
|
|
828
|
+
lines: outputLimit(input.output_limit, limitDefault),
|
|
829
|
+
chars: options.charBudget ?? COMMAND_CHAR_BUDGET,
|
|
830
|
+
};
|
|
721
831
|
const signal = abortSignalOf(options);
|
|
722
832
|
if (plan.operation === 'init' || plan.operation === 'clone') {
|
|
723
833
|
const target = creationTarget(plan);
|
|
@@ -870,13 +980,14 @@ export async function executeGitTool(rawInput, workDir, options = {}) {
|
|
|
870
980
|
return fail(`git command array requires 1 to ${GIT_COMMAND_ARRAY_LIMIT} commands`);
|
|
871
981
|
}
|
|
872
982
|
|
|
983
|
+
const operations = [];
|
|
873
984
|
for (let index = 0; index < commands.length; index += 1) {
|
|
874
985
|
const command = commands[index];
|
|
875
986
|
if (typeof command !== 'string' || !command.trim()) {
|
|
876
987
|
return fail(`git command ${index + 1} must be a non-empty string`);
|
|
877
988
|
}
|
|
878
989
|
try {
|
|
879
|
-
localizeConfigPlan(parseCommand(command, workDir));
|
|
990
|
+
operations.push(localizeConfigPlan(parseCommand(command, workDir)).operation);
|
|
880
991
|
} catch (error) {
|
|
881
992
|
return fail(`git command ${index + 1}: ${error.message}`);
|
|
882
993
|
}
|
|
@@ -887,12 +998,22 @@ export async function executeGitTool(rawInput, workDir, options = {}) {
|
|
|
887
998
|
// not produce. Every command is parsed above before any runs, so a typo in
|
|
888
999
|
// command 3 never leaves commands 1-2 half applied. Each command still
|
|
889
1000
|
// acquires its own repository lock inside executeSingleGitTool.
|
|
1001
|
+
// Headers name the position and subcommand only: echoing the argument list
|
|
1002
|
+
// (a 22-path `add`) cost more than the result it labelled.
|
|
890
1003
|
const results = [];
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
1004
|
+
let used = 0;
|
|
1005
|
+
for (let index = 0; index < commands.length; index += 1) {
|
|
1006
|
+
const label = `${index + 1}: git ${operations[index]}`;
|
|
1007
|
+
const charBudget = Math.min(COMMAND_CHAR_BUDGET, Math.max(MIN_COMMAND_CHARS, ARRAY_CHAR_BUDGET - used));
|
|
1008
|
+
const result = await executeSingleGitTool({ ...input, command: commands[index] }, workDir, {
|
|
1009
|
+
...options,
|
|
1010
|
+
charBudget,
|
|
1011
|
+
});
|
|
1012
|
+
const section = `## ${label}\n${result.text}`;
|
|
1013
|
+
used += section.length;
|
|
1014
|
+
results.push(section);
|
|
894
1015
|
if (result.failed) {
|
|
895
|
-
return appendText(results.join('\n'), `error: command failed: ${
|
|
1016
|
+
return appendText(results.join('\n'), `error: command failed: ${label}`);
|
|
896
1017
|
}
|
|
897
1018
|
}
|
|
898
1019
|
return results.join('\n');
|
|
@@ -104,14 +104,19 @@ function parseFiles(raw) {
|
|
|
104
104
|
return files;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
// Change ids are ordinals (c1, c2, …) in diff order. They are only meaningful
|
|
108
|
+
// together with the diff_id they were listed under: staging first verifies the
|
|
109
|
+
// working diff still hashes to that snapshot, so an ordinal can never address a
|
|
110
|
+
// different change than the one the model saw.
|
|
107
111
|
function annotateChanges(files) {
|
|
108
112
|
const changes = [];
|
|
113
|
+
let ordinal = 0;
|
|
109
114
|
for (const file of files) {
|
|
110
115
|
if (!file.stageable) continue;
|
|
111
116
|
if (file.kind) {
|
|
112
117
|
const entries = file.hunks.flatMap((hunk) => hunk.entries);
|
|
113
118
|
changes.push({
|
|
114
|
-
id: `
|
|
119
|
+
id: `c${++ordinal}`,
|
|
115
120
|
path: file.path,
|
|
116
121
|
kind: file.kind,
|
|
117
122
|
additions: entries.filter(({ line }) => line.startsWith('+')).length,
|
|
@@ -126,9 +131,7 @@ function annotateChanges(files) {
|
|
|
126
131
|
let group = null;
|
|
127
132
|
const finishGroup = () => {
|
|
128
133
|
if (!group) return;
|
|
129
|
-
const id = `
|
|
130
|
-
[file.path, hunkIndex, group.oldStart, group.newStart, group.lines.join('\n')].join('\0')
|
|
131
|
-
).slice(0, 16)}`;
|
|
134
|
+
const id = `c${++ordinal}`;
|
|
132
135
|
for (const entry of group.entries) entry.changeId = id;
|
|
133
136
|
changes.push({
|
|
134
137
|
id,
|
|
@@ -137,7 +140,6 @@ function annotateChanges(files) {
|
|
|
137
140
|
new_start: group.newStart,
|
|
138
141
|
additions: group.additions,
|
|
139
142
|
deletions: group.deletions,
|
|
140
|
-
preview: group.lines.slice(0, 4).map((line) => (line.length <= 180 ? line : `${line.slice(0, 180)}…`)),
|
|
141
143
|
});
|
|
142
144
|
group = null;
|
|
143
145
|
};
|
|
@@ -9,7 +9,7 @@ export function splitGrepLineNumberOnlyPrefix(line) {
|
|
|
9
9
|
};
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export function splitGrepLinePrefix(line) {
|
|
12
|
+
export function splitGrepLinePrefix(line, matchOnly = false) {
|
|
13
13
|
const text = String(line || '');
|
|
14
14
|
if (!text) return null;
|
|
15
15
|
const searchFrom = /^[A-Za-z]:/.test(text) ? 2 : 0;
|
|
@@ -19,7 +19,9 @@ export function splitGrepLinePrefix(line) {
|
|
|
19
19
|
// Caller context decides whether line-number-only output is possible. A
|
|
20
20
|
// relative path may itself start with digits + '-' (e.g. `12-x\path.txt`),
|
|
21
21
|
// so this parser must not reject `^\d+[:\-]` by shape alone.
|
|
22
|
-
|
|
22
|
+
// `matchOnly`: the caller ran rg without context lines, so only `:N:` is a
|
|
23
|
+
// delimiter and a `-N-` segment belongs to the filename (`config-12-a.txt`).
|
|
24
|
+
const delim = text.slice(searchFrom).match(matchOnly ? /(:)(\d+):/ : /([:-])(\d+)\1/);
|
|
23
25
|
if (!delim) return null;
|
|
24
26
|
const pathEnd = searchFrom + delim.index;
|
|
25
27
|
if (pathEnd <= 0) return null;
|
|
@@ -68,7 +70,13 @@ export function parseGrepContextHeader(line) {
|
|
|
68
70
|
};
|
|
69
71
|
}
|
|
70
72
|
|
|
71
|
-
export function normalizeGrepLine(
|
|
73
|
+
export function normalizeGrepLine(
|
|
74
|
+
line,
|
|
75
|
+
pathOnly = false,
|
|
76
|
+
outputMode = 'content',
|
|
77
|
+
filenameOmitted = false,
|
|
78
|
+
matchOnly = false
|
|
79
|
+
) {
|
|
72
80
|
if (process.platform !== 'win32') return line;
|
|
73
81
|
// files_with_matches mode: the WHOLE line is a path, so every separator is
|
|
74
82
|
// a path separator and a full `\`->`/` normalisation is correct.
|
|
@@ -79,7 +87,7 @@ export function normalizeGrepLine(line, pathOnly = false, outputMode = 'content'
|
|
|
79
87
|
// There is no path prefix to normalise; everything after ^\d+[:\-] is
|
|
80
88
|
// source content and must remain byte-exact.
|
|
81
89
|
if (filenameOmitted && splitGrepLineNumberOnlyPrefix(line)) return line;
|
|
82
|
-
const split = splitGrepLinePrefix(line);
|
|
90
|
+
const split = splitGrepLinePrefix(line, matchOnly);
|
|
83
91
|
if (split) {
|
|
84
92
|
return line.slice(0, split.pathEnd).replace(/\\/g, '/') + line.slice(split.pathEnd);
|
|
85
93
|
}
|
|
@@ -99,7 +107,8 @@ export function normalizeGrepLine(line, pathOnly = false, outputMode = 'content'
|
|
|
99
107
|
function parseGrepContentLine(line) {
|
|
100
108
|
const text = String(line || '');
|
|
101
109
|
if (!text || text === '--' || text.startsWith('... [')) return null;
|
|
102
|
-
|
|
110
|
+
// Grouping only runs on context-free content output.
|
|
111
|
+
const split = splitGrepLinePrefix(text, true);
|
|
103
112
|
if (split?.delimiter !== ':') return null;
|
|
104
113
|
const content = text.slice(split.markerEnd);
|
|
105
114
|
return { path: split.path, lineNo: split.lineNo, content };
|