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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Discovery of importable foreign conversations on disk (read-only).
|
|
3
3
|
*
|
|
4
|
-
* codex $CODEX_HOME/sessions/**\/rollout-*.jsonl (default ~/.codex)
|
|
4
|
+
* codex $CODEX_HOME/sessions/**\/rollout-*.jsonl[.zst] (default ~/.codex)
|
|
5
5
|
* claude $CLAUDE_CONFIG_DIR/projects/*\/*.jsonl (default ~/.claude)
|
|
6
6
|
*
|
|
7
7
|
* Enumeration is stat-only; per-file metadata (foreign id, cwd, title, and
|
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
import { createHash, randomUUID } from 'node:crypto';
|
|
14
14
|
import { open, readdir, realpath, stat } from 'node:fs/promises';
|
|
15
15
|
import { homedir } from 'node:os';
|
|
16
|
-
import { basename, dirname,
|
|
16
|
+
import { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path';
|
|
17
|
+
import { pipeline } from 'node:stream';
|
|
18
|
+
import zlib from 'node:zlib';
|
|
17
19
|
import {
|
|
18
20
|
IMPORT_MAX_FILE_BYTES,
|
|
19
21
|
IMPORT_MAX_LINE_BYTES,
|
|
@@ -24,7 +26,13 @@ import {
|
|
|
24
26
|
isImportSource,
|
|
25
27
|
} from '../../runtime/agent/orchestrator/session/conversation-import/convert.mjs';
|
|
26
28
|
import { codexMetaFromTruncatedLine } from '../../runtime/agent/orchestrator/session/conversation-import/codex.mjs';
|
|
27
|
-
import {
|
|
29
|
+
import {
|
|
30
|
+
IMPORT_ERROR_NEEDS_NEWER_NODE,
|
|
31
|
+
IMPORT_WARNING_CWD_MISSING,
|
|
32
|
+
IMPORT_WARNING_HISTORY_PARTIAL,
|
|
33
|
+
IMPORT_WARNING_HISTORY_SIZE_LIMIT,
|
|
34
|
+
IMPORT_WARNING_HISTORY_UNAVAILABLE,
|
|
35
|
+
} from '../../runtime/agent/orchestrator/session/conversation-import/turns.mjs';
|
|
28
36
|
import { importOriginKey } from '../../runtime/agent/orchestrator/session/conversation-import/imported-session.mjs';
|
|
29
37
|
import { loadCodexThreadTitles } from './codex-titles.mjs';
|
|
30
38
|
|
|
@@ -106,6 +114,51 @@ export function isNetworkOrDevicePath(path) {
|
|
|
106
114
|
|
|
107
115
|
const fileIdentity = (info) => `${info.dev}:${info.ino}`;
|
|
108
116
|
|
|
117
|
+
// Rollout file-name rules, as the source app applies them: a compressed rollout is a
|
|
118
|
+
// name ending `.jsonl.zst`; a rollout name is, after dropping a `.zst` suffix,
|
|
119
|
+
// `rollout-` … `.jsonl`. Both are case-sensitive.
|
|
120
|
+
const COMPRESSED_ROLLOUT_SUFFIX = '.jsonl.zst';
|
|
121
|
+
const isCompressed = (path) => basename(path).endsWith(COMPRESSED_ROLLOUT_SUFFIX);
|
|
122
|
+
const isRolloutName = (name) => {
|
|
123
|
+
const plain = name.endsWith(COMPRESSED_ROLLOUT_SUFFIX) ? name.slice(0, -'.zst'.length) : name;
|
|
124
|
+
return plain.startsWith('rollout-') && plain.endsWith('.jsonl');
|
|
125
|
+
};
|
|
126
|
+
const zstdSupported = () => typeof zlib.createZstdDecompress === 'function';
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Sequential `read(buffer, offset, length, position)` / `close()` over the
|
|
130
|
+
* decompressed bytes of an open compressed file, shaped like a file handle so
|
|
131
|
+
* the line reader needs no other change. Positions must run on from the last
|
|
132
|
+
* read; closing stops the decompression.
|
|
133
|
+
*/
|
|
134
|
+
function zstdReader(handle) {
|
|
135
|
+
if (!zstdSupported()) throw importError(IMPORT_ERROR_NEEDS_NEWER_NODE);
|
|
136
|
+
const decoder = zlib.createZstdDecompress();
|
|
137
|
+
pipeline(handle.createReadStream({ autoClose: false }), decoder, () => {});
|
|
138
|
+
const chunks = decoder[Symbol.asyncIterator]();
|
|
139
|
+
let rest = Buffer.alloc(0);
|
|
140
|
+
let position = 0;
|
|
141
|
+
return {
|
|
142
|
+
async read(buffer, offset, length, from) {
|
|
143
|
+
if (from !== position) throw importError('unreadable');
|
|
144
|
+
if (!rest.length) {
|
|
145
|
+
const next = await chunks.next();
|
|
146
|
+
if (next.done) return { bytesRead: 0, buffer };
|
|
147
|
+
rest = next.value;
|
|
148
|
+
}
|
|
149
|
+
const bytesRead = Math.min(length, rest.length);
|
|
150
|
+
rest.copy(buffer, offset, 0, bytesRead);
|
|
151
|
+
rest = rest.subarray(bytesRead);
|
|
152
|
+
position += bytesRead;
|
|
153
|
+
return { bytesRead, buffer };
|
|
154
|
+
},
|
|
155
|
+
async close() {
|
|
156
|
+
decoder.destroy();
|
|
157
|
+
await handle.close();
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
109
162
|
export function candidateId(source, canonicalPath) {
|
|
110
163
|
return createHash('sha256')
|
|
111
164
|
.update(`${source}\0${caseFold(canonicalPath)}`)
|
|
@@ -144,7 +197,10 @@ async function walkCodex(rootReal, dir, files, seenDirs) {
|
|
|
144
197
|
continue;
|
|
145
198
|
}
|
|
146
199
|
}
|
|
147
|
-
if (
|
|
200
|
+
if (!isRolloutName(entry.name)) continue;
|
|
201
|
+
// A compressed rollout is skipped while its plain sibling exists.
|
|
202
|
+
if (isCompressed(entry.name) && (await stat(path.slice(0, -'.zst'.length)).catch(() => null))) continue;
|
|
203
|
+
files.push(path);
|
|
148
204
|
}
|
|
149
205
|
}
|
|
150
206
|
|
|
@@ -275,7 +331,7 @@ async function openCandidate(candidate) {
|
|
|
275
331
|
) {
|
|
276
332
|
throw importError('unreadable');
|
|
277
333
|
}
|
|
278
|
-
return handle;
|
|
334
|
+
return isCompressed(candidate.path) ? zstdReader(handle) : handle;
|
|
279
335
|
} catch (error) {
|
|
280
336
|
await handle.close();
|
|
281
337
|
throw error;
|
|
@@ -351,6 +407,10 @@ async function readTailLines(handle, size) {
|
|
|
351
407
|
return (size > length ? text.slice(text.indexOf('\n') + 1) : text).split('\n');
|
|
352
408
|
}
|
|
353
409
|
|
|
410
|
+
// Whether the rollout a listed file continues is absent (a stat-only search): its own records are then all there is to name and count.
|
|
411
|
+
const baseIsMissing = async (candidate, meta) =>
|
|
412
|
+
!!meta.historyBaseId && !(await findRolloutById(dirname(candidate.root ?? sourceRoot('codex')), meta.historyBaseId));
|
|
413
|
+
|
|
354
414
|
async function readPrefixMeta(candidate) {
|
|
355
415
|
const converter = createConversationConverter(candidate.source);
|
|
356
416
|
const handle = await openCandidate(candidate);
|
|
@@ -385,12 +445,14 @@ async function readPrefixMeta(candidate) {
|
|
|
385
445
|
}
|
|
386
446
|
const conversion = converter.result();
|
|
387
447
|
// A thread continuing a history base is only counted, named and judged empty once the base is followed (on import).
|
|
388
|
-
const listing = (meta) =>
|
|
389
|
-
conversion.historyBase
|
|
448
|
+
const listing = async (meta) =>
|
|
449
|
+
conversion.historyBase && !(await baseIsMissing(candidate, meta))
|
|
390
450
|
? { ...meta, title: null, messageCount: null, errorCode: meta.errorCode === 'empty' ? null : meta.errorCode }
|
|
391
|
-
:
|
|
451
|
+
: conversion.historyBase
|
|
452
|
+
? { ...meta, warnings: [...meta.warnings, IMPORT_WARNING_HISTORY_UNAVAILABLE] }
|
|
453
|
+
: meta;
|
|
392
454
|
if (read.eof) return listing(metaFromConversion(conversion, true));
|
|
393
|
-
const meta = listing(metaFromConversion(conversion, false));
|
|
455
|
+
const meta = await listing(metaFromConversion(conversion, false));
|
|
394
456
|
if (candidate.source === 'codex' && (!meta.foreignSessionId || !meta.cwd) && read.firstPartial) {
|
|
395
457
|
// A session_meta line longer than the prefix still names its id/cwd.
|
|
396
458
|
const fromLine = codexMetaFromTruncatedLine(read.firstPartial.replace(/^\uFEFF/, ''));
|
|
@@ -404,10 +466,13 @@ async function readPrefixMeta(candidate) {
|
|
|
404
466
|
// ── Codex history base chain ─────────────────────────────────────────────────
|
|
405
467
|
const HISTORY_CHAIN_MAX_DEPTH = 32;
|
|
406
468
|
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
407
|
-
const ROLLOUT_ID_RE = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl
|
|
469
|
+
const ROLLOUT_ID_RE = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl(?:\.zst)?$/i;
|
|
408
470
|
|
|
409
|
-
/** Rollout id a rollout file name ends with (`…-<thread>.jsonl` or `…-<thread>_<rollout>.jsonl`). */
|
|
410
|
-
const rolloutIdOf = (path) =>
|
|
471
|
+
/** Rollout id a rollout file name ends with (`…-<thread>.jsonl[.zst]` or `…-<thread>_<rollout>.jsonl[.zst]`). */
|
|
472
|
+
const rolloutIdOf = (path) => {
|
|
473
|
+
const name = basename(path);
|
|
474
|
+
return isRolloutName(name) ? (name.match(ROLLOUT_ID_RE)?.[1].toLowerCase() ?? null) : null;
|
|
475
|
+
};
|
|
411
476
|
|
|
412
477
|
const META_CHUNK_BYTES = 8 * 1024;
|
|
413
478
|
|
|
@@ -439,20 +504,34 @@ async function firstRecord(candidate, { maxBytes, maxLineBytes }) {
|
|
|
439
504
|
}
|
|
440
505
|
}
|
|
441
506
|
|
|
442
|
-
// Whether a cutoff falls on a record boundary: the end of the file or just after a line feed.
|
|
507
|
+
// Whether a cutoff, in (decompressed) file bytes, falls on a record boundary: the end of the file or just after a line feed.
|
|
443
508
|
async function endsOnRecord(candidate, end) {
|
|
444
|
-
|
|
509
|
+
const compressed = isCompressed(candidate.path);
|
|
510
|
+
if (!compressed && end === candidate.size) return true;
|
|
445
511
|
const handle = await openCandidate(candidate);
|
|
446
512
|
try {
|
|
447
513
|
const byte = Buffer.alloc(1);
|
|
448
|
-
|
|
449
|
-
|
|
514
|
+
if (!compressed) {
|
|
515
|
+
const { bytesRead } = await handle.read(byte, 0, 1, end - 1);
|
|
516
|
+
return bytesRead === 1 && byte[0] === 10;
|
|
517
|
+
}
|
|
518
|
+
// The decompressed size is unknown: read up to the cutoff, then see whether the file ends there.
|
|
519
|
+
const chunk = Buffer.allocUnsafe(IMPORT_CHUNK_BYTES);
|
|
520
|
+
let position = 0;
|
|
521
|
+
let last = 0;
|
|
522
|
+
while (position < end) {
|
|
523
|
+
const { bytesRead } = await handle.read(chunk, 0, Math.min(chunk.length, end - position), position);
|
|
524
|
+
if (!bytesRead) return false;
|
|
525
|
+
position += bytesRead;
|
|
526
|
+
last = chunk[bytesRead - 1];
|
|
527
|
+
}
|
|
528
|
+
return last === 10 || (await handle.read(byte, 0, 1, position)).bytesRead === 0;
|
|
450
529
|
} finally {
|
|
451
530
|
await handle.close();
|
|
452
531
|
}
|
|
453
532
|
}
|
|
454
533
|
|
|
455
|
-
/** The
|
|
534
|
+
/** The rollout file with this rollout id under the live, then the archived, sessions folder (walking lists a plain file instead of its compressed sibling). */
|
|
456
535
|
async function findRolloutById(home, rolloutId) {
|
|
457
536
|
for (const folder of ['sessions', 'archived_sessions']) {
|
|
458
537
|
let rootReal;
|
|
@@ -475,23 +554,43 @@ async function findRolloutById(home, rolloutId) {
|
|
|
475
554
|
return null;
|
|
476
555
|
}
|
|
477
556
|
|
|
557
|
+
// Size of a compressed file once decompressed, counting no further than `cap`.
|
|
558
|
+
async function decompressedLength(candidate, cap) {
|
|
559
|
+
const handle = await openCandidate(candidate);
|
|
560
|
+
try {
|
|
561
|
+
const chunk = Buffer.allocUnsafe(IMPORT_CHUNK_BYTES);
|
|
562
|
+
let length = 0;
|
|
563
|
+
while (length < cap) {
|
|
564
|
+
const { bytesRead } = await handle.read(chunk, 0, Math.min(chunk.length, cap - length), length);
|
|
565
|
+
if (!bytesRead) break;
|
|
566
|
+
length += bytesRead;
|
|
567
|
+
}
|
|
568
|
+
return length;
|
|
569
|
+
} finally {
|
|
570
|
+
await handle.close();
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
478
574
|
/**
|
|
479
575
|
* Rollouts a `history_base` leads to, nearest first, each with the byte offset
|
|
480
576
|
* its contribution ends at, and `metaBytes`, what reading their metadata took.
|
|
481
|
-
*
|
|
482
|
-
*
|
|
483
|
-
*
|
|
484
|
-
* does not end a record, or that would take the total read (the file, the
|
|
577
|
+
* Cutoffs and byte counts are of the decompressed rollout. Stops (`partial`,
|
|
578
|
+
* the warning code saying why) at a base that is missing or unreadable
|
|
579
|
+
* (`historyUnavailable`), that would take the total read (the file, the
|
|
485
580
|
* `spent` metadata reads so far, every cutoff and every metadata read) beyond
|
|
486
|
-
* `maxFileBytes
|
|
581
|
+
* `maxFileBytes` (`historySizeLimit`), or is not paginated, already visited,
|
|
582
|
+
* past the depth cap, with a cutoff that excludes the session metadata,
|
|
583
|
+
* passes the end of the file or does not end a record (`historyPartial`).
|
|
487
584
|
*/
|
|
488
585
|
async function resolveHistoryChain(candidate, firstBase, { maxFileBytes, maxLineBytes, spent }) {
|
|
489
586
|
const home = dirname(candidate.root ?? sourceRoot('codex'));
|
|
490
587
|
const seen = new Set([rolloutIdOf(candidate.path)]);
|
|
491
588
|
const segments = [];
|
|
492
|
-
|
|
589
|
+
// The file itself is reserved at its decompressed size, which only reading it tells.
|
|
590
|
+
let used =
|
|
591
|
+
(isCompressed(candidate.path) ? await decompressedLength(candidate, maxFileBytes) : candidate.size) + spent;
|
|
493
592
|
let metaBytes = 0;
|
|
494
|
-
const partial = () => ({ segments, partial:
|
|
593
|
+
const partial = (warning = IMPORT_WARNING_HISTORY_PARTIAL) => ({ segments, partial: warning, metaBytes });
|
|
495
594
|
for (let base = firstBase; base; ) {
|
|
496
595
|
const id = typeof base.thread_id === 'string' ? base.thread_id.toLowerCase() : '';
|
|
497
596
|
const end = base.end_byte_offset;
|
|
@@ -500,13 +599,20 @@ async function resolveHistoryChain(candidate, firstBase, { maxFileBytes, maxLine
|
|
|
500
599
|
seen.add(id);
|
|
501
600
|
if (!Number.isSafeInteger(ordinal) || ordinal <= 0 || !Number.isSafeInteger(end) || end <= 0) return partial();
|
|
502
601
|
const found = await findRolloutById(home, id);
|
|
503
|
-
if (!found
|
|
602
|
+
if (!found) return partial(IMPORT_WARNING_HISTORY_UNAVAILABLE);
|
|
603
|
+
if (!isCompressed(found.path) && end > found.size) return partial();
|
|
604
|
+
if (used + end > maxFileBytes) return partial(IMPORT_WARNING_HISTORY_SIZE_LIMIT);
|
|
504
605
|
let head;
|
|
505
606
|
try {
|
|
506
607
|
if (!(await endsOnRecord(found, end))) return partial();
|
|
507
608
|
head = await firstRecord(found, { maxBytes: Math.min(end, maxFileBytes - used - end), maxLineBytes });
|
|
508
|
-
} catch {
|
|
509
|
-
|
|
609
|
+
} catch (error) {
|
|
610
|
+
// A runtime without zstd names its own fix; any other failure to open or read the base is "unavailable".
|
|
611
|
+
return partial(
|
|
612
|
+
error?.code === IMPORT_ERROR_NEEDS_NEWER_NODE
|
|
613
|
+
? IMPORT_ERROR_NEEDS_NEWER_NODE
|
|
614
|
+
: IMPORT_WARNING_HISTORY_UNAVAILABLE
|
|
615
|
+
);
|
|
510
616
|
}
|
|
511
617
|
used += end + head.bytes;
|
|
512
618
|
metaBytes += head.bytes;
|
|
@@ -515,7 +621,7 @@ async function resolveHistoryChain(candidate, firstBase, { maxFileBytes, maxLine
|
|
|
515
621
|
const next = head.record.payload.history_base;
|
|
516
622
|
base = next && typeof next === 'object' ? next : null;
|
|
517
623
|
}
|
|
518
|
-
return { segments, partial:
|
|
624
|
+
return { segments, partial: null, metaBytes };
|
|
519
625
|
}
|
|
520
626
|
|
|
521
627
|
/**
|
|
@@ -524,8 +630,10 @@ async function resolveHistoryChain(candidate, firstBase, { maxFileBytes, maxLine
|
|
|
524
630
|
* converter's limits fails the file with `tooLarge` without reading the rest.
|
|
525
631
|
* A Codex rollout continuing a `history_base` is preceded by the records of
|
|
526
632
|
* each base up to its cutoff, oldest first (their session metadata dropped),
|
|
527
|
-
* all within the one `maxFileBytes
|
|
528
|
-
*
|
|
633
|
+
* all within the one `maxFileBytes` (counted in decompressed bytes for a
|
|
634
|
+
* compressed rollout); a base that cannot be followed leaves a `historyPartial`,
|
|
635
|
+
* `historySizeLimit` or `historyUnavailable` warning. `bytesRead` is how far
|
|
636
|
+
* the read got.
|
|
529
637
|
*/
|
|
530
638
|
export async function convertCandidateFile(
|
|
531
639
|
candidate,
|
|
@@ -553,10 +661,10 @@ export async function convertCandidateFile(
|
|
|
553
661
|
const chain =
|
|
554
662
|
head.record.payload.history_mode === 'paginated'
|
|
555
663
|
? await resolveHistoryChain(candidate, base, { maxFileBytes, maxLineBytes, spent: inheritedBytes })
|
|
556
|
-
: { segments: [], partial:
|
|
664
|
+
: { segments: [], partial: IMPORT_WARNING_HISTORY_PARTIAL, metaBytes: 0 };
|
|
557
665
|
inheritedBytes += chain.metaBytes;
|
|
558
666
|
const { segments, partial } = chain;
|
|
559
|
-
if (partial) converter.markHistoryPartial();
|
|
667
|
+
if (partial) converter.markHistoryPartial(partial);
|
|
560
668
|
for (const { candidate: baseFile, end } of segments.reverse()) {
|
|
561
669
|
const baseHandle = await openCandidate(baseFile);
|
|
562
670
|
try {
|
|
@@ -587,12 +695,22 @@ export async function convertCandidateFile(
|
|
|
587
695
|
}
|
|
588
696
|
}
|
|
589
697
|
|
|
698
|
+
// On a runtime without zstd, a listed conversation whose history base is compressed says so on its row.
|
|
699
|
+
async function withCompressedBaseNotice(candidate, meta) {
|
|
700
|
+
if (!meta.historyBaseId || zstdSupported()) return meta;
|
|
701
|
+
const found = await findRolloutById(dirname(candidate.root ?? sourceRoot('codex')), meta.historyBaseId);
|
|
702
|
+
return found && isCompressed(found.path)
|
|
703
|
+
? { ...meta, warnings: [...meta.warnings, IMPORT_ERROR_NEEDS_NEWER_NODE] }
|
|
704
|
+
: meta;
|
|
705
|
+
}
|
|
706
|
+
|
|
590
707
|
function pumpMetaQueue() {
|
|
591
708
|
while (state.active < META_CONCURRENCY && state.queue.length) {
|
|
592
709
|
const job = state.queue.shift();
|
|
593
710
|
state.active += 1;
|
|
594
711
|
readPrefixMeta(job.candidate)
|
|
595
|
-
.
|
|
712
|
+
.then((meta) => withCompressedBaseNotice(job.candidate, meta))
|
|
713
|
+
.catch((error) => ({
|
|
596
714
|
foreignSessionId: null,
|
|
597
715
|
cwd: null,
|
|
598
716
|
title: null,
|
|
@@ -600,7 +718,7 @@ function pumpMetaQueue() {
|
|
|
600
718
|
historyBaseId: null,
|
|
601
719
|
messageCount: null,
|
|
602
720
|
warnings: [],
|
|
603
|
-
errorCode: 'unreadable',
|
|
721
|
+
errorCode: error?.code === IMPORT_ERROR_NEEDS_NEWER_NODE ? IMPORT_ERROR_NEEDS_NEWER_NODE : 'unreadable',
|
|
604
722
|
}))
|
|
605
723
|
.then((value) => {
|
|
606
724
|
state.meta.set(job.candidate.path, { stampKey: stampKey(job.candidate), value });
|
|
@@ -684,7 +802,7 @@ function rowFor(candidate, meta, cwdInfo, imported, titles) {
|
|
|
684
802
|
};
|
|
685
803
|
}
|
|
686
804
|
|
|
687
|
-
|
|
805
|
+
async function buildRow(candidate, imported, cwdCache = new Map(), titles = null) {
|
|
688
806
|
const meta = cachedMeta(candidate);
|
|
689
807
|
const cwdInfo = meta?.cwd ? await resolveSourceCwd(meta.cwd, cwdCache) : null;
|
|
690
808
|
return rowFor(candidate, meta, cwdInfo, imported, titles);
|
|
@@ -903,7 +1021,7 @@ export async function resolveViewSelection(viewId, excludeIds, imported) {
|
|
|
903
1021
|
}
|
|
904
1022
|
|
|
905
1023
|
// ── picked files ─────────────────────────────────────────────────────────────
|
|
906
|
-
/** Validate and register a file chosen in a native picker (a local regular .jsonl). */
|
|
1024
|
+
/** Validate and register a file chosen in a native picker (a local regular .jsonl, or a Codex .jsonl.zst). */
|
|
907
1025
|
export async function registerFile({ source, path } = {}, { imported, limits, env = process.env } = {}) {
|
|
908
1026
|
requireSource(source);
|
|
909
1027
|
if (typeof path !== 'string' || !path.trim() || path.includes('\0')) throw importError('invalidPath');
|
|
@@ -911,7 +1029,8 @@ export async function registerFile({ source, path } = {}, { imported, limits, en
|
|
|
911
1029
|
// Network/device forms are refused before any filesystem call.
|
|
912
1030
|
if (isNetworkOrDevicePath(requested)) throw importError('unsupported');
|
|
913
1031
|
if (!isAbsolute(requested)) throw importError('invalidPath');
|
|
914
|
-
|
|
1032
|
+
const pickable = (path) => /\.jsonl$/i.test(path) || (source === 'codex' && isCompressed(path));
|
|
1033
|
+
if (!pickable(basename(requested))) throw importError('unsupported');
|
|
915
1034
|
let real;
|
|
916
1035
|
let info;
|
|
917
1036
|
try {
|
|
@@ -920,7 +1039,7 @@ export async function registerFile({ source, path } = {}, { imported, limits, en
|
|
|
920
1039
|
} catch {
|
|
921
1040
|
throw importError('unreadable');
|
|
922
1041
|
}
|
|
923
|
-
if (isNetworkOrDevicePath(real) || !info.isFile() ||
|
|
1042
|
+
if (isNetworkOrDevicePath(real) || !info.isFile() || !pickable(basename(real))) {
|
|
924
1043
|
throw importError('unsupported');
|
|
925
1044
|
}
|
|
926
1045
|
const candidate = registerCandidate({
|
|
@@ -935,8 +1054,8 @@ export async function registerFile({ source, path } = {}, { imported, limits, en
|
|
|
935
1054
|
let conversion;
|
|
936
1055
|
try {
|
|
937
1056
|
conversion = await convertCandidateFile(candidate, limits);
|
|
938
|
-
} catch {
|
|
939
|
-
throw importError('unreadable');
|
|
1057
|
+
} catch (error) {
|
|
1058
|
+
throw importError(error?.code === IMPORT_ERROR_NEEDS_NEWER_NODE ? IMPORT_ERROR_NEEDS_NEWER_NODE : 'unreadable');
|
|
940
1059
|
}
|
|
941
1060
|
if (conversion.errorCode) throw importError(conversion.errorCode);
|
|
942
1061
|
recordConversion(candidate, conversion);
|
|
@@ -20,7 +20,10 @@ import {
|
|
|
20
20
|
createImportedSession,
|
|
21
21
|
importOriginKey,
|
|
22
22
|
} from '../../runtime/agent/orchestrator/session/conversation-import/imported-session.mjs';
|
|
23
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
IMPORT_ERROR_NEEDS_NEWER_NODE,
|
|
25
|
+
IMPORT_WARNING_CWD_MISSING,
|
|
26
|
+
} from '../../runtime/agent/orchestrator/session/conversation-import/turns.mjs';
|
|
24
27
|
import { sessionPath } from '../../runtime/agent/orchestrator/session/store/session-paths.mjs';
|
|
25
28
|
import {
|
|
26
29
|
cachedMeta,
|
|
@@ -185,8 +188,11 @@ async function importOne(candidateId, context) {
|
|
|
185
188
|
candidate.size = info.size;
|
|
186
189
|
candidate.mtimeMs = info.mtimeMs;
|
|
187
190
|
conversion = await convertCandidateFile(candidate, context.limits);
|
|
188
|
-
} catch {
|
|
189
|
-
return failed(
|
|
191
|
+
} catch (error) {
|
|
192
|
+
return failed(
|
|
193
|
+
candidateId,
|
|
194
|
+
error?.code === IMPORT_ERROR_NEEDS_NEWER_NODE ? IMPORT_ERROR_NEEDS_NEWER_NODE : 'unreadable'
|
|
195
|
+
);
|
|
190
196
|
}
|
|
191
197
|
const title = displayTitle(
|
|
192
198
|
{ foreignSessionId: conversion.foreignSessionId, title: listedTitle || conversion.title },
|
|
@@ -523,7 +523,7 @@ export function turnSlice(messages, { runId = '', since = 0 } = {}) {
|
|
|
523
523
|
* what its final reply names, then media/office/visualize outputs, then the
|
|
524
524
|
* files it edited. `written`: only the files it created or modified (no
|
|
525
525
|
* reply paths, no visualize open targets). */
|
|
526
|
-
|
|
526
|
+
function turnArtifactCandidates(messages, { written = false } = {}) {
|
|
527
527
|
const list = Array.isArray(messages) ? messages : [];
|
|
528
528
|
const reply = list.findLast((message) => message?.role === 'assistant' && textOf(message.content).trim());
|
|
529
529
|
const produced = [];
|
|
@@ -139,11 +139,13 @@ export function createHeldRequests({
|
|
|
139
139
|
tool: request.name,
|
|
140
140
|
target: request.outbound?.target || '',
|
|
141
141
|
reason: request.reason || '',
|
|
142
|
+
// The connector account the call is bound to (tool-exec.mjs).
|
|
143
|
+
account: request.account,
|
|
142
144
|
...(request.kind === 'outbound'
|
|
143
145
|
? {
|
|
144
146
|
payload: request.outbound?.payload || '',
|
|
145
147
|
action: request.outbound?.category,
|
|
146
|
-
account: request.outbound?.account,
|
|
148
|
+
account: request.outbound?.account || request.account,
|
|
147
149
|
editable: request.outbound?.editable,
|
|
148
150
|
details: request.outbound?.details,
|
|
149
151
|
}
|
|
@@ -50,6 +50,8 @@ export function createFeatureToolHandlers({ rt, setupTool, officeToolsEnabled, m
|
|
|
50
50
|
await setupTool.execute(args || {}, {
|
|
51
51
|
signal: signalFor(callerCtx),
|
|
52
52
|
callerSessionId: callerCtx?.callerSessionId || null,
|
|
53
|
+
requestApproval: callerCtx?.toolApprovalHook || null,
|
|
54
|
+
toolCallId: callerCtx?.toolCallId || null,
|
|
53
55
|
}),
|
|
54
56
|
};
|
|
55
57
|
}
|
|
@@ -88,6 +88,14 @@ export function createKnowledgeToolHandlers({
|
|
|
88
88
|
if (!codeGraphMod?.executeCodeGraphTool) throw new Error('code_graph runtime is not available');
|
|
89
89
|
return await codeGraphMod.executeCodeGraphTool(name, args || {}, args?.cwd || callerCwd);
|
|
90
90
|
},
|
|
91
|
+
explore: async (args, { callerCtx, callerCwd }) => {
|
|
92
|
+
const { runExplore } = await import('../../runtime/explore/tool.mjs');
|
|
93
|
+
return await runExplore(args || {}, {
|
|
94
|
+
cwd: callerCwd,
|
|
95
|
+
signal: signalFor(callerCtx),
|
|
96
|
+
callerSessionId: callerCtx?.callerSessionId || callerCtx?.sessionId || rt.session?.id || null,
|
|
97
|
+
});
|
|
98
|
+
},
|
|
91
99
|
load_tool: toolSearch,
|
|
92
100
|
Skill: (args) => skillToolContent(args?.name, activeToolSurface(), rt.mode),
|
|
93
101
|
};
|