* Starts an *interactive* run: the choice executes immediately with a remote * prompt provider, and any runtime prompt (currently `quickAddApi.suggester`) is * forwarded to the caller over the interactive server instead of an Obsidian * modal. Returns the connection details right away — {port, se
( plugin: QuickAdd, params: CliData, )
| 713 | * delivered over the server (a `done`/`error` poll event), not this response. |
| 714 | */ |
| 715 | async function interactiveHandler( |
| 716 | plugin: QuickAdd, |
| 717 | params: CliData, |
| 718 | ): Promise<string> { |
| 719 | const command = CLI_COMMANDS.interactive; |
| 720 | let choice: IChoice; |
| 721 | try { |
| 722 | choice = resolveChoiceFromParams(plugin, params); |
| 723 | } catch (error) { |
| 724 | return serialize({ |
| 725 | ok: false, |
| 726 | command, |
| 727 | error: error instanceof Error ? error.message : String(error), |
| 728 | }); |
| 729 | } |
| 730 | |
| 731 | if (choice.type === "Multi") { |
| 732 | return serialize({ |
| 733 | ok: false, |
| 734 | command, |
| 735 | error: "Multi choices cannot be run interactively via CLI.", |
| 736 | choice: describeChoice(choice), |
| 737 | }); |
| 738 | } |
| 739 | |
| 740 | try { |
| 741 | const port = await interactivePromptServer.ensureStarted(); |
| 742 | const { id: sessionId, token } = interactivePromptServer.createSession(); |
| 743 | |
| 744 | const choiceExecutor = new ChoiceExecutor( |
| 745 | plugin.app, |
| 746 | plugin, |
| 747 | ) as IChoiceExecutor; |
| 748 | setExecutorVariables( |
| 749 | choiceExecutor, |
| 750 | extractVariables(params, RESERVED_INTERACTIVE_PARAMS), |
| 751 | ); |
| 752 | choiceExecutor.interactive = true; |
| 753 | choiceExecutor.promptProvider = new RemotePromptProvider(sessionId); |
| 754 | |
| 755 | // Fire-and-forget: the run proceeds while the caller attaches and answers |
| 756 | // prompts. Its result/error is delivered to the caller via the server, so |
| 757 | // this handler must not await it. |
| 758 | void (async () => { |
| 759 | try { |
| 760 | // Template/Capture engines can swallow a runtime failure on the void |
| 761 | // execute() path, so use the verified-outcome path (mirrors run-choice) |
| 762 | // to avoid reporting a failed file create as success. |
| 763 | if ( |
| 764 | (choice.type === "Template" || choice.type === "Capture") && |
| 765 | typeof choiceExecutor.executeWithOutcome === "function" |
| 766 | ) { |
| 767 | const outcome = await choiceExecutor.executeWithOutcome( |
| 768 | choice as ITemplateChoice | ICaptureChoice, |
| 769 | ); |
| 770 | if (outcome.status === "success") { |
| 771 | interactivePromptServer.finish(sessionId, { |
| 772 | kind: "done", |
no test coverage detected