mixdog 1.4.1 → 1.4.3
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 +4 -3
- package/scripts/build-shipped-history.mjs +125 -33
- package/scripts/gate-local.mjs +220 -63
- package/scripts/graph-parity.mjs +8 -3
- package/scripts/lib/gate-scheduler.mjs +139 -32
- package/scripts/lib/gate-timing-reporter.mjs +16 -0
- package/scripts/lib/run-node-tests.mjs +71 -34
- package/scripts/lib/scoped-temp.mjs +1 -0
- package/scripts/lib/test-failure-records.mjs +14 -1
- package/scripts/lib/test-failure-summary.mjs +9 -4
- package/scripts/lib/test-spawn-ledger.mjs +43 -3
- package/scripts/post-release-check.mjs +26 -16
- package/scripts/pptx-kit-index.mjs +5 -6
- package/scripts/provider-pingpong-live.mjs +1 -1
- package/scripts/prune-embedding-runtime.mjs +3 -1
- package/scripts/release-paths.mjs +7 -1
- package/scripts/suite-health.mjs +110 -28
- package/scripts/test.mjs +9 -14
- package/src/agents/advisor/AGENT.md +4 -4
- package/src/agents/advisor/agent.json +1 -1
- package/src/agents/explore/AGENT.md +22 -0
- package/src/agents/explore/agent.json +6 -0
- package/src/cli.mjs +7 -0
- package/src/defaults/agents.json +7 -0
- package/src/defaults/shipped-history.json +38 -2
- package/src/defaults/skills/browser-use/SKILL.md +4 -1
- package/src/defaults/skills/code-tidy/SKILL.md +71 -102
- package/src/defaults/skills/code-tidy/references/agent-cleanup.md +66 -114
- package/src/defaults/skills/code-tidy/references/cleanup-report.md +19 -35
- package/src/defaults/skills/code-tidy/references/dead-code.md +3 -9
- package/src/defaults/skills/code-tidy/references/test-suite-slop.md +16 -27
- package/src/defaults/skills/computer-use/SKILL.md +12 -2
- package/src/defaults/skills/setup/SKILL.md +2 -2
- package/src/defaults/skills/setup/references/actions.md +28 -9
- package/src/defaults/skills/setup/references/surfaces.md +5 -2
- package/src/defaults/skills/setup-guide/SKILL.md +11 -3
- package/src/defaults/skills/setup-guide/model-recommendations.json +13 -0
- package/src/defaults/skills/skill-creator/SKILL.md +85 -190
- package/src/defaults/skills/skill-creator/references/design.md +70 -162
- package/src/defaults/skills/skill-creator/references/evaluation.md +33 -92
- package/src/defaults/skills/test-suite/SKILL.md +194 -0
- package/src/defaults/skills/test-suite/references/case-management.md +51 -0
- package/src/defaults/skills/test-suite/references/flaky-policy.md +39 -0
- package/src/defaults/skills/test-suite/references/reliability.md +49 -0
- package/src/defaults/skills/test-suite/references/suite-design.md +78 -0
- package/src/defaults/skills/test-suite/scripts/inventory.mjs +335 -0
- package/src/defaults/skills/visualize/SKILL.md +6 -2
- package/src/lib/instruction-text.cjs +36 -0
- package/src/lib/rules-builder.cjs +40 -50
- package/src/orchestration/balanced.md +23 -0
- package/src/orchestration/focused.md +22 -0
- package/src/orchestration/none.md +5 -0
- package/src/orchestration/swarm.md +24 -0
- package/src/rules/agent-mode/AGENT_MODE.md +3 -1
- package/src/rules/agent-mode/MIXY.md +2 -2
- package/src/rules/lead/LEAD.md +3 -3
- package/src/rules/shared/20-research.md +3 -6
- package/src/rules/shared/40-editing.md +1 -0
- package/src/rules/shared/60-verification.md +10 -9
- package/src/rules/shared/70-delivery.md +4 -3
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/abort-link.mjs +5 -1
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/session-prep.mjs +3 -3
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +10 -2
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +132 -21
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +13 -9
- package/src/runtime/agent/orchestrator/agent-runtime/heartbeat-completion.mjs +2 -2
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +4 -1
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +67 -0
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +1 -0
- package/src/runtime/agent/orchestrator/config.mjs +12 -7
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +7 -7
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +9 -30
- package/src/runtime/agent/orchestrator/internal-agents.mjs +3 -14
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +124 -12
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +204 -49
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +16 -7
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +157 -57
- package/src/runtime/agent/orchestrator/mcp/client.mjs +54 -23
- package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +1 -1
- package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +8 -2
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +83 -52
- package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +1 -1
- package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +14 -0
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +43 -27
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +43 -8
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +30 -28
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +31 -21
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-stop.mjs +3 -3
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +40 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider-keys.mjs +34 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +14 -7
- package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +48 -31
- package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +0 -18
- package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +138 -6
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/model-cache.mjs +100 -33
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/oauth-secret-fields.fixtures.mjs +45 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +4 -6
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2784 -2872
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +5 -8
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +26 -28
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +288 -300
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/registry.mjs +33 -2
- package/src/runtime/agent/orchestrator/providers/vertex-ai-auth.mjs +622 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai-maas.mjs +185 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai-models.mjs +445 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai.mjs +576 -0
- package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +10 -30
- package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +32 -0
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +0 -11
- package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +8 -0
- package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-delta.mjs +17 -3
- package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +47 -27
- package/src/runtime/agent/orchestrator/runtime-core/goal-deadlines.mjs +141 -10
- package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +26 -63
- package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +28 -3
- package/src/runtime/agent/orchestrator/runtime-core/goal-runtime.mjs +36 -11
- package/src/runtime/agent/orchestrator/runtime-core/goal-state.mjs +88 -56
- package/src/runtime/agent/orchestrator/runtime-core/goal-storage.mjs +4 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +51 -32
- package/src/runtime/agent/orchestrator/runtime-core/goal-text.mjs +45 -145
- package/src/runtime/agent/orchestrator/runtime-core/goal-tool-defs.mjs +15 -98
- package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +32 -99
- package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +23 -78
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +69 -47
- package/src/runtime/agent/orchestrator/runtime-core/todo-list.mjs +367 -0
- package/src/runtime/agent/orchestrator/runtime-core/todo-tool-defs.mjs +47 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-availability.mjs +155 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +12 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +119 -35
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +4 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +15 -6
- package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +28 -22
- package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +30 -0
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -5
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +171 -37
- package/src/runtime/agent/orchestrator/session/attachment-preflight.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/cache-warm.mjs +94 -10
- package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/compact/summary-route.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -12
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +4 -4
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +11 -6
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +6 -6
- package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +7 -3
- package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +11 -1
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -3
- package/src/runtime/agent/orchestrator/session/human-gate/held-message.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +37 -8
- package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/image-strip-recovery.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +11 -1
- package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +5 -3
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +8 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/todo-check.mjs +196 -0
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +116 -50
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +8 -1
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +5 -6
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +27 -3
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +18 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +23 -1
- package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +13 -8
- package/src/runtime/agent/orchestrator/session/loop/turn-report.mjs +35 -0
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +103 -50
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +9 -7
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +21 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-failure.mjs +27 -11
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-open.mjs +37 -34
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +25 -15
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +79 -24
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +12 -1
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +6 -1
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +9 -1
- package/src/runtime/agent/orchestrator/session/manager/pending-spool-path.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/manager/pending-spool-shard.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/prompt-settings.mjs +598 -0
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +20 -0
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +22 -14
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +56 -14
- package/src/runtime/agent/orchestrator/session/manager/session-lock.mjs +31 -0
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +59 -20
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/session-scratch-environment.mjs +70 -0
- package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +0 -3
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +18 -4
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +8 -9
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +339 -88
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-recovery.mjs +135 -11
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +377 -104
- package/src/runtime/agent/orchestrator/session/manager/turn-durability.mjs +144 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +48 -30
- package/src/runtime/agent/orchestrator/session/manager/turn-reap.mjs +125 -0
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/mixy-name.mjs +12 -6
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +8 -1
- package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/save-session-worker.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/store/canonical-reader.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/liveness-veto.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +23 -2
- package/src/runtime/agent/orchestrator/session/store/sweep/sub-agent-retention.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/store/transcript-durability.mjs +88 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/store-summary-log.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +243 -38
- package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +163 -64
- package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +177 -8
- package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +142 -18
- package/src/runtime/agent/orchestrator/session/store.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +7 -1
- package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +9 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/agent-envelope.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +2 -2
- package/src/runtime/agent/orchestrator/stall-policy.mjs +3 -5
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +4 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/misuse-guard.mjs +21 -3
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/worktree-add-guard.mjs +77 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +0 -1
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +42 -28
- package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +30 -14
- package/src/runtime/agent/orchestrator/tools/builtin/lib/search-input-helpers.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +58 -20
- package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-fast-paths.mjs +0 -1
- package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +20 -15
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +0 -10
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +95 -20
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +59 -10
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +1 -24
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary/child-kill.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +1 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/modes/calls.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/modes/symbols.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +4 -5
- package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +3 -4
- package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4 -22
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs +99 -2
- package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +105 -15
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +49 -15
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +45 -27
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +35 -11
- package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/lib/wait-until-fixture.mjs +26 -0
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -6
- package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +0 -1
- package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
- package/src/runtime/attachments/attachment-reference.mjs +1 -1
- package/src/runtime/attachments/pdf-extract.mjs +1 -1
- package/src/runtime/attachments/store.d.mts +1 -0
- package/src/runtime/attachments/store.mjs +2 -2
- package/src/runtime/channels/lib/config-reload-watch.mjs +42 -0
- package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +29 -9
- package/src/runtime/channels/lib/scheduler.mjs +33 -0
- package/src/runtime/channels/lib/schedules-db.mjs +11 -4
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +4 -1
- package/src/runtime/channels/lib/webhooks-db.mjs +9 -3
- package/src/runtime/channels/lib/whisper-port.mjs +19 -10
- package/src/runtime/channels/lib/whisper-server.mjs +22 -13
- package/src/runtime/channels/lib/worker-main.mjs +9 -31
- package/src/runtime/computer-bridge/linux-readiness.mjs +10 -14
- package/src/runtime/connectors/connector-accounts-mcp.mjs +372 -103
- package/src/runtime/connectors/gmail-app-password.mjs +4 -4
- package/src/runtime/connectors/google-mcp.mjs +1 -1
- package/src/runtime/effort-judge/judge-client.mjs +2 -2
- package/src/runtime/effort-judge/judge-input.mjs +4 -4
- package/src/runtime/explore/explorer.mjs +88 -0
- package/src/runtime/explore/tool-defs.mjs +35 -0
- package/src/runtime/explore/tool.mjs +123 -0
- package/src/runtime/local-provider/hardware.mjs +1 -1
- package/src/runtime/media/adapters/codex-image.mjs +3 -3
- package/src/runtime/media/adapters/gemini-video.mjs +1 -1
- package/src/runtime/media/media-usage.mjs +1 -1
- package/src/runtime/media/store.mjs +1 -1
- package/src/runtime/memory/index.mjs +15 -1
- package/src/runtime/memory/lib/embedding-provider.mjs +4 -1
- package/src/runtime/memory/lib/embedding-reindex.mjs +27 -0
- package/src/runtime/memory/lib/embedding-worker.mjs +4 -0
- package/src/runtime/memory/lib/memory-embed.mjs +83 -14
- package/src/runtime/memory/lib/memory-process-lock.mjs +159 -36
- package/src/runtime/memory/lib/memory-text-utils.mjs +6 -1
- package/src/runtime/memory/lib/memory.mjs +17 -0
- package/src/runtime/memory/lib/pg/process.mjs +1 -1
- package/src/runtime/memory/lib/pg/supervisor.mjs +16 -96
- package/src/runtime/memory/lib/recall-hybrid/hybrid-sql.mjs +12 -3
- package/src/runtime/office/authoring/docx-html-runner.mjs +1 -1
- package/src/runtime/office/authoring/pptx-author-action.mjs +1 -1
- package/src/runtime/office/authoring/xlsx-html-build.mjs +1 -1
- package/src/runtime/office/authoring/xlsx-html-runner.mjs +1 -1
- package/src/runtime/office/capabilities.mjs +1 -1
- package/src/runtime/office/core/office-core.mjs +1 -1
- package/src/runtime/office/design/content-model.mjs +3 -3
- package/src/runtime/office/design/docx/design-docx/section.mjs +6 -6
- package/src/runtime/office/design/xlsx/design-xlsx-components.mjs +1 -1
- package/src/runtime/office/design/xlsx/design-xlsx.mjs +1 -1
- package/src/runtime/office/pdf/ocr-engine.mjs +1 -1
- package/src/runtime/office/pdf/pdf-writer.mjs +4 -4
- package/src/runtime/office/portable/portable-docx-operations.mjs +2 -2
- package/src/runtime/office/portable/portable-soffice.mjs +8 -6
- package/src/runtime/office/portable/xlsx-contract.mjs +1 -1
- package/src/runtime/office/quality/assurance-structure-docx.mjs +1 -1
- package/src/runtime/shared/agent-route-config.mjs +17 -2
- package/src/runtime/shared/atomic-file.d.mts +8 -0
- package/src/runtime/shared/atomic-file.mjs +103 -2
- package/src/runtime/shared/background-tasks.mjs +37 -10
- package/src/runtime/shared/background-wait.mjs +66 -0
- package/src/runtime/shared/child-guardian.mjs +17 -7
- package/src/runtime/shared/config.mjs +313 -16
- package/src/runtime/shared/connector-accounts.mjs +5 -5
- package/src/runtime/shared/connector-catalog.d.mts +14 -8
- package/src/runtime/shared/connector-catalog.mjs +70 -52
- package/src/runtime/shared/custom-provider-keys.mjs +20 -0
- package/src/runtime/shared/file-has-data.mjs +26 -2
- package/src/runtime/shared/file-lock.mjs +21 -18
- package/src/runtime/shared/git-launch.d.mts +9 -0
- package/src/runtime/shared/git-launch.mjs +213 -0
- package/src/runtime/shared/git-runner-worker.mjs +2 -1
- package/src/runtime/shared/git-runner.mjs +7 -2
- package/src/runtime/shared/idle-gc.mjs +30 -7
- package/src/runtime/shared/llm/cost.mjs +6 -1
- package/src/runtime/shared/llm/http-agent.mjs +316 -29
- package/src/runtime/shared/llm/model-catalog-projection.mjs +3 -2
- package/src/runtime/shared/llm/model-catalog.mjs +46 -6
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +3 -0
- package/src/runtime/shared/llm/system-proxy.mjs +453 -0
- package/src/runtime/shared/llm/usage-ledger-quota.mjs +31 -12
- package/src/runtime/shared/llm/usage-ledger-rollup.mjs +84 -8
- package/src/runtime/shared/llm/usage-ledger.mjs +3 -0
- package/src/runtime/shared/llm/usage-rollup.mjs +48 -0
- package/src/runtime/shared/maintenance-schedule.mjs +109 -0
- package/src/runtime/shared/process-runner.mjs +8 -4
- package/src/runtime/shared/provider-accounts.mjs +52 -2
- package/src/runtime/shared/routine-trigger.d.mts +13 -0
- package/src/runtime/shared/routine-trigger.mjs +34 -0
- package/src/runtime/shared/run-child.d.mts +2 -1
- package/src/runtime/shared/run-child.mjs +70 -18
- package/src/runtime/shared/session-scratch.mjs +14 -2
- package/src/runtime/shared/shipped-definitions.mjs +7 -1
- package/src/runtime/shared/staged-install-worker.mjs +5 -0
- package/src/runtime/shared/staged-update.mjs +47 -2
- package/src/runtime/shared/tool-card-model.golden.json +3 -12
- package/src/runtime/shared/tool-execution-contract.mjs +2 -0
- package/src/runtime/shared/tool-surface.mjs +110 -36
- package/src/runtime/shared/tool-work-units.mjs +35 -6
- package/src/runtime/shared/turn-snapshot.mjs +26 -4
- package/src/runtime/shared/turn-worktree-snapshot.mjs +409 -54
- package/src/runtime/shared/worker-requests.mjs +17 -3
- package/src/runtime/shared/worktrees/activity-gate.mjs +215 -318
- package/src/runtime/shared/worktrees/activity-ledger-worker.mjs +56 -0
- package/src/runtime/shared/worktrees/activity-ledger.mjs +391 -0
- package/src/runtime/shared/worktrees/branch-management.mjs +5 -3
- package/src/runtime/shared/worktrees/contract.mjs +16 -6
- package/src/runtime/shared/worktrees/dependencies.mjs +127 -89
- package/src/runtime/shared/worktrees/disk.mjs +79 -2
- package/src/runtime/shared/worktrees/git.mjs +97 -7
- package/src/runtime/shared/worktrees/include.mjs +6 -4
- package/src/runtime/shared/worktrees/maintenance.mjs +422 -30
- package/src/runtime/shared/worktrees/manager.mjs +962 -197
- package/src/runtime/shared/worktrees/settings.mjs +33 -7
- package/src/runtime/shared/worktrees/test-support.mjs +5 -1
- package/src/runtime/shared/worktrees/worker-snapshots.mjs +82 -0
- package/src/runtime/tidy/install.mjs +95 -15
- package/src/runtime/tidy/languages.mjs +17 -15
- package/src/runtime/tidy/process.mjs +9 -5
- package/src/runtime/tidy/resolve.mjs +19 -16
- package/src/runtime/tidy/runners/biome.mjs +3 -3
- package/src/runtime/tidy/tool.mjs +1 -1
- package/src/runtime/tidy/worktree.mjs +10 -6
- package/src/runtime/visualize-bridge/client.mjs +4 -1
- package/src/runtime/visualize-bridge/tool-defs.mjs +7 -2
- package/src/runtime/web-search/index.mjs +4 -23
- package/src/runtime/web-search/lib/web-tools.mjs +2 -2
- package/src/runtime/web-search/tool-defs.mjs +17 -26
- package/src/session-runtime/agent-profile-changes.mjs +55 -4
- package/src/session-runtime/agent-task-sessions.mjs +410 -353
- package/src/session-runtime/boot/apis.mjs +27 -4
- package/src/session-runtime/boot/begin.mjs +2 -0
- package/src/session-runtime/boot/config.mjs +10 -1
- package/src/session-runtime/boot/facade.mjs +1 -0
- package/src/session-runtime/boot/providers.mjs +70 -3
- package/src/session-runtime/boot/session.mjs +2 -0
- package/src/session-runtime/boot/tools.mjs +71 -25
- package/src/session-runtime/bot-status.mjs +103 -103
- package/src/session-runtime/channel-config-api.mjs +1 -0
- package/src/session-runtime/config-change-effects.mjs +179 -0
- package/src/session-runtime/config-lifecycle/config-writers.mjs +1 -0
- package/src/session-runtime/config-lifecycle.mjs +160 -24
- package/src/session-runtime/connector-merge-migration.mjs +18 -15
- package/src/session-runtime/conversation-import/discovery.mjs +245 -47
- package/src/session-runtime/conversation-import/service.mjs +12 -5
- package/src/session-runtime/goal-facade-api.mjs +49 -3
- package/src/session-runtime/handoff-attachments.mjs +1 -1
- package/src/session-runtime/held-requests.mjs +3 -1
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +3 -0
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -2
- package/src/session-runtime/internal-tool-executor/feature-tools.mjs +5 -11
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +8 -0
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +161 -120
- package/src/session-runtime/internal-tool-executor.mjs +12 -19
- package/src/session-runtime/lifecycle/cold-heir.mjs +7 -0
- package/src/session-runtime/lifecycle/memory-ingest.mjs +3 -3
- package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +53 -5
- package/src/session-runtime/lifecycle/session-switch.mjs +13 -2
- package/src/session-runtime/lifecycle/teardown/session-close.mjs +10 -5
- package/src/session-runtime/lifecycle/teardown.mjs +1 -1
- package/src/session-runtime/lifecycle-api.mjs +1 -0
- package/src/session-runtime/mcp-glue/server-catalog.mjs +27 -10
- package/src/session-runtime/mcp-glue/server-connection.mjs +34 -8
- package/src/session-runtime/mcp-glue/server-input.mjs +4 -1
- package/src/session-runtime/mixy-heartbeat.mjs +1 -1
- package/src/session-runtime/model-route/set-route.mjs +40 -7
- package/src/session-runtime/native-web-search/routes.mjs +3 -3
- package/src/session-runtime/provider-auth/login.mjs +2 -2
- package/src/session-runtime/provider-auth/refresh.mjs +6 -3
- package/src/session-runtime/provider-auth/setup.mjs +1 -1
- package/src/session-runtime/provider-readiness.mjs +53 -4
- package/src/session-runtime/resource-api.mjs +1 -1
- package/src/session-runtime/resource-extension-sync.mjs +4 -8
- package/src/session-runtime/resource-mcp-api.mjs +98 -35
- package/src/session-runtime/resource-mcp-connector-accounts.mjs +49 -32
- package/src/session-runtime/resource-mcp-secrets.mjs +27 -10
- package/src/session-runtime/resource-mcp-servers.mjs +5 -4
- package/src/session-runtime/resource-plugins-api.mjs +4 -0
- package/src/session-runtime/routine-executor.mjs +152 -0
- package/src/session-runtime/routine-home-turn.mjs +46 -5
- package/src/session-runtime/runtime-facade.mjs +5 -0
- package/src/session-runtime/runtime-feature-gates.mjs +2 -11
- package/src/session-runtime/schedule-session-run.mjs +1 -0
- package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +6 -1
- package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +7 -0
- package/src/session-runtime/services/agent-tool/send-flow.mjs +120 -8
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +12 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +5 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +8 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +28 -7
- package/src/session-runtime/services/agent-tool.mjs +51 -1
- package/src/session-runtime/services/agent-watchdog-registry.mjs +32 -4
- package/src/session-runtime/services/channel-admin.mjs +18 -0
- package/src/session-runtime/services/channel-worker/daemon-spawn.mjs +2 -0
- package/src/session-runtime/services/daemon-candidate.mjs +4 -1
- package/src/session-runtime/services/hook-bus/command-handler.mjs +7 -11
- package/src/session-runtime/services/memory-runtime-proxy/daemon-spawn.mjs +4 -0
- package/src/session-runtime/services/plugin-admin.mjs +14 -6
- package/src/session-runtime/services/provider-admin.mjs +281 -10
- package/src/session-runtime/services/seeds.mjs +7 -0
- package/src/session-runtime/services/usage-stats-model.mjs +32 -11
- package/src/session-runtime/session-create/materialize.mjs +4 -2
- package/src/session-runtime/session-create/session-options.mjs +2 -0
- package/src/session-runtime/session-turn-api.mjs +2 -0
- package/src/session-runtime/settings-builtin-tools-api.mjs +5 -10
- package/src/session-runtime/settings-system-api.mjs +1 -1
- package/src/session-runtime/setup-tool/agent-settings-actions.mjs +13 -3
- package/src/session-runtime/setup-tool/connector-widen-approval.mjs +96 -0
- package/src/session-runtime/setup-tool/executor.mjs +14 -3
- package/src/session-runtime/setup-tool/extended-actions.mjs +2 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +28 -0
- package/src/session-runtime/setup-tool/tool-defs.mjs +28 -2
- package/src/session-runtime/tool-policy/agent-profile-fold.mjs +40 -43
- package/src/session-runtime/tool-policy/mode-switch.mjs +1 -1
- package/src/session-runtime/tool-policy/policy-stage.mjs +106 -8
- package/src/session-runtime/tool-policy/workflow-overlay.mjs +2 -1
- package/src/session-runtime/tool-policy-refresh.mjs +182 -5
- package/src/session-runtime/tool-surface.mjs +38 -1
- package/src/session-runtime/turn/agent-ops.mjs +33 -2
- package/src/session-runtime/turn/session-ops.mjs +2 -0
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +5 -0
- package/src/session-runtime/turn/turn-run.mjs +1 -1
- package/src/session-runtime/webhook-session-run.mjs +2 -0
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +46 -11
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +2 -0
- package/src/session-runtime/workflow-agents-api/instruction-files.mjs +165 -0
- package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +5 -4
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +2 -3
- package/src/session-runtime/workflow-agents-api.mjs +2 -0
- package/src/session-runtime/workspace/activity-guards.mjs +176 -0
- package/src/session-runtime/workspace/project-branches.mjs +1 -1
- package/src/session-runtime/workspace/session-view.mjs +149 -0
- package/src/session-runtime/workspace/side-checkouts.mjs +203 -0
- package/src/session-runtime/workspace/transition-runner.mjs +188 -0
- package/src/session-runtime/workspace/transitions.mjs +128 -1070
- package/src/session-runtime/workspace/workspace-merge.mjs +132 -0
- package/src/session-runtime/workspace/worktree-intents.mjs +242 -0
- package/src/session-runtime/workspace/worktree-maintenance.mjs +200 -0
- package/src/session-runtime/workspace/worktree-setup.mjs +97 -0
- package/src/session-runtime/workspace/worktree-tool.mjs +70 -54
- package/src/standalone/daemon-agent-control.mjs +25 -8
- package/src/standalone/daemon-desktop-runtime.mjs +8 -2
- package/src/standalone/daemon-lag-profiler.mjs +7 -7
- package/src/standalone/daemon-session-control.mjs +151 -136
- package/src/standalone/daemon.mjs +61 -2
- package/src/standalone/desktop-service-registry.mjs +9 -0
- package/src/standalone/local-session-runtime.mjs +21 -1
- package/src/standalone/session-client/daemon-unavailable.mjs +4 -1
- package/src/standalone/session-client.mjs +5 -1
- package/src/standalone/session-frame-stream.mjs +83 -11
- package/src/standalone/session-protocol.mjs +15 -0
- package/src/standalone/session-service/agent-route-follow.mjs +23 -20
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +18 -6
- package/src/standalone/session-service/agent-tree.mjs +45 -9
- package/src/standalone/session-service/projection/transcript-window.mjs +700 -64
- package/src/standalone/session-service/quota-resume.mjs +9 -0
- package/src/standalone/session-service/session-calls/session-action.mjs +51 -1
- package/src/standalone/session-service/session-calls/session-turns.mjs +37 -18
- package/src/standalone/session-service/session-calls/session-views.mjs +160 -104
- package/src/standalone/session-service/session-calls/turn-gate.mjs +34 -0
- package/src/standalone/session-service/session-calls.mjs +2 -1
- package/src/standalone/session-service/stored-reader.mjs +127 -40
- package/src/tui/App.jsx +162 -164
- package/src/tui/app/app-view/floating-panel.jsx +3 -0
- package/src/tui/app/app-view/text-entry-labels.mjs +1 -0
- package/src/tui/app/clipboard.mjs +22 -11
- package/src/tui/app/create-app-pickers.mjs +2 -0
- package/src/tui/app/doctor.mjs +2 -2
- package/src/tui/app/panel-signature.mjs +1 -1
- package/src/tui/app/prompt-handlers/use-prompt-history-nav.mjs +1 -1
- package/src/tui/app/prompt-handlers/use-prompt-interrupt.mjs +3 -0
- package/src/tui/app/prompt-submit/provider-prompts.mjs +3 -1
- package/src/tui/app/provider-setup/api-key-actions.mjs +31 -1
- package/src/tui/app/provider-setup/oauth-actions.mjs +25 -6
- package/src/tui/app/provider-setup-picker.mjs +20 -13
- package/src/tui/app/settings-picker.mjs +53 -8
- package/src/tui/app/shell-layout/row-budgets.mjs +14 -12
- package/src/tui/app/slash-commands.mjs +2 -1
- package/src/tui/app/slash-dispatch/route-commands.mjs +1 -1
- package/src/tui/app/slash-dispatch/session-commands.mjs +47 -1
- package/src/tui/app/slash-dispatch.mjs +1 -1
- package/src/tui/app/use-btw-panel.mjs +29 -0
- package/src/tui/app/use-context-panel-refresh.mjs +31 -0
- package/src/tui/app/use-model-catalog-cache.mjs +13 -10
- package/src/tui/app/use-mouse-input.mjs +11 -0
- package/src/tui/app/use-onboarding-start.mjs +8 -3
- package/src/tui/app/use-panel-transition.mjs +10 -1
- package/src/tui/app/use-pasted-buffers.mjs +28 -20
- package/src/tui/app/use-prompt-draft-flow.mjs +7 -0
- package/src/tui/app/use-prompt-layout-rows.mjs +3 -3
- package/src/tui/app/use-prompt-queue-history.mjs +5 -4
- package/src/tui/app/use-selection-focus.mjs +11 -2
- package/src/tui/app/use-selection-geometry.mjs +18 -9
- package/src/tui/app/use-selection-paint.mjs +4 -4
- package/src/tui/app/use-selection-stitch.mjs +3 -3
- package/src/tui/app/use-slash-palette.mjs +62 -0
- package/src/tui/app/use-terminal-chrome.mjs +2 -2
- package/src/tui/app/use-transcript-activity.mjs +48 -33
- package/src/tui/app/use-transcript-follow.mjs +12 -4
- package/src/tui/app/use-transcript-scroll.mjs +46 -17
- package/src/tui/app/use-transcript-swap-reset.mjs +27 -0
- package/src/tui/app/use-transcript-window/geometry.mjs +20 -6
- package/src/tui/app/use-transcript-window/instance-state.mjs +4 -0
- package/src/tui/app/use-transcript-window/selection-shift.mjs +5 -1
- package/src/tui/app/use-transcript-window.mjs +21 -11
- package/src/tui/app/use-tui-ready.mjs +18 -0
- package/src/tui/app/use-welcome-prompt-hint.mjs +5 -0
- package/src/tui/app/use-workflow-tab-cycle.mjs +5 -3
- package/src/tui/components/Picker.jsx +27 -3
- package/src/tui/components/SignInUrl.jsx +68 -0
- package/src/tui/components/TextEntryPanel.jsx +76 -46
- package/src/tui/components/prompt-input/escape-policy.d.mts +0 -1
- package/src/tui/components/prompt-input/escape-policy.mjs +1 -1
- package/src/tui/components/question-panel-model.mjs +4 -4
- package/src/tui/components/sign-in-url-layout.mjs +24 -0
- package/src/tui/components/tool-execution/standard-card.jsx +3 -4
- package/src/tui/components/user-message-skills.mjs +1 -1
- package/src/tui/dist/index.mjs +2205 -1371
- package/src/tui/markdown/render-ansi.mjs +1 -1
- package/src/tui/session/agent-job-feed/notification-router.mjs +10 -0
- package/src/tui/session/agent-job-feed.mjs +2 -0
- package/src/tui/session/context-state.mjs +3 -0
- package/src/tui/session/goal-turn-state.mjs +6 -2
- package/src/tui/session/quota-resume.mjs +1 -1
- package/src/tui/session/session-api/controls.mjs +4 -0
- package/src/tui/session/session-api/extensions.mjs +8 -0
- package/src/tui/session/session-api/intake/abort.mjs +2 -1
- package/src/tui/session/session-api/intake.mjs +2 -0
- package/src/tui/session/session-api/integrations.mjs +2 -2
- package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
- package/src/tui/session/session-api/lifecycle/session-reset.mjs +7 -0
- package/src/tui/session/session-api/routes-agent-definitions.mjs +6 -0
- package/src/tui/session/session-api/settings.mjs +2 -2
- package/src/tui/session/session-api/worktree.mjs +13 -1
- package/src/tui/session/session-flow/drain.mjs +11 -14
- package/src/tui/session/tool-card-results/grouped-result.mjs +2 -2
- package/src/tui/session/transcript-spill/spill-writer.mjs +15 -0
- package/src/tui/session/transcript-spill.mjs +92 -4
- package/src/tui/session/transcript-store.mjs +2 -0
- package/src/tui/session/turn-quiet.mjs +1 -1
- package/src/tui/session/turn.mjs +3 -0
- package/src/tui/session/worktree-setup-notice.mjs +1 -1
- package/src/tui/spinner-meta.mjs +3 -3
- package/src/tui/spinner-verbs.mjs +2 -2
- package/src/defaults/skills/goal-management/SKILL.md +0 -169
- package/src/defaults/skills/skill-creator/references/source-review.md +0 -94
- package/src/runtime/agent/orchestrator/runtime-core/goal-tasks.mjs +0 -156
- package/src/session-runtime/goal-tasks.mjs +0 -1
|
@@ -104,9 +104,10 @@ async function runGit(
|
|
|
104
104
|
maxBytes = COMMAND_MAX_BYTES,
|
|
105
105
|
allowFailure = false,
|
|
106
106
|
stdoutEncoding = 'utf8',
|
|
107
|
+
env = null,
|
|
107
108
|
} = {}
|
|
108
109
|
) {
|
|
109
|
-
const result = await runGitOffThread(args, { cwd, input, timeoutMs, maxBytes, stdoutEncoding });
|
|
110
|
+
const result = await runGitOffThread(args, { cwd, input, env, timeoutMs, maxBytes, stdoutEncoding });
|
|
110
111
|
if (result.code !== 0 && !allowFailure) throw commandError(args, result.stderr, result.code);
|
|
111
112
|
return result;
|
|
112
113
|
}
|
|
@@ -142,6 +143,7 @@ function stateForRoot(root) {
|
|
|
142
143
|
gitDir,
|
|
143
144
|
initialized: false,
|
|
144
145
|
sourceIndexPath: null,
|
|
146
|
+
sourcePaths: null,
|
|
145
147
|
sourceIndexIdentity: null,
|
|
146
148
|
sourceTracked: new Set(),
|
|
147
149
|
lineEndingArgs: [],
|
|
@@ -233,7 +235,7 @@ function assertStateLive(state) {
|
|
|
233
235
|
throw error;
|
|
234
236
|
}
|
|
235
237
|
|
|
236
|
-
function shadowArgs(state, args) {
|
|
238
|
+
function shadowArgs(state, args, workTree = state.root) {
|
|
237
239
|
assertStateLive(state);
|
|
238
240
|
return [
|
|
239
241
|
...state.lineEndingArgs,
|
|
@@ -245,7 +247,7 @@ function shadowArgs(state, args) {
|
|
|
245
247
|
'--git-dir',
|
|
246
248
|
state.gitDir,
|
|
247
249
|
'--work-tree',
|
|
248
|
-
|
|
250
|
+
workTree,
|
|
249
251
|
...args,
|
|
250
252
|
];
|
|
251
253
|
}
|
|
@@ -259,21 +261,54 @@ async function sourceGitPath(root, suffix) {
|
|
|
259
261
|
return result.code === 0 && value ? resolve(root, value) : null;
|
|
260
262
|
}
|
|
261
263
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
264
|
+
/** The source repository's info/exclude, index and common directory paths
|
|
265
|
+
* from one `rev-parse`, kept for the state's lifetime once answered (the
|
|
266
|
+
* index path already was). An unanswered or unexpected reply falls back to
|
|
267
|
+
* the per-path reads, uncached, so a failure is retried as before. */
|
|
268
|
+
async function sourceGitPaths(state) {
|
|
269
|
+
if (state.sourcePaths) return state.sourcePaths;
|
|
270
|
+
const result = await runGit(
|
|
271
|
+
['rev-parse', '--path-format=absolute', '--git-path', 'info/exclude', '--git-path', 'index', '--git-common-dir'],
|
|
272
|
+
{ cwd: state.root, allowFailure: true }
|
|
273
|
+
);
|
|
274
|
+
const lines = String(result.stdout || '')
|
|
275
|
+
.split(/\r?\n/)
|
|
276
|
+
.filter((line) => line !== '');
|
|
277
|
+
if (result.code === 0 && lines.length === 3 && lines.every((line) => clean(line))) {
|
|
278
|
+
const [exclude, index, commonDir] = lines.map((line) => clean(line));
|
|
279
|
+
state.sourcePaths = {
|
|
280
|
+
exclude: resolve(state.root, exclude),
|
|
281
|
+
index: resolve(state.root, index),
|
|
282
|
+
commonDir,
|
|
283
|
+
};
|
|
284
|
+
return state.sourcePaths;
|
|
285
|
+
}
|
|
286
|
+
const [exclude, index, commonDir] = await Promise.all([
|
|
287
|
+
sourceGitPath(state.root, 'info/exclude'),
|
|
288
|
+
sourceGitPath(state.root, 'index'),
|
|
289
|
+
sourceCommonDir(state.root),
|
|
290
|
+
]);
|
|
291
|
+
return { exclude, index, commonDir };
|
|
268
292
|
}
|
|
269
293
|
|
|
270
|
-
async function
|
|
294
|
+
async function sourceCommonDir(root) {
|
|
271
295
|
const result = await runGit(['rev-parse', '--path-format=absolute', '--git-common-dir'], {
|
|
272
|
-
cwd:
|
|
296
|
+
cwd: root,
|
|
273
297
|
allowFailure: true,
|
|
274
298
|
});
|
|
275
299
|
const commonDir = clean(result.stdout);
|
|
276
|
-
|
|
300
|
+
return result.code === 0 && commonDir ? commonDir : null;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
async function syncSourceExclude(state, source) {
|
|
304
|
+
if (!source || !(await exists(source))) return;
|
|
305
|
+
const target = join(state.gitDir, 'info', 'exclude');
|
|
306
|
+
await mkdir(dirname(target), { recursive: true });
|
|
307
|
+
await copyFile(source, target).catch(() => {});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
async function syncAlternates(state, commonDir) {
|
|
311
|
+
if (!commonDir) return;
|
|
277
312
|
const sourceObjects = join(resolve(state.root, commonDir), 'objects');
|
|
278
313
|
if (!(await exists(sourceObjects))) return;
|
|
279
314
|
const alternates = [sourceObjects];
|
|
@@ -294,7 +329,7 @@ async function syncAlternates(state) {
|
|
|
294
329
|
}
|
|
295
330
|
|
|
296
331
|
async function sourceIndexIdentity(state) {
|
|
297
|
-
state.sourceIndexPath ??= await
|
|
332
|
+
state.sourceIndexPath ??= (await sourceGitPaths(state)).index;
|
|
298
333
|
if (!state.sourceIndexPath) return 'missing';
|
|
299
334
|
try {
|
|
300
335
|
const stat = await lstat(state.sourceIndexPath);
|
|
@@ -349,10 +384,14 @@ async function ensureState(state) {
|
|
|
349
384
|
'utf8'
|
|
350
385
|
);
|
|
351
386
|
}
|
|
387
|
+
// One layout read serves both syncs below. Every (re)initialisation reads the
|
|
388
|
+
// source layout afresh, so a changed `.git` indirection is never served stale.
|
|
389
|
+
state.sourcePaths = null;
|
|
390
|
+
const paths = await sourceGitPaths(state);
|
|
352
391
|
const [lineEndingArgs] = await Promise.all([
|
|
353
392
|
sourceLineEndingArgs(state.root),
|
|
354
|
-
syncSourceExclude(state),
|
|
355
|
-
syncAlternates(state),
|
|
393
|
+
syncSourceExclude(state, paths.exclude),
|
|
394
|
+
syncAlternates(state, paths.commonDir),
|
|
356
395
|
]);
|
|
357
396
|
state.lineEndingArgs = lineEndingArgs;
|
|
358
397
|
// Seed once per process, then keep this index synchronized with the live
|
|
@@ -366,7 +405,7 @@ async function ensureState(state) {
|
|
|
366
405
|
|
|
367
406
|
async function resetShadowIndex(state) {
|
|
368
407
|
state.lastCapture = null;
|
|
369
|
-
state.sourceIndexPath ??= await
|
|
408
|
+
state.sourceIndexPath ??= (await sourceGitPaths(state)).index;
|
|
370
409
|
const sourceIndex = state.sourceIndexPath;
|
|
371
410
|
const target = join(state.gitDir, 'index');
|
|
372
411
|
if (sourceIndex && (await exists(sourceIndex))) {
|
|
@@ -545,7 +584,9 @@ function withOmittedBaselines(snapshot, review) {
|
|
|
545
584
|
return { ...review, files, patch, diffTooLarge: reviewDiffTooLarge(files, patch) };
|
|
546
585
|
}
|
|
547
586
|
|
|
548
|
-
|
|
587
|
+
/** `tree` with `allEntries` (recorded first states) applied. `absent`: keys of
|
|
588
|
+
* paths known not to be in `tree`, whose removal is a no-op and runs no git. */
|
|
589
|
+
async function applyBaselineFilesUnlocked(state, tree, allEntries, { absent = null } = {}) {
|
|
549
590
|
// Omitted baselines change no tree: they are carried as metadata only.
|
|
550
591
|
const files = allEntries
|
|
551
592
|
.filter((entry) => entry?.omitted === true)
|
|
@@ -555,37 +596,260 @@ async function applyBaselineFilesUnlocked(state, tree, allEntries) {
|
|
|
555
596
|
omitted: true,
|
|
556
597
|
size: Number(entry.size) || 0,
|
|
557
598
|
}));
|
|
558
|
-
const entries = allEntries
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
try {
|
|
562
|
-
await runGit(shadowArgs(state, ['read-tree', tree]), { cwd: state.root });
|
|
563
|
-
for (const entry of entries) {
|
|
599
|
+
const entries = allEntries
|
|
600
|
+
.filter((entry) => entry?.omitted !== true)
|
|
601
|
+
.map((entry) => {
|
|
564
602
|
const path = safeRelativePath(state.root, entry.path);
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
603
|
+
const content = entry.content !== undefined && entry.content !== null ? entry.content : null;
|
|
604
|
+
const noop = content === null && !entry.oid && Boolean(absent?.has(pathKey(path)));
|
|
605
|
+
return { path, content, oid: entry.oid || null, noop };
|
|
606
|
+
});
|
|
607
|
+
if (entries.every((entry) => entry.noop)) {
|
|
608
|
+
return { tree, files: [...files, ...entries.map(({ path }) => ({ path, oid: null }))] };
|
|
609
|
+
}
|
|
610
|
+
try {
|
|
611
|
+
return await applyInIndex(state, tree, entries, files, temporaryIndexEnv(state), { batch: true });
|
|
612
|
+
} catch {
|
|
613
|
+
// The original sequence in the shadow index: it fails, if at all, as before.
|
|
614
|
+
return await applyInShadowIndex(state, tree, entries, files);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
let temporaryIndexSeq = 0;
|
|
619
|
+
|
|
620
|
+
/** An environment whose git index is a fresh file in the shadow repository. */
|
|
621
|
+
function temporaryIndexEnv(state) {
|
|
622
|
+
const index = join(state.gitDir, `index.baseline-${process.pid}-${++temporaryIndexSeq}`);
|
|
623
|
+
return { ...process.env, GIT_INDEX_FILE: index };
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/** `content` written as a blob, converted as the file at `path` would be. */
|
|
627
|
+
async function hashBlob(state, path, content, env) {
|
|
628
|
+
const result = await runGit(shadowArgs(state, ['hash-object', '-w', '--stdin', '--path', path]), {
|
|
629
|
+
cwd: state.root,
|
|
630
|
+
input: content,
|
|
631
|
+
env,
|
|
632
|
+
});
|
|
633
|
+
return clean(result.stdout);
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
let blobWorkSeq = 0;
|
|
637
|
+
// A path component a scratch worktree file could not carry unchanged: a
|
|
638
|
+
// character or name the platform rewrites (Windows device names, trailing dots
|
|
639
|
+
// and spaces, 8.3 aliases) or git treats specially (`.git`, `.gitattributes`).
|
|
640
|
+
const UNBATCHABLE_COMPONENT =
|
|
641
|
+
/[\u0000-\u001f"*:<>?|\\]|[. ]$|~\d|^(?:con|prn|aux|nul|(?:com|lpt)[0-9\u00b9\u00b2\u00b3])(?:\..*)?$|^\.(?:git|gitattributes)$/i;
|
|
642
|
+
// Longest scratch file path written: below the classic Windows MAX_PATH.
|
|
643
|
+
const MAX_BATCH_PATH = 240;
|
|
644
|
+
|
|
645
|
+
function batchKey(path) {
|
|
646
|
+
return path.normalize('NFC').toLowerCase();
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/** Blob ids of `items` (`{ path, content }`) as `hash-object --stdin --path`
|
|
650
|
+
* gives them, in a constant number of git processes. hash-object takes its
|
|
651
|
+
* attributes, `core.autocrlf` and eol conversion from the file's path, so the
|
|
652
|
+
* contents are written to a scratch worktree at the same relative paths, with
|
|
653
|
+
* the real worktree's `.gitattributes` files beside them, and hashed there by
|
|
654
|
+
* one `hash-object --stdin-paths`: the same attribute stack, the same
|
|
655
|
+
* conversion code. A path with a `filter=` attribute (a clean driver may read
|
|
656
|
+
* the worktree) and a path the scratch worktree cannot represent exactly are
|
|
657
|
+
* hashed one by one as before. Any failure throws and the caller falls back. */
|
|
658
|
+
async function hashBlobs(state, items, env) {
|
|
659
|
+
const ids = new Map();
|
|
660
|
+
const batched = [];
|
|
661
|
+
const single = [];
|
|
662
|
+
const keys = new Set();
|
|
663
|
+
const scratch = join(state.gitDir, `baseline-work-${process.pid}-${++blobWorkSeq}`);
|
|
664
|
+
for (const item of items) {
|
|
665
|
+
const key = batchKey(item.path);
|
|
666
|
+
const fits =
|
|
667
|
+
!keys.has(key) &&
|
|
668
|
+
scratch.length + 1 + item.path.length <= MAX_BATCH_PATH &&
|
|
669
|
+
!item.path.split('/').some((part) => UNBATCHABLE_COMPONENT.test(part));
|
|
670
|
+
if (fits) {
|
|
671
|
+
keys.add(key);
|
|
672
|
+
batched.push(item);
|
|
673
|
+
} else {
|
|
674
|
+
single.push(item);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
if (batched.length > 0) {
|
|
678
|
+
try {
|
|
679
|
+
const directories = new Set(['']);
|
|
680
|
+
for (const { path } of batched) {
|
|
681
|
+
for (let dir = dirname(path); dir !== '.'; dir = dirname(dir)) directories.add(dir);
|
|
682
|
+
}
|
|
683
|
+
await mkdir(scratch, { recursive: true });
|
|
684
|
+
await Promise.all([...directories].map((dir) => mkdir(join(scratch, dir), { recursive: true })));
|
|
685
|
+
await Promise.all([
|
|
686
|
+
...batched.map(({ path, content }) => writeFile(join(scratch, path), content)),
|
|
687
|
+
// git ignores a symbolic-link .gitattributes, so only a regular file is carried over.
|
|
688
|
+
...[...directories].map(async (dir) => {
|
|
689
|
+
const source = join(state.root, dir, '.gitattributes');
|
|
690
|
+
if ((await lstat(source).catch(() => null))?.isFile())
|
|
691
|
+
await copyFile(source, join(scratch, dir, '.gitattributes'));
|
|
692
|
+
}),
|
|
693
|
+
]);
|
|
694
|
+
const options = { cwd: scratch, env };
|
|
695
|
+
const filtered = await runGit(shadowArgs(state, ['check-attr', '-z', '--stdin', 'filter'], scratch), {
|
|
696
|
+
...options,
|
|
697
|
+
input: `${batched.map(({ path }) => path).join('\0')}\0`,
|
|
698
|
+
});
|
|
699
|
+
const fields = filtered.stdout.split('\0');
|
|
700
|
+
const driven = new Set();
|
|
701
|
+
for (let index = 0; index + 2 < fields.length; index += 3) {
|
|
702
|
+
if (fields[index + 2] !== 'unspecified') driven.add(fields[index]);
|
|
703
|
+
}
|
|
704
|
+
const plain = batched.filter((item) => {
|
|
705
|
+
if (!driven.has(item.path)) return true;
|
|
706
|
+
single.push(item);
|
|
707
|
+
return false;
|
|
708
|
+
});
|
|
709
|
+
if (plain.length > 0) {
|
|
710
|
+
const hashed = await runGit(shadowArgs(state, ['hash-object', '-w', '--stdin-paths'], scratch), {
|
|
711
|
+
...options,
|
|
712
|
+
input: `${plain.map(({ path }) => path).join('\n')}\n`,
|
|
713
|
+
});
|
|
714
|
+
const oids = hashed.stdout.split('\n').filter(Boolean);
|
|
715
|
+
if (oids.length !== plain.length) throw new Error('hash-object answered a different number of blobs');
|
|
716
|
+
plain.forEach((item, index) => {
|
|
717
|
+
ids.set(item, oids[index].trim());
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
} finally {
|
|
721
|
+
await rm(scratch, { recursive: true, force: true }).catch(() => {});
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
for (const item of single) ids.set(item, await hashBlob(state, item.path, item.content, env));
|
|
725
|
+
return ids;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// Longest ls-tree command line the directory/file probe sends.
|
|
729
|
+
const MAX_PROBE_CHARS = 24_000;
|
|
730
|
+
|
|
731
|
+
/** Every proper parent directory of `path`, outermost last. */
|
|
732
|
+
function parentDirectories(path) {
|
|
733
|
+
const parents = [];
|
|
734
|
+
for (let dir = dirname(path); dir !== '.' && dir !== '/'; dir = dirname(dir)) parents.push(dir);
|
|
735
|
+
return parents;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
/** Could `update-index --index-info` take `addPaths` on top of `tree` without
|
|
739
|
+
* replacing anything? Unlike `--cacheinfo`, it replaces a file by a directory
|
|
740
|
+
* of the same name and the reverse; the per-file sequence refuses both and
|
|
741
|
+
* the caller must see that refusal. False for a pair of added paths where one
|
|
742
|
+
* is a directory of the other, or an added path whose parent is a file (or
|
|
743
|
+
* submodule) in `tree`, or that is a directory in `tree`. A path the probe
|
|
744
|
+
* cannot ask about exactly (a leading ':' is pathspec magic) or too many to
|
|
745
|
+
* ask at once counts as unsafe, so the caller runs the per-file sequence. */
|
|
746
|
+
async function addsReplaceNothing(state, tree, addPaths, env) {
|
|
747
|
+
if (addPaths.length === 0) return true;
|
|
748
|
+
if (addPaths.some((path) => path.startsWith(':'))) return false;
|
|
749
|
+
const added = new Set(addPaths);
|
|
750
|
+
const parents = new Set(addPaths.flatMap(parentDirectories));
|
|
751
|
+
if ([...parents].some((dir) => added.has(dir))) return false;
|
|
752
|
+
const asked = [...new Set([...added, ...parents])];
|
|
753
|
+
if (asked.reduce((total, path) => total + path.length + 1, 0) > MAX_PROBE_CHARS) return false;
|
|
754
|
+
const listed = await runGit(shadowArgs(state, ['ls-tree', '-z', tree, '--', ...asked]), {
|
|
755
|
+
cwd: state.root,
|
|
756
|
+
env,
|
|
757
|
+
});
|
|
758
|
+
for (const record of listed.stdout.split('\0')) {
|
|
759
|
+
const tab = record.indexOf('\t');
|
|
760
|
+
if (tab < 0) continue;
|
|
761
|
+
const isTree = record.slice(0, tab).split(' ')[1] === 'tree';
|
|
762
|
+
const path = record.slice(tab + 1);
|
|
763
|
+
if (isTree ? added.has(path) : parents.has(path)) return false;
|
|
764
|
+
}
|
|
765
|
+
return true;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/** The entries applied on top of `tree` in an index of their own, removed
|
|
769
|
+
* afterwards: the shadow index is never touched, so it needs no save and
|
|
770
|
+
* restore. Every command (hash-object's attribute lookup included) sees the
|
|
771
|
+
* same index content the original sequence does: `tree` plus the entries so
|
|
772
|
+
* far. Null `env`: the shadow index itself (the caller saves and restores).
|
|
773
|
+
* `batch`: when it spawns fewer git processes and no entry swaps a file for a
|
|
774
|
+
* directory (addsReplaceNothing), every blob is hashed together (hashBlobs)
|
|
775
|
+
* and every add and removal is one `update-index --index-info`, instead of a
|
|
776
|
+
* `hash-object` and an `update-index` per entry. */
|
|
777
|
+
async function applyInIndex(state, tree, entries, baseFiles, env, { batch = false } = {}) {
|
|
778
|
+
const files = [...baseFiles];
|
|
779
|
+
try {
|
|
780
|
+
const live = entries.filter(({ noop }) => !noop);
|
|
781
|
+
const contents = live.filter(({ content }) => content !== null).length;
|
|
782
|
+
const adds = live.filter(({ content, oid }) => content !== null || oid).map(({ path }) => path);
|
|
783
|
+
// Per entry: a hash (content) plus an update-index, or an update-index. In
|
|
784
|
+
// batch: check-attr and hash-object for all contents, an ls-tree probe
|
|
785
|
+
// when anything is added, and one update-index.
|
|
786
|
+
const worthBatching =
|
|
787
|
+
batch && (contents > 0 ? 2 : 0) + 1 + (adds.length > 0 ? 1 : 0) < 2 * contents + (live.length - contents);
|
|
788
|
+
const [, replacesNothing] = await Promise.all([
|
|
789
|
+
runGit(shadowArgs(state, ['read-tree', tree]), { cwd: state.root, env }),
|
|
790
|
+
worthBatching ? addsReplaceNothing(state, tree, adds, env) : false,
|
|
791
|
+
]);
|
|
792
|
+
if (replacesNothing) {
|
|
793
|
+
const hashed = await hashBlobs(
|
|
794
|
+
state,
|
|
795
|
+
live.filter(({ content }) => content !== null),
|
|
796
|
+
env
|
|
797
|
+
);
|
|
798
|
+
const nullOid = '0'.repeat(tree.length);
|
|
799
|
+
let info = '';
|
|
800
|
+
for (const entry of entries) {
|
|
801
|
+
if (entry.noop) {
|
|
802
|
+
files.push({ path: entry.path, oid: null });
|
|
803
|
+
continue;
|
|
804
|
+
}
|
|
805
|
+
const oid = entry.content !== null ? hashed.get(entry) : entry.oid;
|
|
806
|
+
// Mode 0 removes the path, as `update-index --force-remove` did.
|
|
807
|
+
info += oid ? `100644 ${oid}\t${entry.path}\0` : `0 ${nullOid}\t${entry.path}\0`;
|
|
808
|
+
files.push({ path: entry.path, oid });
|
|
809
|
+
}
|
|
810
|
+
await runGit(shadowArgs(state, ['update-index', '-z', '--index-info']), {
|
|
811
|
+
cwd: state.root,
|
|
812
|
+
env,
|
|
813
|
+
input: info,
|
|
814
|
+
});
|
|
815
|
+
entries = [];
|
|
816
|
+
}
|
|
817
|
+
for (const { path, content, oid: recorded, noop } of entries) {
|
|
818
|
+
if (noop) {
|
|
819
|
+
files.push({ path, oid: null });
|
|
820
|
+
continue;
|
|
821
|
+
}
|
|
822
|
+
let oid = recorded;
|
|
823
|
+
if (content !== null) {
|
|
824
|
+
oid = await hashBlob(state, path, content, env);
|
|
575
825
|
}
|
|
576
826
|
if (oid) {
|
|
577
827
|
await runGit(shadowArgs(state, ['update-index', '--add', '--cacheinfo', '100644', oid, path]), {
|
|
578
828
|
cwd: state.root,
|
|
829
|
+
env,
|
|
579
830
|
});
|
|
580
831
|
} else {
|
|
581
|
-
await runGit(shadowArgs(state, ['update-index', '--force-remove', '--', path]), { cwd: state.root });
|
|
832
|
+
await runGit(shadowArgs(state, ['update-index', '--force-remove', '--', path]), { cwd: state.root, env });
|
|
582
833
|
}
|
|
583
834
|
files.push({ path, oid });
|
|
584
835
|
}
|
|
585
836
|
return {
|
|
586
|
-
tree: clean((await runGit(shadowArgs(state, ['write-tree']), { cwd: state.root })).stdout),
|
|
837
|
+
tree: clean((await runGit(shadowArgs(state, ['write-tree']), { cwd: state.root, env })).stdout),
|
|
587
838
|
files,
|
|
588
839
|
};
|
|
840
|
+
} finally {
|
|
841
|
+
if (env) {
|
|
842
|
+
await rm(env.GIT_INDEX_FILE, { force: true }).catch(() => {});
|
|
843
|
+
await rm(`${env.GIT_INDEX_FILE}.lock`, { force: true }).catch(() => {});
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
/** The original sequence: the shadow index saved as a tree, used, restored. */
|
|
849
|
+
async function applyInShadowIndex(state, tree, entries, files) {
|
|
850
|
+
const saved = clean((await runGit(shadowArgs(state, ['write-tree']), { cwd: state.root })).stdout);
|
|
851
|
+
try {
|
|
852
|
+
return await applyInIndex(state, tree, entries, files, null);
|
|
589
853
|
} finally {
|
|
590
854
|
await runGit(shadowArgs(state, ['read-tree', saved]), { cwd: state.root });
|
|
591
855
|
}
|
|
@@ -603,13 +867,26 @@ async function materializeToolBaselines(snapshot) {
|
|
|
603
867
|
}
|
|
604
868
|
);
|
|
605
869
|
const present = new Set(splitNulList(listed.stdout).map(pathKey));
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
870
|
+
// A leading ':' is pathspec magic to ls-tree and check-ignore: such a path
|
|
871
|
+
// may not have been read literally, so every read below runs as before.
|
|
872
|
+
const literal = paths.every((path) => !path.startsWith(':'));
|
|
873
|
+
// The ignore answer is only consulted for bytes kept for a path that is
|
|
874
|
+
// neither in the baseline tree nor tracked, and small enough to keep.
|
|
875
|
+
const asksIgnored = ([path, content]) =>
|
|
876
|
+
Buffer.isBuffer(content) &&
|
|
877
|
+
!present.has(pathKey(path)) &&
|
|
878
|
+
!state.sourceTracked.has(pathKey(path)) &&
|
|
879
|
+
content.length <= MAX_UNTRACKED_FILE_BYTES;
|
|
880
|
+
let ignored = new Set();
|
|
881
|
+
if (!literal || pending.some(asksIgnored)) {
|
|
882
|
+
const ignoredResult = await runGit(['check-ignore', '--no-index', '-z', '--stdin'], {
|
|
883
|
+
cwd: state.root,
|
|
884
|
+
input: `${paths.join('\0')}\0`,
|
|
885
|
+
allowFailure: true,
|
|
886
|
+
});
|
|
887
|
+
if (ignoredResult.code > 1) throw commandError(['check-ignore'], ignoredResult.stderr, ignoredResult.code);
|
|
888
|
+
ignored = new Set(splitNulList(ignoredResult.stdout).map(pathKey));
|
|
889
|
+
}
|
|
613
890
|
const missing = pending
|
|
614
891
|
.filter(
|
|
615
892
|
([path, content]) =>
|
|
@@ -624,7 +901,9 @@ async function materializeToolBaselines(snapshot) {
|
|
|
624
901
|
.map(([path, content]) =>
|
|
625
902
|
isOmittedBaseline(content) ? { path, omitted: true, size: content.size } : { path, content }
|
|
626
903
|
);
|
|
627
|
-
|
|
904
|
+
// A path ls-tree read literally and did not list is not in the tree.
|
|
905
|
+
const absent = literal ? new Set(paths.map(pathKey).filter((key) => !present.has(key))) : null;
|
|
906
|
+
const applied = await applyBaselineFilesUnlocked(state, snapshot.baselineTree, missing, { absent });
|
|
628
907
|
snapshot.baselineTree = applied.tree;
|
|
629
908
|
for (const entry of applied.files) snapshot.baselineFiles.set(pathKey(entry.path), entry);
|
|
630
909
|
for (const [path] of pending) snapshot.pendingBaselines.delete(path);
|
|
@@ -710,14 +989,68 @@ async function patchSectionsByPath(state, baselineTree, currentTree, pathspec, m
|
|
|
710
989
|
if (error?.code === 'EMAXBUFFER') return null;
|
|
711
990
|
throw error;
|
|
712
991
|
}
|
|
992
|
+
return sectionsByPath(result.stdout);
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
function sectionsByPath(patchText) {
|
|
713
996
|
const sections = new Map();
|
|
714
|
-
for (const section of splitPatchSections(Buffer.from(
|
|
997
|
+
for (const section of splitPatchSections(Buffer.from(patchText, 'utf8'))) {
|
|
715
998
|
const path = section.newPath ?? section.oldPath;
|
|
716
999
|
if (path) sections.set(pathKey(path), section.patch);
|
|
717
1000
|
}
|
|
718
1001
|
return sections;
|
|
719
1002
|
}
|
|
720
1003
|
|
|
1004
|
+
/** A range's name-status, numstat and whole patch from one `git diff`
|
|
1005
|
+
* (`--raw --numstat --patch -z`: raw records, numstat records, a NUL, then
|
|
1006
|
+
* the same patch bytes a patch-only read prints). Null when that read fails
|
|
1007
|
+
* or passes the patch read's byte cap, or its output is not that shape: the
|
|
1008
|
+
* caller then takes the separate reads, which fail or bound exactly as
|
|
1009
|
+
* before. */
|
|
1010
|
+
async function combinedTreeDiff(state, rangeArgs) {
|
|
1011
|
+
let result;
|
|
1012
|
+
try {
|
|
1013
|
+
result = await runGit(
|
|
1014
|
+
shadowArgs(state, ['diff', '--raw', '--numstat', '--patch', '--no-ext-diff', '--unified=3', '-z', ...rangeArgs]),
|
|
1015
|
+
{ cwd: state.root, maxBytes: COMMAND_MAX_BYTES + PATCH_OUTPUT_SLACK_BYTES, allowFailure: true }
|
|
1016
|
+
);
|
|
1017
|
+
} catch (error) {
|
|
1018
|
+
if (error?.code === 'EMAXBUFFER') return null;
|
|
1019
|
+
throw error;
|
|
1020
|
+
}
|
|
1021
|
+
if (result.code !== 0) return null;
|
|
1022
|
+
const text = String(result.stdout || '');
|
|
1023
|
+
if (!text) return { statuses: new Map(), stats: new Map(), sections: new Map() };
|
|
1024
|
+
// Raw records (each starts with ':') re-shaped as name-status tokens.
|
|
1025
|
+
const nameStatus = [];
|
|
1026
|
+
let cursor = 0;
|
|
1027
|
+
const token = () => {
|
|
1028
|
+
const end = text.indexOf('\0', cursor);
|
|
1029
|
+
if (end < 0) return null;
|
|
1030
|
+
const value = text.slice(cursor, end);
|
|
1031
|
+
cursor = end + 1;
|
|
1032
|
+
return value;
|
|
1033
|
+
};
|
|
1034
|
+
while (text[cursor] === ':') {
|
|
1035
|
+
const header = token();
|
|
1036
|
+
const status = header?.slice(header.lastIndexOf(' ') + 1);
|
|
1037
|
+
if (!status) return null;
|
|
1038
|
+
const paths = [token()];
|
|
1039
|
+
if (status[0] === 'R' || status[0] === 'C') paths.push(token());
|
|
1040
|
+
if (paths.some((path) => !path)) return null;
|
|
1041
|
+
nameStatus.push(status, ...paths);
|
|
1042
|
+
}
|
|
1043
|
+
// Numstat records never hold an empty token after a NUL, so the first NUL
|
|
1044
|
+
// pair ends them; the separator NUL follows.
|
|
1045
|
+
const numstatEnd = text[cursor] === '\0' ? cursor : text.indexOf('\0\0', cursor) + 1;
|
|
1046
|
+
if (numstatEnd <= 0) return null;
|
|
1047
|
+
return {
|
|
1048
|
+
statuses: parseNameStatus(`${nameStatus.join('\0')}\0`),
|
|
1049
|
+
stats: parseNumstat(text.slice(cursor, numstatEnd)),
|
|
1050
|
+
sections: sectionsByPath(text.slice(numstatEnd + 1)),
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
|
|
721
1054
|
/** After the whole range overflowed: patches read in path batches, the
|
|
722
1055
|
* smallest changes first, until the reply's total is spent. A batch that
|
|
723
1056
|
* overflows is halved; a single file that does is too large. */
|
|
@@ -761,6 +1094,12 @@ async function boundedTreePatch(state, baselineTree, currentTree, pathspec, file
|
|
|
761
1094
|
sections = new Map();
|
|
762
1095
|
await batchedPatchSections(state, baselineTree, currentTree, files, sections);
|
|
763
1096
|
}
|
|
1097
|
+
return boundedTreePatchFromSections(files, sections, whole);
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
/** `files` with the patch `sections` that fit the reply caps; `whole`: the
|
|
1101
|
+
* sections are a complete read, so a file without one has no patch. */
|
|
1102
|
+
function boundedTreePatchFromSections(files, sections, whole) {
|
|
764
1103
|
const budget = createReviewPatchBudget();
|
|
765
1104
|
const kept = [];
|
|
766
1105
|
const bounded = files.map((file) => {
|
|
@@ -783,12 +1122,35 @@ async function diffTreesUnlocked(state, baselineTree, currentTree, paths = null)
|
|
|
783
1122
|
// baseline describes the whole worktree, concurrent sessions included.
|
|
784
1123
|
const pathspec = Array.isArray(paths) && paths.length > 0 ? paths : ['.'];
|
|
785
1124
|
const rangeArgs = ['--find-renames', baselineTree, currentTree, '--', ...pathspec];
|
|
1125
|
+
const combined = await combinedTreeDiff(state, rangeArgs);
|
|
1126
|
+
if (combined) {
|
|
1127
|
+
const files = reviewFiles(combined.statuses, combined.stats);
|
|
1128
|
+
const bounded = boundedTreePatchFromSections(files, combined.sections, true);
|
|
1129
|
+
return {
|
|
1130
|
+
patch: bounded.patch,
|
|
1131
|
+
files: bounded.files,
|
|
1132
|
+
patchTruncated: false,
|
|
1133
|
+
diffTooLarge: reviewDiffTooLarge(bounded.files, bounded.patch),
|
|
1134
|
+
currentTree,
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
786
1137
|
const [nameStatus, numstat] = await Promise.all([
|
|
787
1138
|
runGit(shadowArgs(state, ['diff', '--name-status', '-z', ...rangeArgs]), { cwd: state.root }),
|
|
788
1139
|
runGit(shadowArgs(state, ['diff', '--numstat', '-z', ...rangeArgs]), { cwd: state.root }),
|
|
789
1140
|
]);
|
|
790
|
-
const
|
|
791
|
-
const
|
|
1141
|
+
const files = reviewFiles(parseNameStatus(nameStatus.stdout), parseNumstat(numstat.stdout));
|
|
1142
|
+
const bounded = await boundedTreePatch(state, baselineTree, currentTree, pathspec, files);
|
|
1143
|
+
return {
|
|
1144
|
+
patch: bounded.patch,
|
|
1145
|
+
files: bounded.files,
|
|
1146
|
+
patchTruncated: false,
|
|
1147
|
+
diffTooLarge: reviewDiffTooLarge(bounded.files, bounded.patch),
|
|
1148
|
+
currentTree,
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
/** Review rows from the name-status and numstat reads of one range. */
|
|
1153
|
+
function reviewFiles(statuses, stats) {
|
|
792
1154
|
const keys = [...new Set([...statuses.keys(), ...stats.keys()])];
|
|
793
1155
|
const files = keys
|
|
794
1156
|
.map((key) => {
|
|
@@ -804,14 +1166,7 @@ async function diffTreesUnlocked(state, baselineTree, currentTree, paths = null)
|
|
|
804
1166
|
};
|
|
805
1167
|
})
|
|
806
1168
|
.sort((left, right) => left.path.localeCompare(right.path));
|
|
807
|
-
|
|
808
|
-
return {
|
|
809
|
-
patch: bounded.patch,
|
|
810
|
-
files: bounded.files,
|
|
811
|
-
patchTruncated: false,
|
|
812
|
-
diffTooLarge: reviewDiffTooLarge(bounded.files, bounded.patch),
|
|
813
|
-
currentTree,
|
|
814
|
-
};
|
|
1169
|
+
return files;
|
|
815
1170
|
}
|
|
816
1171
|
|
|
817
1172
|
/** One file's patch between two trees (a rename read with its old path), up
|
|
@@ -67,8 +67,15 @@ export function createWorkerRequestClient(url, { idleExitMs = 0, onEvent = null,
|
|
|
67
67
|
created.unref();
|
|
68
68
|
if (worker === created) armIdleTimer(created);
|
|
69
69
|
}
|
|
70
|
-
if (error)
|
|
71
|
-
|
|
70
|
+
if (error) {
|
|
71
|
+
entry.reject(
|
|
72
|
+
Object.assign(
|
|
73
|
+
new Error(error.message),
|
|
74
|
+
{ code: error.code },
|
|
75
|
+
typeof error.childExited === 'boolean' ? { childExited: error.childExited, pid: error.pid } : {}
|
|
76
|
+
)
|
|
77
|
+
);
|
|
78
|
+
} else entry.resolve(result);
|
|
72
79
|
});
|
|
73
80
|
created.on('error', (error) => {
|
|
74
81
|
if (worker === created) {
|
|
@@ -132,7 +139,14 @@ export function serveWorkerRequests(handler) {
|
|
|
132
139
|
(error) =>
|
|
133
140
|
parentPort.postMessage({
|
|
134
141
|
id,
|
|
135
|
-
error: {
|
|
142
|
+
error: {
|
|
143
|
+
message: String(error?.message || error),
|
|
144
|
+
code: error?.code ?? null,
|
|
145
|
+
// A timed-out child's fate (run-child.mjs waitForExitMs).
|
|
146
|
+
...(typeof error?.childExited === 'boolean'
|
|
147
|
+
? { childExited: error.childExited, pid: error.pid ?? null }
|
|
148
|
+
: {}),
|
|
149
|
+
},
|
|
136
150
|
})
|
|
137
151
|
);
|
|
138
152
|
});
|