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
|
@@ -53,6 +53,7 @@ import {
|
|
|
53
53
|
cancelPromptImmediateFlush,
|
|
54
54
|
schedulePromptImmediateFlush,
|
|
55
55
|
} from './prompt-input/immediate-render.mjs';
|
|
56
|
+
import { classifyPromptEscape } from './prompt-input/escape-policy.mjs';
|
|
56
57
|
|
|
57
58
|
// Windows Terminal IME composition can clip a glyph that starts exactly at the
|
|
58
59
|
// left edge of the editable text node. The rounded prompt box already adds a
|
|
@@ -86,6 +87,7 @@ export function PromptInput({
|
|
|
86
87
|
interruptActive = false,
|
|
87
88
|
onInterrupt,
|
|
88
89
|
commandPaletteActive = false,
|
|
90
|
+
commandPaletteOpen = commandPaletteActive,
|
|
89
91
|
mask = false,
|
|
90
92
|
hint = '',
|
|
91
93
|
hintTone = 'info',
|
|
@@ -98,6 +100,8 @@ export function PromptInput({
|
|
|
98
100
|
onCommandPaletteCancel,
|
|
99
101
|
onCommandPaletteComplete,
|
|
100
102
|
onRestoreQueued,
|
|
103
|
+
hasQueuedMessages = false,
|
|
104
|
+
hasMessages = false,
|
|
101
105
|
onHistoryNavigate,
|
|
102
106
|
onPasteText,
|
|
103
107
|
selectionRef,
|
|
@@ -112,7 +116,6 @@ export function PromptInput({
|
|
|
112
116
|
});
|
|
113
117
|
const [, bumpCursorAnchorEpoch] = useState(0);
|
|
114
118
|
const draftRef = useRef(draft);
|
|
115
|
-
const interruptActiveRef = useRef(interruptActive);
|
|
116
119
|
const lastReportedValueRef = useRef(draft.value);
|
|
117
120
|
// Bumped on every submit/draftOverride replace/unmount so an async paste
|
|
118
121
|
// (clipboard read or onPasteText promise) that resolves after the draft
|
|
@@ -122,6 +125,7 @@ export function PromptInput({
|
|
|
122
125
|
// One physical Enter must not enqueue twice when the terminal delivers the
|
|
123
126
|
// chord as multiple input events before the draft clears (Windows CR/LF).
|
|
124
127
|
const submitGateRef = useRef(false);
|
|
128
|
+
const escapeClearAtRef = useRef(0);
|
|
125
129
|
if (valueRef) valueRef.current = draftRef.current.value;
|
|
126
130
|
const { isRawModeSupported } = useStdin();
|
|
127
131
|
// The text box's ink DOM node. We mark it as the cursor anchor (forked ink
|
|
@@ -141,7 +145,6 @@ export function PromptInput({
|
|
|
141
145
|
const undoRef = useRef({ past: [], future: [], lastPushAt: 0, lastValue: null });
|
|
142
146
|
const { value, cursor } = draft;
|
|
143
147
|
draftRef.current = draft;
|
|
144
|
-
interruptActiveRef.current = interruptActive;
|
|
145
148
|
if (selectionRef) {
|
|
146
149
|
const range = selectionRange(draft);
|
|
147
150
|
selectionRef.current = range
|
|
@@ -174,14 +177,12 @@ export function PromptInput({
|
|
|
174
177
|
}
|
|
175
178
|
};
|
|
176
179
|
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
// Idle input keeps the leading+trailing immediate flush for crisp caret echo.
|
|
180
|
+
// Keep prompt echo on the same leading+trailing immediate cadence while a
|
|
181
|
+
// turn is active. Claude Code keeps mid-turn typing responsive; suppressing
|
|
182
|
+
// this path made the draft visibly trail the keyboard under streaming load.
|
|
181
183
|
const scheduleImmediateFlush = () => {
|
|
182
184
|
schedulePromptImmediateFlush({
|
|
183
185
|
throttle: flushThrottleRef.current,
|
|
184
|
-
isSuppressed: () => interruptActiveRef.current,
|
|
185
186
|
flush: flushImmediate,
|
|
186
187
|
});
|
|
187
188
|
};
|
|
@@ -191,6 +192,7 @@ export function PromptInput({
|
|
|
191
192
|
}, []);
|
|
192
193
|
|
|
193
194
|
const commitDraft = (next, options = {}) => {
|
|
195
|
+
escapeClearAtRef.current = 0;
|
|
194
196
|
const sameDraft = draftStateEqual(draftRef.current, next);
|
|
195
197
|
if (!options.keepPreferredColumn) preferredColumnRef.current = null;
|
|
196
198
|
if (sameDraft) {
|
|
@@ -449,8 +451,12 @@ export function PromptInput({
|
|
|
449
451
|
return true;
|
|
450
452
|
};
|
|
451
453
|
|
|
452
|
-
const restoreQueuedToDraft = () => {
|
|
453
|
-
return onRestoreQueued?.(
|
|
454
|
+
const restoreQueuedToDraft = ({ showHint = false } = {}) => {
|
|
455
|
+
return onRestoreQueued?.({
|
|
456
|
+
restoreDraft: true,
|
|
457
|
+
showHint,
|
|
458
|
+
currentText: draftRef.current.value,
|
|
459
|
+
}) === true;
|
|
454
460
|
};
|
|
455
461
|
|
|
456
462
|
const applyHistoryNavigation = (direction, meta = {}) => {
|
|
@@ -552,6 +558,7 @@ export function PromptInput({
|
|
|
552
558
|
|
|
553
559
|
const rawInput = String(input ?? '');
|
|
554
560
|
const inputKey = rawInput.toLowerCase();
|
|
561
|
+
if (!key.escape) escapeClearAtRef.current = 0;
|
|
555
562
|
const rawShiftArrowForGrid =
|
|
556
563
|
rawInput === '\x1b[1;2A' || rawInput === '\x1b[a' || rawInput === '[1;2A'
|
|
557
564
|
|| rawInput === '\x1b[1;2B' || rawInput === '\x1b[b' || rawInput === '[1;2B'
|
|
@@ -628,8 +635,8 @@ export function PromptInput({
|
|
|
628
635
|
const lineBreakIndex = rawInput.search(/[\r\n]/);
|
|
629
636
|
const rawEnter = rawInput === '\r' || rawInput === '\n' || rawInput === '\r\n';
|
|
630
637
|
const trailingEnterPrefix = singleTrailingLineBreakPrefix(rawInput);
|
|
631
|
-
const
|
|
632
|
-
const modifiedLineBreak = key.shift || key.meta || key.ctrl ||
|
|
638
|
+
const rawModifiedEnter = isModifiedEnterSequence(rawInput);
|
|
639
|
+
const modifiedLineBreak = key.shift || key.meta || key.ctrl || rawModifiedEnter;
|
|
633
640
|
|
|
634
641
|
// Ctrl+J is the protocol-INDEPENDENT newline that works on every terminal.
|
|
635
642
|
// • Legacy / modifyOtherKeys terminals: Ctrl+J is a lone '\n' (0x0A). A real
|
|
@@ -646,12 +653,9 @@ export function PromptInput({
|
|
|
646
653
|
return;
|
|
647
654
|
}
|
|
648
655
|
|
|
649
|
-
//
|
|
650
|
-
//
|
|
651
|
-
|
|
652
|
-
// never type into the prompt under modifyOtherKeys. Plain Enter (mod=1) is
|
|
653
|
-
// not matched and still submits below.
|
|
654
|
-
if (!rawCtrlEnter && isAnyModifiedEnterSequence(rawInput)) {
|
|
656
|
+
// Consume uncommon modified-Enter combinations outside the normal
|
|
657
|
+
// Shift/Alt/Ctrl newline set so raw CSI bytes never enter the prompt.
|
|
658
|
+
if (!rawModifiedEnter && isAnyModifiedEnterSequence(rawInput)) {
|
|
655
659
|
return;
|
|
656
660
|
}
|
|
657
661
|
|
|
@@ -676,7 +680,7 @@ export function PromptInput({
|
|
|
676
680
|
return;
|
|
677
681
|
}
|
|
678
682
|
|
|
679
|
-
if (
|
|
683
|
+
if (rawModifiedEnter) {
|
|
680
684
|
updateDraft((d) => replaceSelection(d, '\n'));
|
|
681
685
|
return;
|
|
682
686
|
}
|
|
@@ -745,12 +749,10 @@ export function PromptInput({
|
|
|
745
749
|
if (!moveDraftVertically(-1, { extend: true })) {
|
|
746
750
|
updateDraft((d) => moveCursor(d, 0, { extend: true }));
|
|
747
751
|
}
|
|
748
|
-
} else {
|
|
749
|
-
const
|
|
750
|
-
if (!
|
|
751
|
-
|
|
752
|
-
} else if (!moveDraftVertically(-1, { extend: false })) {
|
|
753
|
-
applyHistoryNavigation('up', { emptyDraft: false });
|
|
752
|
+
} else if (!moveDraftVertically(-1, { extend: false })) {
|
|
753
|
+
const emptyDraft = String(draftRef.current.value || '').length === 0;
|
|
754
|
+
if (!hasQueuedMessages || !restoreQueuedToDraft()) {
|
|
755
|
+
applyHistoryNavigation('up', { emptyDraft });
|
|
754
756
|
}
|
|
755
757
|
}
|
|
756
758
|
}
|
|
@@ -768,7 +770,7 @@ export function PromptInput({
|
|
|
768
770
|
updateDraft((d) => moveCursor(d, d.value.length, { extend: true }));
|
|
769
771
|
}
|
|
770
772
|
} else if (!moveDraftVertically(1, { extend: false })) {
|
|
771
|
-
applyHistoryNavigation('down', { emptyDraft: String(draftRef.current.value || '').
|
|
773
|
+
applyHistoryNavigation('down', { emptyDraft: String(draftRef.current.value || '').length === 0 });
|
|
772
774
|
}
|
|
773
775
|
}
|
|
774
776
|
return;
|
|
@@ -806,9 +808,8 @@ export function PromptInput({
|
|
|
806
808
|
}
|
|
807
809
|
|
|
808
810
|
if (key.escape) {
|
|
809
|
-
if (
|
|
811
|
+
if (commandPaletteOpen) {
|
|
810
812
|
onCommandPaletteCancel?.(draftRef.current.value);
|
|
811
|
-
commitDraft({ value: '', cursor: 0, selectionAnchor: null });
|
|
812
813
|
return;
|
|
813
814
|
}
|
|
814
815
|
if (selectionRange(draftRef.current)) {
|
|
@@ -819,23 +820,55 @@ export function PromptInput({
|
|
|
819
820
|
if (onEscape?.(currentValue, { phase: 'before' }) === true) {
|
|
820
821
|
return;
|
|
821
822
|
}
|
|
822
|
-
|
|
823
|
+
let escape = classifyPromptEscape({
|
|
824
|
+
interruptActive,
|
|
825
|
+
hasQueuedMessages,
|
|
826
|
+
hasMessages,
|
|
827
|
+
value: currentValue,
|
|
828
|
+
lastClearPressAt: escapeClearAtRef.current,
|
|
829
|
+
});
|
|
830
|
+
if (escape.action === 'restore-queue') {
|
|
831
|
+
if (restoreQueuedToDraft()) {
|
|
832
|
+
escapeClearAtRef.current = 0;
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
// A stale projected queue can empty between render and key handling.
|
|
836
|
+
// Fall through to the normal draft/idle action in that case.
|
|
837
|
+
escape = classifyPromptEscape({
|
|
838
|
+
interruptActive,
|
|
839
|
+
hasMessages,
|
|
840
|
+
value: currentValue,
|
|
841
|
+
lastClearPressAt: escapeClearAtRef.current,
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
escapeClearAtRef.current = escape.nextClearPressAt;
|
|
845
|
+
// Active work always wins, even if the user has already typed a steering
|
|
846
|
+
// draft. The draft is preserved; the old submitted prompt is restored only
|
|
847
|
+
// when this box is still empty after cancellation.
|
|
848
|
+
if (escape.action === 'interrupt') {
|
|
849
|
+
const restoredText = onInterrupt?.(currentValue);
|
|
850
|
+
if (!currentValue && typeof restoredText === 'string') {
|
|
851
|
+
commitDraft({ value: restoredText, cursor: restoredText.length, selectionAnchor: null });
|
|
852
|
+
}
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
if (escape.action === 'arm-clear') {
|
|
856
|
+
onEscape?.(currentValue, { phase: 'clear-arm' });
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
if (escape.action === 'clear') {
|
|
823
860
|
onEscape?.(currentValue, { phase: 'clear' });
|
|
824
861
|
commitDraft({ value: '', cursor: 0, selectionAnchor: null });
|
|
825
862
|
return;
|
|
826
863
|
}
|
|
827
|
-
//
|
|
828
|
-
//
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
if (interruptActive) {
|
|
832
|
-
const restoredText = onInterrupt?.('');
|
|
833
|
-
if (typeof restoredText === 'string') {
|
|
834
|
-
commitDraft({ value: restoredText, cursor: restoredText.length, selectionAnchor: null });
|
|
835
|
-
}
|
|
864
|
+
// Empty draft + conversation history: first press arms, the second
|
|
865
|
+
// opens the message selector (Claude Code's jump-back list).
|
|
866
|
+
if (escape.action === 'arm-select') {
|
|
867
|
+
onEscape?.('', { phase: 'select-arm' });
|
|
836
868
|
return;
|
|
837
869
|
}
|
|
838
|
-
if (
|
|
870
|
+
if (escape.action === 'message-selector') {
|
|
871
|
+
onEscape?.('', { phase: 'select' });
|
|
839
872
|
return;
|
|
840
873
|
}
|
|
841
874
|
onEscape?.('', { phase: 'empty' });
|
|
@@ -22,7 +22,7 @@ import { Box, Text } from 'ink';
|
|
|
22
22
|
import { useSharedTick } from '../hooks/useSharedTick.mjs';
|
|
23
23
|
import { theme } from '../theme.mjs';
|
|
24
24
|
import { SPINNER_FRAMES, SPINNER_MODE_OVERRIDE_VERBS, spinnerVerbFor } from '../spinner-verbs.mjs';
|
|
25
|
-
import {
|
|
25
|
+
import { buildSpinnerMeta, isReducedMotion } from '../spinner-meta.mjs';
|
|
26
26
|
import { DOWN_ARROW, UP_ARROW } from '../figures.mjs';
|
|
27
27
|
import { formatDuration } from '../time-format.mjs';
|
|
28
28
|
|
|
@@ -96,7 +96,7 @@ export function ToolExecution({ name, args, result, rawResult, isError, errorCou
|
|
|
96
96
|
const elapsedMs = startedAtMs ? Math.max(0, (pending ? nowMs : (completedAtMs || nowMs)) - startedAtMs) : 0;
|
|
97
97
|
const elapsed = elapsedMs >= 1000 ? formatElapsed(elapsedMs) : '';
|
|
98
98
|
const failedCount = clampFailureCount(errorCount, groupCount, isError);
|
|
99
|
-
// Real tool-call failures only (
|
|
99
|
+
// Real tool-call failures only (provider isError / error toolKind). Drives the
|
|
100
100
|
// ● dot color; command/result failures (shell exit, failed status) are counted
|
|
101
101
|
// in `failedCount`/L2 detail but never in `callFailedCount`, so they never
|
|
102
102
|
// paint the dot red. Fall back to 0 (never `isError`) when the engine did not
|
|
@@ -41,26 +41,24 @@ export function draftStateEqual(a, b) {
|
|
|
41
41
|
// Recognize a MODIFIED Enter delivered via the kitty keyboard protocol
|
|
42
42
|
// (\x1b[13;<mod>u) or modifyOtherKeys (\x1b[27;<mod>;13~). The xterm modifier
|
|
43
43
|
// param is (1 + bitmask) where the bitmask bits are shift=1, alt=2, ctrl=4. We
|
|
44
|
-
// treat
|
|
45
|
-
//
|
|
46
|
-
// separately as the protocol-independent fallback.
|
|
47
|
-
const
|
|
44
|
+
// treat Shift+Enter, Alt/Meta+Enter, and Ctrl+Enter as newline chords. Claude
|
|
45
|
+
// Code maps Shift/Meta+Enter to newline; Ctrl+Enter remains a compatible Mixdog
|
|
46
|
+
// extension. Ctrl+J is handled separately as the protocol-independent fallback.
|
|
47
|
+
const MODIFIED_ENTER_NEWLINE = 1 | 2 | 4;
|
|
48
48
|
|
|
49
49
|
export function isModifiedEnterSequence(input) {
|
|
50
50
|
const text = String(input ?? '');
|
|
51
51
|
const body = text.startsWith('\x1b[') ? text.slice(2) : text.startsWith('[') ? text.slice(1) : '';
|
|
52
52
|
if (!body) return false;
|
|
53
53
|
const kitty = /^13;(\d+)(?::\d+)?(?:;[\d:]+)?u$/.exec(body);
|
|
54
|
-
if (kitty) return ((Number(kitty[1]) - 1) &
|
|
54
|
+
if (kitty) return ((Number(kitty[1]) - 1) & MODIFIED_ENTER_NEWLINE) !== 0;
|
|
55
55
|
const modifyOtherKeys = /^27;(\d+);13~$/.exec(body);
|
|
56
|
-
return Boolean(modifyOtherKeys && (((Number(modifyOtherKeys[1]) - 1) &
|
|
56
|
+
return Boolean(modifyOtherKeys && (((Number(modifyOtherKeys[1]) - 1) & MODIFIED_ENTER_NEWLINE) !== 0));
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
// Recognize ANY modified Enter
|
|
60
|
-
// /
|
|
61
|
-
//
|
|
62
|
-
// under modifyOtherKeys. Plain Enter (mod param = 1, bitmask 0) is intentionally
|
|
63
|
-
// NOT matched, so it still submits.
|
|
59
|
+
// Recognize ANY modified Enter. Used to consume uncommon modifier combinations
|
|
60
|
+
// outside the Shift/Alt/Ctrl newline set so raw CSI bytes never reach the draft.
|
|
61
|
+
// Plain Enter (mod param = 1, bitmask 0) intentionally remains a submit.
|
|
64
62
|
export function isAnyModifiedEnterSequence(input) {
|
|
65
63
|
const text = String(input ?? '');
|
|
66
64
|
const body = text.startsWith('\x1b[') ? text.slice(2) : text.startsWith('[') ? text.slice(1) : '';
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export const PROMPT_ESCAPE_CLEAR_WINDOW_MS = 800;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Claude Code-compatible chat Escape priority after overlays/selections have
|
|
5
|
+
* already had a chance to consume the key:
|
|
6
|
+
* active turn -> interrupt, idle queue -> restore for editing,
|
|
7
|
+
* idle non-empty draft -> double-press clear, idle empty draft with history ->
|
|
8
|
+
* double-press message selector, otherwise fallback.
|
|
9
|
+
*/
|
|
10
|
+
export function classifyPromptEscape({
|
|
11
|
+
interruptActive = false,
|
|
12
|
+
hasQueuedMessages = false,
|
|
13
|
+
hasMessages = false,
|
|
14
|
+
value = '',
|
|
15
|
+
lastClearPressAt = 0,
|
|
16
|
+
now = Date.now(),
|
|
17
|
+
} = {}) {
|
|
18
|
+
if (interruptActive) return { action: 'interrupt', nextClearPressAt: 0 };
|
|
19
|
+
if (hasQueuedMessages) return { action: 'restore-queue', nextClearPressAt: 0 };
|
|
20
|
+
|
|
21
|
+
const current = Number(now);
|
|
22
|
+
const previous = Number(lastClearPressAt);
|
|
23
|
+
const repeated = Number.isFinite(current)
|
|
24
|
+
&& Number.isFinite(previous)
|
|
25
|
+
&& previous > 0
|
|
26
|
+
&& current >= previous
|
|
27
|
+
&& current - previous <= PROMPT_ESCAPE_CLEAR_WINDOW_MS;
|
|
28
|
+
const armed = Number.isFinite(current) && current > 0 ? current : 1;
|
|
29
|
+
|
|
30
|
+
// Empty draft: Claude Code's double-press opens the message selector so a
|
|
31
|
+
// previous prompt can be pulled back into the box (nothing to clear here).
|
|
32
|
+
if (String(value ?? '') === '') {
|
|
33
|
+
if (!hasMessages) return { action: 'idle', nextClearPressAt: 0 };
|
|
34
|
+
return repeated
|
|
35
|
+
? { action: 'message-selector', nextClearPressAt: 0 }
|
|
36
|
+
: { action: 'arm-select', nextClearPressAt: armed };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return repeated
|
|
40
|
+
? { action: 'clear', nextClearPressAt: 0 }
|
|
41
|
+
: { action: 'arm-clear', nextClearPressAt: armed };
|
|
42
|
+
}
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
function suppressed(value) {
|
|
2
|
-
return typeof value === 'function' ? value() === true : value === true;
|
|
3
|
-
}
|
|
4
|
-
|
|
5
1
|
export function cancelPromptImmediateFlush(throttle, clearTimer = clearTimeout) {
|
|
6
2
|
if (!throttle || throttle.timer === null) return false;
|
|
7
3
|
clearTimer(throttle.timer);
|
|
@@ -11,7 +7,6 @@ export function cancelPromptImmediateFlush(throttle, clearTimer = clearTimeout)
|
|
|
11
7
|
|
|
12
8
|
export function schedulePromptImmediateFlush({
|
|
13
9
|
throttle,
|
|
14
|
-
isSuppressed = false,
|
|
15
10
|
flush,
|
|
16
11
|
intervalMs = 16,
|
|
17
12
|
now = Date.now,
|
|
@@ -22,10 +17,6 @@ export function schedulePromptImmediateFlush({
|
|
|
22
17
|
if (!throttle || typeof flush !== 'function') {
|
|
23
18
|
throw new TypeError('schedulePromptImmediateFlush requires throttle state and a flush function');
|
|
24
19
|
}
|
|
25
|
-
if (suppressed(isSuppressed)) {
|
|
26
|
-
cancelPromptImmediateFlush(throttle, clearTimer);
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
29
20
|
|
|
30
21
|
const current = now();
|
|
31
22
|
const elapsed = current - throttle.lastAt;
|
|
@@ -39,7 +30,6 @@ export function schedulePromptImmediateFlush({
|
|
|
39
30
|
|
|
40
31
|
throttle.timer = setTimer(() => {
|
|
41
32
|
throttle.timer = null;
|
|
42
|
-
if (suppressed(isSuppressed)) return;
|
|
43
33
|
throttle.lastAt = now();
|
|
44
34
|
flush();
|
|
45
35
|
}, intervalMs - elapsed);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code restores the submitted prompt only when Esc cancelled before a
|
|
3
|
+
* meaningful response and the user has not typed a replacement meanwhile.
|
|
4
|
+
* The engine owns the response-progress guard; the prompt owns the draft guard.
|
|
5
|
+
*/
|
|
6
|
+
export function promptInterruptRestoreText(result, currentText = '') {
|
|
7
|
+
if (!result || result?.aborted === false) return '';
|
|
8
|
+
if (String(currentText ?? '') !== '') return '';
|
|
9
|
+
return String(result?.restoreText || '').trim();
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Queue restore RPCs may settle after the user has continued editing. The
|
|
3
|
+
* session service is asked for queued text only; prepend it to the latest local draft
|
|
4
|
+
* so a delayed response can never replace newer typing.
|
|
5
|
+
*/
|
|
6
|
+
export function mergeQueuedRestoreText(queuedText = '', currentText = '') {
|
|
7
|
+
return [String(queuedText ?? ''), String(currentText ?? '')]
|
|
8
|
+
.filter((text) => text.trim())
|
|
9
|
+
.join('\n');
|
|
10
|
+
}
|
|
@@ -44,7 +44,7 @@ export {
|
|
|
44
44
|
// all failed -> theme.error
|
|
45
45
|
// cancelled -> theme.warning
|
|
46
46
|
// The RED/orange failure color is driven ONLY by real tool-call errors
|
|
47
|
-
// (`callFailedCount` —
|
|
47
|
+
// (`callFailedCount` — provider isError / error toolKind), NOT by command/result
|
|
48
48
|
// failures like a `[status: failed]` result. A shell command-exit
|
|
49
49
|
// (`exitFailedCount`) is its own distinct neutral state: warning color, never
|
|
50
50
|
// red. `terminalStatus` is still consulted so a cancelled card stays warning.
|