mixdog 0.9.95 → 0.9.97
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/LICENSES/Apache-2.0.txt +201 -0
- package/LICENSES/MIT.txt +56 -0
- package/LICENSES/codex-NOTICE.txt +6 -0
- package/NOTICE.md +46 -9
- package/README.md +0 -17
- package/package.json +16 -12
- package/scripts/.tmp-coverage-report.mjs +96 -0
- package/scripts/build-tui.mjs +17 -1
- package/scripts/{channel-daemon-stub.mjs → daemon-stub.mjs} +18 -12
- package/scripts/fixtures/patch-replay-corpus.json +98 -0
- package/src/defaults/mixdog-config.template.json +5 -8
- package/src/defaults/skills/setup/SKILL.md +1 -1
- package/src/lib/keychain-cjs.cjs +1 -1
- package/src/lib/mixdog-debug.cjs +2 -3
- package/src/rules/agent/30-explorer.md +7 -4
- package/src/rules/lead/01-general.md +1 -2
- package/src/rules/lead/lead-tool.md +0 -3
- package/src/rules/shared/01-tool.md +21 -29
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +18 -2
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +31 -1
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +6 -17
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +12 -1
- package/src/runtime/agent/orchestrator/agent-trace-io.mjs +4 -13
- package/src/runtime/agent/orchestrator/config.mjs +246 -67
- package/src/runtime/agent/orchestrator/mcp/client.mjs +104 -41
- package/src/runtime/agent/orchestrator/mcp/reconnect-singleflight.mjs +23 -0
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +113 -14
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +5 -1
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +32 -11
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +89 -2
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +12 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +19 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +144 -39
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +22 -8
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +15 -1
- package/src/runtime/agent/orchestrator/providers/openai-transport-policy.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +3 -4
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +3 -6
- package/src/runtime/agent/orchestrator/providers/registry.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +67 -7
- package/src/runtime/agent/orchestrator/providers/stream-json-pool.mjs +291 -0
- package/src/runtime/agent/orchestrator/providers/stream-json-worker.mjs +21 -0
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +36 -10
- package/src/runtime/agent/orchestrator/session/compact.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +22 -33
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/loop/termination.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +0 -24
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +21 -29
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +7 -10
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +45 -25
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +2 -3
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +142 -84
- package/src/runtime/agent/orchestrator/session/manager/prefetch-bridge.mjs +12 -6
- package/src/runtime/agent/orchestrator/session/manager/runtime-loaders.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +31 -1
- package/src/runtime/agent/orchestrator/session/manager/session-lock.mjs +38 -2
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +29 -9
- package/src/runtime/agent/orchestrator/session/manager.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/result-classification.mjs +65 -0
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +86 -8
- package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +10 -3
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +71 -42
- package/src/runtime/agent/orchestrator/session/tool-batch.mjs +4 -33
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +4 -5
- package/src/runtime/agent/orchestrator/stall-policy.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/bash-session.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +35 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +116 -26
- package/src/runtime/agent/orchestrator/tools/builtin/binary-file.mjs +92 -19
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +8 -9
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/device-paths.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/fs-reachability.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-context-expander.mjs +6 -15
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +12 -26
- package/src/runtime/agent/orchestrator/tools/builtin/read-image.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +83 -33
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +42 -45
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +27 -9
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +7 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +17 -39
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +73 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-spawn.mjs +0 -2
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +3 -8
- package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +30 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +142 -26
- package/src/runtime/agent/orchestrator/tools/code-graph/search-references.mjs +12 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +47 -19
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +3 -2
- package/src/runtime/agent/orchestrator/tools/env-scrub.mjs +1 -2
- package/src/runtime/agent/orchestrator/tools/lib/pwsh-standby-pool.mjs +83 -13
- package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +39 -1
- package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +94 -20
- package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +16 -0
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +108 -12
- package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +12 -11
- package/src/runtime/agent/orchestrator/tools/patch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +63 -9
- package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +2 -2
- package/src/runtime/channels/lib/config.mjs +34 -34
- package/src/runtime/channels/lib/inbound-handler.mjs +8 -8
- package/src/runtime/channels/lib/interaction-handlers.mjs +6 -6
- package/src/runtime/channels/lib/memory-client.mjs +31 -157
- package/src/runtime/channels/lib/output-forwarder.mjs +16 -16
- package/src/runtime/channels/lib/owned-runtime.mjs +60 -60
- package/src/runtime/channels/lib/owner-heartbeat.mjs +1 -1
- package/src/runtime/channels/lib/{backend-dispatch.mjs → provider-dispatch.mjs} +6 -6
- package/src/runtime/channels/lib/runtime-paths.mjs +4 -30
- package/src/runtime/channels/lib/scheduler.mjs +2 -2
- package/src/runtime/channels/lib/status-snapshot.mjs +3 -3
- package/src/runtime/channels/lib/tool-dispatch.mjs +4 -4
- package/src/runtime/channels/lib/worker-bootstrap.mjs +1 -1
- package/src/runtime/channels/lib/worker-ipc.mjs +7 -7
- package/src/runtime/channels/lib/worker-main.mjs +38 -38
- package/src/runtime/channels/{backends → providers}/discord-access.mjs +1 -1
- package/src/runtime/channels/{backends → providers}/discord-gateway.mjs +1 -1
- package/src/runtime/channels/{backends → providers}/discord.mjs +3 -3
- package/src/runtime/channels/{backends → providers}/telegram.mjs +12 -12
- package/src/runtime/channels/tool-defs.mjs +1 -1
- package/src/runtime/memory/index.mjs +76 -248
- package/src/runtime/memory/lib/agent-ipc.mjs +146 -81
- package/src/runtime/memory/lib/compact-vector-cache.mjs +88 -0
- package/src/runtime/memory/lib/core-memory-store.mjs +18 -1
- package/src/runtime/memory/lib/cycle-llm-adapters.mjs +13 -34
- package/src/runtime/memory/lib/embedding-provider.mjs +47 -26
- package/src/runtime/memory/lib/embedding-worker.mjs +30 -34
- package/src/runtime/memory/lib/http-router.mjs +9 -6
- package/src/runtime/memory/lib/ko-morph.mjs +3 -20
- package/src/runtime/memory/lib/memory-action-handlers.mjs +2 -1
- package/src/runtime/memory/lib/memory-config-flags.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle1.mjs +1 -0
- package/src/runtime/memory/lib/memory-cycle2-gate.mjs +4 -2
- package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +1 -0
- package/src/runtime/memory/lib/memory-cycle2-shared.mjs +4 -1
- package/src/runtime/memory/lib/memory-cycle3.mjs +3 -1
- package/src/runtime/memory/lib/memory-daemon-lifecycle.mjs +5 -0
- package/src/runtime/memory/lib/memory-log.mjs +1 -1
- package/src/runtime/memory/lib/memory-process-lock.mjs +5 -60
- package/src/runtime/memory/lib/memory.mjs +1 -1
- package/src/runtime/memory/lib/pg/process.mjs +32 -9
- package/src/runtime/memory/lib/session-ingest.mjs +1 -1
- package/src/runtime/memory/tool-defs.mjs +1 -5
- package/src/runtime/search/index.mjs +2 -2
- package/src/runtime/search/tool-defs.mjs +2 -2
- package/src/runtime/shared/abort-race.mjs +70 -0
- package/src/runtime/shared/agent-route-config.mjs +119 -0
- package/src/runtime/shared/atomic-file.mjs +80 -4
- package/src/runtime/shared/channel-notification-routing.mjs +2 -2
- package/src/runtime/shared/child-guardian.mjs +204 -108
- package/src/runtime/shared/child-spawn-gate.mjs +139 -72
- package/src/runtime/shared/config.mjs +120 -47
- package/src/runtime/shared/llm/index.mjs +1 -1
- package/src/runtime/shared/owner-fair-gate.mjs +134 -0
- package/src/runtime/shared/resource-admission.mjs +150 -100
- package/src/runtime/shared/stream-progress.mjs +6 -0
- package/src/runtime/shared/tool-execution-owner.mjs +12 -0
- package/src/runtime/shared/tool-result-summary.mjs +1 -1
- package/src/runtime/shared/tool-surface.mjs +91 -27
- package/src/runtime/shared/tool-workload-gates.mjs +29 -0
- package/src/runtime/shared/turn-snapshot.mjs +47 -6
- package/src/runtime/shared/turn-worktree-snapshot.mjs +14 -2
- package/src/session-runtime/channel-config-api.mjs +5 -5
- package/src/session-runtime/config-helpers.mjs +39 -37
- package/src/session-runtime/config-lifecycle.mjs +27 -27
- package/src/session-runtime/lifecycle-api.mjs +22 -3
- package/src/session-runtime/memory-runtime-prewarm.mjs +15 -0
- package/src/session-runtime/model-route-api.mjs +7 -5
- package/src/session-runtime/prewarm.mjs +1 -1
- package/src/session-runtime/provider-auth-api.mjs +0 -7
- package/src/session-runtime/provider-models.mjs +1 -1
- package/src/session-runtime/remote-control.mjs +6 -7
- package/src/session-runtime/runtime-core.mjs +63 -39
- package/src/session-runtime/runtime-tunables.mjs +4 -4
- package/src/session-runtime/self-update.mjs +1 -1
- package/src/session-runtime/session-lifecycle.mjs +45 -17
- package/src/session-runtime/session-title.mjs +1 -1
- package/src/session-runtime/session-turn-api.mjs +96 -24
- package/src/session-runtime/settings-api.mjs +12 -24
- package/src/session-runtime/tool-defs.mjs +3 -3
- package/src/session-runtime/workflow-agents-api.mjs +55 -81
- package/src/session-runtime/workflow.mjs +14 -24
- package/src/standalone/agent-dispatch-broker.mjs +198 -0
- package/src/standalone/agent-tool/helpers.mjs +2 -2
- package/src/standalone/agent-tool/spawn-flow.mjs +2 -0
- package/src/standalone/agent-tool/spawn-preset.mjs +11 -21
- package/src/standalone/agent-tool/tool-def.mjs +0 -14
- package/src/standalone/channel-admin.mjs +53 -64
- package/src/standalone/{channel-daemon-client.mjs → channel-client.mjs} +33 -19
- package/src/standalone/{channel-daemon-transport.mjs → channel-transport.mjs} +127 -46
- package/src/standalone/channel-worker.mjs +124 -647
- package/src/standalone/{backend-daemon.mjs → daemon.mjs} +270 -154
- package/src/standalone/explore-tool.mjs +187 -70
- package/src/standalone/fair-call-scheduler.mjs +264 -0
- package/src/standalone/memory-runtime-proxy.mjs +58 -1
- package/src/standalone/session-client.mjs +1134 -0
- package/src/standalone/session-protocol.mjs +192 -0
- package/src/standalone/session-runtime-pool.mjs +393 -0
- package/src/standalone/session-runtime-record.mjs +20 -0
- package/src/standalone/session-runtime-worker.mjs +203 -0
- package/src/standalone/{engine-daemon-service.mjs → session-service.mjs} +481 -224
- package/src/standalone/{engine-daemon-transport.mjs → session-transport.mjs} +390 -121
- package/src/standalone/session-wire.mjs +55 -0
- package/src/tui/App.jsx +34 -21
- package/src/tui/app/app-format.mjs +1 -1
- package/src/tui/app/app-view.jsx +5 -2
- package/src/tui/app/channel-pickers.mjs +41 -41
- package/src/tui/app/core-memory-picker.mjs +19 -19
- package/src/tui/app/doctor.mjs +5 -11
- package/src/tui/app/input-parsers.mjs +2 -2
- package/src/tui/app/message-selector.mjs +103 -0
- package/src/tui/app/onboarding-steps.mjs +3 -4
- package/src/tui/app/project-picker.mjs +80 -56
- package/src/tui/app/prompt-submit.mjs +48 -43
- package/src/tui/app/resume-picker.mjs +2 -2
- package/src/tui/app/route-pickers.mjs +3 -1
- package/src/tui/app/settings-picker.mjs +31 -33
- package/src/tui/app/transcript-window.mjs +38 -0
- package/src/tui/app/use-prompt-draft-flow.mjs +5 -7
- package/src/tui/app/use-prompt-handlers.mjs +86 -21
- package/src/tui/app/use-prompt-hint.mjs +3 -2
- package/src/tui/app/use-prompt-queue-history.mjs +10 -3
- package/src/tui/app/use-transcript-scroll.mjs +10 -3
- package/src/tui/app/use-transcript-window.mjs +50 -17
- package/src/tui/components/PromptInput.jsx +71 -38
- package/src/tui/components/Spinner.jsx +1 -1
- package/src/tui/components/ToolExecution.jsx +1 -1
- package/src/tui/components/prompt-input/edit-helpers.mjs +9 -11
- package/src/tui/components/prompt-input/escape-policy.mjs +42 -0
- package/src/tui/components/prompt-input/immediate-render.mjs +0 -10
- package/src/tui/components/prompt-input/interrupt-policy.mjs +10 -0
- package/src/tui/components/prompt-input/restore-policy.mjs +10 -0
- package/src/tui/components/tool-execution/surface-detail.mjs +1 -1
- package/src/tui/dist/index.mjs +1031 -1676
- package/src/tui/hooks/useSession.mjs +16 -0
- package/src/tui/index.jsx +12 -13
- package/src/tui/{engine → session}/agent-envelope.mjs +3 -3
- package/src/tui/{engine → session}/agent-job-feed.mjs +4 -4
- package/src/tui/{engine → session}/boot-profile.mjs +2 -2
- package/src/tui/{engine → session}/context-state.mjs +3 -3
- package/src/tui/{engine → session}/labels.mjs +2 -2
- package/src/tui/{engine → session}/live-share.mjs +38 -4
- package/src/tui/{engine → session}/notice-text.mjs +2 -2
- package/src/tui/{engine → session}/notification-plan.mjs +3 -3
- package/src/tui/session/oauth-flows.mjs +140 -0
- package/src/tui/{engine → session}/prompt-history.mjs +3 -3
- package/src/tui/{engine → session}/queue-helpers.mjs +2 -2
- package/src/tui/{engine → session}/render-timing.mjs +2 -2
- package/src/tui/{engine → session}/session-api-ext.mjs +30 -20
- package/src/tui/{engine → session}/session-api.mjs +110 -93
- package/src/tui/{engine → session}/session-flow.mjs +8 -2
- package/src/tui/{engine → session}/session-stats.mjs +3 -3
- package/src/tui/{engine → session}/tool-approval.mjs +3 -3
- package/src/tui/{engine → session}/tool-call-fields.mjs +2 -2
- package/src/tui/{engine → session}/tool-card-results.mjs +8 -6
- package/src/tui/{engine → session}/tool-result-status.mjs +5 -5
- package/src/tui/{engine → session}/tool-result-text.mjs +13 -3
- package/src/tui/{engine → session}/transcript-spill.mjs +34 -34
- package/src/tui/{engine → session}/turn.mjs +38 -176
- package/src/tui/{engine-local-session.mjs → session-local.mjs} +103 -103
- package/src/tui/session.mjs +22 -0
- package/src/tui/spinner-meta.mjs +4 -4
- package/src/tui/spinner-verbs.mjs +51 -3
- package/src/ui/statusline-segments.mjs +1 -1
- package/src/ui/statusline.mjs +1 -1
- package/vendor/ink/build/components/App.js +10 -1
- package/src/session-runtime/memory-daemon-probe.mjs +0 -61
- package/src/standalone/engine-daemon-client.mjs +0 -894
- package/src/standalone/engine-daemon-local-bridge.mjs +0 -20
- package/src/standalone/engine-daemon-protocol.mjs +0 -33
- package/src/tui/engine/turn-watchdog.mjs +0 -92
- package/src/tui/engine.mjs +0 -22
- package/src/tui/hooks/useEngine.mjs +0 -16
- /package/src/runtime/agent/orchestrator/session/compact/{engine.mjs → runner.mjs} +0 -0
- /package/src/runtime/channels/{backends → providers}/discord-attachments.mjs +0 -0
- /package/src/tui/{engine → session}/agent-response-tail.mjs +0 -0
- /package/src/tui/{engine → session}/frame-batched-store.mjs +0 -0
- /package/src/tui/{engine → session}/tui-steering-persist.mjs +0 -0
|
@@ -1,26 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* src/tui/
|
|
2
|
+
* src/tui/session/session-api.mjs - part of the public session runtime session object.
|
|
3
3
|
*/
|
|
4
4
|
import { compactEventDetail, projectNameFromPath } from './labels.mjs';
|
|
5
5
|
import { toolErrorDisplay } from './tool-result-text.mjs';
|
|
6
6
|
import { isQueuedEntryEditable, promptDisplayText } from './queue-helpers.mjs';
|
|
7
|
-
import {
|
|
7
|
+
import { createSessionApiB } from './session-api-ext.mjs';
|
|
8
8
|
import { buildDoctorReport } from '../app/doctor.mjs';
|
|
9
9
|
import { recomputePromptHistory } from './prompt-history.mjs';
|
|
10
|
-
import { buildMergedPromptHistory, loadPromptHistory } from '../prompt-history-store.mjs';
|
|
11
|
-
import { touchProjectSelected } from '../../standalone/projects.mjs';
|
|
10
|
+
import { appendPromptHistory, buildMergedPromptHistory, loadPromptHistory, promptHistoryKey } from '../prompt-history-store.mjs';
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
// ask within a tick; this is the belt-and-suspenders window before the bounded
|
|
16
|
-
// recovery timer hard-releases busy so Esc can never wedge input forever.
|
|
17
|
-
const MANUAL_ABORT_RECOVERY_MS = (() => {
|
|
18
|
-
const v = Number(process.env.MIXDOG_MANUAL_ABORT_RECOVERY_MS);
|
|
19
|
-
return Number.isFinite(v) && v > 0 ? v : 4000;
|
|
20
|
-
})();
|
|
21
|
-
|
|
22
|
-
export function createEngineApi(bag) {
|
|
23
|
-
const api = { ...createEngineApiA(bag), ...createEngineApiB(bag) };
|
|
12
|
+
export function createSessionApi(bag) {
|
|
13
|
+
const api = { ...createSessionApiA(bag), ...createSessionApiB(bag) };
|
|
24
14
|
// One-shot settings/status bundle. On a daemon-backed store every getter is
|
|
25
15
|
// its own serialized round-trip and the settings panel needs a dozen of them,
|
|
26
16
|
// so the panel asks for this instead of fanning out. It calls the SAME
|
|
@@ -33,7 +23,7 @@ export function createEngineApi(bag) {
|
|
|
33
23
|
const snapshot = {
|
|
34
24
|
autoClear: await read(api.getAutoClear),
|
|
35
25
|
compaction: await read(api.getCompactionSettings),
|
|
36
|
-
|
|
26
|
+
recap: await read(api.getRecapSettings),
|
|
37
27
|
channels: await read(api.getChannelSettings, { includeStatus: false }),
|
|
38
28
|
systemShell: await read(api.getSystemShell),
|
|
39
29
|
outputStyle: (await read(api.getOutputStyle)) || (await read(api.listOutputStyles)),
|
|
@@ -43,7 +33,7 @@ export function createEngineApi(bag) {
|
|
|
43
33
|
updateSettings: await read(api.getUpdateSettings),
|
|
44
34
|
};
|
|
45
35
|
if (heavy) {
|
|
46
|
-
snapshot.
|
|
36
|
+
snapshot.channelProvider = (await read(api.getChannelSetup))?.provider || 'discord';
|
|
47
37
|
snapshot.mcp = await read(api.mcpStatus);
|
|
48
38
|
snapshot.hooks = await read(api.hooksStatus);
|
|
49
39
|
snapshot.plugins = await read(api.pluginsStatus);
|
|
@@ -54,31 +44,38 @@ export function createEngineApi(bag) {
|
|
|
54
44
|
return api;
|
|
55
45
|
}
|
|
56
46
|
|
|
57
|
-
export function
|
|
47
|
+
export function createSessionApiA(bag) {
|
|
58
48
|
const {
|
|
59
49
|
runtime, nextId, flags, pending, listeners, getState, getPublishedState = getState, set, flushEmitImmediate, pushItem, patchItem, replaceItems, restoreOlderTranscript, restoreNewerTranscript, settleStreamingTail, clearStreamingTail, pushNotice, autoClearState, agentStatusState, routeState, syncContextStats, denyAllToolApprovals, updateAgentJobCard, requeueEntriesFront, enqueue, autoClearBeforeSubmit, restoreQueued, resetStatsAndSyncContext, drain, flushDeferredExecutionPendingResumeKick, discardExecutionPendingResume,
|
|
60
50
|
} = bag;
|
|
61
|
-
const
|
|
51
|
+
const submission = (text, options = {}) => {
|
|
62
52
|
const t = promptDisplayText(text, options).trim();
|
|
63
|
-
if (!t) return
|
|
53
|
+
if (!t) return null;
|
|
64
54
|
const mode = options.mode || 'prompt';
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
55
|
+
// Prompt input queued while a turn is active keeps the default `next`
|
|
56
|
+
// priority, so it is injected at the next tool/model boundary. Explicit
|
|
57
|
+
// options.priority still wins.
|
|
68
58
|
const priority = options.priority;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
59
|
+
return {
|
|
60
|
+
text,
|
|
61
|
+
queueOptions: {
|
|
62
|
+
...options,
|
|
63
|
+
// Always mint a submission id so daemon retries / dual-path intake
|
|
64
|
+
// can dedupe instead of booking the same prompt twice.
|
|
65
|
+
id: String(options.id || '').trim() || nextId(),
|
|
66
|
+
mode,
|
|
67
|
+
displayText: promptDisplayText(text, options),
|
|
68
|
+
priority,
|
|
69
|
+
},
|
|
77
70
|
};
|
|
71
|
+
};
|
|
72
|
+
const submit = (text, options = {}) => {
|
|
73
|
+
const intake = submission(text, options);
|
|
74
|
+
if (!intake) return false;
|
|
78
75
|
// A running clear (idle auto-clear or session_manage) sets commandBusy;
|
|
79
76
|
// queue the prompt instead of dropping it — it drains after the clear.
|
|
80
77
|
if (flags.autoClearRunning) {
|
|
81
|
-
return enqueue(text, queueOptions) !== false;
|
|
78
|
+
return enqueue(intake.text, intake.queueOptions) !== false;
|
|
82
79
|
}
|
|
83
80
|
// Any in-flight session command (clear/setModel/newSession/resume/...)
|
|
84
81
|
// holds commandBusy. Previously the prompt was dropped here and only the
|
|
@@ -86,17 +83,31 @@ export function createEngineApiA(bag) {
|
|
|
86
83
|
// commandBusy, and the central release hook re-kicks drain once the
|
|
87
84
|
// command settles, so the prompt runs afterwards rather than vanishing.
|
|
88
85
|
if (getState().commandBusy) {
|
|
89
|
-
return enqueue(text, queueOptions) !== false;
|
|
86
|
+
return enqueue(intake.text, intake.queueOptions) !== false;
|
|
90
87
|
}
|
|
91
88
|
if (getState().busy) {
|
|
92
|
-
return enqueue(text, queueOptions) !== false;
|
|
89
|
+
return enqueue(intake.text, intake.queueOptions) !== false;
|
|
93
90
|
}
|
|
94
91
|
// If autoClearBeforeSubmit rejects (e.g. compaction timeout throws), the
|
|
95
92
|
// prompt must still be queued — swallow the rejection so enqueue always
|
|
96
93
|
// runs and the submit is never silently lost.
|
|
97
|
-
void autoClearBeforeSubmit().catch(() => {}).then(
|
|
94
|
+
void autoClearBeforeSubmit().catch(() => {}).then(
|
|
95
|
+
() => enqueue(intake.text, intake.queueOptions),
|
|
96
|
+
);
|
|
98
97
|
return true;
|
|
99
98
|
};
|
|
99
|
+
const submitAsync = async (text, options = {}) => {
|
|
100
|
+
const intake = submission(text, options);
|
|
101
|
+
if (!intake) return false;
|
|
102
|
+
// Daemon intake needs an acknowledgement boundary stronger than the TUI's
|
|
103
|
+
// synchronous submit(): by the time this Promise resolves, the prompt is
|
|
104
|
+
// present either as a visible queue entry or as the first durable user row.
|
|
105
|
+
// Provider execution still runs detached through drain().
|
|
106
|
+
if (!flags.autoClearRunning && !getState().commandBusy && !getState().busy) {
|
|
107
|
+
await autoClearBeforeSubmit().catch(() => {});
|
|
108
|
+
}
|
|
109
|
+
return enqueue(intake.text, intake.queueOptions) !== false;
|
|
110
|
+
};
|
|
100
111
|
return {
|
|
101
112
|
getState: () => getPublishedState(),
|
|
102
113
|
patchItem,
|
|
@@ -107,7 +118,7 @@ export function createEngineApiA(bag) {
|
|
|
107
118
|
return () => listeners.delete(listener);
|
|
108
119
|
},
|
|
109
120
|
submit,
|
|
110
|
-
submitAsync
|
|
121
|
+
submitAsync,
|
|
111
122
|
reserveSession: (sessionId) => {
|
|
112
123
|
const id = runtime.reserveSessionId?.(sessionId);
|
|
113
124
|
if (!id) return false;
|
|
@@ -116,6 +127,46 @@ export function createEngineApiA(bag) {
|
|
|
116
127
|
return String(getState().sessionId || '') === String(id);
|
|
117
128
|
},
|
|
118
129
|
restoreQueued,
|
|
130
|
+
// Claude Code's message selector ("jump back to a previous message"):
|
|
131
|
+
// rewind the conversation to just before a user prompt and hand its text
|
|
132
|
+
// back for editing. Idle-only — a live turn must be interrupted first.
|
|
133
|
+
rewindToItem: async (itemId) => {
|
|
134
|
+
const target = String(itemId ?? '').trim();
|
|
135
|
+
if (!target) return null;
|
|
136
|
+
if (getState().busy || getState().commandBusy) return null;
|
|
137
|
+
const items = getState().items || [];
|
|
138
|
+
const index = items.findIndex(
|
|
139
|
+
(item) => item?.kind === 'user' && String(item?.id) === target,
|
|
140
|
+
);
|
|
141
|
+
if (index < 0) return null;
|
|
142
|
+
const text = String(items[index]?.text || '').trim();
|
|
143
|
+
if (!text) return null;
|
|
144
|
+
set({ commandBusy: true });
|
|
145
|
+
try {
|
|
146
|
+
const rewound = await runtime.rewindMessages?.({ text });
|
|
147
|
+
if (!rewound) return null;
|
|
148
|
+
const restoreKey = promptHistoryKey(text);
|
|
149
|
+
set({
|
|
150
|
+
items: replaceItems(items.slice(0, index), {
|
|
151
|
+
preserveSpill: true,
|
|
152
|
+
preserveTranscriptView: true,
|
|
153
|
+
}),
|
|
154
|
+
spinner: null,
|
|
155
|
+
thinking: null,
|
|
156
|
+
lastTurn: null,
|
|
157
|
+
// The prompt returns to the draft, so it must not ALSO sit in the
|
|
158
|
+
// Up-arrow history — otherwise it shows up twice.
|
|
159
|
+
promptHistoryList: (getState().promptHistoryList || [])
|
|
160
|
+
.filter((entry) => promptHistoryKey(entry) !== restoreKey),
|
|
161
|
+
});
|
|
162
|
+
syncContextStats({ allowEstimated: true });
|
|
163
|
+
set({ stats: { ...getState().stats } });
|
|
164
|
+
flushEmitImmediate?.();
|
|
165
|
+
return { text, removed: items.length - index, messages: rewound.removed };
|
|
166
|
+
} finally {
|
|
167
|
+
set({ commandBusy: false });
|
|
168
|
+
}
|
|
169
|
+
},
|
|
119
170
|
setModel: async (m) => {
|
|
120
171
|
if (getState().commandBusy) return false;
|
|
121
172
|
set({ commandBusy: true });
|
|
@@ -209,14 +260,14 @@ export function createEngineApiA(bag) {
|
|
|
209
260
|
set({ commandBusy: false });
|
|
210
261
|
}
|
|
211
262
|
},
|
|
212
|
-
|
|
213
|
-
return runtime.
|
|
263
|
+
getRecapSettings: () => {
|
|
264
|
+
return runtime.getRecapSettings?.() || { enabled: true };
|
|
214
265
|
},
|
|
215
|
-
|
|
266
|
+
setRecapEnabled: async (enabled) => {
|
|
216
267
|
if (getState().commandBusy) return null;
|
|
217
268
|
set({ commandBusy: true });
|
|
218
269
|
try {
|
|
219
|
-
const next = await runtime.
|
|
270
|
+
const next = await runtime.setRecapEnabled?.(enabled);
|
|
220
271
|
set({ ...routeState(), stats: { ...getState().stats } });
|
|
221
272
|
// Deferred for the same reason as setCompactionSettings above: keep
|
|
222
273
|
// the recompute off the key-handler tick so the toggle repaints
|
|
@@ -296,12 +347,6 @@ export function createEngineApiA(bag) {
|
|
|
296
347
|
},
|
|
297
348
|
setCwd: (path, options = {}) => {
|
|
298
349
|
const next = runtime.setCwd(path);
|
|
299
|
-
// "Last opened" recency belongs to the ACTUAL cwd switch, not to one
|
|
300
|
-
// caller: the project picker, its Current Path row and the /cwd prompt
|
|
301
|
-
// all land here, so the project list stays ordered by what was really
|
|
302
|
-
// opened last. Unregistered folders are ignored — this never registers
|
|
303
|
-
// a project on its own (addProject remains the only registration path).
|
|
304
|
-
try { touchProjectSelected(next); } catch { /* best-effort recency */ }
|
|
305
350
|
// Republish up-arrow history for the NEW project: current session prompts
|
|
306
351
|
// merged with the cwd-scoped persisted store for the new cwd.
|
|
307
352
|
const sessionList = recomputePromptHistory(getState().items);
|
|
@@ -311,6 +356,15 @@ export function createEngineApiA(bag) {
|
|
|
311
356
|
}
|
|
312
357
|
return next;
|
|
313
358
|
},
|
|
359
|
+
rememberPromptHistory: (value) => {
|
|
360
|
+
const text = String(value || '').trim();
|
|
361
|
+
if (!text) return false;
|
|
362
|
+
const persisted = appendPromptHistory(getState().cwd, text);
|
|
363
|
+
if (!persisted) return false;
|
|
364
|
+
const sessionList = recomputePromptHistory(getState().items);
|
|
365
|
+
set({ promptHistoryList: buildMergedPromptHistory(sessionList, persisted) });
|
|
366
|
+
return true;
|
|
367
|
+
},
|
|
314
368
|
getSystemShell: () => {
|
|
315
369
|
return runtime.getSystemShell?.() || runtime.systemShell || { source: 'auto', command: '', effective: '' };
|
|
316
370
|
},
|
|
@@ -608,7 +662,7 @@ export function createEngineApiA(bag) {
|
|
|
608
662
|
set({ commandBusy: false, commandStatus: null });
|
|
609
663
|
}
|
|
610
664
|
},
|
|
611
|
-
abort: () => {
|
|
665
|
+
abort: (options = {}) => {
|
|
612
666
|
if (!getState().busy) return false;
|
|
613
667
|
denyAllToolApprovals('interrupted by user');
|
|
614
668
|
const restoreState = flags.activePromptRestore;
|
|
@@ -616,7 +670,9 @@ export function createEngineApiA(bag) {
|
|
|
616
670
|
// interrupting should just cancel the running turn and let the steering
|
|
617
671
|
// prompt run next, NOT resurrect the in-flight prompt back into the draft.
|
|
618
672
|
const hasPendingSteering = pending.some((entry) => isQueuedEntryEditable(entry));
|
|
619
|
-
const canRestore =
|
|
673
|
+
const canRestore = options?.restorePrompt !== false
|
|
674
|
+
&& restoreState?.restorable
|
|
675
|
+
&& !hasPendingSteering;
|
|
620
676
|
const restoreText = canRestore ? restoreState.text : '';
|
|
621
677
|
const restorePastedImages = canRestore && restoreState?.pastedImages ? restoreState.pastedImages : null;
|
|
622
678
|
const restorePastedTexts = canRestore && restoreState?.pastedTexts ? restoreState.pastedTexts : null;
|
|
@@ -644,6 +700,11 @@ export function createEngineApiA(bag) {
|
|
|
644
700
|
restoreState.reclaimed = true;
|
|
645
701
|
const idSet = new Set((restoreState.submittedIds || []).filter((id) => id != null));
|
|
646
702
|
const patch = { spinner: null, thinking: null, lastTurn: null };
|
|
703
|
+
if (restoreText) {
|
|
704
|
+
const restoreKey = promptHistoryKey(restoreText);
|
|
705
|
+
patch.promptHistoryList = (getState().promptHistoryList || [])
|
|
706
|
+
.filter((entry) => promptHistoryKey(entry) !== restoreKey);
|
|
707
|
+
}
|
|
647
708
|
if (idSet.size > 0) {
|
|
648
709
|
const items = getState().items.filter((item) => !idSet.has(item?.id));
|
|
649
710
|
if (items.length !== getState().items.length) {
|
|
@@ -660,11 +721,7 @@ export function createEngineApiA(bag) {
|
|
|
660
721
|
restoreState.requeueEntries = [];
|
|
661
722
|
restoreState.discardExecutionPendingResumeKeys = [];
|
|
662
723
|
}
|
|
663
|
-
//
|
|
664
|
-
// runtime.abort() above normally rejects the in-flight runtime.ask() so
|
|
665
|
-
// the turn's own finally clears busy within a tick. If that unwind is
|
|
666
|
-
// starved the recovery timer below hard-releases busy. Separately from
|
|
667
|
-
// recovery: queued work must never strand behind a cancelled turn
|
|
724
|
+
// Queued work must never strand behind a cancelled turn
|
|
668
725
|
// (abort preserves pending input for the next turn, and the command
|
|
669
726
|
// queue survives cancel and fires when idle). The
|
|
670
727
|
// drain loop that owns a normal turn continues on its own; this bounded
|
|
@@ -679,46 +736,6 @@ export function createEngineApiA(bag) {
|
|
|
679
736
|
} catch { /* best-effort */ }
|
|
680
737
|
}, 150);
|
|
681
738
|
pendingAfterAbortKick.unref?.();
|
|
682
|
-
// If that unwind is
|
|
683
|
-
// starved — e.g. a provider abort that never settles after a post-tool
|
|
684
|
-
// fetch stall — busy would stay true until the far-larger turn watchdog
|
|
685
|
-
// trips, wedging the TUI with dead input. Arm a short grace timer that
|
|
686
|
-
// hard-releases busy exactly like the watchdog force-release, but ONLY
|
|
687
|
-
// when this same turn is still the active owner (epoch unchanged) AND
|
|
688
|
-
// still busy — so a normal cancellation that settles in time is never
|
|
689
|
-
// masked and a newer turn's store is never corrupted.
|
|
690
|
-
const abortEpoch = flags.leadTurnEpoch;
|
|
691
|
-
const recoveryMs = Number(flags.manualAbortRecoveryMs) > 0
|
|
692
|
-
? Number(flags.manualAbortRecoveryMs)
|
|
693
|
-
: MANUAL_ABORT_RECOVERY_MS;
|
|
694
|
-
const recoveryTimer = setTimeout(() => {
|
|
695
|
-
if (flags.disposed) return;
|
|
696
|
-
if (!getState().busy) return; // normal abort settled
|
|
697
|
-
if (flags.leadTurnEpoch !== abortEpoch) return; // a newer turn owns the store
|
|
698
|
-
const streamingTail = getState().streamingTail;
|
|
699
|
-
if (streamingTail?.text?.trim()) {
|
|
700
|
-
settleStreamingTail?.(streamingTail.id, {});
|
|
701
|
-
} else {
|
|
702
|
-
clearStreamingTail?.();
|
|
703
|
-
}
|
|
704
|
-
// Bump the epoch FIRST so the still-stuck turn's eventual finally becomes
|
|
705
|
-
// a no-op for shared getState() writes and cannot corrupt the handoff.
|
|
706
|
-
flags.leadTurnEpoch = (Number(flags.leadTurnEpoch) || 0) + 1;
|
|
707
|
-
set({ busy: false, spinner: null, thinking: null, lastTurn: null });
|
|
708
|
-
flags.activePromptRestore = null;
|
|
709
|
-
// Abandon the drain loop that is still awaiting the stuck turn before
|
|
710
|
-
// releasing the drain lock. Its eventual finally observes the stale
|
|
711
|
-
// epoch and cannot clear a newer drain's ownership or continue work.
|
|
712
|
-
flags.drainEpoch = (Number(flags.drainEpoch) || 0) + 1;
|
|
713
|
-
if (flags.draining) flags.draining = false;
|
|
714
|
-
pushNotice('Interrupt did not settle — input restored.', 'warn', { transcript: true });
|
|
715
|
-
flushEmitImmediate?.();
|
|
716
|
-
if (pending.length > 0 && typeof drain === 'function') void drain();
|
|
717
|
-
// busy→false here bypasses the normal turn-end + drain-finally flushes,
|
|
718
|
-
// so re-arm any deferred completion kick explicitly (idempotent).
|
|
719
|
-
if (typeof flushDeferredExecutionPendingResumeKick === 'function') flushDeferredExecutionPendingResumeKick();
|
|
720
|
-
}, recoveryMs);
|
|
721
|
-
recoveryTimer.unref?.();
|
|
722
739
|
return { aborted, restoreText, pastedImages: restorePastedImages, discardPastedImages, pastedTexts: restorePastedTexts, discardPastedTexts };
|
|
723
740
|
},
|
|
724
741
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* src/tui/
|
|
2
|
+
* src/tui/session/session-flow.mjs - prompt queue drain + session clear/reset. Extracted from session-local.mjs.
|
|
3
3
|
*/
|
|
4
4
|
import { presentErrorText } from '../../runtime/shared/err-text.mjs';
|
|
5
5
|
import { resetAllStreamingMarkdownStablePrefixes } from '../markdown/streaming-markdown.mjs';
|
|
@@ -560,7 +560,13 @@ export function createSessionFlow(bag) {
|
|
|
560
560
|
removeQueuedEntries(queued);
|
|
561
561
|
const queuedText = queued.map((item) => item.text).filter((text) => String(text || '').trim()).join('\n');
|
|
562
562
|
const combinedText = [queuedText, String(currentText || '')].filter((text) => text.trim()).join('\n');
|
|
563
|
-
return {
|
|
563
|
+
return {
|
|
564
|
+
count: queued.length,
|
|
565
|
+
ids: queued.map((item) => String(item.id || '')).filter(Boolean),
|
|
566
|
+
text: combinedText,
|
|
567
|
+
pastedImages: mergePastedImages(queued),
|
|
568
|
+
pastedTexts: mergePastedTexts(queued),
|
|
569
|
+
};
|
|
564
570
|
}
|
|
565
571
|
|
|
566
572
|
const resetStats = () => {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* src/tui/
|
|
2
|
+
* src/tui/session/session-stats.mjs - session-usage accumulator.
|
|
3
3
|
*
|
|
4
|
-
* Inlined (not imported from ui/statusline.mjs) so the
|
|
5
|
-
* dependency on the vendored statusline closure. Extracted from
|
|
4
|
+
* Inlined (not imported from ui/statusline.mjs) so the session runtime has no static
|
|
5
|
+
* dependency on the vendored statusline closure. Extracted from session-local.mjs.
|
|
6
6
|
*/
|
|
7
7
|
export function createSessionStats() {
|
|
8
8
|
return {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* src/tui/
|
|
3
|
-
* from
|
|
2
|
+
* src/tui/session/tool-approval.mjs — tool-approval queue plumbing extracted
|
|
3
|
+
* from the session runtime as a dependency-injection factory.
|
|
4
4
|
*
|
|
5
5
|
* These handlers drive a small FIFO of hook approval requests and reflect the
|
|
6
6
|
* active one into store state (state.toolApproval). They need live session
|
|
7
7
|
* state, so the closure identifiers (state/set/nextId/disposed/timeout) are
|
|
8
8
|
* threaded through the factory argument via getters — never stale snapshots.
|
|
9
|
-
* Every body is the original
|
|
9
|
+
* Every body is the original session-local.mjs logic verbatim.
|
|
10
10
|
*/
|
|
11
11
|
export function createToolApproval({ getState, set, nextId, getDisposed, timeoutMs }) {
|
|
12
12
|
const toolApprovalQueue = [];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* src/tui/
|
|
3
|
-
* tool-result id/name/arg shapes across providers. Extracted from
|
|
2
|
+
* src/tui/session/tool-call-fields.mjs - accessors for the varied tool-call /
|
|
3
|
+
* tool-result id/name/arg shapes across providers. Extracted from session-local.mjs.
|
|
4
4
|
*/
|
|
5
5
|
export function toolCallId(call) {
|
|
6
6
|
return call?.id ?? call?.toolCallId ?? call?.tool_call_id ?? call?.call_id;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* src/tui/
|
|
3
|
-
* (patchToolCardResult + flushToolResults) extracted from
|
|
4
|
-
* (
|
|
2
|
+
* src/tui/session/tool-card-results.mjs — the tool-card result state machine
|
|
3
|
+
* (patchToolCardResult + flushToolResults) extracted from the session runtime
|
|
4
|
+
* (session-local.mjs) as a dependency-injection factory.
|
|
5
5
|
*
|
|
6
6
|
* These handlers own the per-turn accounting that reflects tool results into
|
|
7
7
|
* store items: aggregate cards, non-aggregate/legacy agent-job cards, grouped
|
|
8
8
|
* fallbacks, and the finalize/cancelled sweeps. They mutate live session state,
|
|
9
9
|
* so state/set/patchItem/markToolCallDone/updateAgentJobCard are threaded via
|
|
10
10
|
* the factory argument (getters/callbacks) — never stale snapshots. Every body
|
|
11
|
-
* is the original
|
|
11
|
+
* is the original session-local.mjs logic verbatim.
|
|
12
12
|
*/
|
|
13
13
|
import { summarizeToolResult, aggregateDoneCategories } from '../../runtime/shared/tool-surface.mjs';
|
|
14
|
-
import { toolResultText, toolErrorDisplay, toolGroupedDisplayFallback } from './tool-result-text.mjs';
|
|
14
|
+
import { toolResultText, toolErrorDisplay, toolGroupedDisplayFallback, stripShellExitHeader } from './tool-result-text.mjs';
|
|
15
15
|
import { toolResultCallId } from './tool-call-fields.mjs';
|
|
16
16
|
import { parseAgentJob } from './agent-envelope.mjs';
|
|
17
17
|
import {
|
|
@@ -82,7 +82,9 @@ export function createToolCardResults({
|
|
|
82
82
|
// outcomes remain successful calls with their raw/semantic result detail.
|
|
83
83
|
const { exitCode, isExitError, isCallError } = toolCallOutcome(message, rawText);
|
|
84
84
|
const isError = isCallError;
|
|
85
|
-
const text = isError
|
|
85
|
+
const text = isError
|
|
86
|
+
? toolErrorDisplay(rawText, card?.name || 'tool')
|
|
87
|
+
: (isExitError ? stripShellExitHeader(rawText) : rawText);
|
|
86
88
|
|
|
87
89
|
if (aggregate && card.itemId === aggregate.itemId) {
|
|
88
90
|
if (!callRec) return false;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* src/tui/
|
|
3
|
-
* text helpers extracted from
|
|
2
|
+
* src/tui/session/tool-result-status.mjs — pure tool-result status + aggregate
|
|
3
|
+
* text helpers extracted from the session runtime.
|
|
4
4
|
*
|
|
5
5
|
* These functions were function-declared inside the closure but reference only
|
|
6
6
|
* their arguments plus toolErrorDisplay (imported below) — no session state —
|
|
7
|
-
* so they move out verbatim as free functions.
|
|
7
|
+
* so they move out verbatim as free functions. session-local.mjs imports them and
|
|
8
8
|
* keeps calling them unchanged.
|
|
9
9
|
*/
|
|
10
10
|
import { toolErrorDisplay } from './tool-result-text.mjs';
|
|
@@ -28,7 +28,7 @@ export function shellCommandExitCode(text) {
|
|
|
28
28
|
// `Error: [shell-run-failed] [exit code: N]` as the leading marker header.
|
|
29
29
|
if (!/^\s*(?:Error:\s*)?\[shell-run-failed\]/i.test(body)) return null;
|
|
30
30
|
// Restrict marker parsing to the header region (first line) so only the
|
|
31
|
-
//
|
|
31
|
+
// session runtime-emitted status header — not quoted command output below — counts.
|
|
32
32
|
const header = body.split('\n', 1)[0] || '';
|
|
33
33
|
// Timeout / signal / abort are NOT a plain command exit — keep them "Failed".
|
|
34
34
|
if (/\[timeout:|\[signal:|timed out|aborted|interrupted/i.test(header)) return null;
|
|
@@ -93,7 +93,7 @@ export function withCancelledResultMarker(text, item) {
|
|
|
93
93
|
// Do NOT inspect item.rawResult here: aggregate rawResult is child tool
|
|
94
94
|
// output (`1. grep\n<result>…`) that can incidentally contain a `status:`
|
|
95
95
|
// line, which would false-positive as an already-terminal status and skip
|
|
96
|
-
// the cancelled marker. Only result/text/body are
|
|
96
|
+
// the cancelled marker. Only result/text/body are session runtime-controlled
|
|
97
97
|
// collapsed detail (empty / status word / an existing marker), so they are
|
|
98
98
|
// the trustworthy terminal-status sources.
|
|
99
99
|
const sources = [item?.result, item?.text, body];
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* src/tui/
|
|
2
|
+
* src/tui/session/tool-result-text.mjs - flatten tool-result content shapes into
|
|
3
3
|
* display text, plus collapsed-detail/grouped fallbacks and error framing.
|
|
4
|
-
* Extracted from
|
|
5
|
-
* toolGroupedDisplayFallback remain part of
|
|
4
|
+
* Extracted from session-local.mjs; toolResultText/toolAggregateDetailFallback/
|
|
5
|
+
* toolGroupedDisplayFallback remain part of session-local.mjs's public surface.
|
|
6
6
|
*/
|
|
7
7
|
import { presentErrorText } from '../../runtime/shared/err-text.mjs';
|
|
8
8
|
|
|
@@ -124,3 +124,13 @@ export function toolErrorDisplay(value, surface = 'tool') {
|
|
|
124
124
|
}
|
|
125
125
|
return /^error\s*:/i.test(text) ? text : `Error: ${text}`;
|
|
126
126
|
}
|
|
127
|
+
|
|
128
|
+
// Display-only: a command-exit card already renders `Exit N` as its state, so
|
|
129
|
+
// the machine header (`Error: [shell-run-failed] [exit code: N]`) is redundant
|
|
130
|
+
// in the body — and the bare word "Error" reads as a tool failure even though
|
|
131
|
+
// the tool ran fine and the command merely exited non-zero. The model-facing
|
|
132
|
+
// result keeps the header untouched; only the rendered body drops it.
|
|
133
|
+
export function stripShellExitHeader(text) {
|
|
134
|
+
const body = String(text ?? '');
|
|
135
|
+
return body.replace(/(^|\n)(?:Error:\s*)?\[shell-run-failed\][^\n]*\n{0,2}/i, '$1');
|
|
136
|
+
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
// Transcript spill buffer +
|
|
1
|
+
// Transcript spill buffer + session runtime item state, extracted from session-local.mjs.
|
|
2
2
|
/**
|
|
3
|
-
* src/tui/
|
|
3
|
+
* src/tui/session-local.mjs - the session runtime<->React bridge (React-free).
|
|
4
4
|
*
|
|
5
5
|
* Runs mixdog's session manager outside React and exposes a tiny subscribable
|
|
6
6
|
* store. The React/ink layer consumes it via useSyncExternalStore
|
|
7
|
-
* (see hooks/
|
|
7
|
+
* (see hooks/useSession.mjs).
|
|
8
8
|
*
|
|
9
|
-
* Pure/stateless helpers live in ./
|
|
9
|
+
* Pure/stateless helpers live in ./session/* (boot-profile, session-stats,
|
|
10
10
|
* labels, notice-text, tool-result-text, tool-call-fields, agent-envelope,
|
|
11
11
|
* queue-helpers) and are re-exported here so the public surface is unchanged.
|
|
12
|
-
* This file keeps the stateful
|
|
12
|
+
* This file keeps the stateful session store + notification plan.
|
|
13
13
|
*/
|
|
14
14
|
import { performance } from 'node:perf_hooks';
|
|
15
15
|
import { mkdtempSync, readFileSync, readdirSync, rmSync, statSync, watch, writeFileSync } from 'node:fs';
|
|
@@ -32,8 +32,8 @@ import { presentErrorText } from '../../runtime/shared/err-text.mjs';
|
|
|
32
32
|
import { sessionPath } from '../../runtime/agent/orchestrator/session/store/paths-heartbeat.mjs';
|
|
33
33
|
import { listThemes, getThemeSetting, setThemeSetting } from '../theme.mjs';
|
|
34
34
|
import { resetAllStreamingMarkdownStablePrefixes } from '../markdown/streaming-markdown.mjs';
|
|
35
|
-
import { bootProfile } from '../
|
|
36
|
-
import { createSessionStats, applyUsageDelta } from '../
|
|
35
|
+
import { bootProfile } from '../session/boot-profile.mjs';
|
|
36
|
+
import { createSessionStats, applyUsageDelta } from '../session/session-stats.mjs';
|
|
37
37
|
import {
|
|
38
38
|
pickVerb,
|
|
39
39
|
pickDoneVerb,
|
|
@@ -41,26 +41,26 @@ import {
|
|
|
41
41
|
compactEventLabel,
|
|
42
42
|
compactEventDetail,
|
|
43
43
|
projectNameFromPath,
|
|
44
|
-
} from '../
|
|
45
|
-
import { polishNoticeText } from '../
|
|
44
|
+
} from '../session/labels.mjs';
|
|
45
|
+
import { polishNoticeText } from '../session/notice-text.mjs';
|
|
46
46
|
import {
|
|
47
47
|
toolResultText,
|
|
48
48
|
toolAggregateDetailFallback,
|
|
49
49
|
toolGroupedDisplayFallback,
|
|
50
50
|
toolErrorDisplay,
|
|
51
|
-
} from '../
|
|
51
|
+
} from '../session/tool-result-text.mjs';
|
|
52
52
|
import {
|
|
53
53
|
toolCallId,
|
|
54
54
|
toolResultCallId,
|
|
55
55
|
toolCallName,
|
|
56
56
|
toolCallArgs,
|
|
57
|
-
} from '../
|
|
57
|
+
} from '../session/tool-call-fields.mjs';
|
|
58
58
|
import {
|
|
59
59
|
parseBackgroundTaskEnvelope,
|
|
60
60
|
parseSyntheticAgentMessage,
|
|
61
61
|
toolResultStatus,
|
|
62
62
|
isErrorToolStatus,
|
|
63
|
-
} from '../
|
|
63
|
+
} from '../session/agent-envelope.mjs';
|
|
64
64
|
import {
|
|
65
65
|
queuePriorityValue,
|
|
66
66
|
defaultQueuePriority,
|
|
@@ -74,39 +74,39 @@ import {
|
|
|
74
74
|
mergePastedImages,
|
|
75
75
|
mergePastedTexts,
|
|
76
76
|
callCommitCallbacks,
|
|
77
|
-
} from '../
|
|
77
|
+
} from '../session/queue-helpers.mjs';
|
|
78
78
|
import {
|
|
79
79
|
resolveTuiRuntimeNotificationDelivery,
|
|
80
|
-
} from '../
|
|
81
|
-
import { yieldToRenderer } from '../
|
|
80
|
+
} from '../session/notification-plan.mjs';
|
|
81
|
+
import { yieldToRenderer } from '../session/render-timing.mjs';
|
|
82
82
|
import {
|
|
83
83
|
aggregateRawResult,
|
|
84
84
|
aggregateBucketForCategory,
|
|
85
85
|
aggregateSummaries,
|
|
86
86
|
assignAggregateSummaryOrder,
|
|
87
|
-
} from '../
|
|
88
|
-
import { createToolApproval } from '../
|
|
89
|
-
import { createToolCardResults } from '../
|
|
90
|
-
import { createAgentJobFeed } from '../
|
|
91
|
-
import { appendAgentResponseTail } from '../
|
|
87
|
+
} from '../session/tool-result-status.mjs';
|
|
88
|
+
import { createToolApproval } from '../session/tool-approval.mjs';
|
|
89
|
+
import { createToolCardResults } from '../session/tool-card-results.mjs';
|
|
90
|
+
import { createAgentJobFeed } from '../session/agent-job-feed.mjs';
|
|
91
|
+
import { appendAgentResponseTail } from '../session/agent-response-tail.mjs';
|
|
92
92
|
import {
|
|
93
93
|
appendTuiSteeringPersist,
|
|
94
94
|
dropTuiSteeringPersist,
|
|
95
95
|
drainTuiSteeringPersist,
|
|
96
96
|
flushTuiSteeringPersist,
|
|
97
|
-
} from '../
|
|
98
|
-
import { createContextState } from '../
|
|
99
|
-
import { recomputePromptHistory } from '../
|
|
97
|
+
} from '../session/tui-steering-persist.mjs';
|
|
98
|
+
import { createContextState } from '../session/context-state.mjs';
|
|
99
|
+
import { recomputePromptHistory } from '../session/prompt-history.mjs';
|
|
100
100
|
import {
|
|
101
101
|
appendPromptHistory,
|
|
102
102
|
buildMergedPromptHistory,
|
|
103
103
|
loadPromptHistory,
|
|
104
104
|
} from '../prompt-history-store.mjs';
|
|
105
|
-
import { createSessionFlow } from '../
|
|
106
|
-
import { createRunTurn } from '../
|
|
107
|
-
import {
|
|
108
|
-
import { createFrameBatchedStorePublisher } from '../
|
|
109
|
-
import { createLiveShare, liveSharePipePath } from '../
|
|
105
|
+
import { createSessionFlow } from '../session/session-flow.mjs';
|
|
106
|
+
import { createRunTurn } from '../session/turn.mjs';
|
|
107
|
+
import { createSessionApi } from '../session/session-api.mjs';
|
|
108
|
+
import { createFrameBatchedStorePublisher } from '../session/frame-batched-store.mjs';
|
|
109
|
+
import { createLiveShare, liveSharePipePath } from '../session/live-share.mjs';
|
|
110
110
|
import { displayModelName } from '../../ui/model-display.mjs';
|
|
111
111
|
|
|
112
112
|
export const TUI_DEBUG = /^(1|true|yes|on)$/i.test(String(process.env.MIXDOG_TUI_DEBUG || ''));
|
|
@@ -484,14 +484,14 @@ export function refillTranscriptViewOverlap(viewItems, previousLiveItems, nextLi
|
|
|
484
484
|
}
|
|
485
485
|
|
|
486
486
|
// Re-export the shared tool-result/notification helpers so importers (and tests)
|
|
487
|
-
// keep resolving them from
|
|
487
|
+
// keep resolving them from session-local.mjs unchanged.
|
|
488
488
|
export { toolResultText, toolAggregateDetailFallback, toolGroupedDisplayFallback };
|
|
489
489
|
export { parseBackgroundTaskEnvelope };
|
|
490
|
-
// Re-export the pure notification delivery plan (moved to ./
|
|
491
|
-
// so importers/tests keep resolving resolveTuiRuntimeNotificationDelivery from
|
|
490
|
+
// Re-export the pure notification delivery plan (moved to ./session/notification-plan.mjs)
|
|
491
|
+
// so importers/tests keep resolving resolveTuiRuntimeNotificationDelivery from session-local.mjs.
|
|
492
492
|
export { resolveTuiRuntimeNotificationDelivery };
|
|
493
493
|
|
|
494
|
-
export function
|
|
494
|
+
export function replaceSessionItemsState({
|
|
495
495
|
state,
|
|
496
496
|
items,
|
|
497
497
|
itemIndexById,
|
|
@@ -513,9 +513,9 @@ export function replaceEngineItemsState({
|
|
|
513
513
|
};
|
|
514
514
|
}
|
|
515
515
|
|
|
516
|
-
// Shared by the live
|
|
516
|
+
// Shared by the live session runtime and focused transcript tests so revision/tail
|
|
517
517
|
// regressions exercise the exact mutation implementation used in production.
|
|
518
|
-
export function
|
|
518
|
+
export function createSessionItemMutators({
|
|
519
519
|
getState,
|
|
520
520
|
set,
|
|
521
521
|
itemIndexById,
|