mixdog 1.4.0 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -2
- package/scripts/build-shipped-history.mjs +115 -33
- package/scripts/check-voice-runtime-inputs.mjs +25 -0
- package/scripts/gate-local.mjs +183 -63
- package/scripts/latest-guard.mjs +21 -9
- package/scripts/lib/gate-scheduler.mjs +138 -32
- package/scripts/lib/gate-timing-reporter.mjs +16 -0
- package/scripts/lib/isolated-test-env.mjs +10 -5
- package/scripts/lib/run-node-tests.mjs +91 -66
- package/scripts/lib/scoped-temp.d.mts +16 -0
- package/scripts/lib/scoped-temp.mjs +124 -0
- package/scripts/lib/stale-temp.mjs +44 -0
- package/scripts/lib/test-failure-records.mjs +14 -1
- package/scripts/lib/test-failure-summary.mjs +16 -4
- package/scripts/lib/test-spawn-ledger.mjs +12 -3
- package/scripts/post-release-check.mjs +1 -6
- package/scripts/pptx-kit-index.mjs +17 -5
- package/scripts/suite-health.mjs +115 -24
- package/scripts/test-data-dir.mjs +10 -7
- package/scripts/test.mjs +9 -14
- package/src/agents/advisor/AGENT.md +4 -4
- package/src/agents/advisor/agent.json +1 -1
- package/src/agents/explore/AGENT.md +22 -0
- package/src/agents/explore/agent.json +6 -0
- package/src/app.mjs +4 -0
- package/src/cli.mjs +7 -0
- package/src/defaults/agents.json +7 -0
- package/src/defaults/shipped-history.json +23 -2
- package/src/defaults/skills/browser-use/SKILL.md +10 -5
- package/src/defaults/skills/code-tidy/SKILL.md +71 -102
- package/src/defaults/skills/code-tidy/references/agent-cleanup.md +66 -114
- package/src/defaults/skills/code-tidy/references/cleanup-report.md +19 -35
- package/src/defaults/skills/code-tidy/references/dead-code.md +3 -9
- package/src/defaults/skills/code-tidy/references/test-suite-slop.md +16 -27
- package/src/defaults/skills/computer-use/SKILL.md +16 -4
- package/src/defaults/skills/goal-management/SKILL.md +1 -1
- package/src/defaults/skills/setup/references/actions.md +12 -6
- package/src/defaults/skills/setup/references/surfaces.md +2 -2
- package/src/defaults/skills/setup-guide/SKILL.md +5 -2
- package/src/defaults/skills/setup-guide/model-recommendations.json +13 -0
- package/src/defaults/skills/skill-creator/SKILL.md +85 -190
- package/src/defaults/skills/skill-creator/references/design.md +70 -162
- package/src/defaults/skills/skill-creator/references/evaluation.md +33 -92
- package/src/defaults/skills/test-suite/SKILL.md +194 -0
- package/src/defaults/skills/test-suite/references/case-management.md +51 -0
- package/src/defaults/skills/test-suite/references/flaky-policy.md +39 -0
- package/src/defaults/skills/test-suite/references/reliability.md +49 -0
- package/src/defaults/skills/test-suite/references/suite-design.md +78 -0
- package/src/defaults/skills/test-suite/scripts/inventory.mjs +335 -0
- package/src/defaults/skills/visualize/SKILL.md +6 -2
- package/src/lib/rules-builder.cjs +35 -42
- package/src/output-styles/common.md +2 -2
- package/src/output-styles/simple.md +1 -1
- package/src/rules/agent/AGENT.md +5 -4
- package/src/rules/lead/LEAD.md +12 -7
- package/src/rules/shared/10-tool-workflow.md +3 -1
- package/src/rules/shared/20-research.md +3 -6
- package/src/rules/shared/40-editing.md +1 -0
- package/src/rules/shared/45-destructive.md +0 -2
- package/src/rules/shared/50-execution.md +2 -0
- package/src/rules/shared/60-verification.md +10 -9
- package/src/rules/shared/70-delivery.md +8 -9
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/abort-link.mjs +5 -1
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +10 -1
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +156 -24
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +13 -0
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +4 -1
- package/src/runtime/agent/orchestrator/cache-break-trace.mjs +2 -0
- package/src/runtime/agent/orchestrator/config.mjs +12 -7
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +8 -8
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +5 -26
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +3 -1
- package/src/runtime/agent/orchestrator/internal-agents.mjs +3 -14
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +122 -12
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +5 -3
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +13 -2
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +152 -58
- package/src/runtime/agent/orchestrator/mcp/client.mjs +51 -18
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +88 -54
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +42 -26
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +54 -8
- package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +37 -31
- package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +8 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +31 -21
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +14 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +6 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +40 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider-keys.mjs +34 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +14 -7
- package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/devin.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +248 -41
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -11
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +45 -6
- package/src/runtime/agent/orchestrator/providers/lib/first-output-window.mjs +58 -0
- package/src/runtime/agent/orchestrator/providers/lib/listen-on.mjs +14 -0
- package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +0 -18
- package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +138 -6
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/model-cache.mjs +100 -33
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/oauth-secret-fields.fixtures.mjs +45 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +14 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +4 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +5 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +16 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +13 -3
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +13 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +81 -42
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +160 -31
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +22 -12
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +49 -22
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/registry.mjs +45 -2
- package/src/runtime/agent/orchestrator/providers/vertex-ai-auth.mjs +622 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai-maas.mjs +185 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai-models.mjs +445 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai.mjs +567 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +41 -13
- package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -6
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +7 -3
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +6 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +14 -5
- package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -0
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -5
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +171 -37
- package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +1 -3
- package/src/runtime/agent/orchestrator/session/cache-warm.mjs +102 -12
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -8
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +23 -0
- package/src/runtime/agent/orchestrator/session/compact/observation-supersession.mjs +103 -23
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +160 -36
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +164 -23
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +139 -19
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +38 -7
- package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +100 -22
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -3
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -6
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +33 -3
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +9 -2
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +13 -5
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +23 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +23 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +39 -21
- package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +13 -8
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +50 -28
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +30 -13
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +63 -6
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +35 -13
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +24 -14
- package/src/runtime/agent/orchestrator/session/manager/session-scratch-environment.mjs +70 -0
- package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +0 -3
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +10 -6
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +56 -29
- package/src/runtime/agent/orchestrator/session/manager/turn-reap.mjs +125 -0
- package/src/runtime/agent/orchestrator/session/mixy-name.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +30 -7
- package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +154 -0
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +37 -8
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +252 -39
- package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +163 -64
- package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +164 -4
- package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +142 -18
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +61 -2
- package/src/runtime/agent/orchestrator/stall-policy.mjs +23 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +46 -20
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +67 -31
- package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +25 -13
- package/src/runtime/agent/orchestrator/tools/builtin/lib/scoped-search-flight.mjs +9 -5
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +58 -20
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +23 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +1 -8
- package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +20 -15
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +96 -20
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +59 -10
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/federation.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/lib/isolated-test-env.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs +99 -2
- package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +103 -13
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +49 -15
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +45 -27
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +34 -10
- package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +28 -4
- package/src/runtime/agent/orchestrator/tools/lib/wait-until-fixture.mjs +26 -0
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -2
- package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
- package/src/runtime/channels/lib/webhook/signature.mjs +4 -1
- package/src/runtime/channels/lib/whisper-port.mjs +29 -11
- package/src/runtime/channels/lib/whisper-server.mjs +10 -1
- package/src/runtime/computer-bridge/action-schema.mjs +2 -2
- package/src/runtime/computer-bridge/core-actions.mjs +2 -2
- package/src/runtime/computer-bridge/error-recovery.mjs +5 -4
- package/src/runtime/computer-bridge/linux-action-capabilities.mjs +24 -5
- package/src/runtime/computer-bridge/linux-readiness.d.mts +7 -2
- package/src/runtime/connectors/connector-accounts-mcp.mjs +236 -103
- package/src/runtime/connectors/gmail-app-password.mjs +3 -3
- package/src/runtime/explore/explorer.mjs +93 -0
- package/src/runtime/explore/tool-defs.mjs +35 -0
- package/src/runtime/explore/tool.mjs +123 -0
- package/src/runtime/local-provider/server-process.mjs +2 -1
- package/src/runtime/media/adapters/gemini-video.mjs +4 -1
- package/src/runtime/media/adapters/xai-media.mjs +2 -1
- package/src/runtime/memory/index.mjs +4 -0
- package/src/runtime/memory/lib/embedding-provider.mjs +4 -1
- package/src/runtime/memory/lib/embedding-worker.mjs +10 -3
- package/src/runtime/memory/lib/memory-action-handlers/cycle-backfill-action.mjs +1 -7
- package/src/runtime/memory/lib/memory-chunk-quality.mjs +1 -6
- package/src/runtime/office/authoring/pdf-author-action.mjs +1 -6
- package/src/runtime/office/design/design-art-direction.mjs +29 -27
- package/src/runtime/office/pdf/pdf-writer.mjs +6 -1
- package/src/runtime/office/portable/portable-snapshot-docx.mjs +7 -1
- package/src/runtime/office/portable/portable-snapshot-shared.mjs +6 -1
- package/src/runtime/office/quality/assurance-rendered.mjs +9 -2
- package/src/runtime/office/quality/assurance-structure-docx.mjs +4 -2
- package/src/runtime/office/quality/design-review.mjs +1 -5
- package/src/runtime/office/quality/document-brief.mjs +1 -5
- package/src/runtime/office/quality/forced-break-pages.mjs +9 -6
- package/src/runtime/office/quality/quality-pipeline.mjs +1 -1
- package/src/runtime/shared/agent-route-config.mjs +17 -2
- package/src/runtime/shared/atomic-file.mjs +103 -2
- package/src/runtime/shared/background-tasks.mjs +15 -6
- package/src/runtime/shared/bot-owned-work.mjs +56 -0
- package/src/runtime/shared/connector-accounts.mjs +5 -5
- package/src/runtime/shared/connector-catalog.d.mts +11 -4
- package/src/runtime/shared/connector-catalog.mjs +60 -52
- package/src/runtime/shared/custom-provider-keys.mjs +20 -0
- package/src/runtime/shared/defaults-separation.mjs +1 -4
- package/src/runtime/shared/fetch-safe-listen.d.mts +16 -0
- package/src/runtime/shared/fetch-safe-listen.mjs +50 -0
- package/src/runtime/shared/file-has-data.mjs +26 -2
- package/src/runtime/shared/file-lock.mjs +13 -15
- package/src/runtime/shared/git-launch.d.mts +9 -0
- package/src/runtime/shared/git-launch.mjs +213 -0
- package/src/runtime/shared/git-runner-worker.mjs +2 -1
- package/src/runtime/shared/handoff-artifacts.d.mts +2 -1
- package/src/runtime/shared/handoff-artifacts.mjs +18 -8
- package/src/runtime/shared/idle-auto-clear-gate.mjs +29 -7
- package/src/runtime/shared/llm/cost.mjs +11 -2
- package/src/runtime/shared/llm/http-agent.mjs +313 -29
- package/src/runtime/shared/llm/model-catalog-projection.mjs +3 -2
- package/src/runtime/shared/llm/model-catalog.mjs +46 -6
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +3 -0
- package/src/runtime/shared/llm/system-proxy.mjs +452 -0
- package/src/runtime/shared/loopback-listener.mjs +25 -2
- package/src/runtime/shared/model-route-chain.d.mts +7 -2
- package/src/runtime/shared/model-route-chain.mjs +22 -4
- package/src/runtime/shared/open-url.mjs +10 -0
- package/src/runtime/shared/provider-accounts.mjs +52 -2
- package/src/runtime/shared/session-activity-signal.mjs +14 -0
- package/src/runtime/shared/session-scratch.mjs +37 -0
- package/src/runtime/shared/staged-install-worker.mjs +5 -0
- package/src/runtime/shared/staged-update.mjs +47 -2
- package/src/runtime/shared/tool-card-model/agent-surface.mjs +1 -3
- package/src/runtime/shared/tool-card-model/card-status.mjs +15 -2
- package/src/runtime/shared/tool-result-summary.mjs +1 -1
- package/src/runtime/shared/tool-surface.mjs +113 -36
- package/src/runtime/shared/tool-work-units.mjs +6 -0
- package/src/runtime/shared/turn-snapshot-store.mjs +13 -6
- package/src/runtime/shared/turn-worktree-snapshot.mjs +414 -54
- package/src/runtime/shared/worktrees/activity-gate.mjs +215 -318
- package/src/runtime/shared/worktrees/activity-ledger-worker.mjs +56 -0
- package/src/runtime/shared/worktrees/activity-ledger.mjs +391 -0
- package/src/runtime/shared/worktrees/branch-management.mjs +9 -3
- package/src/runtime/shared/worktrees/contract.mjs +4 -1
- package/src/runtime/shared/worktrees/git.mjs +72 -0
- package/src/runtime/shared/worktrees/manager.mjs +285 -168
- package/src/runtime/shared/worktrees/test-support.mjs +6 -10
- package/src/runtime/tidy/install.mjs +95 -15
- package/src/runtime/tidy/languages.mjs +17 -15
- package/src/runtime/tidy/process.mjs +7 -4
- package/src/runtime/tidy/resolve.mjs +19 -16
- package/src/runtime/tidy/runners/biome.mjs +3 -3
- package/src/runtime/tidy/tool.mjs +1 -1
- package/src/runtime/tidy/worktree.mjs +10 -6
- package/src/runtime/visualize-bridge/client.mjs +6 -1
- package/src/runtime/visualize-bridge/tool-defs.mjs +7 -2
- package/src/runtime/web-search/index.mjs +1 -1
- package/src/session-runtime/agent-home-delivery.mjs +41 -0
- package/src/session-runtime/agent-task-sessions.mjs +458 -312
- package/src/session-runtime/agent-tool-routing.mjs +8 -41
- package/src/session-runtime/boot/tools.mjs +7 -1
- package/src/session-runtime/bot-status.mjs +107 -101
- package/src/session-runtime/bot-target.mjs +38 -0
- package/src/session-runtime/channel-config-api.mjs +6 -1
- package/src/session-runtime/connector-merge-migration.mjs +18 -15
- package/src/session-runtime/conversation-import/codex-titles.mjs +88 -0
- package/src/session-runtime/conversation-import/discovery.mjs +401 -36
- package/src/session-runtime/conversation-import/service.mjs +35 -8
- package/src/session-runtime/handoff-attachments.mjs +82 -31
- package/src/session-runtime/held-requests.mjs +3 -1
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +12 -13
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +1 -0
- package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -0
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +8 -0
- package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +4 -1
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +145 -112
- package/src/session-runtime/lifecycle/cold-heir.mjs +11 -6
- package/src/session-runtime/lifecycle/session-catalog.mjs +9 -1
- package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -1
- package/src/session-runtime/lifecycle/teardown.mjs +1 -1
- package/src/session-runtime/mcp-glue/server-catalog.mjs +16 -10
- package/src/session-runtime/mcp-glue/server-input.mjs +4 -1
- package/src/session-runtime/mixy-heartbeat.mjs +1 -1
- package/src/session-runtime/model-route/set-route.mjs +11 -2
- package/src/session-runtime/provider-auth/login.mjs +2 -2
- package/src/session-runtime/provider-catalog-cache.mjs +82 -36
- package/src/session-runtime/provider-models/catalog-load.mjs +23 -6
- package/src/session-runtime/provider-models.mjs +4 -2
- package/src/session-runtime/resource-mcp-api.mjs +98 -35
- package/src/session-runtime/resource-mcp-connector-accounts.mjs +44 -31
- package/src/session-runtime/resource-mcp-secrets.mjs +28 -11
- package/src/session-runtime/resource-mcp-servers.mjs +5 -4
- package/src/session-runtime/resource-recall-api.mjs +6 -1
- package/src/session-runtime/runtime-feature-gates.mjs +5 -1
- package/src/session-runtime/services/agent-tool/execute.mjs +14 -9
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +20 -4
- package/src/session-runtime/services/agent-tool/model-select.mjs +48 -7
- package/src/session-runtime/services/agent-tool/render.mjs +71 -17
- package/src/session-runtime/services/agent-tool/send-flow.mjs +10 -2
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +8 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +4 -1
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +6 -2
- package/src/session-runtime/services/agent-tool/tool-def.mjs +9 -9
- package/src/session-runtime/services/agent-watchdog-registry.mjs +32 -4
- package/src/session-runtime/services/channel-worker/daemon-spawn.mjs +2 -0
- package/src/session-runtime/services/daemon-candidate.mjs +4 -1
- package/src/session-runtime/services/memory-runtime-proxy/daemon-spawn.mjs +4 -0
- package/src/session-runtime/services/plugin-admin.mjs +10 -6
- package/src/session-runtime/services/provider-admin.mjs +283 -11
- package/src/session-runtime/session-turn-api.mjs +2 -0
- package/src/session-runtime/settings-builtin-tools-api.mjs +4 -1
- package/src/session-runtime/settings-system-api.mjs +1 -1
- package/src/session-runtime/setup-tool/agent-settings-actions.mjs +13 -3
- package/src/session-runtime/setup-tool/connector-widen-approval.mjs +96 -0
- package/src/session-runtime/setup-tool/executor.mjs +6 -2
- package/src/session-runtime/setup-tool/tool-defs.mjs +2 -1
- package/src/session-runtime/tool-policy/policy-stage.mjs +1 -0
- package/src/session-runtime/turn/agent-ops.mjs +23 -0
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +49 -11
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +5 -1
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +25 -5
- package/src/session-runtime/workflow-agents-api/onboarding.mjs +3 -3
- package/src/session-runtime/workspace/activity-guards.mjs +176 -0
- package/src/session-runtime/workspace/session-view.mjs +149 -0
- package/src/session-runtime/workspace/side-checkouts.mjs +203 -0
- package/src/session-runtime/workspace/transition-runner.mjs +188 -0
- package/src/session-runtime/workspace/transitions.mjs +108 -1041
- package/src/session-runtime/workspace/workspace-merge.mjs +132 -0
- package/src/session-runtime/workspace/worktree-intents.mjs +242 -0
- package/src/session-runtime/workspace/worktree-maintenance.mjs +80 -0
- package/src/session-runtime/workspace/worktree-setup.mjs +85 -0
- package/src/session-runtime/workspace/worktree-tool.mjs +73 -56
- package/src/standalone/daemon-desktop-runtime.mjs +2 -0
- package/src/standalone/daemon-session-control.mjs +169 -138
- package/src/standalone/daemon.mjs +7 -0
- package/src/standalone/desktop-service-registry.mjs +9 -0
- package/src/standalone/local-session-runtime.mjs +5 -1
- package/src/standalone/session-client/daemon-unavailable.mjs +3 -0
- package/src/standalone/session-client.mjs +5 -1
- package/src/standalone/session-frame-stream.mjs +83 -11
- package/src/standalone/session-protocol.mjs +4 -0
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +16 -12
- package/src/standalone/session-service/agent-tree.mjs +45 -9
- package/src/standalone/session-service/projection/transcript-window.mjs +700 -64
- package/src/standalone/session-service/session-calls/session-action.mjs +10 -3
- package/src/standalone/session-service/session-calls/session-views.mjs +160 -104
- package/src/standalone/session-service/stored-reader.mjs +127 -40
- package/src/standalone/session-transport/client-registry/client-grace.mjs +12 -9
- package/src/tui/App.jsx +154 -164
- package/src/tui/app/app-view/floating-panel.jsx +10 -4
- package/src/tui/app/app-view/text-entry-labels.mjs +1 -0
- package/src/tui/app/clipboard.mjs +21 -10
- package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +1 -3
- package/src/tui/app/model-picker/route-selection.mjs +5 -6
- package/src/tui/app/prompt-handlers/use-prompt-history-nav.mjs +1 -1
- package/src/tui/app/prompt-handlers/use-prompt-interrupt.mjs +3 -0
- package/src/tui/app/prompt-submit/provider-prompts.mjs +3 -1
- package/src/tui/app/provider-setup/api-key-actions.mjs +31 -1
- package/src/tui/app/provider-setup/oauth-actions.mjs +58 -21
- package/src/tui/app/provider-setup/provider-items.mjs +8 -2
- package/src/tui/app/provider-setup-picker.mjs +29 -18
- package/src/tui/app/shell-layout/row-budgets.mjs +12 -10
- package/src/tui/app/slash-commands.mjs +1 -0
- package/src/tui/app/slash-dispatch/session-commands.mjs +46 -0
- package/src/tui/app/slash-dispatch.mjs +1 -1
- package/src/tui/app/use-btw-panel.mjs +29 -0
- package/src/tui/app/use-context-panel-refresh.mjs +31 -0
- package/src/tui/app/use-model-catalog-cache.mjs +13 -10
- package/src/tui/app/use-mouse-input.mjs +11 -0
- package/src/tui/app/use-onboarding-start.mjs +8 -3
- package/src/tui/app/use-panel-transition.mjs +10 -1
- package/src/tui/app/use-pasted-buffers.mjs +28 -20
- package/src/tui/app/use-prompt-draft-flow.mjs +7 -0
- package/src/tui/app/use-prompt-layout-rows.mjs +3 -3
- package/src/tui/app/use-prompt-queue-history.mjs +3 -2
- package/src/tui/app/use-selection-focus.mjs +11 -2
- package/src/tui/app/use-selection-geometry.mjs +18 -9
- package/src/tui/app/use-selection-paint.mjs +4 -4
- package/src/tui/app/use-selection-stitch.mjs +3 -3
- package/src/tui/app/use-slash-palette.mjs +62 -0
- package/src/tui/app/use-terminal-chrome.mjs +2 -2
- package/src/tui/app/use-transcript-activity.mjs +47 -32
- package/src/tui/app/use-transcript-follow.mjs +12 -4
- package/src/tui/app/use-transcript-scroll.mjs +46 -17
- package/src/tui/app/use-transcript-swap-reset.mjs +27 -0
- package/src/tui/app/use-transcript-window/geometry.mjs +19 -5
- package/src/tui/app/use-transcript-window/instance-state.mjs +4 -0
- package/src/tui/app/use-transcript-window/selection-shift.mjs +5 -1
- package/src/tui/app/use-transcript-window.mjs +21 -11
- package/src/tui/app/use-tui-ready.mjs +18 -0
- package/src/tui/app/use-welcome-prompt-hint.mjs +5 -0
- package/src/tui/app/use-workflow-tab-cycle.mjs +5 -3
- package/src/tui/components/Picker.jsx +27 -3
- package/src/tui/components/QuestionPanel.jsx +13 -4
- package/src/tui/components/SignInUrl.jsx +68 -0
- package/src/tui/components/TextEntryPanel.jsx +76 -46
- package/src/tui/components/sign-in-url-layout.mjs +24 -0
- package/src/tui/dist/index.mjs +1963 -1361
- package/src/tui/session/goal-turn-state.mjs +6 -2
- package/src/tui/session/session-api/controls.mjs +4 -0
- package/src/tui/session/session-api/extensions.mjs +8 -0
- package/src/tui/session/session-api/intake/abort.mjs +2 -1
- package/src/tui/session/session-api/intake.mjs +2 -0
- package/src/tui/session/session-api/integrations.mjs +2 -2
- package/src/tui/session/session-api/routes-agent-definitions.mjs +1 -0
- package/src/tui/session/session-api/settings.mjs +2 -2
- package/src/tui/session/session-flow/queue/take-entries.mjs +11 -0
- package/src/tui/session/transcript-spill/spill-writer.mjs +15 -0
- package/src/tui/session/transcript-spill.mjs +92 -4
- package/src/tui/session/transcript-store.mjs +2 -0
- package/src/ui/statusline-agents.mjs +1 -3
- package/src/defaults/skills/skill-creator/references/source-review.md +0 -94
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
textByteLength,
|
|
13
13
|
} from './text-utils.mjs';
|
|
14
14
|
import {
|
|
15
|
+
callArguments,
|
|
15
16
|
contextAckMessage,
|
|
16
17
|
isCompactConversationRow,
|
|
17
18
|
isProtectedContextAckMessage,
|
|
@@ -25,6 +26,7 @@ import { activeTurnContinuationMessage } from './continuation.mjs';
|
|
|
25
26
|
import { EXECUTION_RECOVERY_SOURCE, buildExecutionTail } from './execution-tail.mjs';
|
|
26
27
|
import { latestSkillBodies, skillMessageText } from '../../context/skill-state.mjs';
|
|
27
28
|
import { effectiveBudget } from './budget.mjs';
|
|
29
|
+
import { parseMcpToolName } from '../../../../shared/tool-primitives.mjs';
|
|
28
30
|
import { stripRuntimeUserContext, withRuntimeUserContext } from '../runtime-user-context.mjs';
|
|
29
31
|
import { carryMessageId, messageIdOf } from '../message-ids.mjs';
|
|
30
32
|
import { normalizeIngestRole, shouldExcludeIngestMessage } from '../../../../memory/lib/session-ingest.mjs';
|
|
@@ -70,12 +72,23 @@ function splitFreshSource(messages) {
|
|
|
70
72
|
break;
|
|
71
73
|
}
|
|
72
74
|
}
|
|
75
|
+
// Where the previous Compact's skill-use window opens: `live` index after
|
|
76
|
+
// the history it kept (see SKILL_WINDOW_SOURCE). Without a marker the whole
|
|
77
|
+
// transcript is the window.
|
|
78
|
+
const isKept = (message) => !isSummaryMessage(message) && message?.meta?.source !== SKILL_WINDOW_SOURCE;
|
|
79
|
+
const markerAt = conversation.findLastIndex((message) => message?.meta?.source === SKILL_WINDOW_SOURCE);
|
|
80
|
+
const span = conversation[markerAt]?.meta?.span;
|
|
81
|
+
const skillWindowStart =
|
|
82
|
+
markerAt >= 0 && Number.isInteger(span) && span >= 0
|
|
83
|
+
? conversation.slice(0, markerAt).filter(isKept).length + span
|
|
84
|
+
: 0;
|
|
73
85
|
const latestUserIndex = latestActualUserInstructionIndex(conversation);
|
|
74
86
|
return {
|
|
75
87
|
protectedPrefix,
|
|
76
88
|
previousSummary: previousSummaryMessage?.content || null,
|
|
77
89
|
previousSummaryMessage,
|
|
78
90
|
previousAck,
|
|
91
|
+
skillWindowStart,
|
|
79
92
|
// Budgeting, AI input and rule-only retention use this same projection.
|
|
80
93
|
// Keep current-turn reminders; remove only proven runtime additions from
|
|
81
94
|
// older requests. Unmarked legacy text remains part of the summary budget.
|
|
@@ -86,7 +99,7 @@ function splitFreshSource(messages) {
|
|
|
86
99
|
.map((message, index) =>
|
|
87
100
|
index === latestUserIndex ? message : referenceMessageMedia(stripRuntimeUserContext(message))
|
|
88
101
|
)
|
|
89
|
-
.filter(
|
|
102
|
+
.filter(isKept),
|
|
90
103
|
sanitized,
|
|
91
104
|
};
|
|
92
105
|
}
|
|
@@ -135,9 +148,11 @@ function toolCallSummaryLine(call, result) {
|
|
|
135
148
|
// Arguments arrive redacted (splitFreshSource); the outcome is redacted
|
|
136
149
|
// here, before any cut can split a secret from its key.
|
|
137
150
|
const outcome = redactRawSecretString(contentText(result?.content)).trim();
|
|
138
|
-
// An ask_user result is the user's own answer: never cut.
|
|
151
|
+
// An ask_user or handoff_user result is the user's own answer: never cut.
|
|
139
152
|
const shown =
|
|
140
|
-
call.name === 'ask_user'
|
|
153
|
+
call.name === 'ask_user' || call.name === 'handoff_user'
|
|
154
|
+
? outcome
|
|
155
|
+
: boundedSummaryText(outcome.replace(/\s+/g, ' '), SUMMARY_TOOL_OUTCOME_CHARS);
|
|
141
156
|
return `[tool call] ${call.name}(${args}) → ${result ? shown || '(empty result)' : '(no result)'}`;
|
|
142
157
|
}
|
|
143
158
|
|
|
@@ -564,44 +579,128 @@ function currentSkillBodyMessage(message, current) {
|
|
|
564
579
|
|
|
565
580
|
const SKILL_RELOAD_SOURCE = 'compact-skill-reload';
|
|
566
581
|
|
|
567
|
-
|
|
582
|
+
// How many Compacts in a row a skill may go unused before even its reload
|
|
583
|
+
// line is dropped: a skill untouched that long belongs to finished work, and
|
|
584
|
+
// the model can still load it by name from the skill manifest.
|
|
585
|
+
export const SKILL_RELOAD_MAX_IDLE = 3;
|
|
586
|
+
|
|
587
|
+
const SKILL_TOOL_NAMES = new Set(['Skill', 'skill_view']);
|
|
588
|
+
|
|
589
|
+
function skillReloadReminder(name, idle = 0) {
|
|
568
590
|
return {
|
|
569
591
|
role: 'user',
|
|
570
|
-
content: `[mixdog-runtime] Skill "${name}" was active, but
|
|
571
|
-
meta: { source: SKILL_RELOAD_SOURCE, synthetic: true, skill: name },
|
|
592
|
+
content: `[mixdog-runtime] Skill "${name}" was active earlier, but Compact did not keep its instructions. Reload it with the Skill tool before relying on them.`,
|
|
593
|
+
meta: { source: SKILL_RELOAD_SOURCE, synthetic: true, skill: name, idle },
|
|
572
594
|
};
|
|
573
595
|
}
|
|
574
596
|
|
|
575
|
-
//
|
|
576
|
-
//
|
|
577
|
-
//
|
|
578
|
-
//
|
|
579
|
-
//
|
|
580
|
-
|
|
597
|
+
// Every Compact leaves this marker just ahead of the skills it restores, with
|
|
598
|
+
// `span`: how many messages follow it (restored skills and retained tail).
|
|
599
|
+
// All of them happened before that Compact, so the next one reads the skill
|
|
600
|
+
// use window from after them, whether or not a summary exists. The marker is
|
|
601
|
+
// not conversation: the next Compact removes it and writes a new one.
|
|
602
|
+
const SKILL_WINDOW_SOURCE = 'compact-skill-window';
|
|
603
|
+
|
|
604
|
+
function skillWindowMarker(span = 0) {
|
|
605
|
+
return {
|
|
606
|
+
role: 'user',
|
|
607
|
+
content: '[mixdog-runtime] Compact boundary.',
|
|
608
|
+
meta: { source: SKILL_WINDOW_SOURCE, synthetic: true, span },
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// Restore the skills the session used since the previous Compact, each as the
|
|
613
|
+
// Skill tool would deliver it now. A skill is used when it was loaded or one of
|
|
614
|
+
// its linked tools ran in that window (`windowStart` onward); its linked
|
|
615
|
+
// tools are the native tool references of its loader pair and, when the
|
|
616
|
+
// resolver gives them, `tools`. `currentSkill(name)` (the caller's resolver)
|
|
617
|
+
// answers `{ body, native, summary, tools? }` for a skill that still loads in
|
|
618
|
+
// the session, or null for one switched off, outside its scope or removed:
|
|
619
|
+
// such a skill is restored neither as a body nor as a reload line, since its
|
|
620
|
+
// instructions are no longer in force. Without a resolver the transcript
|
|
621
|
+
// copies are kept.
|
|
581
622
|
// Never summarize/truncate operating instructions or displace the handoff
|
|
582
|
-
// and current task.
|
|
583
|
-
//
|
|
584
|
-
//
|
|
585
|
-
//
|
|
586
|
-
|
|
623
|
+
// and current task. Every other active skill, and a used one whose body does
|
|
624
|
+
// not fit, is left as a one-line reload line. The line counts the Compacts
|
|
625
|
+
// the skill went unused (`meta.idle`) and is dropped past SKILL_RELOAD_MAX_IDLE.
|
|
626
|
+
// Reload lines are charged to the same budget: every possible line is
|
|
627
|
+
// reserved before any body is restored, and restoring a body releases its own.
|
|
628
|
+
function restoreSkillBodies(live, skillBudget, retainedTail, currentSkill = null, windowStart = 0) {
|
|
587
629
|
const retainedCallIds = new Set(retainedTail.filter((m) => m?.role === 'tool').map((m) => m.toolCallId));
|
|
588
630
|
const current = (name) => (currentSkill ? currentSkill(name) : undefined);
|
|
589
631
|
const loads = (name) => current(name) !== null;
|
|
590
632
|
const transcriptBodies = latestSkillBodies(live);
|
|
591
633
|
const loaded = new Set(transcriptBodies.map((body) => body.name));
|
|
592
634
|
const bodies = transcriptBodies.filter((body) => loads(body.name));
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
(
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
635
|
+
// Reload lines from earlier Compacts: skill -> Compacts it went unused.
|
|
636
|
+
const earlier = new Map();
|
|
637
|
+
for (const m of live) {
|
|
638
|
+
if (m?.meta?.source !== SKILL_RELOAD_SOURCE || loaded.has(m.meta.skill) || !loads(m.meta.skill)) continue;
|
|
639
|
+
earlier.delete(m.meta.skill);
|
|
640
|
+
earlier.set(m.meta.skill, Number.isFinite(m.meta.idle) ? m.meta.idle : 0);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// A loader pair can sit anywhere in the transcript (a restored body stays
|
|
644
|
+
// ahead of the retained tail's pair), so read them all.
|
|
645
|
+
const results = new Map(live.filter((m) => m?.role === 'tool').map((m) => [m.toolCallId, m]));
|
|
646
|
+
const loaderTools = new Map();
|
|
647
|
+
for (const message of live) {
|
|
648
|
+
for (const call of message?.role === 'assistant' ? message.toolCalls || [] : []) {
|
|
649
|
+
const references = results.get(call.id)?.nativeToolSearch?.toolReferences;
|
|
650
|
+
if (call.name !== 'Skill' || !references) continue;
|
|
651
|
+
const name = String(callArguments(call).name || '').trim();
|
|
652
|
+
loaderTools.set(name, [...(loaderTools.get(name) || []), ...references]);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
const skillsOfTool = new Map();
|
|
656
|
+
for (const name of new Set([...earlier.keys(), ...bodies.map((body) => body.name)])) {
|
|
657
|
+
const skill = current(name);
|
|
658
|
+
const tools = [...(skill?.native?.toolReferences || []), ...(skill?.tools || []), ...(loaderTools.get(name) || [])];
|
|
659
|
+
for (const tool of tools) skillsOfTool.set(tool, (skillsOfTool.get(tool) || new Set()).add(name));
|
|
660
|
+
}
|
|
661
|
+
// Use since the previous Compact (from `windowStart`): the newest transcript
|
|
662
|
+
// position of a load or of a linked tool's call.
|
|
663
|
+
const lastUse = new Map();
|
|
664
|
+
const noteUse = (name, index) => lastUse.set(name, Math.max(lastUse.get(name) ?? -1, index));
|
|
665
|
+
live.forEach((message, index) => {
|
|
666
|
+
if (index < windowStart || message?.role !== 'assistant') return;
|
|
667
|
+
for (const call of message.toolCalls || []) {
|
|
668
|
+
const args = callArguments(call);
|
|
669
|
+
if (SKILL_TOOL_NAMES.has(call.name)) noteUse(String(args.name || '').trim(), index);
|
|
670
|
+
else {
|
|
671
|
+
const tool = call.name === 'call_tool' ? args.name : call.name;
|
|
672
|
+
const mcpServer = `mcp:${parseMcpToolName(tool)?.server}`;
|
|
673
|
+
for (const name of [...(skillsOfTool.get(tool) || []), ...(skillsOfTool.get(mcpServer) || [])]) {
|
|
674
|
+
noteUse(name, index);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
});
|
|
679
|
+
for (const { name, message } of bodies) {
|
|
680
|
+
const index = live.lastIndexOf(message);
|
|
681
|
+
if (index >= windowStart) noteUse(name, index);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// Every active skill without a body ends as a reload line: an unused one
|
|
685
|
+
// ages by a Compact and goes once past the bound; one used (or whose body
|
|
686
|
+
// did not fit) starts over.
|
|
687
|
+
const reminders = new Map();
|
|
688
|
+
for (const [name, idle] of earlier) {
|
|
689
|
+
if (lastUse.has(name)) reminders.set(name, 0);
|
|
690
|
+
else if (idle < SKILL_RELOAD_MAX_IDLE) reminders.set(name, idle + 1);
|
|
691
|
+
}
|
|
692
|
+
const used = bodies.filter(({ name }) => lastUse.has(name)).sort((a, b) => lastUse.get(b.name) - lastUse.get(a.name));
|
|
693
|
+
const unused = bodies.filter(({ name }) => !lastUse.has(name));
|
|
694
|
+
|
|
695
|
+
const reminderCost = (name, idle = 0) => estimateMessagesTokens([skillReloadReminder(name, idle)]);
|
|
696
|
+
let reserved =
|
|
697
|
+
[...reminders].reduce((sum, [name, idle]) => sum + reminderCost(name, idle), 0) +
|
|
698
|
+
unused.reduce((sum, { name }) => sum + reminderCost(name, 1), 0) +
|
|
699
|
+
used.reduce((sum, { name }) => sum + reminderCost(name), 0);
|
|
700
|
+
const dropped = new Set();
|
|
602
701
|
const restoredSkills = [];
|
|
603
702
|
let skillTokens = 0;
|
|
604
|
-
for (const { name, message } of
|
|
703
|
+
for (const { name, message } of used) {
|
|
605
704
|
const skill = current(name);
|
|
606
705
|
const restored = [
|
|
607
706
|
...skillLoaderPair(live, live.lastIndexOf(message), name, retainedCallIds, skill),
|
|
@@ -610,24 +709,31 @@ function restoreSkillBodies(live, skillBudget, retainedTail, currentSkill = null
|
|
|
610
709
|
const cost = estimateMessagesTokens(restored);
|
|
611
710
|
const own = reminderCost(name);
|
|
612
711
|
if (skillTokens + cost + reserved - own > skillBudget) {
|
|
613
|
-
dropped.
|
|
712
|
+
dropped.add(name);
|
|
614
713
|
continue;
|
|
615
714
|
}
|
|
616
715
|
restoredSkills.unshift(...restored);
|
|
617
716
|
skillTokens += cost;
|
|
618
717
|
reserved -= own;
|
|
619
718
|
}
|
|
620
|
-
//
|
|
719
|
+
// In transcript order, after the lines of earlier Compacts.
|
|
720
|
+
for (const { name } of bodies) {
|
|
721
|
+
if (!lastUse.has(name)) reminders.set(name, 1);
|
|
722
|
+
else if (dropped.has(name)) reminders.set(name, 0);
|
|
723
|
+
}
|
|
724
|
+
// Newest skill first; only a budget too small for the lines themselves
|
|
621
725
|
// leaves one out.
|
|
622
|
-
const pending = [...
|
|
726
|
+
const pending = [...reminders];
|
|
623
727
|
const reminded = new Set();
|
|
624
|
-
for (const name of pending.toReversed()) {
|
|
625
|
-
const cost = reminderCost(name);
|
|
728
|
+
for (const [name, idle] of pending.toReversed()) {
|
|
729
|
+
const cost = reminderCost(name, idle);
|
|
626
730
|
if (skillTokens + cost > skillBudget) continue;
|
|
627
731
|
reminded.add(name);
|
|
628
732
|
skillTokens += cost;
|
|
629
733
|
}
|
|
630
|
-
restoredSkills.push(
|
|
734
|
+
restoredSkills.push(
|
|
735
|
+
...pending.filter(([name]) => reminded.has(name)).map(([name, idle]) => skillReloadReminder(name, idle))
|
|
736
|
+
);
|
|
631
737
|
return { restoredSkills, skillTokens };
|
|
632
738
|
}
|
|
633
739
|
|
|
@@ -864,15 +970,33 @@ export function freshContextCompactMessages(messages, budgetTokens, options = {}
|
|
|
864
970
|
const summaryContent = String(summaryMessage?.content || '');
|
|
865
971
|
assertHandoffFits(summaryMessage, handoff.room);
|
|
866
972
|
const skillBudget = freshSkillBudget(targetBudget, budget, [...stableHead, ...tail.volatileTail]);
|
|
973
|
+
// Restored skills carry the window marker, which is charged to their budget.
|
|
974
|
+
const markerCost = estimateMessagesTokens([skillWindowMarker()]);
|
|
867
975
|
const skills = {
|
|
868
|
-
...restoreSkillBodies(
|
|
976
|
+
...restoreSkillBodies(
|
|
977
|
+
source.live,
|
|
978
|
+
Math.max(0, skillBudget - markerCost),
|
|
979
|
+
tail.volatileTail,
|
|
980
|
+
opts.currentSkill,
|
|
981
|
+
source.skillWindowStart
|
|
982
|
+
),
|
|
869
983
|
skillBudget,
|
|
870
984
|
};
|
|
871
|
-
|
|
872
|
-
const
|
|
985
|
+
// A session with no skill state has no use to window: no marker.
|
|
986
|
+
const marker = skills.restoredSkills.length ? [skillWindowMarker()] : [];
|
|
987
|
+
const stablePrefixMessages = [...stableHead, ...marker, ...skills.restoredSkills];
|
|
988
|
+
const compacted = rebaseCompactedEffortConfiguration(
|
|
873
989
|
baseSanitized,
|
|
874
990
|
reconcileDedupStubs(sanitizeToolPairs([...stablePrefixMessages, ...tail.volatileTail]))
|
|
875
991
|
);
|
|
992
|
+
// The next Compact reads everything after the marker as history, not as use.
|
|
993
|
+
const markerAt = compacted.findLastIndex((message) => message?.meta?.source === SKILL_WINDOW_SOURCE);
|
|
994
|
+
const result =
|
|
995
|
+
markerAt < 0
|
|
996
|
+
? compacted
|
|
997
|
+
: compacted.map((message, index) =>
|
|
998
|
+
index === markerAt ? skillWindowMarker(compacted.length - markerAt - 1) : message
|
|
999
|
+
);
|
|
876
1000
|
const finalTokens = estimateMessagesTokens(result);
|
|
877
1001
|
if (finalTokens > budget) {
|
|
878
1002
|
throw new Error(`freshContextCompactMessages: compacted result exceeds budget=${budget} (result=${finalTokens})`);
|
|
@@ -581,8 +581,20 @@ function reasoningBreakdown(message, fullTextTokens) {
|
|
|
581
581
|
};
|
|
582
582
|
}
|
|
583
583
|
}
|
|
584
|
+
// Price each reasoning item that is actually sent (a non-empty replay
|
|
585
|
+
// replaces content) at its own cost; the whole-minus-visible difference only
|
|
586
|
+
// caps the sum so the rows never exceed the total.
|
|
587
|
+
const sent = message.providerReplay?.items?.length ? message.providerReplay.items.filter(isReasoningBlock) : blocks;
|
|
584
588
|
return {
|
|
585
|
-
tokens: blocks.length
|
|
589
|
+
tokens: blocks.length
|
|
590
|
+
? Math.max(
|
|
591
|
+
0,
|
|
592
|
+
Math.min(
|
|
593
|
+
sent.reduce((sum, block) => sum + estimateTokens(nativeBlocksEstimateText(block)), 0),
|
|
594
|
+
fullTextTokens() - messageTextTokens(visible)
|
|
595
|
+
)
|
|
596
|
+
)
|
|
597
|
+
: 0,
|
|
586
598
|
blocks,
|
|
587
599
|
message: visible,
|
|
588
600
|
};
|
|
@@ -3,12 +3,22 @@
|
|
|
3
3
|
* import turns. The active branch is followed from the last main-chain entry
|
|
4
4
|
* back through `parentUuid` (and `logicalParentUuid` across a compaction), so
|
|
5
5
|
* replayed or abandoned branches never duplicate. Kept: text blocks and
|
|
6
|
-
* `tool_use` as
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* `tool_use` as tool notes; images become an omission marker; a compaction
|
|
7
|
+
* summary (as an assistant recap) only when the history it replaced is gone;
|
|
8
|
+
* a slash command as `/name args` unless the app answered it locally; pasted
|
|
9
|
+
* text without the app's paste envelope. Dropped: sidechains, meta entries,
|
|
10
|
+
* tool results, thinking, signatures and Claude Code's own
|
|
11
|
+
* command-output/notification envelopes.
|
|
10
12
|
*/
|
|
11
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
IMAGE_OMITTED_TEXT,
|
|
15
|
+
IMPORT_WARNING_IMAGE_OMITTED,
|
|
16
|
+
isWholeElement,
|
|
17
|
+
stringOrNull,
|
|
18
|
+
textPart,
|
|
19
|
+
titleFromText,
|
|
20
|
+
toolNote,
|
|
21
|
+
} from './turns.mjs';
|
|
12
22
|
|
|
13
23
|
const CLAUDE_ENVELOPE_TAGS = [
|
|
14
24
|
'local-command-stdout',
|
|
@@ -20,11 +30,54 @@ const CLAUDE_ENVELOPE_TAGS = [
|
|
|
20
30
|
'bash-input',
|
|
21
31
|
'bash-stdout',
|
|
22
32
|
'bash-stderr',
|
|
33
|
+
// The app's own instructions behind its "create PR" action.
|
|
34
|
+
'create-pr-command',
|
|
23
35
|
];
|
|
24
|
-
const
|
|
36
|
+
const LOCAL_OUTPUT_TAGS = ['local-command-stdout', 'local-command-stderr'];
|
|
37
|
+
const SLASH_COMMAND_RE = /^(?:\s*<(command-name|command-message|command-args|skill-format)>[\s\S]*?<\/\1>)+\s*$/;
|
|
25
38
|
const INTERRUPTED_RE = /^\[Request interrupted by user[^\]\n]*\]$/;
|
|
26
39
|
// Claude Code's text annotation that accompanies a pasted image block.
|
|
27
40
|
const IMAGE_ANNOTATION_RE = /^\[Image\b[^\n]*\]$/;
|
|
41
|
+
// The desktop app's paste envelope: `<pasted_content id="hhhh">\n` body
|
|
42
|
+
// `\n</pasted_content id="hhhh">`, one four-hex id on both tags.
|
|
43
|
+
const PASTE_OPEN = '<pasted_content id="';
|
|
44
|
+
const PASTE_ID_RE = /^[0-9a-f]{4}$/;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Text with the app's paste envelopes unwrapped the way the app displays it:
|
|
48
|
+
* each paste body in place, the text around it trimmed toward it, pieces on
|
|
49
|
+
* their own lines. Only a complete envelope with a matching id is unwrapped; any
|
|
50
|
+
* other `<pasted_content…>` is the user's own text and stays as typed.
|
|
51
|
+
*/
|
|
52
|
+
export function unwrapClaudePastes(text) {
|
|
53
|
+
const pieces = [];
|
|
54
|
+
let cursor = 0;
|
|
55
|
+
let search = 0;
|
|
56
|
+
for (;;) {
|
|
57
|
+
const open = text.indexOf(PASTE_OPEN, search);
|
|
58
|
+
if (open < 0) break;
|
|
59
|
+
const idStart = open + PASTE_OPEN.length;
|
|
60
|
+
const id = text.slice(idStart, idStart + 4);
|
|
61
|
+
const bodyStart = idStart + 7; // past `hhhh">\n`
|
|
62
|
+
if (!PASTE_ID_RE.test(id) || text.slice(idStart + 4, bodyStart) !== '">\n') {
|
|
63
|
+
search = idStart;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const closeTag = `\n</pasted_content id="${id}">`;
|
|
67
|
+
// The line feed ending the open tag may also start the close tag (an empty paste).
|
|
68
|
+
const close = text.indexOf(closeTag, bodyStart - 1);
|
|
69
|
+
if (close < 0) break;
|
|
70
|
+
// Trimmed only toward a paste: the first fragment keeps its leading text.
|
|
71
|
+
const before = text.slice(cursor, open);
|
|
72
|
+
pieces.push(cursor ? before.trim() : before.trimEnd(), text.slice(bodyStart, Math.max(close, bodyStart)));
|
|
73
|
+
cursor = close + closeTag.length;
|
|
74
|
+
search = cursor;
|
|
75
|
+
}
|
|
76
|
+
if (!pieces.length) return text;
|
|
77
|
+
pieces.push(text.slice(cursor).trimStart());
|
|
78
|
+
const unwrapped = pieces.filter((piece, index) => index % 2 === 1 || piece).join('\n');
|
|
79
|
+
return unwrapped.trim() ? unwrapped : text;
|
|
80
|
+
}
|
|
28
81
|
|
|
29
82
|
export function isClaudeEnvelopeText(text) {
|
|
30
83
|
const trimmed = String(text || '').trim();
|
|
@@ -37,8 +90,18 @@ export function isClaudeEnvelopeText(text) {
|
|
|
37
90
|
);
|
|
38
91
|
}
|
|
39
92
|
|
|
93
|
+
const tagValue = (text, tag) => new RegExp(`<${tag}>([\\s\\S]*?)</${tag}>`).exec(text)?.[1].trim() || '';
|
|
94
|
+
|
|
95
|
+
/** A slash-command envelope as Claude Code shows it (`/name args`), else null. */
|
|
96
|
+
function claudeCommandText(text) {
|
|
97
|
+
const trimmed = String(text || '').trim();
|
|
98
|
+
if (!SLASH_COMMAND_RE.test(trimmed)) return null;
|
|
99
|
+
const name = (tagValue(trimmed, 'command-name') || tagValue(trimmed, 'command-message')).replace(/^\//, '');
|
|
100
|
+
if (!name) return null;
|
|
101
|
+
return [`/${name}`, tagValue(trimmed, 'command-args')].filter(Boolean).join(' ');
|
|
102
|
+
}
|
|
103
|
+
|
|
40
104
|
const isMessageEntry = (record) => record?.type === 'user' || record?.type === 'assistant';
|
|
41
|
-
const stringOrNull = (value) => (typeof value === 'string' && value.trim() ? value.trim() : null);
|
|
42
105
|
const uuidOrNull = (value) => (typeof value === 'string' ? value : null);
|
|
43
106
|
const timestampOrNull = (value) => (typeof value === 'string' || typeof value === 'number' ? value : null);
|
|
44
107
|
// Rough fixed cost of one retained entry object, so tiny entries still count.
|
|
@@ -49,42 +112,69 @@ const metadataLength = (entry) =>
|
|
|
49
112
|
(entry.logicalParentUuid?.length || 0) +
|
|
50
113
|
(typeof entry.at === 'string' ? entry.at.length : 0);
|
|
51
114
|
|
|
115
|
+
// The main-chain message written last before file position `seq`: the leaf of
|
|
116
|
+
// the history a compaction boundary replaced.
|
|
117
|
+
function precedingMain(entries, seq) {
|
|
118
|
+
for (let index = seq - 1; index >= 0; index--) {
|
|
119
|
+
if (entries[index].main && entries[index].uuid !== null) return entries[index];
|
|
120
|
+
}
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
|
|
52
124
|
/**
|
|
53
125
|
* The active branch, root first: walked back from the last main-chain entry.
|
|
54
|
-
*
|
|
55
|
-
*
|
|
126
|
+
* A compaction boundary links back to the history it replaced through its
|
|
127
|
+
* logical parent, or, when Claude Code never wrote that message, to the last
|
|
128
|
+
* message before the boundary. `replaced` holds the compaction summaries whose
|
|
129
|
+
* history the walk crossed into (that history is imported instead).
|
|
56
130
|
*/
|
|
57
131
|
function activeChain(entries) {
|
|
58
132
|
const main = entries.filter((entry) => entry.main);
|
|
59
133
|
const leaf = main[main.length - 1];
|
|
60
|
-
if (!leaf || leaf.uuid === null) return { chain: main,
|
|
134
|
+
if (!leaf || leaf.uuid === null) return { chain: main, replaced: new Set() };
|
|
61
135
|
const byUuid = new Map();
|
|
62
136
|
for (const entry of entries) {
|
|
63
137
|
if (entry.uuid !== null) byUuid.set(entry.uuid, entry);
|
|
64
138
|
}
|
|
65
139
|
const chain = [];
|
|
66
140
|
const seen = new Set();
|
|
67
|
-
|
|
141
|
+
const replaced = new Set();
|
|
142
|
+
let summary = null;
|
|
68
143
|
let current = leaf;
|
|
69
144
|
while (current && !seen.has(current.uuid)) {
|
|
70
145
|
seen.add(current.uuid);
|
|
71
146
|
chain.push(current);
|
|
147
|
+
if (current.summary) summary = current;
|
|
72
148
|
const parent = current.parentUuid !== null ? byUuid.get(current.parentUuid) : null;
|
|
73
|
-
const logical =
|
|
74
|
-
|
|
149
|
+
const logical =
|
|
150
|
+
!parent && current.logicalParentUuid !== null
|
|
151
|
+
? byUuid.get(current.logicalParentUuid) || precedingMain(entries, current.seq)
|
|
152
|
+
: null;
|
|
153
|
+
if (logical && summary) {
|
|
154
|
+
replaced.add(summary);
|
|
155
|
+
summary = null;
|
|
156
|
+
}
|
|
75
157
|
current = parent || logical;
|
|
76
158
|
}
|
|
77
|
-
return { chain: chain.reverse().filter((entry) => entry.main),
|
|
159
|
+
return { chain: chain.reverse().filter((entry) => entry.main), replaced };
|
|
78
160
|
}
|
|
79
161
|
|
|
80
|
-
|
|
162
|
+
/** Kept parts of a message; a slash command is a `command` part, a local command's output marks `localOutput`. */
|
|
163
|
+
function entryParts(role, content, warnings, marks) {
|
|
81
164
|
const blocks = typeof content === 'string' ? [{ type: 'text', text: content }] : content;
|
|
82
165
|
if (!Array.isArray(blocks)) return [];
|
|
83
166
|
const parts = [];
|
|
84
167
|
for (const block of blocks) {
|
|
85
168
|
if (!block || typeof block !== 'object') continue;
|
|
86
169
|
if (block.type === 'text' && typeof block.text === 'string') {
|
|
87
|
-
if (role === 'user'
|
|
170
|
+
if (role === 'user') {
|
|
171
|
+
const command = claudeCommandText(block.text);
|
|
172
|
+
if (command) parts.push({ ...textPart(command), command: true });
|
|
173
|
+
if (isWholeElement(block.text, LOCAL_OUTPUT_TAGS)) marks.localOutput = true;
|
|
174
|
+
if (isClaudeEnvelopeText(block.text)) continue;
|
|
175
|
+
parts.push(textPart(unwrapClaudePastes(block.text)));
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
88
178
|
parts.push(textPart(block.text));
|
|
89
179
|
} else if (block.type === 'image') {
|
|
90
180
|
warnings.add(IMPORT_WARNING_IMAGE_OMITTED);
|
|
@@ -96,6 +186,31 @@ function entryParts(role, content, warnings) {
|
|
|
96
186
|
return parts;
|
|
97
187
|
}
|
|
98
188
|
|
|
189
|
+
/**
|
|
190
|
+
* The title Claude Code's resume list shows from the records it appends to a
|
|
191
|
+
* transcript: the last `custom-title` (a `/rename`), else the last `ai-title`,
|
|
192
|
+
* then the last `summary`, then the last `last-prompt`. A blank custom title
|
|
193
|
+
* (a cleared rename) ends the name tier without falling back to the AI title.
|
|
194
|
+
* Other record types, such as `task-summary` or `agent-name`, never name it.
|
|
195
|
+
*/
|
|
196
|
+
function createClaudeTitleScan() {
|
|
197
|
+
let custom;
|
|
198
|
+
let ai;
|
|
199
|
+
let summary;
|
|
200
|
+
let lastPrompt;
|
|
201
|
+
return {
|
|
202
|
+
push(record) {
|
|
203
|
+
if (record.type === 'custom-title' && typeof record.customTitle === 'string') custom = record.customTitle;
|
|
204
|
+
else if (record.type === 'ai-title' && typeof record.aiTitle === 'string') ai = record.aiTitle;
|
|
205
|
+
else if (record.type === 'summary' && typeof record.summary === 'string') summary = record.summary;
|
|
206
|
+
else if (record.type === 'last-prompt' && typeof record.lastPrompt === 'string') lastPrompt = record.lastPrompt;
|
|
207
|
+
},
|
|
208
|
+
title() {
|
|
209
|
+
return titleFromText(custom ?? ai) || titleFromText(summary) || titleFromText(lastPrompt);
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
99
214
|
function skippedEntry(record) {
|
|
100
215
|
// Claude Code flags its compaction summary transcript-only as well.
|
|
101
216
|
if (record.isCompactSummary === true) return false;
|
|
@@ -111,9 +226,12 @@ function skippedEntry(record) {
|
|
|
111
226
|
*/
|
|
112
227
|
export function createClaudeReducer() {
|
|
113
228
|
const entries = [];
|
|
229
|
+
const titleScan = createClaudeTitleScan();
|
|
114
230
|
let recognized = false;
|
|
115
231
|
let foreignSessionId = null;
|
|
116
232
|
let cwd = null;
|
|
233
|
+
let sidechainSeen = false;
|
|
234
|
+
let mainSeen = false;
|
|
117
235
|
let chars = 0;
|
|
118
236
|
let metadataBytes = 0;
|
|
119
237
|
return {
|
|
@@ -126,10 +244,23 @@ export function createClaudeReducer() {
|
|
|
126
244
|
get metadataBytes() {
|
|
127
245
|
return metadataBytes;
|
|
128
246
|
},
|
|
247
|
+
/** Cheap running check: messages seen so far are all sidechain (a verdict only at the end of the file). */
|
|
248
|
+
get sidechainOnly() {
|
|
249
|
+
return sidechainSeen && !mainSeen;
|
|
250
|
+
},
|
|
251
|
+
/** Feed a record for its stored title only (a transcript's tail window). */
|
|
252
|
+
pushTitle(record) {
|
|
253
|
+
titleScan.push(record);
|
|
254
|
+
},
|
|
129
255
|
push(record) {
|
|
256
|
+
titleScan.push(record);
|
|
130
257
|
const message = isMessageEntry(record);
|
|
131
258
|
if (message) recognized = true;
|
|
132
259
|
const main = message && record.isSidechain !== true;
|
|
260
|
+
if (message) {
|
|
261
|
+
if (main) mainSeen = true;
|
|
262
|
+
else sidechainSeen = true;
|
|
263
|
+
}
|
|
133
264
|
if (main) {
|
|
134
265
|
foreignSessionId ||= stringOrNull(record.sessionId);
|
|
135
266
|
cwd ||= stringOrNull(record.cwd);
|
|
@@ -145,13 +276,14 @@ export function createClaudeReducer() {
|
|
|
145
276
|
parts: null,
|
|
146
277
|
warnings: null,
|
|
147
278
|
at: timestampOrNull(record.timestamp),
|
|
279
|
+
seq: entries.length,
|
|
148
280
|
};
|
|
149
281
|
metadataBytes += ENTRY_OVERHEAD_BYTES + metadataLength(entry);
|
|
150
282
|
if (main && !skippedEntry(record)) {
|
|
151
283
|
const body = record.message && typeof record.message === 'object' ? record.message : null;
|
|
152
284
|
entry.role = body?.role === 'user' || body?.role === 'assistant' ? body.role : record.type;
|
|
153
285
|
const warnings = new Set();
|
|
154
|
-
entry.parts = entryParts(entry.role, body ? body.content : null, warnings);
|
|
286
|
+
entry.parts = entryParts(entry.role, body ? body.content : null, warnings, entry);
|
|
155
287
|
if (record.isCompactSummary === true) {
|
|
156
288
|
entry.summary = true;
|
|
157
289
|
entry.parts = entry.parts.map((part) => ({ ...part, summary: true }));
|
|
@@ -164,15 +296,24 @@ export function createClaudeReducer() {
|
|
|
164
296
|
result() {
|
|
165
297
|
const warnings = new Set();
|
|
166
298
|
const rawTurns = [];
|
|
167
|
-
const { chain,
|
|
168
|
-
for (const entry of chain) {
|
|
299
|
+
const { chain, replaced } = activeChain(entries);
|
|
300
|
+
for (const [index, entry] of chain.entries()) {
|
|
169
301
|
if (!entry.parts?.length) continue;
|
|
170
|
-
// The summary stands in for history only when that history is gone
|
|
171
|
-
|
|
172
|
-
|
|
302
|
+
// The summary stands in for history only when that history is gone,
|
|
303
|
+
// and then as the model's recap, never as something the user wrote.
|
|
304
|
+
if (entry.summary && replaced.has(entry)) continue;
|
|
305
|
+
const role = entry.summary ? 'assistant' : entry.role;
|
|
306
|
+
// A local command (`/model`, `/rename`…) answered by the app itself is not part of the conversation.
|
|
307
|
+
const local =
|
|
308
|
+
entry.parts.some((part) => part.command) &&
|
|
309
|
+
chain.slice(index + 1).find((next) => next.parts?.length || next.localOutput)?.localOutput;
|
|
310
|
+
const parts = local ? entry.parts.filter((part) => !part.command) : entry.parts;
|
|
311
|
+
rawTurns.push({ role, parts, at: entry.at });
|
|
173
312
|
for (const code of entry.warnings || []) warnings.add(code);
|
|
174
313
|
}
|
|
175
|
-
|
|
314
|
+
// A transcript whose every message is a sidechain is a subagent's own, not a conversation.
|
|
315
|
+
const internalKind = this.sidechainOnly ? 'subagent' : null;
|
|
316
|
+
return { recognized, foreignSessionId, cwd, internalKind, rawTurns, warnings, storedTitle: titleScan.title() };
|
|
176
317
|
},
|
|
177
318
|
};
|
|
178
319
|
}
|