From cdc92d16e4f0c61cf416f67d0b2ae50e93f0380c Mon Sep 17 00:00:00 2001 From: KRATOS <84986124+gnanam1990@users.noreply.github.com> Date: Sat, 4 Apr 2026 17:57:59 +0530 Subject: [PATCH] fix(repl): queue prompt guidance for next turn (#333) Keep normal prompt submissions during generation queued instead of interrupting the current turn. Add a visible next-turn banner in the prompt area so users can tell their follow-up guidance was accepted, and cover the new behavior with focused tests. Fixes #328 Co-authored-by: Claude --- .../PromptInputQueuedCommands.test.tsx | 35 ++++++++ .../PromptInput/PromptInputQueuedCommands.tsx | 24 +++-- src/utils/handlePromptSubmit.test.ts | 89 +++++++++++++++++++ src/utils/handlePromptSubmit.ts | 7 +- 4 files changed, 147 insertions(+), 8 deletions(-) create mode 100644 src/components/PromptInput/PromptInputQueuedCommands.test.tsx create mode 100644 src/utils/handlePromptSubmit.test.ts diff --git a/src/components/PromptInput/PromptInputQueuedCommands.test.tsx b/src/components/PromptInput/PromptInputQueuedCommands.test.tsx new file mode 100644 index 00000000..50cf4403 --- /dev/null +++ b/src/components/PromptInput/PromptInputQueuedCommands.test.tsx @@ -0,0 +1,35 @@ +import React from 'react' +import { afterEach, beforeEach, describe, expect, it, mock } from 'bun:test' +import { renderToString } from '../../utils/staticRender.js' + +describe('PromptInputQueuedCommands', () => { + beforeEach(() => { + mock.module('../../hooks/useCommandQueue.js', () => ({ + useCommandQueue: () => [ + { + value: 'Use another library', + mode: 'prompt', + }, + ], + })) + + mock.module('src/state/AppState.js', () => ({ + useAppState: ( + selector: (state: { viewingAgentTaskId?: string; isBriefOnly: boolean }) => unknown, + ) => selector({ viewingAgentTaskId: undefined, isBriefOnly: false }), + })) + }) + + afterEach(() => { + mock.restore() + }) + + it('shows a next-turn guidance banner for queued prompt messages', async () => { + const { PromptInputQueuedCommands } = await import('./PromptInputQueuedCommands.js') + + const output = await renderToString(, 100) + + expect(output).toContain('1 message queued for next turn') + expect(output).toContain('Use another library') + }) +}) diff --git a/src/components/PromptInput/PromptInputQueuedCommands.tsx b/src/components/PromptInput/PromptInputQueuedCommands.tsx index 16129692..7f251af3 100644 --- a/src/components/PromptInput/PromptInputQueuedCommands.tsx +++ b/src/components/PromptInput/PromptInputQueuedCommands.tsx @@ -1,13 +1,14 @@ import { feature } from 'bun:bundle'; import * as React from 'react'; import { useMemo } from 'react'; -import { Box } from 'src/ink.js'; +import { Box, Text } from 'src/ink.js'; import { useAppState } from 'src/state/AppState.js'; +import type { AppState } from 'src/state/AppState.js'; import { STATUS_TAG, SUMMARY_TAG, TASK_NOTIFICATION_TAG } from '../../constants/xml.js'; import { QueuedMessageProvider } from '../../context/QueuedMessageContext.js'; import { useCommandQueue } from '../../hooks/useCommandQueue.js'; import type { QueuedCommand } from '../../types/textInputTypes.js'; -import { isQueuedCommandVisible } from '../../utils/messageQueueManager.js'; +import { isQueuedCommandEditable, isQueuedCommandVisible } from '../../utils/messageQueueManager.js'; import { createUserMessage, EMPTY_LOOKUPS, normalizeMessages } from '../../utils/messages.js'; import { jsonParse } from '../../utils/slowOperations.js'; import { Message } from '../Message.js'; @@ -70,17 +71,25 @@ function processQueuedCommands(queuedCommands: QueuedCommand[]): QueuedCommand[] } function PromptInputQueuedCommandsImpl(): React.ReactNode { const queuedCommands = useCommandQueue(); - const viewingAgent = useAppState(s => !!s.viewingAgentTaskId); + const viewingAgent = useAppState((s: AppState) => !!s.viewingAgentTaskId); // Brief layout: dim queue items + skip the paddingX (brief messages // already indent themselves). Gate mirrors the brief-spinner/message // check elsewhere — no teammate-view override needed since this // component early-returns when viewing a teammate. const useBriefLayout = feature('KAIROS') || feature('KAIROS_BRIEF') ? // biome-ignore lint/correctness/useHookAtTopLevel: feature() is a compile-time constant - useAppState(s_0 => s_0.isBriefOnly) : false; + useAppState((s_0: AppState) => s_0.isBriefOnly) : false; // createUserMessage mints a fresh UUID per call; without memoization, streaming // re-renders defeat Message's areMessagePropsEqual (compares uuid) → flicker. + const queuedPromptCount = useMemo( + () => + queuedCommands.filter( + cmd => isQueuedCommandEditable(cmd) && cmd.mode === 'prompt', + ).length, + [queuedCommands], + ); + const messages = useMemo(() => { if (queuedCommands.length === 0) return null; // task-notification is shown via useInboxNotification; most isMeta commands @@ -108,10 +117,15 @@ function PromptInputQueuedCommandsImpl(): React.ReactNode { return null; } return + {queuedPromptCount > 0 && + + {queuedPromptCount === 1 ? '1 message queued for next turn' : `${queuedPromptCount} messages queued for next turn`} + + } {messages.map((message, i) => )} ; } export const PromptInputQueuedCommands = React.memo(PromptInputQueuedCommandsImpl); -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJmZWF0dXJlIiwiUmVhY3QiLCJ1c2VNZW1vIiwiQm94IiwidXNlQXBwU3RhdGUiLCJTVEFUVVNfVEFHIiwiU1VNTUFSWV9UQUciLCJUQVNLX05PVElGSUNBVElPTl9UQUciLCJRdWV1ZWRNZXNzYWdlUHJvdmlkZXIiLCJ1c2VDb21tYW5kUXVldWUiLCJRdWV1ZWRDb21tYW5kIiwiaXNRdWV1ZWRDb21tYW5kVmlzaWJsZSIsImNyZWF0ZVVzZXJNZXNzYWdlIiwiRU1QVFlfTE9PS1VQUyIsIm5vcm1hbGl6ZU1lc3NhZ2VzIiwianNvblBhcnNlIiwiTWVzc2FnZSIsIkVNUFRZX1NFVCIsIlNldCIsImlzSWRsZU5vdGlmaWNhdGlvbiIsInZhbHVlIiwicGFyc2VkIiwidHlwZSIsIk1BWF9WSVNJQkxFX05PVElGSUNBVElPTlMiLCJjcmVhdGVPdmVyZmxvd05vdGlmaWNhdGlvbk1lc3NhZ2UiLCJjb3VudCIsInByb2Nlc3NRdWV1ZWRDb21tYW5kcyIsInF1ZXVlZENvbW1hbmRzIiwiZmlsdGVyZWRDb21tYW5kcyIsImZpbHRlciIsImNtZCIsInRhc2tOb3RpZmljYXRpb25zIiwibW9kZSIsIm90aGVyQ29tbWFuZHMiLCJsZW5ndGgiLCJ2aXNpYmxlTm90aWZpY2F0aW9ucyIsInNsaWNlIiwib3ZlcmZsb3dDb3VudCIsIm92ZXJmbG93Q29tbWFuZCIsIlByb21wdElucHV0UXVldWVkQ29tbWFuZHNJbXBsIiwiUmVhY3ROb2RlIiwidmlld2luZ0FnZW50IiwicyIsInZpZXdpbmdBZ2VudFRhc2tJZCIsInVzZUJyaWVmTGF5b3V0IiwiaXNCcmllZk9ubHkiLCJtZXNzYWdlcyIsInZpc2libGVDb21tYW5kcyIsInByb2Nlc3NlZENvbW1hbmRzIiwibWFwIiwiY29udGVudCIsIm1lc3NhZ2UiLCJpIiwiUHJvbXB0SW5wdXRRdWV1ZWRDb21tYW5kcyIsIm1lbW8iXSwic291cmNlcyI6WyJQcm9tcHRJbnB1dFF1ZXVlZENvbW1hbmRzLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBmZWF0dXJlIH0gZnJvbSAnYnVuOmJ1bmRsZSdcbmltcG9ydCAqIGFzIFJlYWN0IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgdXNlTWVtbyB9IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgQm94IH0gZnJvbSAnc3JjL2luay5qcydcbmltcG9ydCB7IHVzZUFwcFN0YXRlIH0gZnJvbSAnc3JjL3N0YXRlL0FwcFN0YXRlLmpzJ1xuaW1wb3J0IHtcbiAgU1RBVFVTX1RBRyxcbiAgU1VNTUFSWV9UQUcsXG4gIFRBU0tfTk9USUZJQ0FUSU9OX1RBRyxcbn0gZnJvbSAnLi4vLi4vY29uc3RhbnRzL3htbC5qcydcbmltcG9ydCB7IFF1ZXVlZE1lc3NhZ2VQcm92aWRlciB9IGZyb20gJy4uLy4uL2NvbnRleHQvUXVldWVkTWVzc2FnZUNvbnRleHQuanMnXG5pbXBvcnQgeyB1c2VDb21tYW5kUXVldWUgfSBmcm9tICcuLi8uLi9ob29rcy91c2VDb21tYW5kUXVldWUuanMnXG5pbXBvcnQgdHlwZSB7IFF1ZXVlZENvbW1hbmQgfSBmcm9tICcuLi8uLi90eXBlcy90ZXh0SW5wdXRUeXBlcy5qcydcbmltcG9ydCB7IGlzUXVldWVkQ29tbWFuZFZpc2libGUgfSBmcm9tICcuLi8uLi91dGlscy9tZXNzYWdlUXVldWVNYW5hZ2VyLmpzJ1xuaW1wb3J0IHtcbiAgY3JlYXRlVXNlck1lc3NhZ2UsXG4gIEVNUFRZX0xPT0tVUFMsXG4gIG5vcm1hbGl6ZU1lc3NhZ2VzLFxufSBmcm9tICcuLi8uLi91dGlscy9tZXNzYWdlcy5qcydcbmltcG9ydCB7IGpzb25QYXJzZSB9IGZyb20gJy4uLy4uL3V0aWxzL3Nsb3dPcGVyYXRpb25zLmpzJ1xuaW1wb3J0IHsgTWVzc2FnZSB9IGZyb20gJy4uL01lc3NhZ2UuanMnXG5cbmNvbnN0IEVNUFRZX1NFVCA9IG5ldyBTZXQ8c3RyaW5nPigpXG5cbi8qKlxuICogQ2hlY2sgaWYgYSBjb21tYW5kIHZhbHVlIGlzIGFuIGlkbGUgbm90aWZpY2F0aW9uIHRoYXQgc2hvdWxkIGJlIGhpZGRlbi5cbiAqIElkbGUgbm90aWZpY2F0aW9ucyBhcmUgcHJvY2Vzc2VkIHNpbGVudGx5IHdpdGhvdXQgc2hvd2luZyB0byB0aGUgdXNlci5cbiAqL1xuZnVuY3Rpb24gaXNJZGxlTm90aWZpY2F0aW9uKHZhbHVlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgdHJ5IHtcbiAgICBjb25zdCBwYXJzZWQgPSBqc29uUGFyc2UodmFsdWUpXG4gICAgcmV0dXJuIHBhcnNlZD8udHlwZSA9PT0gJ2lkbGVfbm90aWZpY2F0aW9uJ1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gZmFsc2VcbiAgfVxufVxuXG4vLyBNYXhpbXVtIG51bWJlciBvZiB0YXNrIG5vdGlmaWNhdGlvbiBsaW5lcyB0byBzaG93XG5jb25zdCBNQVhfVklTSUJMRV9OT1RJRklDQVRJT05TID0gM1xuXG4vKipcbiAqIENyZWF0ZSBhIHN5bnRoZXRpYyBvdmVyZmxvdyBub3RpZmljYXRpb24gbWVzc2FnZSBmb3IgY2FwcGVkIHRhc2sgbm90aWZpY2F0aW9ucy5cbiAqL1xuZnVuY3Rpb24gY3JlYXRlT3ZlcmZsb3dOb3RpZmljYXRpb25NZXNzYWdlKGNvdW50OiBudW1iZXIpOiBzdHJpbmcge1xuICByZXR1cm4gYDwke1RBU0tfTk9USUZJQ0FUSU9OX1RBR30+XG48JHtTVU1NQVJZX1RBR30+KyR7Y291bnR9IG1vcmUgdGFza3MgY29tcGxldGVkPC8ke1NVTU1BUllfVEFHfT5cbjwke1NUQVRVU19UQUd9PmNvbXBsZXRlZDwvJHtTVEFUVVNfVEFHfT5cbjwvJHtUQVNLX05PVElGSUNBVElPTl9UQUd9PmBcbn1cblxuLyoqXG4gKiBQcm9jZXNzIHF1ZXVlZCBjb21tYW5kcyB0byBjYXAgdGFzayBub3RpZmljYXRpb25zIGF0IE1BWF9WSVNJQkxFX05PVElGSUNBVElPTlMgbGluZXMuXG4gKiBPdGhlciBjb21tYW5kIHR5cGVzIGFyZSBhbHdheXMgc2hvd24gaW4gZnVsbC5cbiAqIElkbGUgbm90aWZpY2F0aW9ucyBhcmUgZmlsdGVyZWQgb3V0IGVudGlyZWx5LlxuICovXG5mdW5jdGlvbiBwcm9jZXNzUXVldWVkQ29tbWFuZHMoXG4gIHF1ZXVlZENvbW1hbmRzOiBRdWV1ZWRDb21tYW5kW10sXG4pOiBRdWV1ZWRDb21tYW5kW10ge1xuICAvLyBGaWx0ZXIgb3V0IGlkbGUgbm90aWZpY2F0aW9ucyAtIHRoZXkgYXJlIHByb2Nlc3NlZCBzaWxlbnRseVxuICBjb25zdCBmaWx0ZXJlZENvbW1hbmRzID0gcXVldWVkQ29tbWFuZHMuZmlsdGVyKFxuICAgIGNtZCA9PiB0eXBlb2YgY21kLnZhbHVlICE9PSAnc3RyaW5nJyB8fCAhaXNJZGxlTm90aWZpY2F0aW9uKGNtZC52YWx1ZSksXG4gIClcblxuICAvLyBTZXBhcmF0ZSB0YXNrIG5vdGlmaWNhdGlvbnMgZnJvbSBvdGhlciBjb21tYW5kc1xuICBjb25zdCB0YXNrTm90aWZpY2F0aW9ucyA9IGZpbHRlcmVkQ29tbWFuZHMuZmlsdGVyKFxuICAgIGNtZCA9PiBjbWQubW9kZSA9PT0gJ3Rhc2stbm90aWZpY2F0aW9uJyxcbiAgKVxuICBjb25zdCBvdGhlckNvbW1hbmRzID0gZmlsdGVyZWRDb21tYW5kcy5maWx0ZXIoXG4gICAgY21kID0+IGNtZC5tb2RlICE9PSAndGFzay1ub3RpZmljYXRpb24nLFxuICApXG5cbiAgLy8gSWYgbm90aWZpY2F0aW9ucyBmaXQgd2l0aGluIGxpbWl0LCByZXR1cm4gYWxsIGNvbW1hbmRzIGFzLWlzXG4gIGlmICh0YXNrTm90aWZpY2F0aW9ucy5sZW5ndGggPD0gTUFYX1ZJU0lCTEVfTk9USUZJQ0FUSU9OUykge1xuICAgIHJldHVybiBbLi4ub3RoZXJDb21tYW5kcywgLi4udGFza05vdGlmaWNhdGlvbnNdXG4gIH1cblxuICAvLyBTaG93IGZpcnN0IChNQVhfVklTSUJMRV9OT1RJRklDQVRJT05TIC0gMSkgbm90aWZpY2F0aW9ucywgdGhlbiBhIHN1bW1hcnlcbiAgY29uc3QgdmlzaWJsZU5vdGlmaWNhdGlvbnMgPSB0YXNrTm90aWZpY2F0aW9ucy5zbGljZShcbiAgICAwLFxuICAgIE1BWF9WSVNJQkxFX05PVElGSUNBVElPTlMgLSAxLFxuICApXG4gIGNvbnN0IG92ZXJmbG93Q291bnQgPVxuICAgIHRhc2tOb3RpZmljYXRpb25zLmxlbmd0aCAtIChNQVhfVklTSUJMRV9OT1RJRklDQVRJT05TIC0gMSlcblxuICAvLyBDcmVhdGUgc3ludGhldGljIG92ZXJmbG93IG1lc3NhZ2VcbiAgY29uc3Qgb3ZlcmZsb3dDb21tYW5kOiBRdWV1ZWRDb21tYW5kID0ge1xuICAgIHZhbHVlOiBjcmVhdGVPdmVyZmxvd05vdGlmaWNhdGlvbk1lc3NhZ2Uob3ZlcmZsb3dDb3VudCksXG4gICAgbW9kZTogJ3Rhc2stbm90aWZpY2F0aW9uJyxcbiAgfVxuXG4gIHJldHVybiBbLi4ub3RoZXJDb21tYW5kcywgLi4udmlzaWJsZU5vdGlmaWNhdGlvbnMsIG92ZXJmbG93Q29tbWFuZF1cbn1cblxuZnVuY3Rpb24gUHJvbXB0SW5wdXRRdWV1ZWRDb21tYW5kc0ltcGwoKTogUmVhY3QuUmVhY3ROb2RlIHtcbiAgY29uc3QgcXVldWVkQ29tbWFuZHMgPSB1c2VDb21tYW5kUXVldWUoKVxuICBjb25zdCB2aWV3aW5nQWdlbnQgPSB1c2VBcHBTdGF0ZShzID0+ICEhcy52aWV3aW5nQWdlbnRUYXNrSWQpXG4gIC8vIEJyaWVmIGxheW91dDogZGltIHF1ZXVlIGl0ZW1zICsgc2tpcCB0aGUgcGFkZGluZ1ggKGJyaWVmIG1lc3NhZ2VzXG4gIC8vIGFscmVhZHkgaW5kZW50IHRoZW1zZWx2ZXMpLiBHYXRlIG1pcnJvcnMgdGhlIGJyaWVmLXNwaW5uZXIvbWVzc2FnZVxuICAvLyBjaGVjayBlbHNld2hlcmUg4oCUIG5vIHRlYW1tYXRlLXZpZXcgb3ZlcnJpZGUgbmVlZGVkIHNpbmNlIHRoaXNcbiAgLy8gY29tcG9uZW50IGVhcmx5LXJldHVybnMgd2hlbiB2aWV3aW5nIGEgdGVhbW1hdGUuXG4gIGNvbnN0IHVzZUJyaWVmTGF5b3V0ID1cbiAgICBmZWF0dXJlKCdLQUlST1MnKSB8fCBmZWF0dXJlKCdLQUlST1NfQlJJRUYnKVxuICAgICAgPyAvLyBiaW9tZS1pZ25vcmUgbGludC9jb3JyZWN0bmVzcy91c2VIb29rQXRUb3BMZXZlbDogZmVhdHVyZSgpIGlzIGEgY29tcGlsZS10aW1lIGNvbnN0YW50XG4gICAgICAgIHVzZUFwcFN0YXRlKHMgPT4gcy5pc0JyaWVmT25seSlcbiAgICAgIDogZmFsc2VcblxuICAvLyBjcmVhdGVVc2VyTWVzc2FnZSBtaW50cyBhIGZyZXNoIFVVSUQgcGVyIGNhbGw7IHdpdGhvdXQgbWVtb2l6YXRpb24sIHN0cmVhbWluZ1xuICAvLyByZS1yZW5kZXJzIGRlZmVhdCBNZXNzYWdlJ3MgYXJlTWVzc2FnZVByb3BzRXF1YWwgKGNvbXBhcmVzIHV1aWQpIOKGkiBmbGlja2VyLlxuICBjb25zdCBtZXNzYWdlcyA9IHVzZU1lbW8oKCkgPT4ge1xuICAgIGlmIChxdWV1ZWRDb21tYW5kcy5sZW5ndGggPT09IDApIHJldHVybiBudWxsXG4gICAgLy8gdGFzay1ub3RpZmljYXRpb24gaXMgc2hvd24gdmlhIHVzZUluYm94Tm90aWZpY2F0aW9uOyBtb3N0IGlzTWV0YSBjb21tYW5kc1xuICAgIC8vIChzY2hlZHVsZWQgdGFza3MsIHByb2FjdGl2ZSB0aWNrcykgYXJlIHN5c3RlbS1nZW5lcmF0ZWQgYW5kIGhpZGRlbi5cbiAgICAvLyBDaGFubmVsIG1lc3NhZ2VzIGFyZSB0aGUgZXhjZXB0aW9uIOKAlCBpc01ldGEgYnV0IHNob3duIHNvIHRoZSBrZXlib2FyZFxuICAgIC8vIHVzZXIgc2VlcyB3aGF0IGFycml2ZWQuXG4gICAgY29uc3QgdmlzaWJsZUNvbW1hbmRzID0gcXVldWVkQ29tbWFuZHMuZmlsdGVyKGlzUXVldWVkQ29tbWFuZFZpc2libGUpXG4gICAgaWYgKHZpc2libGVDb21tYW5kcy5sZW5ndGggPT09IDApIHJldHVybiBudWxsXG4gICAgY29uc3QgcHJvY2Vzc2VkQ29tbWFuZHMgPSBwcm9jZXNzUXVldWVkQ29tbWFuZHModmlzaWJsZUNvbW1hbmRzKVxuICAgIHJldHVybiBub3JtYWxpemVNZXNzYWdlcyhcbiAgICAgIHByb2Nlc3NlZENvbW1hbmRzLm1hcChjbWQgPT4ge1xuICAgICAgICBsZXQgY29udGVudCA9IGNtZC52YWx1ZVxuICAgICAgICBpZiAoY21kLm1vZGUgPT09ICdiYXNoJyAmJiB0eXBlb2YgY29udGVudCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICBjb250ZW50ID0gYDxiYXNoLWlucHV0PiR7Y29udGVudH08L2Jhc2gtaW5wdXQ+YFxuICAgICAgICB9XG4gICAgICAgIC8vIFtJbWFnZSAjTl0gcGxhY2Vob2xkZXJzIGFyZSBpbmxpbmUgaW4gdGhlIHRleHQgdmFsdWUgKGluc2VydGVkIGF0XG4gICAgICAgIC8vIHBhc3RlIHRpbWUpLCBzbyB0aGUgcXVldWUgcHJldmlldyBzaG93cyB0aGVtIHdpdGhvdXQgc3R1YiBibG9ja3MuXG4gICAgICAgIHJldHVybiBjcmVhdGVVc2VyTWVzc2FnZSh7IGNvbnRlbnQgfSlcbiAgICAgIH0pLFxuICAgIClcbiAgfSwgW3F1ZXVlZENvbW1hbmRzXSlcblxuICAvLyBEb24ndCBzaG93IGxlYWRlcidzIHF1ZXVlZCBjb21tYW5kcyB3aGVuIHZpZXdpbmcgYW55IGFnZW50J3MgdHJhbnNjcmlwdFxuICBpZiAodmlld2luZ0FnZW50IHx8IG1lc3NhZ2VzID09PSBudWxsKSB7XG4gICAgcmV0dXJuIG51bGxcbiAgfVxuXG4gIHJldHVybiAoXG4gICAgPEJveCBtYXJnaW5Ub3A9ezF9IGZsZXhEaXJlY3Rpb249XCJjb2x1bW5cIj5cbiAgICAgIHttZXNzYWdlcy5tYXAoKG1lc3NhZ2UsIGkpID0+IChcbiAgICAgICAgPFF1ZXVlZE1lc3NhZ2VQcm92aWRlclxuICAgICAgICAgIGtleT17aX1cbiAgICAgICAgICBpc0ZpcnN0PXtpID09PSAwfVxuICAgICAgICAgIHVzZUJyaWVmTGF5b3V0PXt1c2VCcmllZkxheW91dH1cbiAgICAgICAgPlxuICAgICAgICAgIDxNZXNzYWdlXG4gICAgICAgICAgICBtZXNzYWdlPXttZXNzYWdlfVxuICAgICAgICAgICAgbG9va3Vwcz17RU1QVFlfTE9PS1VQU31cbiAgICAgICAgICAgIGFkZE1hcmdpbj17ZmFsc2V9XG4gICAgICAgICAgICB0b29scz17W119XG4gICAgICAgICAgICBjb21tYW5kcz17W119XG4gICAgICAgICAgICB2ZXJib3NlPXtmYWxzZX1cbiAgICAgICAgICAgIGluUHJvZ3Jlc3NUb29sVXNlSURzPXtFTVBUWV9TRVR9XG4gICAgICAgICAgICBwcm9ncmVzc01lc3NhZ2VzRm9yTWVzc2FnZT17W119XG4gICAgICAgICAgICBzaG91bGRBbmltYXRlPXtmYWxzZX1cbiAgICAgICAgICAgIHNob3VsZFNob3dEb3Q9e2ZhbHNlfVxuICAgICAgICAgICAgaXNUcmFuc2NyaXB0TW9kZT17ZmFsc2V9XG4gICAgICAgICAgICBpc1N0YXRpYz17dHJ1ZX1cbiAgICAgICAgICAvPlxuICAgICAgICA8L1F1ZXVlZE1lc3NhZ2VQcm92aWRlcj5cbiAgICAgICkpfVxuICAgIDwvQm94PlxuICApXG59XG5cbmV4cG9ydCBjb25zdCBQcm9tcHRJbnB1dFF1ZXVlZENvbW1hbmRzID0gUmVhY3QubWVtbyhcbiAgUHJvbXB0SW5wdXRRdWV1ZWRDb21tYW5kc0ltcGwsXG4pXG4iXSwibWFwcGluZ3MiOiJBQUFBLFNBQVNBLE9BQU8sUUFBUSxZQUFZO0FBQ3BDLE9BQU8sS0FBS0MsS0FBSyxNQUFNLE9BQU87QUFDOUIsU0FBU0MsT0FBTyxRQUFRLE9BQU87QUFDL0IsU0FBU0MsR0FBRyxRQUFRLFlBQVk7QUFDaEMsU0FBU0MsV0FBVyxRQUFRLHVCQUF1QjtBQUNuRCxTQUNFQyxVQUFVLEVBQ1ZDLFdBQVcsRUFDWEMscUJBQXFCLFFBQ2hCLHdCQUF3QjtBQUMvQixTQUFTQyxxQkFBcUIsUUFBUSx1Q0FBdUM7QUFDN0UsU0FBU0MsZUFBZSxRQUFRLGdDQUFnQztBQUNoRSxjQUFjQyxhQUFhLFFBQVEsK0JBQStCO0FBQ2xFLFNBQVNDLHNCQUFzQixRQUFRLG9DQUFvQztBQUMzRSxTQUNFQyxp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 \ No newline at end of file +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJmZWF0dXJlIiwiUmVhY3QiLCJ1c2VNZW1vIiwiQm94IiwidXNlQXBwU3RhdGUiLCJTVEFUVVNfVEFHIiwiU1VNTUFSWV9UQUciLCJUQVNLX05PVElGSUNBVElPTl9UQUciLCJRdWV1ZWRNZXNzYWdlUHJvdmlkZXIiLCJ1c2VDb21tYW5kUXVldWUiLCJRdWV1ZWRDb21tYW5kIiwiaXNRdWV1ZWRDb21tYW5kVmlzaWJsZSIsImNyZWF0ZVVzZXJNZXNzYWdlIiwiRU1QVFlfTE9PS1VQUyIsIm5vcm1hbGl6ZU1lc3NhZ2VzIiwianNvblBhcnNlIiwiTWVzc2FnZSIsIkVNUFRZX1NFVCIsIlNldCIsImlzSWRsZU5vdGlmaWNhdGlvbiIsInZhbHVlIiwicGFyc2VkIiwidHlwZSIsIk1BWF9WSVNJQkxFX05PVElGSUNBVElPTlMiLCJjcmVhdGVPdmVyZmxvd05vdGlmaWNhdGlvbk1lc3NhZ2UiLCJjb3VudCIsInByb2Nlc3NRdWV1ZWRDb21tYW5kcyIsInF1ZXVlZENvbW1hbmRzIiwiZmlsdGVyZWRDb21tYW5kcyIsImZpbHRlciIsImNtZCIsInRhc2tOb3RpZmljYXRpb25zIiwibW9kZSIsIm90aGVyQ29tbWFuZHMiLCJsZW5ndGgiLCJ2aXNpYmxlTm90aWZpY2F0aW9ucyIsInNsaWNlIiwib3ZlcmZsb3dDb3VudCIsIm92ZXJmbG93Q29tbWFuZCIsIlByb21wdElucHV0UXVldWVkQ29tbWFuZHNJbXBsIiwiUmVhY3ROb2RlIiwidmlld2luZ0FnZW50IiwicyIsInZpZXdpbmdBZ2VudFRhc2tJZCIsInVzZUJyaWVmTGF5b3V0IiwiaXNCcmllZk9ubHkiLCJtZXNzYWdlcyIsInZpc2libGVDb21tYW5kcyIsInByb2Nlc3NlZENvbW1hbmRzIiwibWFwIiwiY29udGVudCIsIm1lc3NhZ2UiLCJpIiwiUHJvbXB0SW5wdXRRdWV1ZWRDb21tYW5kcyIsIm1lbW8iXSwic291cmNlcyI6WyJQcm9tcHRJbnB1dFF1ZXVlZENvbW1hbmRzLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBmZWF0dXJlIH0gZnJvbSAnYnVuOmJ1bmRsZSdcbmltcG9ydCAqIGFzIFJlYWN0IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgdXNlTWVtbyB9IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgQm94IH0gZnJvbSAnc3JjL2luay5qcydcbmltcG9ydCB7IHVzZUFwcFN0YXRlIH0gZnJvbSAnc3JjL3N0YXRlL0FwcFN0YXRlLmpzJ1xuaW1wb3J0IHtcbiAgU1RBVFVTX1RBRyxcbiAgU1VNTUFSWV9UQUcsXG4gIFRBU0tfTk9USUZJQ0FUSU9OX1RBRyxcbn0gZnJvbSAnLi4vLi4vY29uc3RhbnRzL3htbC5qcydcbmltcG9ydCB7IFF1ZXVlZE1lc3NhZ2VQcm92aWRlciB9IGZyb20gJy4uLy4uL2NvbnRleHQvUXVldWVkTWVzc2FnZUNvbnRleHQuanMnXG5pbXBvcnQgeyB1c2VDb21tYW5kUXVldWUgfSBmcm9tICcuLi8uLi9ob29rcy91c2VDb21tYW5kUXVldWUuanMnXG5pbXBvcnQgdHlwZSB7IFF1ZXVlZENvbW1hbmQgfSBmcm9tICcuLi8uLi90eXBlcy90ZXh0SW5wdXRUeXBlcy5qcydcbmltcG9ydCB7IGlzUXVldWVkQ29tbWFuZFZpc2libGUgfSBmcm9tICcuLi8uLi91dGlscy9tZXNzYWdlUXVldWVNYW5hZ2VyLmpzJ1xuaW1wb3J0IHtcbiAgY3JlYXRlVXNlck1lc3NhZ2UsXG4gIEVNUFRZX0xPT0tVUFMsXG4gIG5vcm1hbGl6ZU1lc3NhZ2VzLFxufSBmcm9tICcuLi8uLi91dGlscy9tZXNzYWdlcy5qcydcbmltcG9ydCB7IGpzb25QYXJzZSB9IGZyb20gJy4uLy4uL3V0aWxzL3Nsb3dPcGVyYXRpb25zLmpzJ1xuaW1wb3J0IHsgTWVzc2FnZSB9IGZyb20gJy4uL01lc3NhZ2UuanMnXG5cbmNvbnN0IEVNUFRZX1NFVCA9IG5ldyBTZXQ8c3RyaW5nPigpXG5cbi8qKlxuICogQ2hlY2sgaWYgYSBjb21tYW5kIHZhbHVlIGlzIGFuIGlkbGUgbm90aWZpY2F0aW9uIHRoYXQgc2hvdWxkIGJlIGhpZGRlbi5cbiAqIElkbGUgbm90aWZpY2F0aW9ucyBhcmUgcHJvY2Vzc2VkIHNpbGVudGx5IHdpdGhvdXQgc2hvd2luZyB0byB0aGUgdXNlci5cbiAqL1xuZnVuY3Rpb24gaXNJZGxlTm90aWZpY2F0aW9uKHZhbHVlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgdHJ5IHtcbiAgICBjb25zdCBwYXJzZWQgPSBqc29uUGFyc2UodmFsdWUpXG4gICAgcmV0dXJuIHBhcnNlZD8udHlwZSA9PT0gJ2lkbGVfbm90aWZpY2F0aW9uJ1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gZmFsc2VcbiAgfVxufVxuXG4vLyBNYXhpbXVtIG51bWJlciBvZiB0YXNrIG5vdGlmaWNhdGlvbiBsaW5lcyB0byBzaG93XG5jb25zdCBNQVhfVklTSUJMRV9OT1RJRklDQVRJT05TID0gM1xuXG4vKipcbiAqIENyZWF0ZSBhIHN5bnRoZXRpYyBvdmVyZmxvdyBub3RpZmljYXRpb24gbWVzc2FnZSBmb3IgY2FwcGVkIHRhc2sgbm90aWZpY2F0aW9ucy5cbiAqL1xuZnVuY3Rpb24gY3JlYXRlT3ZlcmZsb3dOb3RpZmljYXRpb25NZXNzYWdlKGNvdW50OiBudW1iZXIpOiBzdHJpbmcge1xuICByZXR1cm4gYDwke1RBU0tfTk9USUZJQ0FUSU9OX1RBR30+XG48JHtTVU1NQVJZX1RBR30+KyR7Y291bnR9IG1vcmUgdGFza3MgY29tcGxldGVkPC8ke1NVTU1BUllfVEFHfT5cbjwke1NUQVRVU19UQUd9PmNvbXBsZXRlZDwvJHtTVEFUVVNfVEFHfT5cbjwvJHtUQVNLX05PVElGSUNBVElPTl9UQUd9PmBcbn1cblxuLyoqXG4gKiBQcm9jZXNzIHF1ZXVlZCBjb21tYW5kcyB0byBjYXAgdGFzayBub3RpZmljYXRpb25zIGF0IE1BWF9WSVNJQkxFX05PVElGSUNBVElPTlMgbGluZXMuXG4gKiBPdGhlciBjb21tYW5kIHR5cGVzIGFyZSBhbHdheXMgc2hvd24gaW4gZnVsbC5cbiAqIElkbGUgbm90aWZpY2F0aW9ucyBhcmUgZmlsdGVyZWQgb3V0IGVudGlyZWx5LlxuICovXG5mdW5jdGlvbiBwcm9jZXNzUXVldWVkQ29tbWFuZHMoXG4gIHF1ZXVlZENvbW1hbmRzOiBRdWV1ZWRDb21tYW5kW10sXG4pOiBRdWV1ZWRDb21tYW5kW10ge1xuICAvLyBGaWx0ZXIgb3V0IGlkbGUgbm90aWZpY2F0aW9ucyAtIHRoZXkgYXJlIHByb2Nlc3NlZCBzaWxlbnRseVxuICBjb25zdCBmaWx0ZXJlZENvbW1hbmRzID0gcXVldWVkQ29tbWFuZHMuZmlsdGVyKFxuICAgIGNtZCA9PiB0eXBlb2YgY21kLnZhbHVlICE9PSAnc3RyaW5nJyB8fCAhaXNJZGxlTm90aWZpY2F0aW9uKGNtZC52YWx1ZSksXG4gIClcblxuICAvLyBTZXBhcmF0ZSB0YXNrIG5vdGlmaWNhdGlvbnMgZnJvbSBvdGhlciBjb21tYW5kc1xuICBjb25zdCB0YXNrTm90aWZpY2F0aW9ucyA9IGZpbHRlcmVkQ29tbWFuZHMuZmlsdGVyKFxuICAgIGNtZCA9PiBjbWQubW9kZSA9PT0gJ3Rhc2stbm90aWZpY2F0aW9uJyxcbiAgKVxuICBjb25zdCBvdGhlckNvbW1hbmRzID0gZmlsdGVyZWRDb21tYW5kcy5maWx0ZXIoXG4gICAgY21kID0+IGNtZC5tb2RlICE9PSAndGFzay1ub3RpZmljYXRpb24nLFxuICApXG5cbiAgLy8gSWYgbm90aWZpY2F0aW9ucyBmaXQgd2l0aGluIGxpbWl0LCByZXR1cm4gYWxsIGNvbW1hbmRzIGFzLWlzXG4gIGlmICh0YXNrTm90aWZpY2F0aW9ucy5sZW5ndGggPD0gTUFYX1ZJU0lCTEVfTk9USUZJQ0FUSU9OUykge1xuICAgIHJldHVybiBbLi4ub3RoZXJDb21tYW5kcywgLi4udGFza05vdGlmaWNhdGlvbnNdXG4gIH1cblxuICAvLyBTaG93IGZpcnN0IChNQVhfVklTSUJMRV9OT1RJRklDQVRJT05TIC0gMSkgbm90aWZpY2F0aW9ucywgdGhlbiBhIHN1bW1hcnlcbiAgY29uc3QgdmlzaWJsZU5vdGlmaWNhdGlvbnMgPSB0YXNrTm90aWZpY2F0aW9ucy5zbGljZShcbiAgICAwLFxuICAgIE1BWF9WSVNJQkxFX05PVElGSUNBVElPTlMgLSAxLFxuICApXG4gIGNvbnN0IG92ZXJmbG93Q291bnQgPVxuICAgIHRhc2tOb3RpZmljYXRpb25zLmxlbmd0aCAtIChNQVhfVklTSUJMRV9OT1RJRklDQVRJT05TIC0gMSlcblxuICAvLyBDcmVhdGUgc3ludGhldGljIG92ZXJmbG93IG1lc3NhZ2VcbiAgY29uc3Qgb3ZlcmZsb3dDb21tYW5kOiBRdWV1ZWRDb21tYW5kID0ge1xuICAgIHZhbHVlOiBjcmVhdGVPdmVyZmxvd05vdGlmaWNhdGlvbk1lc3NhZ2Uob3ZlcmZsb3dDb3VudCksXG4gICAgbW9kZTogJ3Rhc2stbm90aWZpY2F0aW9uJyxcbiAgfVxuXG4gIHJldHVybiBbLi4ub3RoZXJDb21tYW5kcywgLi4udmlzaWJsZU5vdGlmaWNhdGlvbnMsIG92ZXJmbG93Q29tbWFuZF1cbn1cblxuZnVuY3Rpb24gUHJvbXB0SW5wdXRRdWV1ZWRDb21tYW5kc0ltcGwoKTogUmVhY3QuUmVhY3ROb2RlIHtcbiAgY29uc3QgcXVldWVkQ29tbWFuZHMgPSB1c2VDb21tYW5kUXVldWUoKVxuICBjb25zdCB2aWV3aW5nQWdlbnQgPSB1c2VBcHBTdGF0ZShzID0+ICEhcy52aWV3aW5nQWdlbnRUYXNrSWQpXG4gIC8vIEJyaWVmIGxheW91dDogZGltIHF1ZXVlIGl0ZW1zICsgc2tpcCB0aGUgcGFkZGluZ1ggKGJyaWVmIG1lc3NhZ2VzXG4gIC8vIGFscmVhZHkgaW5kZW50IHRoZW1zZWx2ZXMpLiBHYXRlIG1pcnJvcnMgdGhlIGJyaWVmLXNwaW5uZXIvbWVzc2FnZVxuICAvLyBjaGVjayBlbHNld2hlcmUg4oCUIG5vIHRlYW1tYXRlLXZpZXcgb3ZlcnJpZGUgbmVlZGVkIHNpbmNlIHRoaXNcbiAgLy8gY29tcG9uZW50IGVhcmx5LXJldHVybnMgd2hlbiB2aWV3aW5nIGEgdGVhbW1hdGUuXG4gIGNvbnN0IHVzZUJyaWVmTGF5b3V0ID1cbiAgICBmZWF0dXJlKCdLQUlST1MnKSB8fCBmZWF0dXJlKCdLQUlST1NfQlJJRUYnKVxuICAgICAgPyAvLyBiaW9tZS1pZ25vcmUgbGludC9jb3JyZWN0bmVzcy91c2VIb29rQXRUb3BMZXZlbDogZmVhdHVyZSgpIGlzIGEgY29tcGlsZS10aW1lIGNvbnN0YW50XG4gICAgICAgIHVzZUFwcFN0YXRlKHMgPT4gcy5pc0JyaWVmT25seSlcbiAgICAgIDogZmFsc2VcblxuICAvLyBjcmVhdGVVc2VyTWVzc2FnZSBtaW50cyBhIGZyZXNoIFVVSUQgcGVyIGNhbGw7IHdpdGhvdXQgbWVtb2l6YXRpb24sIHN0cmVhbWluZ1xuICAvLyByZS1yZW5kZXJzIGRlZmVhdCBNZXNzYWdlJ3MgYXJlTWVzc2FnZVByb3BzRXF1YWwgKGNvbXBhcmVzIHV1aWQpIOKGkiBmbGlja2VyLlxuICBjb25zdCBtZXNzYWdlcyA9IHVzZU1lbW8oKCkgPT4ge1xuICAgIGlmIChxdWV1ZWRDb21tYW5kcy5sZW5ndGggPT09IDApIHJldHVybiBudWxsXG4gICAgLy8gdGFzay1ub3RpZmljYXRpb24gaXMgc2hvd24gdmlhIHVzZUluYm94Tm90aWZpY2F0aW9uOyBtb3N0IGlzTWV0YSBjb21tYW5kc1xuICAgIC8vIChzY2hlZHVsZWQgdGFza3MsIHByb2FjdGl2ZSB0aWNrcykgYXJlIHN5c3RlbS1nZW5lcmF0ZWQgYW5kIGhpZGRlbi5cbiAgICAvLyBDaGFubmVsIG1lc3NhZ2VzIGFyZSB0aGUgZXhjZXB0aW9uIOKAlCBpc01ldGEgYnV0IHNob3duIHNvIHRoZSBrZXlib2FyZFxuICAgIC8vIHVzZXIgc2VlcyB3aGF0IGFycml2ZWQuXG4gICAgY29uc3QgdmlzaWJsZUNvbW1hbmRzID0gcXVldWVkQ29tbWFuZHMuZmlsdGVyKGlzUXVldWVkQ29tbWFuZFZpc2libGUpXG4gICAgaWYgKHZpc2libGVDb21tYW5kcy5sZW5ndGggPT09IDApIHJldHVybiBudWxsXG4gICAgY29uc3QgcHJvY2Vzc2VkQ29tbWFuZHMgPSBwcm9jZXNzUXVldWVkQ29tbWFuZHModmlzaWJsZUNvbW1hbmRzKVxuICAgIHJldHVybiBub3JtYWxpemVNZXNzYWdlcyhcbiAgICAgIHByb2Nlc3NlZENvbW1hbmRzLm1hcChjbWQgPT4ge1xuICAgICAgICBsZXQgY29udGVudCA9IGNtZC52YWx1ZVxuICAgICAgICBpZiAoY21kLm1vZGUgPT09ICdiYXNoJyAmJiB0eXBlb2YgY29udGVudCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICBjb250ZW50ID0gYDxiYXNoLWlucHV0PiR7Y29udGVudH08L2Jhc2gtaW5wdXQ+YFxuICAgICAgICB9XG4gICAgICAgIC8vIFtJbWFnZSAjTl0gcGxhY2Vob2xkZXJzIGFyZSBpbmxpbmUgaW4gdGhlIHRleHQgdmFsdWUgKGluc2VydGVkIGF0XG4gICAgICAgIC8vIHBhc3RlIHRpbWUpLCBzbyB0aGUgcXVldWUgcHJldmlldyBzaG93cyB0aGVtIHdpdGhvdXQgc3R1YiBibG9ja3MuXG4gICAgICAgIHJldHVybiBjcmVhdGVVc2VyTWVzc2FnZSh7IGNvbnRlbnQgfSlcbiAgICAgIH0pLFxuICAgIClcbiAgfSwgW3F1ZXVlZENvbW1hbmRzXSlcblxuICAvLyBEb24ndCBzaG93IGxlYWRlcidzIHF1ZXVlZCBjb21tYW5kcyB3aGVuIHZpZXdpbmcgYW55IGFnZW50J3MgdHJhbnNjcmlwdFxuICBpZiAodmlld2luZ0FnZW50IHx8IG1lc3NhZ2VzID09PSBudWxsKSB7XG4gICAgcmV0dXJuIG51bGxcbiAgfVxuXG4gIHJldHVybiAoXG4gICAgPEJveCBtYXJnaW5Ub3A9ezF9IGZsZXhEaXJlY3Rpb249XCJjb2x1bW5cIj5cbiAgICAgIHttZXNzYWdlcy5tYXAoKG1lc3NhZ2UsIGkpID0+IChcbiAgICAgICAgPFF1ZXVlZE1lc3NhZ2VQcm92aWRlclxuICAgICAgICAgIGtleT17aX1cbiAgICAgICAgICBpc0ZpcnN0PXtpID09PSAwfVxuICAgICAgICAgIHVzZUJyaWVmTGF5b3V0PXt1c2VCcmllZkxheW91dH1cbiAgICAgICAgPlxuICAgICAgICAgIDxNZXNzYWdlXG4gICAgICAgICAgICBtZXNzYWdlPXttZXNzYWdlfVxuICAgICAgICAgICAgbG9va3Vwcz17RU1QVFlfTE9PS1VQU31cbiAgICAgICAgICAgIGFkZE1hcmdpbj17ZmFsc2V9XG4gICAgICAgICAgICB0b29scz17W119XG4gICAgICAgICAgICBjb21tYW5kcz17W119XG4gICAgICAgICAgICB2ZXJib3NlPXtmYWxzZX1cbiAgICAgICAgICAgIGluUHJvZ3Jlc3NUb29sVXNlSURzPXtFTVBUWV9TRVR9XG4gICAgICAgICAgICBwcm9ncmVzc01lc3NhZ2VzRm9yTWVzc2FnZT17W119XG4gICAgICAgICAgICBzaG91bGRBbmltYXRlPXtmYWxzZX1cbiAgICAgICAgICAgIHNob3VsZFNob3dEb3Q9e2ZhbHNlfVxuICAgICAgICAgICAgaXNUcmFuc2NyaXB0TW9kZT17ZmFsc2V9XG4gICAgICAgICAgICBpc1N0YXRpYz17dHJ1ZX1cbiAgICAgICAgICAvPlxuICAgICAgICA8L1F1ZXVlZE1lc3NhZ2VQcm92aWRlcj5cbiAgICAgICkpfVxuICAgIDwvQm94PlxuICApXG59XG5cbmV4cG9ydCBjb25zdCBQcm9tcHRJbnB1dFF1ZXVlZENvbW1hbmRzID0gUmVhY3QubWVtbyhcbiAgUHJvbXB0SW5wdXRRdWV1ZWRDb21tYW5kc0ltcGwsXG4pXG4iXSwibWFwcGluZ3MiOiJBQUFBLFNBQVNBLE9BQU8sUUFBUSxZQUFZO0FBQ3BDLE9BQU8sS0FBS0MsS0FBSyxNQUFNLE9BQU87QUFDOUIsU0FBU0MsT0FBTyxRQUFRLE9BQU87QUFDL0IsU0FBU0MsR0FBRyxRQUFRLFlBQVk7QUFDaEMsU0FBU0MsV0FBVyxRQUFRLHVCQUF1QjtBQUNuRCxTQUNFQyxVQUFVLEVBQ1ZDLFdBQVcsRUFDWEMscUJBQXFCLFFBQ2hCLHdCQUF3QjtBQUMvQixTQUFTQyxxQkFBcUIsUUFBUSx1Q0FBdUM7QUFDN0UsU0FBU0MsZUFBZSxRQUFRLGdDQUFnQztBQUNoRSxjQUFjQyxhQUFhLFFBQVEsK0JBQStCO0FBQ2xFLFNBQVNDLHNCQUFzQixRQUFRLG9DQUFvQztBQUMzRSxTQUNFQyxp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 diff --git a/src/utils/handlePromptSubmit.test.ts b/src/utils/handlePromptSubmit.test.ts new file mode 100644 index 00000000..c6dbb4f5 --- /dev/null +++ b/src/utils/handlePromptSubmit.test.ts @@ -0,0 +1,89 @@ +import { afterEach, beforeEach, describe, expect, it, mock } from 'bun:test' +import { getCommandQueue, resetCommandQueue } from './messageQueueManager.js' + +describe('handlePromptSubmit', () => { + beforeEach(() => { + resetCommandQueue() + mock.module('src/services/analytics/index.js', () => ({ + logEvent: () => {}, + })) + }) + + afterEach(() => { + resetCommandQueue() + mock.restore() + }) + + it('queues prompt submissions during generation without interrupting the current turn', async () => { + const { handlePromptSubmit } = await import('./handlePromptSubmit.js') + + const abortCalls: unknown[] = [] + const inputChanges: string[] = [] + let cursorOffset = 123 + let bufferCleared = false + let pastedContentsCleared = false + let historyReset = false + + await handlePromptSubmit({ + input: ' use another library ', + mode: 'prompt', + pastedContents: {}, + helpers: { + setCursorOffset: offset => { + cursorOffset = offset + }, + clearBuffer: () => { + bufferCleared = true + }, + resetHistory: () => { + historyReset = true + }, + }, + onInputChange: value => { + inputChanges.push(value) + }, + setPastedContents: updater => { + const nextValue = + typeof updater === 'function' + ? updater({ 1: { id: 1, type: 'text', content: 'x' } }) + : updater + pastedContentsCleared = Object.keys(nextValue).length === 0 + }, + abortController: { + abort: (reason: unknown) => { + abortCalls.push(reason) + }, + } as never, + hasInterruptibleToolInProgress: true, + queryGuard: { + isActive: true, + } as never, + isExternalLoading: false, + commands: [], + messages: [], + mainLoopModel: 'sonnet', + ideSelection: undefined, + querySource: 'repl' as never, + setToolJSX: () => {}, + getToolUseContext: () => ({}) as never, + setUserInputOnProcessing: () => {}, + setAbortController: () => {}, + onQuery: async () => {}, + setAppState: () => ({}) as never, + }) + + expect(abortCalls).toEqual([]) + expect(inputChanges).toEqual(['']) + expect(cursorOffset).toBe(0) + expect(bufferCleared).toBe(true) + expect(pastedContentsCleared).toBe(true) + expect(historyReset).toBe(true) + expect(getCommandQueue()).toMatchObject([ + { + value: 'use another library', + preExpansionValue: 'use another library', + mode: 'prompt', + }, + ]) + }) +}) diff --git a/src/utils/handlePromptSubmit.ts b/src/utils/handlePromptSubmit.ts index 4e514dd0..c11de745 100644 --- a/src/utils/handlePromptSubmit.ts +++ b/src/utils/handlePromptSubmit.ts @@ -316,9 +316,10 @@ export async function handlePromptSubmit( return } - // Interrupt the current turn when all executing tools have - // interruptBehavior 'cancel' (e.g. SleepTool). - if (params.hasInterruptibleToolInProgress) { + // Prompt submissions during generation should guide the next turn without + // interrupting the current one. Keep the explicit interrupt path only for + // non-prompt inputs that opt into that behavior. + if (mode !== 'prompt' && params.hasInterruptibleToolInProgress) { logForDebugging( `[interrupt] Aborting current turn: streamMode=${params.streamMode}`, )