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
|
@@ -64,7 +64,7 @@ export function useSelectionStitchBuffer({ store, dragRef, scrollTargetRef }) {
|
|
|
64
64
|
if (!Array.isArray(rows)) return;
|
|
65
65
|
storeStitchRows(stitchBufferRef.current, rows, stitchHarvestScrollRef.current);
|
|
66
66
|
}, 0);
|
|
67
|
-
}, [store]);
|
|
67
|
+
}, [store, dragRef, scrollTargetRef]);
|
|
68
68
|
|
|
69
69
|
// Synchronous sibling: snapshot the rows CURRENTLY under the selection
|
|
70
70
|
// immediately, keyed by the given (pre-scroll) offset. Called right before
|
|
@@ -80,7 +80,7 @@ export function useSelectionStitchBuffer({ store, dragRef, scrollTargetRef }) {
|
|
|
80
80
|
if (!Array.isArray(rows)) return;
|
|
81
81
|
storeStitchRows(stitchBufferRef.current, rows, Number(scroll) || 0);
|
|
82
82
|
},
|
|
83
|
-
[store]
|
|
83
|
+
[store, dragRef]
|
|
84
84
|
);
|
|
85
85
|
|
|
86
86
|
// Map the CURRENT rect + current scrollTarget onto the content-key range and
|
|
@@ -122,7 +122,7 @@ export function useSelectionStitchBuffer({ store, dragRef, scrollTargetRef }) {
|
|
|
122
122
|
}
|
|
123
123
|
const text = logical.map((l) => l.replace(/\s+$/u, '')).join('\n');
|
|
124
124
|
return text.trim() ? { text, complete } : empty;
|
|
125
|
-
}, []);
|
|
125
|
+
}, [dragRef, scrollTargetRef]);
|
|
126
126
|
|
|
127
127
|
return { clearStitchBuffer, harvestStitchRowsSoon, harvestStitchRowsNow, getStitchedSelectionText };
|
|
128
128
|
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* app/use-slash-palette.mjs — the slash / `$skill` palette above the prompt.
|
|
3
|
+
*
|
|
4
|
+
* useSlashPaletteState owns the selection index, the dismissed-draft marker
|
|
5
|
+
* and the live open/count ref the mouse handler reads; it is declared early
|
|
6
|
+
* because the mouse and draft hooks need the setters. useSlashPalette derives
|
|
7
|
+
* the palette for this render from the prompt and the surfaces that suppress
|
|
8
|
+
* it, publishes it to that ref, and keeps the index inside the list.
|
|
9
|
+
*/
|
|
10
|
+
import { useEffect, useRef, useState } from 'react';
|
|
11
|
+
import { deriveSlashPalette } from './slash-palette.mjs';
|
|
12
|
+
import { skillMentionQuery, useSkillMentionSkills } from './skill-mention-palette.mjs';
|
|
13
|
+
|
|
14
|
+
export function useSlashPaletteState() {
|
|
15
|
+
const [slashIndex, setSlashIndex] = useState(0);
|
|
16
|
+
const [slashDismissedFor, setSlashDismissedFor] = useState('');
|
|
17
|
+
const slashPaletteRef = useRef({ open: false, count: 0 });
|
|
18
|
+
return { slashIndex, setSlashIndex, slashDismissedFor, setSlashDismissedFor, slashPaletteRef };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function useSlashPalette({
|
|
22
|
+
store,
|
|
23
|
+
slashPaletteRef,
|
|
24
|
+
setSlashIndex,
|
|
25
|
+
slashDismissedFor,
|
|
26
|
+
promptDraft,
|
|
27
|
+
promptCaret,
|
|
28
|
+
providerPrompt,
|
|
29
|
+
settingsPrompt,
|
|
30
|
+
toolApproval,
|
|
31
|
+
contextPanel,
|
|
32
|
+
usagePanel,
|
|
33
|
+
picker,
|
|
34
|
+
exiting,
|
|
35
|
+
commandBusy,
|
|
36
|
+
}) {
|
|
37
|
+
const mentionSkills = useSkillMentionSkills(store, skillMentionQuery(promptDraft, promptCaret) !== null);
|
|
38
|
+
const palette = deriveSlashPalette({
|
|
39
|
+
providerPrompt,
|
|
40
|
+
settingsPrompt,
|
|
41
|
+
toolApproval,
|
|
42
|
+
contextPanel,
|
|
43
|
+
usagePanel,
|
|
44
|
+
picker,
|
|
45
|
+
exiting,
|
|
46
|
+
commandBusy,
|
|
47
|
+
promptDraft,
|
|
48
|
+
slashDismissedFor,
|
|
49
|
+
skills: mentionSkills,
|
|
50
|
+
promptCaret,
|
|
51
|
+
});
|
|
52
|
+
const { activeSlashQuery, slashCommands, slashPaletteOpen } = palette;
|
|
53
|
+
slashPaletteRef.current = { open: slashPaletteOpen, count: slashCommands.length };
|
|
54
|
+
|
|
55
|
+
// A query change re-clamps even when the list length stays the same.
|
|
56
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies(activeSlashQuery): query-change re-clamp trigger
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
setSlashIndex((index) => Math.min(index, Math.max(0, slashCommands.length - 1)));
|
|
59
|
+
}, [slashCommands.length, activeSlashQuery, setSlashIndex]);
|
|
60
|
+
|
|
61
|
+
return palette;
|
|
62
|
+
}
|
|
@@ -47,7 +47,7 @@ export function useTerminalChrome({ stdout, isRawModeSupported, setResizeState }
|
|
|
47
47
|
if (trailing) clearTimeout(trailing);
|
|
48
48
|
stdout.off('resize', onResize);
|
|
49
49
|
};
|
|
50
|
-
}, [stdout]);
|
|
50
|
+
}, [stdout, setResizeState]);
|
|
51
51
|
|
|
52
52
|
// Enable extended keyboard reporting (kitty + xterm modifyOtherKeys)
|
|
53
53
|
// SYNCHRONOUSLY, ONCE, with NO query/round-trip. ink
|
|
@@ -61,7 +61,7 @@ export function useTerminalChrome({ stdout, isRawModeSupported, setResizeState }
|
|
|
61
61
|
// \x1b[27;5;13~ (or kitty \x1b[13;5u) instead of a bare \r — fixing the old
|
|
62
62
|
// "first Ctrl+Enter submits, second works" race. Teardown lives in index.jsx's
|
|
63
63
|
// restoreTerminal(). The empty dep array makes this run exactly once on mount.
|
|
64
|
-
//
|
|
64
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: one-shot mount enable; teardown is owned by restoreTerminal()
|
|
65
65
|
useEffect(() => {
|
|
66
66
|
if (!isRawModeSupported || !stdout?.write) return;
|
|
67
67
|
if (!supportsExtendedKeys()) return;
|
|
@@ -105,38 +105,53 @@ export function useTranscriptActivity({ state }) {
|
|
|
105
105
|
// StatusLine only reads a small stats subset; engine clones the full stats
|
|
106
106
|
// object on many updates. Memoize by field value so identical usage keeps
|
|
107
107
|
// the same object reference and React.memo / effect deps stay quiet.
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
108
|
+
const {
|
|
109
|
+
currentContextSource,
|
|
110
|
+
currentEstimatedContextTokens,
|
|
111
|
+
currentContextTokens,
|
|
112
|
+
contextTokens,
|
|
113
|
+
latestPromptTokens,
|
|
114
|
+
latestInputTokens,
|
|
115
|
+
latestCachedTokens,
|
|
116
|
+
latestCacheWriteTokens,
|
|
117
|
+
inputTokens,
|
|
118
|
+
cachedTokens,
|
|
119
|
+
cacheWriteTokens,
|
|
120
|
+
promptTokens,
|
|
121
|
+
turns,
|
|
122
|
+
} = state.stats || {};
|
|
123
|
+
const statuslineStats = useMemo(
|
|
124
|
+
() => ({
|
|
125
|
+
currentContextSource: currentContextSource ?? null,
|
|
126
|
+
currentEstimatedContextTokens: currentEstimatedContextTokens ?? 0,
|
|
127
|
+
currentContextTokens: currentContextTokens ?? null,
|
|
128
|
+
contextTokens: contextTokens ?? 0,
|
|
129
|
+
latestPromptTokens: latestPromptTokens ?? 0,
|
|
130
|
+
latestInputTokens: latestInputTokens ?? 0,
|
|
131
|
+
latestCachedTokens: latestCachedTokens ?? 0,
|
|
132
|
+
latestCacheWriteTokens: latestCacheWriteTokens ?? 0,
|
|
133
|
+
inputTokens: inputTokens ?? 0,
|
|
134
|
+
cachedTokens: cachedTokens ?? 0,
|
|
135
|
+
cacheWriteTokens: cacheWriteTokens ?? 0,
|
|
136
|
+
promptTokens: promptTokens ?? 0,
|
|
137
|
+
turns: turns ?? 0,
|
|
138
|
+
}),
|
|
139
|
+
[
|
|
140
|
+
currentContextSource,
|
|
141
|
+
currentEstimatedContextTokens,
|
|
142
|
+
currentContextTokens,
|
|
143
|
+
contextTokens,
|
|
144
|
+
latestPromptTokens,
|
|
145
|
+
latestInputTokens,
|
|
146
|
+
latestCachedTokens,
|
|
147
|
+
latestCacheWriteTokens,
|
|
148
|
+
inputTokens,
|
|
149
|
+
cachedTokens,
|
|
150
|
+
cacheWriteTokens,
|
|
151
|
+
promptTokens,
|
|
152
|
+
turns,
|
|
153
|
+
]
|
|
154
|
+
);
|
|
140
155
|
|
|
141
156
|
return { agentRevision, activeTools, statuslineStats };
|
|
142
157
|
}
|
|
@@ -44,11 +44,11 @@ export function useTranscriptFollow({
|
|
|
44
44
|
setScrollOffset(Math.max(0, Math.round(scrollPositionRef.current)));
|
|
45
45
|
}, 16);
|
|
46
46
|
scrollAnimationRef.current.unref?.();
|
|
47
|
-
}, [stopSmoothScroll]);
|
|
47
|
+
}, [scrollPositionRef, scrollTargetRef, followingRef, setScrollOffset, stopSmoothScroll]);
|
|
48
48
|
|
|
49
49
|
const cancelTranscriptFollow = useCallback(() => {
|
|
50
50
|
followingRef.current = false;
|
|
51
|
-
}, []);
|
|
51
|
+
}, [followingRef]);
|
|
52
52
|
|
|
53
53
|
const resetTranscriptScroll = useCallback(() => {
|
|
54
54
|
stopSmoothScroll();
|
|
@@ -65,7 +65,15 @@ export function useTranscriptFollow({
|
|
|
65
65
|
// and every new row piled up below the fold.
|
|
66
66
|
followingRef.current = true;
|
|
67
67
|
setScrollOffset(0);
|
|
68
|
-
}, [
|
|
68
|
+
}, [
|
|
69
|
+
scrollPositionRef,
|
|
70
|
+
scrollTargetRef,
|
|
71
|
+
followingRef,
|
|
72
|
+
transcriptAnchorRef,
|
|
73
|
+
transcriptAnchorDirtyRef,
|
|
74
|
+
setScrollOffset,
|
|
75
|
+
stopSmoothScroll,
|
|
76
|
+
]);
|
|
69
77
|
|
|
70
78
|
const armTranscriptFollow = useCallback(() => {
|
|
71
79
|
// Do not mutate scrollOffset here. During prompt submit the transcript rows
|
|
@@ -78,7 +86,7 @@ export function useTranscriptFollow({
|
|
|
78
86
|
pendingReadbackRowsRef.current = 0;
|
|
79
87
|
followingRef.current = true;
|
|
80
88
|
stopSmoothScroll();
|
|
81
|
-
}, [stopSmoothScroll]);
|
|
89
|
+
}, [followingRef, transcriptAnchorRef, transcriptAnchorDirtyRef, stopSmoothScroll]);
|
|
82
90
|
|
|
83
91
|
return {
|
|
84
92
|
pendingReadbackRowsRef,
|
|
@@ -141,7 +141,7 @@ export function useTranscriptScroll({
|
|
|
141
141
|
if (!anchor) return;
|
|
142
142
|
transcriptAnchorRef.current = anchor;
|
|
143
143
|
transcriptAnchorDirtyRef.current = false;
|
|
144
|
-
}, []);
|
|
144
|
+
}, [transcriptGeomRef, scrollTargetRef, transcriptAnchorRef, transcriptAnchorDirtyRef]);
|
|
145
145
|
|
|
146
146
|
// A manual scroll moves the reading position. Capture the new anchor
|
|
147
147
|
// SYNCHRONOUSLY from the latest published geometry so the very next render
|
|
@@ -149,20 +149,23 @@ export function useTranscriptScroll({
|
|
|
149
149
|
// streaming growth could lurch the view. Only at the true bottom drop the
|
|
150
150
|
// anchor so the bottom-follow path owns the viewport again: a positive
|
|
151
151
|
// wheel offset is an explicit reading position, even inside the old slack.
|
|
152
|
-
const captureReadingAnchor = useCallback(
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
152
|
+
const captureReadingAnchor = useCallback(
|
|
153
|
+
(target) => {
|
|
154
|
+
if (target === 0) {
|
|
155
|
+
transcriptAnchorRef.current = null;
|
|
156
|
+
transcriptAnchorDirtyRef.current = false;
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const anchor = readingAnchorAt(transcriptGeomRef.current || {}, target);
|
|
160
|
+
if (anchor) {
|
|
161
|
+
transcriptAnchorRef.current = anchor;
|
|
162
|
+
transcriptAnchorDirtyRef.current = false;
|
|
163
|
+
} else {
|
|
164
|
+
transcriptAnchorDirtyRef.current = true;
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
[transcriptGeomRef, transcriptAnchorRef, transcriptAnchorDirtyRef]
|
|
168
|
+
);
|
|
166
169
|
|
|
167
170
|
// Scrolling past the oldest/newest loaded edge pages transcript history
|
|
168
171
|
// instead of moving the target. Returns true when the edge owned the
|
|
@@ -190,7 +193,15 @@ export function useTranscriptScroll({
|
|
|
190
193
|
}
|
|
191
194
|
return true;
|
|
192
195
|
},
|
|
193
|
-
[
|
|
196
|
+
[
|
|
197
|
+
store,
|
|
198
|
+
scrollTargetRef,
|
|
199
|
+
scrollPositionRef,
|
|
200
|
+
setScrollOffset,
|
|
201
|
+
captureRestoreAnchor,
|
|
202
|
+
stopSmoothScroll,
|
|
203
|
+
cancelTranscriptFollow,
|
|
204
|
+
]
|
|
194
205
|
);
|
|
195
206
|
|
|
196
207
|
// Keep a live selection on its content after the viewport moved. An active
|
|
@@ -229,7 +240,14 @@ export function useTranscriptScroll({
|
|
|
229
240
|
// (Ctrl+C after scrolling then copied just that fragment).
|
|
230
241
|
paintSelectionRect(clippedRect, { rememberText: false });
|
|
231
242
|
},
|
|
232
|
-
[
|
|
243
|
+
[
|
|
244
|
+
dragRef,
|
|
245
|
+
buildSpanRect,
|
|
246
|
+
selectionPointAtCurrentScroll,
|
|
247
|
+
withSelectionClip,
|
|
248
|
+
cancelPendingSelectionPaint,
|
|
249
|
+
paintSelectionRect,
|
|
250
|
+
]
|
|
233
251
|
);
|
|
234
252
|
|
|
235
253
|
const scrollTranscriptRows = useCallback(
|
|
@@ -294,6 +312,17 @@ export function useTranscriptScroll({
|
|
|
294
312
|
setScrollOffset(Math.round(target));
|
|
295
313
|
},
|
|
296
314
|
[
|
|
315
|
+
maxScrollRowsRef,
|
|
316
|
+
transcriptGeomRef,
|
|
317
|
+
scrollTargetRef,
|
|
318
|
+
scrollPositionRef,
|
|
319
|
+
pendingReadbackRowsRef,
|
|
320
|
+
dragRef,
|
|
321
|
+
transcriptAnchorRef,
|
|
322
|
+
transcriptAnchorDirtyRef,
|
|
323
|
+
followingRef,
|
|
324
|
+
selectionLayoutRef,
|
|
325
|
+
setScrollOffset,
|
|
297
326
|
pageTranscriptHistory,
|
|
298
327
|
captureReadingAnchor,
|
|
299
328
|
rebuildSelectionAfterScroll,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* app/use-transcript-swap-reset.mjs — returns the viewport to the live tail
|
|
3
|
+
* when the transcript items are bulk-swapped.
|
|
4
|
+
*
|
|
5
|
+
* Item-count changes never infer follow permission from scrollTarget=0. A
|
|
6
|
+
* first read-back input can be waiting one frame for committed row geometry;
|
|
7
|
+
* only prompt submit, session reset, or an explicit return to bottom arms
|
|
8
|
+
* follow. Pure streaming height growth is handled in the row-delta effect.
|
|
9
|
+
*/
|
|
10
|
+
import { useLayoutEffect } from 'react';
|
|
11
|
+
import { transcriptSwapReturnsToTail } from './transcript-window.mjs';
|
|
12
|
+
|
|
13
|
+
export function useTranscriptSwapReset({ items, lastItemsCountRef, lastFirstItemIdRef, resetTranscriptScroll }) {
|
|
14
|
+
useLayoutEffect(() => {
|
|
15
|
+
const count = items.length;
|
|
16
|
+
const previousCount = lastItemsCountRef.current;
|
|
17
|
+
lastItemsCountRef.current = count;
|
|
18
|
+
const firstId = count > 0 ? (items[0]?.id ?? null) : null;
|
|
19
|
+
const previousFirstId = lastFirstItemIdRef.current;
|
|
20
|
+
lastFirstItemIdRef.current = firstId;
|
|
21
|
+
// A bulk swap (compaction included) is an explicit return to the tail: the
|
|
22
|
+
// rows the reader was anchored to no longer exist.
|
|
23
|
+
if (transcriptSwapReturnsToTail({ count, previousCount, firstId, previousFirstId })) {
|
|
24
|
+
resetTranscriptScroll();
|
|
25
|
+
}
|
|
26
|
+
}, [items, lastItemsCountRef, lastFirstItemIdRef, resetTranscriptScroll]);
|
|
27
|
+
}
|
|
@@ -81,7 +81,12 @@ export function useTranscriptGeometry(state, props) {
|
|
|
81
81
|
// settled-prefix row-index instead of re-walking all N items. Any structural
|
|
82
82
|
// change misses the cache and falls back to a full rebuild, so the prefix
|
|
83
83
|
// table is byte-identical to a full rebuild for the settled prefix. All those
|
|
84
|
-
// invalidators are folded into the memo deps
|
|
84
|
+
// invalidators are folded into the memo deps: revision + tailSig stand in
|
|
85
|
+
// for the items/tail identities, and measuredRowsVersion folds in measured
|
|
86
|
+
// corrections.
|
|
87
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies(transcriptItems): keyed by revision + tailSig
|
|
88
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies(streamingTailItem): keyed by tailSig
|
|
89
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies(tailSig): tail id + height recompute key
|
|
85
90
|
const transcriptRowIndex = useMemo(
|
|
86
91
|
() =>
|
|
87
92
|
buildTranscriptRowIndexIncremental(transcriptItems, {
|
|
@@ -92,9 +97,8 @@ export function useTranscriptGeometry(state, props) {
|
|
|
92
97
|
cacheRef: state.incrementalRowIndexCacheRef,
|
|
93
98
|
prefixRevision: revision,
|
|
94
99
|
streamingTailItem,
|
|
95
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps -- revision/tail height capture structural geometry; measuredRowsVersion folds in measured corrections
|
|
96
100
|
}),
|
|
97
|
-
[revision, tailSig, frameColumns, toolOutputExpanded, measuredRowsVersion]
|
|
101
|
+
[revision, tailSig, frameColumns, toolOutputExpanded, measuredRowsVersion, state.incrementalRowIndexCacheRef]
|
|
98
102
|
);
|
|
99
103
|
const renderScrollOffset = resolveRenderScrollOffset({
|
|
100
104
|
scrollOffset,
|
|
@@ -109,6 +113,10 @@ export function useTranscriptGeometry(state, props) {
|
|
|
109
113
|
geomRef: transcriptGeomRef,
|
|
110
114
|
prevViewportRef: state.prevViewportGeomRef,
|
|
111
115
|
});
|
|
116
|
+
// transcriptStructureSig stands in for the items identity (it also encodes
|
|
117
|
+
// frameColumns and toolOutputExpanded); scroll/viewport capture the rest.
|
|
118
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies(transcriptItems): keyed by transcriptStructureSig
|
|
119
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies(transcriptStructureSig): items recompute key
|
|
112
120
|
const transcriptWindow = useMemo(
|
|
113
121
|
() =>
|
|
114
122
|
transcriptRenderWindow(transcriptItems, {
|
|
@@ -117,9 +125,15 @@ export function useTranscriptGeometry(state, props) {
|
|
|
117
125
|
columns: frameColumns,
|
|
118
126
|
toolOutputExpanded,
|
|
119
127
|
rowIndex: transcriptRowIndex,
|
|
120
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps -- intentional: sig+scroll/viewport capture the relevant changes
|
|
121
128
|
}),
|
|
122
|
-
[
|
|
129
|
+
[
|
|
130
|
+
transcriptStructureSig,
|
|
131
|
+
renderScrollOffset,
|
|
132
|
+
transcriptContentHeight,
|
|
133
|
+
transcriptRowIndex,
|
|
134
|
+
frameColumns,
|
|
135
|
+
toolOutputExpanded,
|
|
136
|
+
]
|
|
123
137
|
);
|
|
124
138
|
publishMaxScrollRows(state, transcriptWindow, { maxScrollRowsRef, frameColumns, toolOutputExpanded });
|
|
125
139
|
// Publish this frame's geometry so a manual scroll can capture the reading
|
|
@@ -65,6 +65,10 @@ export function useTranscriptInstanceState({ sessionKey, scrollOffset, setScroll
|
|
|
65
65
|
followingRef.current = true;
|
|
66
66
|
selectionLayoutRef.current = null;
|
|
67
67
|
}
|
|
68
|
+
// Runs on a session switch only: normalizedSessionKey is the trigger, and
|
|
69
|
+
// scrollOffset is read (not tracked) so scrolling never re-runs the reset.
|
|
70
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies(normalizedSessionKey): session-switch trigger
|
|
71
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies(scrollOffset): read at switch time only
|
|
68
72
|
useLayoutEffect(() => {
|
|
69
73
|
if (scrollOffset !== 0) setScrollOffset(0);
|
|
70
74
|
}, [normalizedSessionKey, setScrollOffset]);
|
|
@@ -40,12 +40,16 @@ export function useSelectionLayoutShift({
|
|
|
40
40
|
// with only the still-visible fragment (partial Ctrl+C after scrolling).
|
|
41
41
|
paintSelectionRect(clippedRect, { rememberText: false });
|
|
42
42
|
}, [
|
|
43
|
+
transcriptViewportRef,
|
|
44
|
+
selectionLayoutRef,
|
|
45
|
+
dragRef,
|
|
43
46
|
transcriptContentHeight,
|
|
44
47
|
transcriptWindow.totalRows,
|
|
45
48
|
transcriptWindow.effectiveScrollOffset,
|
|
46
49
|
withSelectionClip,
|
|
47
50
|
paintSelectionRect,
|
|
48
51
|
]);
|
|
52
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies(themeEpoch): theme-change repaint trigger
|
|
49
53
|
useEffect(() => {
|
|
50
54
|
if (!dragRef.current.rect) return;
|
|
51
55
|
const clippedRect = withSelectionClip(dragRef.current.rect);
|
|
@@ -53,5 +57,5 @@ export function useSelectionLayoutShift({
|
|
|
53
57
|
// Theme repaint: same cells, same text — no need to re-harvest (and a
|
|
54
58
|
// clipped rect would clobber the remembered full text with a fragment).
|
|
55
59
|
paintSelectionRect(clippedRect, { rememberText: false });
|
|
56
|
-
}, [themeEpoch, withSelectionClip, paintSelectionRect]);
|
|
60
|
+
}, [themeEpoch, dragRef, withSelectionClip, paintSelectionRect]);
|
|
57
61
|
}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* use-transcript-window/visible-items.mjs — on-screen slice, overlay hint placement
|
|
14
14
|
* use-transcript-window/selection-shift.mjs — selection rect follows geometry/theme
|
|
15
15
|
*/
|
|
16
|
-
import { useCallback, useEffect, useLayoutEffect } from 'react';
|
|
16
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo } from 'react';
|
|
17
17
|
import { harvestMeasuredRows, measureRefFor } from './transcript-measure.mjs';
|
|
18
18
|
import {
|
|
19
19
|
clampScrollToOverflow,
|
|
@@ -66,7 +66,10 @@ export function useTranscriptWindow({
|
|
|
66
66
|
selectionLayoutRef,
|
|
67
67
|
};
|
|
68
68
|
const state = useTranscriptInstanceState({ sessionKey, scrollOffset, setScrollOffset, refs });
|
|
69
|
-
const transcriptMeasureRef = useCallback(
|
|
69
|
+
const transcriptMeasureRef = useCallback(
|
|
70
|
+
(item) => measureRefFor(state.measureStateRef.current, item),
|
|
71
|
+
[state.measureStateRef]
|
|
72
|
+
);
|
|
70
73
|
const { revision, streamingTailItem, transcriptItems, transcriptRowIndex, transcriptWindow } = useTranscriptGeometry(
|
|
71
74
|
state,
|
|
72
75
|
{
|
|
@@ -102,13 +105,12 @@ export function useTranscriptWindow({
|
|
|
102
105
|
transcriptGuardRows,
|
|
103
106
|
themeEpoch,
|
|
104
107
|
};
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
scrollTargetRef,
|
|
109
|
-
scrollPositionRef,
|
|
110
|
-
|
|
111
|
-
};
|
|
108
|
+
// Memoized over the App-owned refs (stable identities), so the effects below
|
|
109
|
+
// can depend on the bundle without re-running.
|
|
110
|
+
const scrollRefs = useMemo(
|
|
111
|
+
() => ({ transcriptAnchorRef, transcriptAnchorDirtyRef, scrollTargetRef, scrollPositionRef, followingRef }),
|
|
112
|
+
[transcriptAnchorRef, transcriptAnchorDirtyRef, scrollTargetRef, scrollPositionRef, followingRef]
|
|
113
|
+
);
|
|
112
114
|
// ── Measured height harvest (every commit, no deps) ─────────────────────
|
|
113
115
|
useLayoutEffect(() => {
|
|
114
116
|
harvestMeasuredRows(state.measureStateRef.current, {
|
|
@@ -120,6 +122,10 @@ export function useTranscriptWindow({
|
|
|
120
122
|
});
|
|
121
123
|
});
|
|
122
124
|
// ── Bottom-follow / anchor post-commit sync ─────────────────────────────
|
|
125
|
+
// transcriptItems is read alongside transcriptRowIndex, which is derived
|
|
126
|
+
// from it; the sync keys on the row index so a same-geometry items swap
|
|
127
|
+
// does not re-run it.
|
|
128
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies(transcriptItems): keyed on the derived row index
|
|
123
129
|
useLayoutEffect(() => {
|
|
124
130
|
const totalRows = Math.max(0, Number(transcriptWindow.totalRows) || 0);
|
|
125
131
|
const previousTotalRows = Math.max(0, Number(state.transcriptTotalRowsRef.current) || 0);
|
|
@@ -144,10 +150,14 @@ export function useTranscriptWindow({
|
|
|
144
150
|
transcriptContentHeight,
|
|
145
151
|
scrollOffset,
|
|
146
152
|
stopSmoothScroll,
|
|
153
|
+
scrollRefs,
|
|
154
|
+
state.transcriptTotalRowsRef,
|
|
155
|
+
dragRef,
|
|
156
|
+
setScrollOffset,
|
|
147
157
|
]);
|
|
148
158
|
useLayoutEffect(() => {
|
|
149
159
|
resetScrollWhenUnanchored(scrollRefs, { scrollOffset, setScrollOffset, stopSmoothScroll });
|
|
150
|
-
}, [scrollOffset, stopSmoothScroll]);
|
|
160
|
+
}, [scrollRefs, scrollOffset, setScrollOffset, stopSmoothScroll]);
|
|
151
161
|
// ── Selection layout shift ──────────────────────────────────────────────
|
|
152
162
|
useSelectionLayoutShift({
|
|
153
163
|
transcriptWindow,
|
|
@@ -166,7 +176,7 @@ export function useTranscriptWindow({
|
|
|
166
176
|
setScrollOffset,
|
|
167
177
|
stopSmoothScroll,
|
|
168
178
|
});
|
|
169
|
-
}, [transcriptWindow.maxScrollRows, scrollOffset, stopSmoothScroll]);
|
|
179
|
+
}, [scrollRefs, transcriptWindow.maxScrollRows, scrollOffset, setScrollOffset, stopSmoothScroll]);
|
|
170
180
|
|
|
171
181
|
return {
|
|
172
182
|
transcriptWindow,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* app/use-tui-ready.mjs — post-mount input gate.
|
|
3
|
+
*
|
|
4
|
+
* tuiReady stays false across the first render + commit. Let one event-loop
|
|
5
|
+
* poll pass so Ink processes (and discards, because PromptInput is still
|
|
6
|
+
* disabled) any keystrokes the OS buffered during terminal setup / initial
|
|
7
|
+
* mount. After the tick, enable the input — new keystrokes land normally.
|
|
8
|
+
*/
|
|
9
|
+
import { useEffect, useState } from 'react';
|
|
10
|
+
|
|
11
|
+
export function useTuiReady() {
|
|
12
|
+
const [tuiReady, setTuiReady] = useState(false);
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const timer = setTimeout(() => setTuiReady(true), 0);
|
|
15
|
+
return () => clearTimeout(timer);
|
|
16
|
+
}, []);
|
|
17
|
+
return tuiReady;
|
|
18
|
+
}
|
|
@@ -26,6 +26,11 @@ export function useWelcomePromptHint({ store, state, toastErrorSignature }) {
|
|
|
26
26
|
setWelcomePromptHintDismissed(true);
|
|
27
27
|
}, []);
|
|
28
28
|
|
|
29
|
+
// The probe re-runs when the workflow id changes; the workflow snapshot it
|
|
30
|
+
// hands to the summary probe is read, not tracked, so an identity-only
|
|
31
|
+
// workflow refresh does not re-probe.
|
|
32
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies(state.workflow): keyed by workflow id
|
|
33
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies(state.workflow?.id): workflow id re-probe key
|
|
29
34
|
useEffect(() => {
|
|
30
35
|
let alive = true;
|
|
31
36
|
const refreshConditionalWelcomeHint = async () => {
|
|
@@ -20,10 +20,12 @@ export function useWorkflowTabCycle({
|
|
|
20
20
|
// async switch and pushes a toast, producing a rapid bottom-layout repaint
|
|
21
21
|
// storm that can visually tear the prompt box in Windows Terminal.
|
|
22
22
|
const workflowTabCycleRef = useRef({ pending: false, lastAt: 0 });
|
|
23
|
+
// The cycle reads only these two state fields.
|
|
24
|
+
const { commandBusy, workflow } = state;
|
|
23
25
|
return useCallback(() => {
|
|
24
26
|
if (slashPaletteOpen || toolApproval || picker || settingsPrompt || providerPrompt || contextPanel || usagePanel)
|
|
25
27
|
return true;
|
|
26
|
-
return cycleWorkflow({ store, state, cycleGuard: workflowTabCycleRef.current });
|
|
28
|
+
return cycleWorkflow({ store, state: { commandBusy, workflow }, cycleGuard: workflowTabCycleRef.current });
|
|
27
29
|
}, [
|
|
28
30
|
slashPaletteOpen,
|
|
29
31
|
toolApproval,
|
|
@@ -32,8 +34,8 @@ export function useWorkflowTabCycle({
|
|
|
32
34
|
providerPrompt,
|
|
33
35
|
contextPanel,
|
|
34
36
|
usagePanel,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
commandBusy,
|
|
38
|
+
workflow,
|
|
37
39
|
store,
|
|
38
40
|
]);
|
|
39
41
|
}
|