mixdog 1.4.1 → 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/gate-local.mjs +172 -61
- package/scripts/lib/gate-scheduler.mjs +138 -32
- package/scripts/lib/gate-timing-reporter.mjs +16 -0
- package/scripts/lib/run-node-tests.mjs +54 -29
- package/scripts/lib/scoped-temp.mjs +1 -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/pptx-kit-index.mjs +5 -6
- 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 +18 -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/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 +6 -30
- 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.mjs +10 -1
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +130 -21
- 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/config.mjs +12 -7
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +7 -7
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +5 -26
- 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 +83 -52
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +42 -26
- 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/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/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-oauth-login.mjs +26 -28
- 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 +567 -0
- package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +2 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +3 -0
- 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/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-warm.mjs +94 -10
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +10 -5
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +5 -5
- 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/requests.mjs +36 -6
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +5 -3
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +21 -2
- 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/turn-limits.mjs +13 -8
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +50 -28
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +3 -4
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +2 -0
- 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 +25 -14
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +17 -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 +7 -3
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +47 -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/restart-prefix-parity.fixture.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 +164 -4
- package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +142 -18
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +36 -26
- package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +3 -5
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +58 -20
- 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/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 +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 +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 -2
- package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
- package/src/runtime/channels/lib/whisper-port.mjs +19 -10
- package/src/runtime/channels/lib/whisper-server.mjs +10 -1
- 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/memory/index.mjs +4 -0
- package/src/runtime/memory/lib/embedding-provider.mjs +4 -1
- package/src/runtime/memory/lib/embedding-worker.mjs +4 -0
- 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.mjs +103 -2
- package/src/runtime/shared/background-tasks.mjs +15 -6
- 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/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/llm/cost.mjs +6 -1
- 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/provider-accounts.mjs +52 -2
- package/src/runtime/shared/staged-install-worker.mjs +5 -0
- package/src/runtime/shared/staged-update.mjs +47 -2
- package/src/runtime/shared/tool-surface.mjs +110 -36
- package/src/runtime/shared/tool-work-units.mjs +4 -0
- 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/git.mjs +57 -0
- package/src/runtime/shared/worktrees/manager.mjs +205 -137
- 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 +4 -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-task-sessions.mjs +410 -353
- package/src/session-runtime/boot/tools.mjs +2 -0
- package/src/session-runtime/bot-status.mjs +103 -103
- package/src/session-runtime/connector-merge-migration.mjs +18 -15
- package/src/session-runtime/conversation-import/discovery.mjs +159 -40
- package/src/session-runtime/conversation-import/service.mjs +9 -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/feature-tools.mjs +2 -0
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +8 -0
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +143 -116
- 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/provider-auth/login.mjs +2 -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/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-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 +281 -10
- 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/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-route.mjs +10 -1
- 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 -1066
- 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 +54 -54
- package/src/standalone/daemon-desktop-runtime.mjs +2 -0
- package/src/standalone/daemon-session-control.mjs +151 -136
- 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.mjs +45 -9
- package/src/standalone/session-service/projection/transcript-window.mjs +700 -64
- package/src/standalone/session-service/session-calls/session-views.mjs +160 -104
- package/src/standalone/session-service/stored-reader.mjs +127 -40
- package/src/tui/App.jsx +154 -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 +21 -10
- 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/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/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 +1896 -1341
- 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/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/defaults/skills/skill-creator/references/source-review.md +0 -94
|
@@ -24,21 +24,34 @@ import {
|
|
|
24
24
|
stampedDerivation,
|
|
25
25
|
storedSessionCatalogRow,
|
|
26
26
|
} from './store-summary-catalog.mjs';
|
|
27
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
createStoredTranscriptCache,
|
|
29
|
+
historyStampOf,
|
|
30
|
+
producedSlice,
|
|
31
|
+
projectionStampEpoch,
|
|
32
|
+
transcriptTextHash,
|
|
33
|
+
} from './store-transcript-cache.mjs';
|
|
28
34
|
import {
|
|
29
35
|
forgetStoredTranscriptOffThread,
|
|
30
36
|
OFFLOAD_MIN_CHARS,
|
|
31
37
|
projectStoredTranscriptOffThread,
|
|
32
38
|
storedTranscriptWorkerRunning,
|
|
33
39
|
} from './store-transcript-worker.mjs';
|
|
34
|
-
import {
|
|
40
|
+
import {
|
|
41
|
+
cursorPageRows,
|
|
42
|
+
heldRowsDigester,
|
|
43
|
+
prepareStoredTranscriptBase,
|
|
44
|
+
projectStoredTranscript,
|
|
45
|
+
storedHistorySlice,
|
|
46
|
+
windowStoredTranscript,
|
|
47
|
+
} from './store-transcript-projection.mjs';
|
|
35
48
|
import { dataDir } from './store-summary-locations.mjs';
|
|
36
49
|
import { isStoredSessionId, workspaceSummary } from './store-summary-fields.mjs';
|
|
37
50
|
import { readArchivedAgentResult } from './store-summary-archived-agent.mjs';
|
|
38
51
|
import {
|
|
52
|
+
compactionArchivePageFromText,
|
|
39
53
|
compactionArchivePath,
|
|
40
54
|
compactionArchiveRange,
|
|
41
|
-
readCompactionArchivePage,
|
|
42
55
|
visitCompactionArchive,
|
|
43
56
|
} from './compaction-archive.mjs';
|
|
44
57
|
import { attachmentHistoryRows } from './stored-attachment-history.mjs';
|
|
@@ -76,15 +89,55 @@ const storedTranscriptCache = createStoredTranscriptCache();
|
|
|
76
89
|
// lookup can neither fill nor evict.
|
|
77
90
|
const attachmentHistoryCache = createStoredTranscriptCache();
|
|
78
91
|
|
|
92
|
+
// The display histories of SMALL sessions (record and archive under
|
|
93
|
+
// OFFLOAD_MIN_CHARS, projected on this thread), kept for slicing within a
|
|
94
|
+
// source-character budget; a larger one never stays on this thread (its
|
|
95
|
+
// history lives in the projection worker, or is projected per read as a
|
|
96
|
+
// bounded window).
|
|
97
|
+
const SMALL_HISTORY_MAX_CHARS = 4 * 1024 * 1024;
|
|
98
|
+
const smallHistories = (() => {
|
|
99
|
+
const entries = new Map();
|
|
100
|
+
let chars = 0;
|
|
101
|
+
const drop = (sessionId) => {
|
|
102
|
+
const entry = entries.get(sessionId);
|
|
103
|
+
if (!entry) return;
|
|
104
|
+
entries.delete(sessionId);
|
|
105
|
+
chars -= entry.chars;
|
|
106
|
+
};
|
|
107
|
+
return {
|
|
108
|
+
get(sessionId, identity) {
|
|
109
|
+
const entry = entries.get(sessionId);
|
|
110
|
+
if (!entry || entry.identity !== identity) return null;
|
|
111
|
+
entries.delete(sessionId);
|
|
112
|
+
entries.set(sessionId, entry);
|
|
113
|
+
return entry.history;
|
|
114
|
+
},
|
|
115
|
+
retain(sessionId, identity, sourceChars, history) {
|
|
116
|
+
drop(sessionId);
|
|
117
|
+
if (sourceChars > SMALL_HISTORY_MAX_CHARS) return;
|
|
118
|
+
entries.set(sessionId, { identity, chars: sourceChars, history });
|
|
119
|
+
chars += sourceChars;
|
|
120
|
+
while (chars > SMALL_HISTORY_MAX_CHARS && entries.size > 1) drop(entries.keys().next().value);
|
|
121
|
+
},
|
|
122
|
+
forget: drop,
|
|
123
|
+
clear() {
|
|
124
|
+
entries.clear();
|
|
125
|
+
chars = 0;
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
})();
|
|
129
|
+
|
|
79
130
|
/** Test seam: forget every cached projection. */
|
|
80
131
|
export function clearStoredTranscriptCache() {
|
|
81
132
|
storedTranscriptCache.clear();
|
|
133
|
+
smallHistories.clear();
|
|
82
134
|
}
|
|
83
135
|
|
|
84
136
|
/** Drop one session's cold projections: it went live, or its last view left. */
|
|
85
137
|
export function forgetStoredSessionTranscript(sessionId) {
|
|
86
138
|
const id = String(sessionId || '').trim();
|
|
87
139
|
storedTranscriptCache.forget(`${id}|`);
|
|
140
|
+
smallHistories.forget(id);
|
|
88
141
|
if (id) forgetStoredTranscriptOffThread(id);
|
|
89
142
|
}
|
|
90
143
|
|
|
@@ -386,10 +439,16 @@ export function storedSessionTranscriptStamp(id) {
|
|
|
386
439
|
* itself). The answer is the cache's `project` contract; a worker failure
|
|
387
440
|
* rejects and the cache runs the in-process pipeline instead. */
|
|
388
441
|
async function projectStoredTranscriptElsewhere(known, context) {
|
|
389
|
-
const { sessionId, recordPath,
|
|
442
|
+
const { sessionId, recordPath, timing, fingerprint, slice } = context;
|
|
390
443
|
timing.worker = storedTranscriptWorkerRunning(sessionId) ? 'warm' : 'cold';
|
|
391
444
|
const workerStartedAt = performance.now();
|
|
392
|
-
const answer = await projectStoredTranscriptOffThread({
|
|
445
|
+
const answer = await projectStoredTranscriptOffThread({
|
|
446
|
+
sessionId,
|
|
447
|
+
recordPath,
|
|
448
|
+
known,
|
|
449
|
+
fingerprint,
|
|
450
|
+
slice: { ...slice, epoch: projectionStampEpoch() },
|
|
451
|
+
});
|
|
393
452
|
timing.workerMs = performance.now() - workerStartedAt;
|
|
394
453
|
Object.assign(timing, answer.timing);
|
|
395
454
|
context.readState = answer.state;
|
|
@@ -397,15 +456,66 @@ async function projectStoredTranscriptElsewhere(known, context) {
|
|
|
397
456
|
if (answer.same) return answer;
|
|
398
457
|
if (answer.unreadable) return { ...answer, value: null };
|
|
399
458
|
if (answer.stamp) readCanonicalLifecycle.rememberStrictVerdict(recordPath, answer.stamp, answer.lifecycle);
|
|
400
|
-
|
|
401
|
-
answer.value.projectionStamp = nextProjectionStamp();
|
|
459
|
+
if (answer.historyBuilt === false) timing.history = 'retained';
|
|
402
460
|
return answer;
|
|
403
461
|
}
|
|
404
462
|
|
|
463
|
+
/** A projector (projectStoredTranscript's signature) for a historical-position
|
|
464
|
+
* read on this thread (a checkpoint sidecar, or the worker unavailable): the
|
|
465
|
+
* base once, then tail windows doubling from twice the page until one holds
|
|
466
|
+
* the cursor's row with the page beside it, or history ends. Never the whole
|
|
467
|
+
* display history: only as deep as the row itself. */
|
|
468
|
+
const CURSOR_WINDOW_MAX_ITEMS = 8_192;
|
|
469
|
+
|
|
470
|
+
function cursorWindowProjector(cursor, timing) {
|
|
471
|
+
return async (sessionId, doc, options) => {
|
|
472
|
+
const base = await prepareStoredTranscriptBase(sessionId, doc, options);
|
|
473
|
+
const id = cursor.before ?? cursor.after;
|
|
474
|
+
for (
|
|
475
|
+
let itemLimit = Math.max(64, cursor.maxRows * 2);
|
|
476
|
+
;
|
|
477
|
+
itemLimit = Math.min(itemLimit * 2, CURSOR_WINDOW_MAX_ITEMS)
|
|
478
|
+
) {
|
|
479
|
+
timing.cursorWindowItems = itemLimit;
|
|
480
|
+
const window = await windowStoredTranscript(sessionId, base, { itemLimit, includeMessages: false });
|
|
481
|
+
const at = window.items.findIndex((item) => item?.id === id);
|
|
482
|
+
if ((at >= 0 && (cursor.before == null || at >= cursor.maxRows)) || !window.transcriptHasOlder) return window;
|
|
483
|
+
// Never deeper on this thread: a row past the bound answers `reset`
|
|
484
|
+
// (the slice finds no such row), one at its edge a shorter page.
|
|
485
|
+
if (itemLimit >= CURSOR_WINDOW_MAX_ITEMS) return at >= 0 ? window : { ...window, items: [] };
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/** The slice `request` names of `history` (the display history, or a window
|
|
491
|
+
* of it), stamped `<history stamp>/<slice>`. */
|
|
492
|
+
async function sliceOf(history, request, historyStamp) {
|
|
493
|
+
const proven = Boolean(request.held) && request.baseHistory === historyStamp;
|
|
494
|
+
const value = storedHistorySlice(
|
|
495
|
+
history,
|
|
496
|
+
{ ...request, proven },
|
|
497
|
+
{ digestOf: request.held && !proven ? await heldRowsDigester() : null }
|
|
498
|
+
);
|
|
499
|
+
const { windowStamp } = value;
|
|
500
|
+
delete value.windowStamp;
|
|
501
|
+
value.projectionStamp = `${historyStamp}/${windowStamp}`;
|
|
502
|
+
return value;
|
|
503
|
+
}
|
|
504
|
+
|
|
405
505
|
/** Projects the strictly parsed record `text` (read at full stamp `stamp`, or
|
|
406
506
|
* null when not provably stable) into the cached transcript value. */
|
|
407
507
|
async function produceStoredTranscript(text, stamp, context) {
|
|
408
|
-
const { sessionId, recordPath, itemLimit, includeMessages, mode, checkpointAbsent, timing } =
|
|
508
|
+
const { sessionId, recordPath, itemLimit, slice, fingerprint, includeMessages, mode, checkpointAbsent, timing } =
|
|
509
|
+
context;
|
|
510
|
+
const historyStamp =
|
|
511
|
+
mode === 'items' ? historyStampOf(sessionId, transcriptTextHash(text), text.length, fingerprint) : null;
|
|
512
|
+
// A small session's retained history answers every other slice of it.
|
|
513
|
+
const keepHistory = mode === 'items' && checkpointAbsent && context.sourceChars < OFFLOAD_MIN_CHARS;
|
|
514
|
+
const retained = keepHistory ? smallHistories.get(sessionId, historyStamp) : null;
|
|
515
|
+
if (retained) {
|
|
516
|
+
timing.history = 'retained';
|
|
517
|
+
return producedSlice(await sliceOf(retained, slice, historyStamp), { historyBuilt: false });
|
|
518
|
+
}
|
|
409
519
|
const parseStartedAt = performance.now();
|
|
410
520
|
const record = readTopLevelLifecycleRecord(text);
|
|
411
521
|
timing.parseMs = performance.now() - parseStartedAt;
|
|
@@ -431,22 +541,29 @@ async function produceStoredTranscript(text, stamp, context) {
|
|
|
431
541
|
// load the hand-off serves, and projects the load cache's session
|
|
432
542
|
// exactly as before; only that projection is detached.
|
|
433
543
|
const projectStartedAt = performance.now();
|
|
434
|
-
const
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
544
|
+
const project = keepHistory || !slice.cursor ? projectStoredTranscript : cursorWindowProjector(slice.cursor, timing);
|
|
545
|
+
const projected = await project(sessionId, handedOver && checkpointAbsent ? JSON.parse(text) : record.doc, {
|
|
546
|
+
itemLimit,
|
|
547
|
+
// Only a small session's whole display history is built (and kept) on
|
|
548
|
+
// this thread; any other item read projects just its bounded window
|
|
549
|
+
// (a tail of that history) and slices it; a historical-position read
|
|
550
|
+
// projects the tail window reaching its row (cursorWindowProjector).
|
|
551
|
+
history: keepHistory,
|
|
552
|
+
includeMessages,
|
|
553
|
+
checkpointAbsent,
|
|
554
|
+
});
|
|
443
555
|
timing.projectMs = performance.now() - projectStartedAt;
|
|
444
|
-
if (
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
556
|
+
if (mode !== 'items' || !projected) return projected;
|
|
557
|
+
if (keepHistory) smallHistories.retain(sessionId, historyStamp, context.sourceChars, projected);
|
|
558
|
+
let value = await sliceOf(projected, slice, historyStamp);
|
|
559
|
+
if (handedOver && !checkpointAbsent) {
|
|
560
|
+
try {
|
|
561
|
+
value = structuredClone(value);
|
|
562
|
+
} catch {
|
|
563
|
+
// Served as projected.
|
|
564
|
+
}
|
|
449
565
|
}
|
|
566
|
+
return producedSlice(value);
|
|
450
567
|
}
|
|
451
568
|
|
|
452
569
|
/** The rows of one session's whole stored conversation that name attachments
|
|
@@ -492,6 +609,37 @@ async function readStoredAttachmentHistory(sessionId, recordPath, archivePath) {
|
|
|
492
609
|
return value ?? null;
|
|
493
610
|
}
|
|
494
611
|
|
|
612
|
+
/** One page of a session's compaction archive (`{ after, before, skip,
|
|
613
|
+
* limit }`, as readCompactionArchivePage pages it), cut from its visible rows
|
|
614
|
+
* built once per archive content in the transcript cache: paging a live
|
|
615
|
+
* session through a large segment slices instead of re-parsing it; `paging`
|
|
616
|
+
* keeps it cached under pressure (the cache's `pin`). */
|
|
617
|
+
async function readCachedCompactionArchivePage(sessionId, archivePath, range, paging) {
|
|
618
|
+
const after = Math.max(0, Math.floor(Number(range.after) || 0));
|
|
619
|
+
const before = Number(range.before);
|
|
620
|
+
const visible = { after, before: Number.isFinite(before) ? before : Number.POSITIVE_INFINITY };
|
|
621
|
+
const archive = probePath(archivePath);
|
|
622
|
+
if (archive.state !== PROBE_PRESENT) return { items: [], hasOlder: false };
|
|
623
|
+
const { value } = await storedTranscriptCache.read({
|
|
624
|
+
key: `${sessionId}|archive|${visible.after}:${visible.before}`,
|
|
625
|
+
group: `${sessionId}|archive`,
|
|
626
|
+
fingerprint: '',
|
|
627
|
+
fileStat: archive,
|
|
628
|
+
pin: paging,
|
|
629
|
+
loadText: () => {
|
|
630
|
+
const body = readTextFile(archivePath);
|
|
631
|
+
return body.state === PROBE_PRESENT ? body.text : null;
|
|
632
|
+
},
|
|
633
|
+
produce: async (text) => ({
|
|
634
|
+
items: (await compactionArchivePageFromText(text, { ...visible, limit: Number.POSITIVE_INFINITY })).items,
|
|
635
|
+
}),
|
|
636
|
+
});
|
|
637
|
+
const items = Array.isArray(value?.items) ? value.items : [];
|
|
638
|
+
const end = Math.max(0, items.length - Math.max(0, Math.floor(Number(range.skip) || 0)));
|
|
639
|
+
const start = Math.max(0, end - Math.max(0, Math.floor(Number(range.limit) || 0)));
|
|
640
|
+
return { items: items.slice(start, end), hasOlder: start > 0 };
|
|
641
|
+
}
|
|
642
|
+
|
|
495
643
|
/** Read exactly one persisted session for a visible desktop pane. This never
|
|
496
644
|
* enumerates siblings. Normal reads stay independent of runtime ownership;
|
|
497
645
|
* interrupted turns conditionally use the same durable reconnect recovery as
|
|
@@ -508,7 +656,7 @@ export async function readStoredSessionTranscript(id, options = {}) {
|
|
|
508
656
|
// One page of the display-only compaction archive (the live head loader
|
|
509
657
|
// pages it once a runtime's in-memory rows are exhausted).
|
|
510
658
|
if (options.compactionArchive && typeof options.compactionArchive === 'object') {
|
|
511
|
-
return
|
|
659
|
+
return readCachedCompactionArchivePage(sessionId, archivePath, options.compactionArchive, options.paging === true);
|
|
512
660
|
}
|
|
513
661
|
// The checkpoint sidecar shapes the projection as much as the record does,
|
|
514
662
|
// so its identity joins the cache fingerprint. Only a PROVABLY absent
|
|
@@ -524,6 +672,51 @@ export async function readStoredSessionTranscript(id, options = {}) {
|
|
|
524
672
|
const archive = probePath(archivePath);
|
|
525
673
|
const requestedLimit = Number(options.transcriptItemLimit);
|
|
526
674
|
const itemLimit = Number.isFinite(requestedLimit) && requestedLimit > 0 ? requestedLimit : Number.POSITIVE_INFINITY;
|
|
675
|
+
// `transcriptSkip`: the window's newest rows to leave out (a range read
|
|
676
|
+
// slices only the rows above them, with `skippedFirstId`).
|
|
677
|
+
const requestedSkip = Number(options.transcriptSkip);
|
|
678
|
+
const skip =
|
|
679
|
+
Number.isFinite(itemLimit) && Number.isSafeInteger(requestedSkip) && requestedSkip > 0
|
|
680
|
+
? Math.min(requestedSkip, itemLimit)
|
|
681
|
+
: 0;
|
|
682
|
+
// `transcriptHeld` (`{ firstId, count, digest }`): the newest rows a paged
|
|
683
|
+
// caller holds, proven by `transcriptBaseHistory` (the history stamp they
|
|
684
|
+
// were served under) or their digest, where the history is: only the page
|
|
685
|
+
// above them (`transcriptPage`: `{ maxRows, byteBudget }`) is sliced,
|
|
686
|
+
// whatever their count. Unproven, a tail of at most `maxRows` rows.
|
|
687
|
+
const heldOption = options.transcriptHeld;
|
|
688
|
+
const held =
|
|
689
|
+
Number.isFinite(itemLimit) && heldOption && Number.isSafeInteger(heldOption.count) && heldOption.count > 0
|
|
690
|
+
? { firstId: heldOption.firstId, count: heldOption.count, digest: String(heldOption.digest ?? '') }
|
|
691
|
+
: null;
|
|
692
|
+
const page = options.transcriptPage || {};
|
|
693
|
+
// `transcriptCursor` (`{ before | after, maxRows, byteBudget }`): a
|
|
694
|
+
// historical-position read — the rows next to one row, by its id.
|
|
695
|
+
const cursorOption = options.transcriptCursor;
|
|
696
|
+
const cursor =
|
|
697
|
+
cursorOption && (cursorOption.before != null || cursorOption.after != null)
|
|
698
|
+
? {
|
|
699
|
+
...(cursorOption.before != null ? { before: cursorOption.before } : { after: cursorOption.after }),
|
|
700
|
+
maxRows: cursorPageRows(cursorOption.maxRows),
|
|
701
|
+
byteBudget: Number(cursorOption.byteBudget) > 0 ? Number(cursorOption.byteBudget) : null,
|
|
702
|
+
}
|
|
703
|
+
: null;
|
|
704
|
+
const slice = cursor
|
|
705
|
+
? { cursor }
|
|
706
|
+
: held
|
|
707
|
+
? {
|
|
708
|
+
limit: itemLimit,
|
|
709
|
+
held,
|
|
710
|
+
baseHistory: typeof options.transcriptBaseHistory === 'string' ? options.transcriptBaseHistory : null,
|
|
711
|
+
maxRows: Math.max(1, Math.floor(Number(page.maxRows) || itemLimit)),
|
|
712
|
+
byteBudget: Number(page.byteBudget) > 0 ? Number(page.byteBudget) : null,
|
|
713
|
+
}
|
|
714
|
+
: { limit: itemLimit, skip };
|
|
715
|
+
const sliceKey = cursor
|
|
716
|
+
? `cursor:${cursor.before ?? ''}:${cursor.after ?? ''}:${cursor.maxRows}:${cursor.byteBudget}`
|
|
717
|
+
: held
|
|
718
|
+
? `held:${held.count}:${held.firstId}:${held.digest}:${slice.baseHistory}:${slice.maxRows}:${slice.byteBudget}`
|
|
719
|
+
: skip;
|
|
527
720
|
// Full stamp the loaded text provably came from (unchanged around the
|
|
528
721
|
// read), or null. Only such a parse may serve other readers.
|
|
529
722
|
let readStamp = null;
|
|
@@ -533,11 +726,27 @@ export async function readStoredSessionTranscript(id, options = {}) {
|
|
|
533
726
|
const mode = includeMessages ? 'messages' : 'items';
|
|
534
727
|
const checkpointAbsent = checkpoint.state === PROBE_ABSENT;
|
|
535
728
|
// Large, checkpoint-free item projections run off the daemon event loop.
|
|
536
|
-
|
|
729
|
+
// A large compaction archive counts: the display history holds its rows.
|
|
730
|
+
const sourceChars = recordStat.size + (archive.state === PROBE_PRESENT ? Number(archive.size) || 0 : 0);
|
|
731
|
+
const offloadable = !includeMessages && checkpointAbsent && sourceChars >= OFFLOAD_MIN_CHARS;
|
|
732
|
+
const fingerprint = [
|
|
733
|
+
checkpoint.state,
|
|
734
|
+
checkpoint.mtimeMs,
|
|
735
|
+
checkpoint.ctimeMs,
|
|
736
|
+
checkpoint.size,
|
|
737
|
+
checkpoint.ino,
|
|
738
|
+
checkpoint.dev,
|
|
739
|
+
archive.state,
|
|
740
|
+
archive.mtimeMs,
|
|
741
|
+
archive.size,
|
|
742
|
+
].join(':');
|
|
537
743
|
const produceContext = {
|
|
538
744
|
sessionId,
|
|
539
745
|
recordPath,
|
|
540
746
|
itemLimit,
|
|
747
|
+
slice,
|
|
748
|
+
sourceChars,
|
|
749
|
+
fingerprint,
|
|
541
750
|
includeMessages,
|
|
542
751
|
mode,
|
|
543
752
|
checkpointAbsent,
|
|
@@ -545,21 +754,16 @@ export async function readStoredSessionTranscript(id, options = {}) {
|
|
|
545
754
|
// How the record read went (the worker's read or loadText below).
|
|
546
755
|
readState: PROBE_PRESENT,
|
|
547
756
|
};
|
|
548
|
-
const { value, hit, read } = await storedTranscriptCache.read({
|
|
549
|
-
|
|
757
|
+
const { value, hit, read, built } = await storedTranscriptCache.read({
|
|
758
|
+
// One slice (window or page) per request; the group keeps one per
|
|
759
|
+
// session: the display history it is cut from stays with the thread
|
|
760
|
+
// that built it.
|
|
761
|
+
key: `${sessionId}|${itemLimit}|${sliceKey}|${mode}`,
|
|
550
762
|
// Growing history windows of one session replace each other.
|
|
551
763
|
group: `${sessionId}|${mode}`,
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
checkpoint.ctimeMs,
|
|
556
|
-
checkpoint.size,
|
|
557
|
-
checkpoint.ino,
|
|
558
|
-
checkpoint.dev,
|
|
559
|
-
archive.state,
|
|
560
|
-
archive.mtimeMs,
|
|
561
|
-
archive.size,
|
|
562
|
-
].join(':'),
|
|
764
|
+
// A page read keeps its slice cached under pressure.
|
|
765
|
+
pin: options.paging === true,
|
|
766
|
+
fingerprint,
|
|
563
767
|
fileStat: recordStat,
|
|
564
768
|
project: offloadable ? (known) => projectStoredTranscriptElsewhere(known, produceContext) : null,
|
|
565
769
|
loadText: async () => {
|
|
@@ -589,7 +793,8 @@ export async function readStoredSessionTranscript(id, options = {}) {
|
|
|
589
793
|
if (typeof options.trace === 'function') {
|
|
590
794
|
options.trace({
|
|
591
795
|
sessionId,
|
|
592
|
-
hit
|
|
796
|
+
// A slice of a history already built counts as a hit: nothing was projected.
|
|
797
|
+
hit: hit || built === false,
|
|
593
798
|
read,
|
|
594
799
|
ms: performance.now() - startedAt,
|
|
595
800
|
chars: recordStat.size,
|