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
|
@@ -75,10 +75,11 @@ function parseAnchor(line, { workDir, rgSpawnCwd, grepResolvedPath, searchPath,
|
|
|
75
75
|
content: String(line).slice(split.markerEnd),
|
|
76
76
|
};
|
|
77
77
|
}
|
|
78
|
-
|
|
78
|
+
// The anchor pass runs rg without context lines: every line is a match.
|
|
79
|
+
const raw = splitGrepLinePrefix(line, true);
|
|
79
80
|
if (raw?.delimiter !== ':') return null;
|
|
80
|
-
const normalized = relativeGrepLine(line, workDir, false, outputMode, false);
|
|
81
|
-
const display = splitGrepLinePrefix(normalized);
|
|
81
|
+
const normalized = relativeGrepLine(line, workDir, false, outputMode, false, true);
|
|
82
|
+
const display = splitGrepLinePrefix(normalized, true);
|
|
82
83
|
if (display?.delimiter !== ':') return null;
|
|
83
84
|
return {
|
|
84
85
|
path: display.path,
|
|
@@ -301,8 +301,9 @@ export function formatGrepOutput({
|
|
|
301
301
|
includeMatchCount = false,
|
|
302
302
|
}) {
|
|
303
303
|
const lines = headLimit === Infinity ? windowed : windowed.slice(0, headLimit);
|
|
304
|
+
const matchOnly = outputMode === 'content' && !(beforeN > 0 || afterN > 0 || contextN > 0);
|
|
304
305
|
const normalized = lines.map((line) =>
|
|
305
|
-
relativeGrepLine(line, workDir, outputMode === 'files_with_matches', outputMode, filenameOmitted)
|
|
306
|
+
relativeGrepLine(line, workDir, outputMode === 'files_with_matches', outputMode, filenameOmitted, matchOnly)
|
|
306
307
|
);
|
|
307
308
|
const remaining = Math.max(0, totalWindowed - lines.length);
|
|
308
309
|
const shown = lines.length;
|
|
@@ -82,23 +82,25 @@ function combinedPathRequest(args, defaultHeadLimit) {
|
|
|
82
82
|
// order; null when one is a glob, unreachable, or on a share — the legacy
|
|
83
83
|
// fan-out owns those diagnostics.
|
|
84
84
|
async function resolvePathRoots(list, workDir) {
|
|
85
|
-
const roots = await Promise.all(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
85
|
+
const roots = await Promise.all(
|
|
86
|
+
list.map(async (p) => {
|
|
87
|
+
const cleaned = normalizeInputPath(p);
|
|
88
|
+
if (hasGlobMagic(cleaned)) return null;
|
|
89
|
+
const resolved = resolveSearchScope(cleaned, workDir);
|
|
90
|
+
if (isUncOrSmbPath(cleaned) || isUncOrSmbPath(resolved)) return null;
|
|
91
|
+
let st;
|
|
92
|
+
try {
|
|
93
|
+
st = await statReachable(resolved);
|
|
94
|
+
} catch {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
arg: p,
|
|
99
|
+
abs: normalizeOutputPath(isAbsolute(resolved) ? await trueCasePath(resolved) : resolved),
|
|
100
|
+
isDir: st.isDirectory(),
|
|
101
|
+
};
|
|
102
|
+
})
|
|
103
|
+
);
|
|
102
104
|
if (roots.some((root) => !root)) return null;
|
|
103
105
|
// An overlapping operand would scan a file twice and then attribute both
|
|
104
106
|
// copies to each containing section. Keep independent scope semantics.
|
|
@@ -123,7 +125,7 @@ function attributeLinesToRoots(lines, roots, wdFwd) {
|
|
|
123
125
|
for (const line of lines) {
|
|
124
126
|
const norm = line.replace(/\\/g, '/');
|
|
125
127
|
const lineKey = pathKey(norm);
|
|
126
|
-
const rel = lineKey.startsWith(workDirKey) ?
|
|
128
|
+
const rel = lineKey.startsWith(workDirKey) ? line.slice(wdFwd.length + 1) : line;
|
|
127
129
|
for (let i = 0; i < roots.length; i++) {
|
|
128
130
|
const rootKey = pathKey(roots[i].abs);
|
|
129
131
|
if (lineKey === rootKey || lineKey.startsWith(`${rootKey}/`) || lineKey.startsWith(`${rootKey}:`)) {
|
|
@@ -143,7 +145,7 @@ function renderedRootLines(root, windowedLines, wdFwd) {
|
|
|
143
145
|
const rootPrefix = `${pathKey(rootRel)}:`;
|
|
144
146
|
return windowedLines.map((l) => {
|
|
145
147
|
const lineFwd = l.replace(/\\/g, '/');
|
|
146
|
-
return pathKey(lineFwd).startsWith(rootPrefix) ?
|
|
148
|
+
return pathKey(lineFwd).startsWith(rootPrefix) ? l.slice(rootRel.length + 1) : l;
|
|
147
149
|
});
|
|
148
150
|
}
|
|
149
151
|
|
|
@@ -151,13 +153,13 @@ async function combinedPathBody(request, root, linesFor, { workDir, wdFwd, optio
|
|
|
151
153
|
const { pattern, outMode, headLimit, offset, contextN, autoContext, caseInsensitive } = request;
|
|
152
154
|
if (outMode === 'content' && (autoContext || contextN > 0)) {
|
|
153
155
|
const ctx = await expandGrepAnchorContextOutput({
|
|
154
|
-
allLines: linesFor,
|
|
156
|
+
allLines: renderedRootLines(root, linesFor, wdFwd),
|
|
155
157
|
workDir,
|
|
156
158
|
rgSpawnCwd: wdFwd,
|
|
157
159
|
grepResolvedPath: root.abs,
|
|
158
160
|
searchPath: root.arg,
|
|
159
161
|
outputMode: outMode,
|
|
160
|
-
filenameOmitted:
|
|
162
|
+
filenameOmitted: !root.isDir,
|
|
161
163
|
headLimit,
|
|
162
164
|
offset,
|
|
163
165
|
totalKnown: true,
|
|
@@ -229,29 +231,31 @@ async function runCombinedPathFanout({ args, list, workDir, options, callContext
|
|
|
229
231
|
|
|
230
232
|
// One rg invocation over every root's files at once.
|
|
231
233
|
async function combinedPathRgArgs(args, request, roots, workDir) {
|
|
232
|
-
const perRoot = await Promise.all(
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
234
|
+
const perRoot = await Promise.all(
|
|
235
|
+
roots.map(async (root) => {
|
|
236
|
+
const scope = await resolveGrepScope({ ...args, path: root.arg }, workDir);
|
|
237
|
+
if (scope.result !== undefined) return null;
|
|
238
|
+
return buildGrepRgArgs({
|
|
239
|
+
patterns: [request.pattern],
|
|
240
|
+
includeNoise: args.include_noise === true,
|
|
241
|
+
text: args.text === true,
|
|
242
|
+
searchPath: isAbsolute(scope.searchPath) ? root.abs : scope.searchPath,
|
|
243
|
+
// Match buildGrepScope: an explicit file operand wins over its glob.
|
|
244
|
+
globPatterns: root.isDir ? scope.normalizedGlobPatterns : [],
|
|
245
|
+
outputMode: request.outMode,
|
|
246
|
+
caseInsensitive: request.caseInsensitive,
|
|
247
|
+
showLineNumbers: true,
|
|
248
|
+
beforeN: null,
|
|
249
|
+
afterN: null,
|
|
250
|
+
contextN: null,
|
|
251
|
+
multilineMode: false,
|
|
252
|
+
fileType: '',
|
|
253
|
+
onlyMatching: false,
|
|
254
|
+
pcre2: false,
|
|
255
|
+
withFilename: true,
|
|
256
|
+
}).slice(0, -1);
|
|
257
|
+
})
|
|
258
|
+
);
|
|
255
259
|
if (perRoot.some((argv) => !argv)) return null;
|
|
256
260
|
const first = JSON.stringify(perRoot[0]);
|
|
257
261
|
// Native filters are rooted at each operand. Only identical normalized
|
|
@@ -3,12 +3,19 @@ import { canonicalizeGlobSlashes } from '../path-utils.mjs';
|
|
|
3
3
|
import { relativePathPrefix } from '../search-path-diagnostics.mjs';
|
|
4
4
|
import { normalizeGrepLine, splitGrepCountPrefix, splitGrepLinePrefix } from '../grep-formatting.mjs';
|
|
5
5
|
|
|
6
|
-
export function relativeGrepLine(
|
|
7
|
-
|
|
6
|
+
export function relativeGrepLine(
|
|
7
|
+
line,
|
|
8
|
+
workDir,
|
|
9
|
+
pathOnly = false,
|
|
10
|
+
outputMode = 'content',
|
|
11
|
+
filenameOmitted = false,
|
|
12
|
+
matchOnly = false
|
|
13
|
+
) {
|
|
14
|
+
const normalized = normalizeGrepLine(line, pathOnly, outputMode, filenameOmitted, matchOnly);
|
|
8
15
|
if (!workDir) return normalized;
|
|
9
16
|
if (pathOnly) return relativePathPrefix(normalized, workDir);
|
|
10
17
|
if (filenameOmitted) return normalized;
|
|
11
|
-
const split = splitGrepLinePrefix(normalized);
|
|
18
|
+
const split = splitGrepLinePrefix(normalized, matchOnly);
|
|
12
19
|
if (split) {
|
|
13
20
|
return relativePathPrefix(normalized.slice(0, split.pathEnd), workDir) + normalized.slice(split.pathEnd);
|
|
14
21
|
}
|
|
@@ -21,11 +21,31 @@
|
|
|
21
21
|
* partial `.json`, and a marker never exists without its `.json`.
|
|
22
22
|
*/
|
|
23
23
|
import { access, mkdir, readFile, readdir, rm, stat, writeFile } from 'node:fs/promises';
|
|
24
|
+
import { unlinkSync } from 'node:fs';
|
|
24
25
|
import { homedir } from 'node:os';
|
|
25
26
|
import { join } from 'node:path';
|
|
26
27
|
import { writeJsonAtomicAsync } from '../../../../../shared/atomic-file.mjs';
|
|
27
28
|
import { isPidAlive } from '../../../../../shared/pid-liveness.mjs';
|
|
28
29
|
import { displayShellCommand } from '../../../../../shared/shell-display.mjs';
|
|
30
|
+
import { tryAdmitWorkspaceActivity } from '../../../../../shared/worktrees/activity-gate.mjs';
|
|
31
|
+
import { worktreeError } from '../../../../../shared/worktrees/contract.mjs';
|
|
32
|
+
import { workspaceSees } from '../../../../../shared/worktrees/workspace-visibility.mjs';
|
|
33
|
+
|
|
34
|
+
const workspaceLeases = new Map();
|
|
35
|
+
|
|
36
|
+
/** Transfer a foreground reader to a surviving-descendant task without a lease gap. */
|
|
37
|
+
export function adoptShellWorkspaceAdmission(jobId, leave) {
|
|
38
|
+
const prior = workspaceLeases.get(jobId);
|
|
39
|
+
workspaceLeases.set(
|
|
40
|
+
jobId,
|
|
41
|
+
prior
|
|
42
|
+
? () => {
|
|
43
|
+
prior();
|
|
44
|
+
leave();
|
|
45
|
+
}
|
|
46
|
+
: leave
|
|
47
|
+
);
|
|
48
|
+
}
|
|
29
49
|
|
|
30
50
|
// A record whose owner process is gone is garbage. Age alone never deletes a
|
|
31
51
|
// live owner's job, so an unlimited long-running shell keeps its record.
|
|
@@ -155,10 +175,26 @@ async function sweepOrphanRecords(dir) {
|
|
|
155
175
|
/** Publish the record for a job that has just started or been promoted. */
|
|
156
176
|
export function publishShellJobRecord(
|
|
157
177
|
task,
|
|
158
|
-
{
|
|
178
|
+
{
|
|
179
|
+
ownerSessionId = null,
|
|
180
|
+
clientHostPid = null,
|
|
181
|
+
startedAtMs = 0,
|
|
182
|
+
foreground = false,
|
|
183
|
+
terminationUnconfirmed = false,
|
|
184
|
+
} = {}
|
|
159
185
|
) {
|
|
160
186
|
const jobId = String(task?.jobId || '').trim();
|
|
161
187
|
if (!jobId) return;
|
|
188
|
+
if (task?.cwd) {
|
|
189
|
+
const leave = tryAdmitWorkspaceActivity(ownerSessionId || jobId, task.cwd, {
|
|
190
|
+
pid: Number(task.pid) || process.pid,
|
|
191
|
+
kind: 'command',
|
|
192
|
+
});
|
|
193
|
+
if (!leave) throw worktreeError('WORKTREE_BUSY_JOBS', 'The command folder is being managed.');
|
|
194
|
+
// A descendant handoff can reuse the job id with a different live pid.
|
|
195
|
+
// Acquire its reader before releasing any predecessor's admission.
|
|
196
|
+
adoptShellWorkspaceAdmission(jobId, leave);
|
|
197
|
+
}
|
|
162
198
|
const ownerPid = Number(clientHostPid ?? task?.clientHostPid) || process.pid;
|
|
163
199
|
const dir = jobsDir();
|
|
164
200
|
const jsonPath = join(dir, `${jobId}.json`);
|
|
@@ -192,6 +228,12 @@ export function publishShellJobRecord(
|
|
|
192
228
|
// removed on settle. Restart recovery skips them: there is no
|
|
193
229
|
// task id to report and no waiter to notify.
|
|
194
230
|
...(foreground ? { foreground: true } : {}),
|
|
231
|
+
// A killed command whose processes are not confirmed gone: its
|
|
232
|
+
// result is reported, but the readouts keep listing it.
|
|
233
|
+
...(terminationUnconfirmed ? { terminationUnconfirmed: true } : {}),
|
|
234
|
+
// Its owner session closed: any session that sees the folder lists
|
|
235
|
+
// (and may release) it.
|
|
236
|
+
...(closedOwnerSessions.has(String(ownerSessionId || '')) ? { ownerSessionClosed: true } : {}),
|
|
195
237
|
};
|
|
196
238
|
records.set(jobId, record);
|
|
197
239
|
incarnations.delete(jobId);
|
|
@@ -205,26 +247,146 @@ export function publishShellJobRecord(
|
|
|
205
247
|
}
|
|
206
248
|
|
|
207
249
|
/** Preserve a bounded terminal snapshot for manual recovery after restart. */
|
|
250
|
+
// jobId -> { ownerSessionId, release } for every job whose result is reported
|
|
251
|
+
// but whose processes are not confirmed gone. The hold is dropped by the
|
|
252
|
+
// termination watch on confirmation, or by an explicit user force-release —
|
|
253
|
+
// never by a timer.
|
|
254
|
+
const terminationHolds = new Map();
|
|
255
|
+
// Owner sessions that closed in this runtime: their holds have no owner left
|
|
256
|
+
// to release them, so any session that sees the workspace may.
|
|
257
|
+
const closedOwnerSessions = new Set();
|
|
258
|
+
|
|
259
|
+
export function registerTerminationHold(jobId, { ownerSessionId = null, cwd = null, release }) {
|
|
260
|
+
const key = String(jobId || '').trim();
|
|
261
|
+
if (key && typeof release === 'function') terminationHolds.set(key, { ownerSessionId, cwd, release });
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function clearTerminationHold(jobId) {
|
|
265
|
+
terminationHolds.delete(String(jobId || '').trim());
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/** The owner session closed: its live records are flagged so every surface
|
|
269
|
+
* can list them for the sessions that see their folder. */
|
|
270
|
+
export function noteShellOwnerSessionClosed(sessionId) {
|
|
271
|
+
const id = String(sessionId || '').trim();
|
|
272
|
+
if (!id) return;
|
|
273
|
+
closedOwnerSessions.add(id);
|
|
274
|
+
for (const [jobId, record] of records) {
|
|
275
|
+
if (record?.ownerSessionId === id) void patchRunningShellJobRecord(jobId, { ownerSessionClosed: true });
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const releaseRequestPath = (key) => join(jobsDir(), `${key}.release-requested`);
|
|
280
|
+
|
|
281
|
+
async function requestRemoteRelease(key, caller) {
|
|
282
|
+
const id = validJobId(key);
|
|
283
|
+
const record = id ? JSON.parse(await readFile(join(jobsDir(), `${id}.json`), 'utf8')) : null;
|
|
284
|
+
if (record?.status !== 'running' || record.terminationUnconfirmed !== true) throw new Error('not held');
|
|
285
|
+
const hold = { ownerSessionId: record.ownerSessionId || null, cwd: record.cwd };
|
|
286
|
+
if (!mayRelease(hold, { ...caller, ownerClosed: record.ownerSessionClosed === true })) {
|
|
287
|
+
throw new Error('not permitted');
|
|
288
|
+
}
|
|
289
|
+
await writeFile(releaseRequestPath(id), '', 'utf8');
|
|
290
|
+
return { released: true, deferred: true };
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/** Consume a cross-process release request for `jobId`; true when one existed. */
|
|
294
|
+
export function takeReleaseRequest(jobId) {
|
|
295
|
+
const key = validJobId(jobId);
|
|
296
|
+
if (!key) return false;
|
|
297
|
+
try {
|
|
298
|
+
unlinkSync(releaseRequestPath(key));
|
|
299
|
+
return true;
|
|
300
|
+
} catch {
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function mayRelease(hold, { callerSessionId, callerCwd, ownerClosed = closedOwnerSessions.has(hold.ownerSessionId) }) {
|
|
306
|
+
if (!hold.ownerSessionId || hold.ownerSessionId === callerSessionId) return true;
|
|
307
|
+
return ownerClosed && workspaceSees(hold.cwd, callerCwd);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/** Explicit user action ("Release anyway"): drop the workspace hold of a job
|
|
311
|
+
* whose termination is unconfirmed. The surface asks for confirmation first.
|
|
312
|
+
* The owning session may release it; once that session has closed, any
|
|
313
|
+
* session whose workspace (`callerCwd`) sees the hold's folder may. */
|
|
314
|
+
export async function forceReleaseTerminationHold(jobId, { callerSessionId = null, callerCwd = null } = {}) {
|
|
315
|
+
const key = String(jobId || '').trim();
|
|
316
|
+
const refused = { released: false, error: `no unconfirmed termination hold: ${key}` };
|
|
317
|
+
const hold = terminationHolds.get(key);
|
|
318
|
+
// The hold lives in another runtime process (a desktop pane's session shard):
|
|
319
|
+
// its own observation loop honours the request at its next pass.
|
|
320
|
+
if (!hold) return requestRemoteRelease(key, { callerSessionId, callerCwd }).catch(() => refused);
|
|
321
|
+
if (!mayRelease(hold, { callerSessionId, callerCwd })) return refused;
|
|
322
|
+
try {
|
|
323
|
+
await hold.release();
|
|
324
|
+
} catch (error) {
|
|
325
|
+
return { released: false, error: error instanceof Error ? error.message : String(error) };
|
|
326
|
+
}
|
|
327
|
+
if (terminationHolds.get(key) === hold) terminationHolds.delete(key);
|
|
328
|
+
return { released: true };
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/** Release the workspace admission adopted under `jobId` without a record of
|
|
332
|
+
* its own (survivors a finished foreground command left behind), once they
|
|
333
|
+
* are confirmed gone. */
|
|
334
|
+
export function releaseShellJobWorkspace(jobId) {
|
|
335
|
+
const key = String(jobId || '').trim();
|
|
336
|
+
const leave = workspaceLeases.get(key);
|
|
337
|
+
if (!leave) return;
|
|
338
|
+
leave();
|
|
339
|
+
if (workspaceLeases.get(key) === leave) workspaceLeases.delete(key);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/** Flag a still-open job record as "termination unconfirmed" for the readouts. */
|
|
343
|
+
export function markShellJobTerminationUnconfirmed(jobId) {
|
|
344
|
+
return patchRunningShellJobRecord(jobId, { terminationUnconfirmed: true });
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function patchRunningShellJobRecord(jobId, patch) {
|
|
348
|
+
const key = validJobId(jobId);
|
|
349
|
+
if (!key) return Promise.resolve(false);
|
|
350
|
+
const jsonPath = join(jobsDir(), `${key}.json`);
|
|
351
|
+
return enqueue(key, async () => {
|
|
352
|
+
const record = records.get(key);
|
|
353
|
+
if (record?.status !== 'running') return false;
|
|
354
|
+
const next = { ...record, ...patch };
|
|
355
|
+
records.set(key, next);
|
|
356
|
+
await writeJsonAtomicAsync(jsonPath, next, { fsync: false });
|
|
357
|
+
return true;
|
|
358
|
+
}).catch(() => false);
|
|
359
|
+
}
|
|
360
|
+
|
|
208
361
|
export function completeShellJobRecord(jobId, detail) {
|
|
209
362
|
const key = validJobId(jobId);
|
|
210
363
|
if (!key) return Promise.resolve(false);
|
|
364
|
+
const leaveWorkspace = workspaceLeases.get(key);
|
|
211
365
|
const dir = jobsDir();
|
|
212
366
|
const jsonPath = join(dir, `${key}.json`);
|
|
213
367
|
const donePath = join(dir, `${key}.done`);
|
|
214
368
|
const list = paths.get(key) || [jsonPath];
|
|
215
369
|
const ownerPaths = list.filter((path) => path.includes('.owner-'));
|
|
216
370
|
return enqueue(key, async () => {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
371
|
+
try {
|
|
372
|
+
await mkdir(dir, { recursive: true });
|
|
373
|
+
let base = records.get(key) || null;
|
|
374
|
+
if (!base) {
|
|
375
|
+
try {
|
|
376
|
+
base = JSON.parse(await readFile(jsonPath, 'utf8'));
|
|
377
|
+
} catch {}
|
|
378
|
+
}
|
|
379
|
+
const record = terminalRecord(base, { ...detail, jobId: key });
|
|
380
|
+
records.set(key, record);
|
|
381
|
+
await writeJsonAtomicAsync(jsonPath, record, { fsync: false });
|
|
382
|
+
await writeFile(donePath, '', 'utf8');
|
|
383
|
+
} finally {
|
|
384
|
+
// Callers complete a record only once its processes are confirmed gone
|
|
385
|
+
// (or explicitly released): the workspace admission follows that, not
|
|
386
|
+
// the record write, so a failed write cannot strand it with no handle.
|
|
387
|
+
leaveWorkspace?.();
|
|
388
|
+
if (workspaceLeases.get(key) === leaveWorkspace) workspaceLeases.delete(key);
|
|
223
389
|
}
|
|
224
|
-
const record = terminalRecord(base, { ...detail, jobId: key });
|
|
225
|
-
records.set(key, record);
|
|
226
|
-
await writeJsonAtomicAsync(jsonPath, record, { fsync: false });
|
|
227
|
-
await writeFile(donePath, '', 'utf8');
|
|
228
390
|
await removePaths(ownerPaths);
|
|
229
391
|
paths.set(key, [jsonPath, donePath]);
|
|
230
392
|
const incarnation = ++incarnationSeq;
|
|
@@ -245,33 +407,51 @@ export function completeShellJobRecord(jobId, detail) {
|
|
|
245
407
|
}).catch(() => false);
|
|
246
408
|
}
|
|
247
409
|
|
|
248
|
-
|
|
410
|
+
/** Test support: settles once every record write queued so far for `jobId`
|
|
411
|
+
* has finished, so a test waits on the write itself, not on elapsed turns. */
|
|
412
|
+
export function _shellJobRecordWritesSettledForTest(jobId) {
|
|
413
|
+
return chains.get(String(jobId || '').trim()) || Promise.resolve();
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
export async function readShellJobRecord(jobId, { strict = false } = {}) {
|
|
249
417
|
const key = validJobId(jobId);
|
|
250
418
|
if (!key) return null;
|
|
251
419
|
const dir = jobsDir();
|
|
252
420
|
const jsonPath = join(dir, `${key}.json`);
|
|
253
421
|
try {
|
|
254
422
|
const record = JSON.parse(await readFile(jsonPath, 'utf8'));
|
|
423
|
+
if (
|
|
424
|
+
strict &&
|
|
425
|
+
(!record ||
|
|
426
|
+
!['running', 'completed', 'failed', 'cancelled'].includes(record.status) ||
|
|
427
|
+
(record.status === 'running' && !record.cwd))
|
|
428
|
+
)
|
|
429
|
+
throw new Error(`Cannot inspect shell job ${key}.`);
|
|
255
430
|
const done = await access(join(dir, `${key}.done`)).then(
|
|
256
431
|
() => true,
|
|
257
|
-
() =>
|
|
432
|
+
(error) => {
|
|
433
|
+
if (strict && error?.code !== 'ENOENT') throw error;
|
|
434
|
+
return false;
|
|
435
|
+
}
|
|
258
436
|
);
|
|
259
437
|
return { ...record, recovered: true, terminal: done || record?.status !== 'running' };
|
|
260
|
-
} catch {
|
|
438
|
+
} catch (error) {
|
|
439
|
+
if (strict && error?.code !== 'ENOENT') throw error;
|
|
261
440
|
return null;
|
|
262
441
|
}
|
|
263
442
|
}
|
|
264
443
|
|
|
265
|
-
export async function listShellJobRecords() {
|
|
444
|
+
export async function listShellJobRecords({ strict = false } = {}) {
|
|
266
445
|
const dir = jobsDir();
|
|
267
446
|
let names;
|
|
268
447
|
try {
|
|
269
448
|
names = await readdir(dir);
|
|
270
|
-
} catch {
|
|
449
|
+
} catch (error) {
|
|
450
|
+
if (strict && error?.code !== 'ENOENT') throw error;
|
|
271
451
|
return [];
|
|
272
452
|
}
|
|
273
453
|
const rows = await Promise.all(
|
|
274
|
-
names.filter((name) => name.endsWith('.json')).map((name) => readShellJobRecord(name.slice(0, -5)))
|
|
454
|
+
names.filter((name) => name.endsWith('.json')).map((name) => readShellJobRecord(name.slice(0, -5), { strict }))
|
|
275
455
|
);
|
|
276
456
|
const cutoff = Date.now() - COMPLETED_SHELL_JOB_TTL_MS;
|
|
277
457
|
return rows.filter((record) => {
|
|
@@ -286,6 +466,8 @@ export async function listShellJobRecords() {
|
|
|
286
466
|
export function retireShellJobRecord(jobId) {
|
|
287
467
|
const key = String(jobId || '').trim();
|
|
288
468
|
if (!key) return;
|
|
469
|
+
const leaveWorkspace = workspaceLeases.get(key);
|
|
470
|
+
workspaceLeases.delete(key);
|
|
289
471
|
const list = paths.get(key);
|
|
290
472
|
paths.delete(key);
|
|
291
473
|
// Queued behind every earlier publish and ahead of any later one: a promoted
|
|
@@ -294,5 +476,6 @@ export function retireShellJobRecord(jobId) {
|
|
|
294
476
|
records.delete(key);
|
|
295
477
|
incarnations.delete(key);
|
|
296
478
|
await removePaths(list);
|
|
479
|
+
leaveWorkspace?.();
|
|
297
480
|
});
|
|
298
481
|
}
|
|
@@ -2,9 +2,10 @@ import { closeSync, fstatSync, openSync, readSync } from 'node:fs';
|
|
|
2
2
|
import { stripAnsi } from '../../shell-exec-output.mjs';
|
|
3
3
|
import { FileEncodingSniffer, ShellStreamDecoder, alignedOffset, oemTextEncoding } from '../../shell-codepage.mjs';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
const COMPLETION_BYTES = 12 * 1024;
|
|
5
|
+
import { TOOL_OUTPUT_PAGE_BYTES, TOOL_OUTPUT_TAIL_BYTES } from '../../../../../shared/tool-output-budget.mjs';
|
|
7
6
|
const cursors = new WeakMap();
|
|
7
|
+
const ESC = '\x1b';
|
|
8
|
+
const PENDING_ANSI_INTRODUCER = new RegExp(`${ESC}(?:\\[[0-?]*[ -/]*|\\](?:(?!${ESC}\\\\)[^\x07\x9c])*)?$`);
|
|
8
9
|
|
|
9
10
|
function newCursor() {
|
|
10
11
|
return {
|
|
@@ -36,7 +37,7 @@ function visibleText(cursor, text) {
|
|
|
36
37
|
const value = cursor.ansi + text;
|
|
37
38
|
// Retain only the introducer of an unfinished CSI/OSC, not its potentially
|
|
38
39
|
// unbounded payload. It will be stripped with the following chunk.
|
|
39
|
-
const pending =
|
|
40
|
+
const pending = PENDING_ANSI_INTRODUCER.exec(value);
|
|
40
41
|
cursor.ansi = '';
|
|
41
42
|
if (!pending) return stripAnsi(value);
|
|
42
43
|
const sequence = pending[0];
|
|
@@ -53,7 +54,7 @@ function visibleText(cursor, text) {
|
|
|
53
54
|
export function readShellTaskOutput(task, result = {}, { output = 'new' } = {}) {
|
|
54
55
|
const replay = output === 'tail';
|
|
55
56
|
const terminal = task.status !== 'running';
|
|
56
|
-
const limit = terminal || replay ?
|
|
57
|
+
const limit = terminal || replay ? TOOL_OUTPUT_TAIL_BYTES : TOOL_OUTPUT_PAGE_BYTES;
|
|
57
58
|
let streams = replay ? new Map() : cursors.get(task);
|
|
58
59
|
if (!streams) {
|
|
59
60
|
streams = new Map();
|
|
@@ -79,10 +79,15 @@ export function parseLineLimitArg(value, defaultValue) {
|
|
|
79
79
|
return Math.max(1, Math.trunc(n));
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
/** Whether the read display clips this source line. */
|
|
83
|
+
export function isReadLineClipped(line, { truncateLongLine = true } = {}) {
|
|
84
|
+
return truncateLongLine && String(line ?? '').length > READ_MAX_RENDERED_LINE_CHARS;
|
|
85
|
+
}
|
|
86
|
+
|
|
82
87
|
export function truncateReadLineText(line, { truncateLongLine = true } = {}) {
|
|
83
88
|
let text = String(line ?? '');
|
|
84
89
|
const originalLength = text.length;
|
|
85
|
-
if (
|
|
90
|
+
if (isReadLineClipped(text, { truncateLongLine })) {
|
|
86
91
|
const cps = [...text];
|
|
87
92
|
const head = cps.slice(0, 1_500).join('');
|
|
88
93
|
const tail = cps.slice(-300).join('');
|
|
@@ -3,6 +3,7 @@ import { assertPathReachable, assertPathsReachable } from './fs-reachability.mjs
|
|
|
3
3
|
import { isAbsolute, join, resolve } from 'node:path';
|
|
4
4
|
import { tmpdir } from 'node:os';
|
|
5
5
|
import { randomUUID } from 'node:crypto';
|
|
6
|
+
import { isBuiltin } from 'node:module';
|
|
6
7
|
import { cwdRelativePath, normalizeInputPath, normalizeOutputPath, resolveAgainstCwd } from './path-utils.mjs';
|
|
7
8
|
|
|
8
9
|
// Hard-block patterns live exclusively in ../shell-policy.mjs (BLOCKED_PATTERNS /
|
|
@@ -661,6 +662,24 @@ const LONG_INLINE_SCRIPT_RE =
|
|
|
661
662
|
/\b(node(?:\.exe)?|python3?|py)((?:\s+--?[\w-]+(?:=[^\s"']+)?)*)\s+(-e|--eval|-c)\s+(?:"((?:[^"\\]|\\.)*)"|'((?:[^']|'')*)')/i;
|
|
662
663
|
const POWERSHELL_FILE_SEMANTIC_RE = /\$(?:PSScriptRoot|PSCommandPath|MyInvocation)\b|^\s*(?:param\s*\(|#requires\b)/im;
|
|
663
664
|
|
|
665
|
+
// `node -e` resolves a package name from the working directory; a hoisted file
|
|
666
|
+
// resolves it from the temp directory it lives in, where no node_modules is.
|
|
667
|
+
// Any package specifier (not a Node builtin), require.resolve, or a specifier
|
|
668
|
+
// that is not a string literal therefore keeps the -e form.
|
|
669
|
+
const NODE_SPECIFIER_RE = /(?:\brequire\s*\(\s*|\bimport\s*\(\s*|\bfrom\s+|\bimport\s+)['"]([^'"]+)['"]/g;
|
|
670
|
+
const NODE_LOADER_CALL_RE = /\b(?:require|import)\s*\(/g;
|
|
671
|
+
const NODE_LITERAL_LOADER_CALL_RE = /\b(?:require|import)\s*\(\s*['"][^'"]+['"]/g;
|
|
672
|
+
function importsPackage(body) {
|
|
673
|
+
if (/\brequire\s*\.\s*resolve\b/.test(body)) return true;
|
|
674
|
+
if ((body.match(NODE_LOADER_CALL_RE) || []).length !== (body.match(NODE_LITERAL_LOADER_CALL_RE) || []).length) {
|
|
675
|
+
return true;
|
|
676
|
+
}
|
|
677
|
+
for (const [, specifier] of body.matchAll(NODE_SPECIFIER_RE)) {
|
|
678
|
+
if (!isBuiltin(specifier)) return true;
|
|
679
|
+
}
|
|
680
|
+
return false;
|
|
681
|
+
}
|
|
682
|
+
|
|
664
683
|
/** File extension a hoisted inline script gets: Python, or the Node module kind the flags declare. */
|
|
665
684
|
function inlineScriptExtension(isNode, esm) {
|
|
666
685
|
if (!isNode) return '.py';
|
|
@@ -684,6 +703,7 @@ export function planInlineScriptHoist(command) {
|
|
|
684
703
|
const [whole, exe, rawFlags, , body] = match;
|
|
685
704
|
if (INLINE_UNSAFE_BODY.test(body)) return null;
|
|
686
705
|
if (INLINE_FILE_RELATIVE.test(body)) return null;
|
|
706
|
+
if (/^node/i.test(exe) && importsPackage(body)) return null;
|
|
687
707
|
const { extension, keptFlags } = inlineScriptFileShape(exe, rawFlags);
|
|
688
708
|
return {
|
|
689
709
|
exe,
|