From ed30ee62ed48c3ae6e603b3139ab188496f29b35 Mon Sep 17 00:00:00 2001 From: Christian Bager Bach Houmann Date: Sat, 24 Oct 2026 17:20:45 +0200 Subject: [PATCH 1/3] docs(api): document pickChoice, getChoice, executeChoice by id and importPackage --- .../content/docs/docs/Advanced/APIOverview.md | 1 + docs/src/content/docs/docs/QuickAddAPI.md | 54 +++++++++++++++++-- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/docs/src/content/docs/docs/Advanced/APIOverview.md b/docs/src/content/docs/docs/Advanced/APIOverview.md index 5afd6091e..e96e4bda5 100644 --- a/docs/src/content/docs/docs/Advanced/APIOverview.md +++ b/docs/src/content/docs/docs/Advanced/APIOverview.md @@ -30,6 +30,7 @@ needs logic. | --- | --- | --- | | Ask for text, selections, dates, or grouped inputs | User input methods | [QuickAdd API Reference](/docs/QuickAddAPI/#user-input-methods) | | Run another choice from a script | Choice execution | [Choice Execution](/docs/QuickAddAPI/#choice-execution) | +| Let the user pick a choice, or install a ready-made one | Choice execution, packages | [Choice Execution](/docs/QuickAddAPI/#choice-execution), [Packages](/docs/QuickAddAPI/#packages) | | Read selected text or clipboard content | Utility module | [Utility Module](/docs/QuickAddAPI/#utility-module) | | Format dates | Date module | [Date Module](/docs/QuickAddAPI/#date-module) | | Call configured AI providers | AI module | [AI Module](/docs/QuickAddAPI/#ai-module) | diff --git a/docs/src/content/docs/docs/QuickAddAPI.md b/docs/src/content/docs/docs/QuickAddAPI.md index 71068fbba..0d975ee6d 100644 --- a/docs/src/content/docs/docs/QuickAddAPI.md +++ b/docs/src/content/docs/docs/QuickAddAPI.md @@ -13,7 +13,8 @@ call an AI model, or read values already in your vault. | Module | What it does | | --- | --- | | [User input](#user-input-methods) | Ask for text, pick from a list, confirm, or collect several answers at once | -| [Choice execution](#choice-execution) | Run another choice, or apply a template to the current note | +| [Choice execution](#choice-execution) | Pick, look up, or run a choice, or apply a template to the current note | +| [Packages](#packages) | Install a ready-made package that your plugin ships | | [Formatting](#formatting) | Run format syntax such as `{{DATE}}` or `{{VALUE:name}}` on a string | | [Utility](#utility-module) | Read and set the clipboard, read the editor's selection | | [Date](#date-module) | Format today, tomorrow, yesterday, or any day offset | @@ -425,15 +426,15 @@ const due = await quickAddApi.datePrompt("Due date", { dateFormat: "YYYY-MM-DD" ## Choice Execution -### `executeChoice(choiceName: string, variables?: {[key: string]: any}, options?: { date?: string | Date }): Promise` +### `executeChoice(choice: string | { id: string }, variables?: {[key: string]: any}, options?: { date?: string | Date }): Promise` Executes another QuickAdd choice programmatically. This is a one-way trigger: it passes variables into the target choice, waits for that choice to finish, and resolves with `undefined`. It does not return data from the target choice to the caller. After the target choice finishes, QuickAdd clears the temporary variable map used by that API execution. If you call it from inside a Macro script, do not expect the caller's current `params.variables` values to still be available afterward unless you saved or restored them yourself. For the Macro data-flow implications, see [`executeChoice` is a trigger](/docs/VariablesDataFlow/#executechoice-is-a-trigger). -**Cancellation:** If the target choice is cancelled or aborted, for example because you pressed Escape at one of its prompts, the promise rejects with `MacroAbortError`, and an uncaught rejection stops your script. If the choice name doesn't match a choice, QuickAdd reports an error and the promise resolves. +**Cancellation:** If the target choice is cancelled or aborted, for example because you pressed Escape at one of its prompts, the promise rejects with `MacroAbortError`, and an uncaught rejection stops your script. If no choice has that name or id, QuickAdd reports an error and the promise resolves. **Parameters:** -- `choiceName`: Name of the choice to execute +- `choice`: The choice's name, or `{ id }` with the choice's id. A name runs the first choice with that name, in the order the settings list shows them. An id still works after the user renames the choice, so store the id if your code runs the same choice later. `pickChoice` and `getChoice` return it. - `variables`: (Optional) Variables to pass to the choice - `options.date`: (Optional) The day `{{DATE}}` should use. Pass a `Date`, `last week`, or `"ask"` if you want the picker. @@ -449,6 +450,9 @@ await quickAddApi.executeChoice("Create Meeting Note", { }); await quickAddApi.executeChoice("Weekly review", {}, { date: "lw" }); + +// Run a choice by the id you stored +await quickAddApi.executeChoice({ id: choiceId }, { value: "Main agenda content" }); ``` Batch processing example: @@ -467,6 +471,35 @@ for (const contact of contacts) { } ``` +### `getChoice(choice: string | { id: string }): { id: string; name: string; type: "Template" | "Capture" | "Macro" | "Multi"; path: string[] } | null` +Looks up a choice without running it. Pass the choice's name or `{ id }`. A name returns the first choice with that name, in the order the settings list shows them. `path` lists the folder names from the top level down, with the choice's own name last. If no choice matches, `getChoice` returns `null` and shows no notice. + +**Example:** +```javascript +const choice = quickAddApi.getChoice({ id: choiceId }); +if (choice === null) { + // The user deleted the choice. +} +``` + +### `pickChoice(options?: { placeholder?: string }): Promise<{ id: string; name: string; type: "Template" | "Capture" | "Macro"; path: string[] }>` +Opens the picker that **QuickAdd: Run** opens and resolves with the choice the user picks. The picked choice does not run. Folders open as they do in **QuickAdd: Run**, and only a Template, Capture, or Macro can be picked. Typing searches the choices inside folders too and shows each one's folder, whatever **Search nested choices** is set to. The result has the same shape as `getChoice` returns. + +**Cancellation:** If the user closes the picker, the promise rejects with a cancellation. If there are no choices to pick, QuickAdd shows the same notice as **QuickAdd: Run**, opens nothing, and the promise rejects with a cancellation. + +**Parameters:** +- `options.placeholder`: (Optional) The hint in the empty search field. The default is "Select a choice". + +**Example:** +```javascript +try { + const choice = await quickAddApi.pickChoice({ placeholder: "Choose a capture choice" }); + settings.choiceId = choice.id; +} catch { + // The user closed the picker. +} +``` + ### `applyTemplateToActiveFile(templatePath: string, options?: { mode?: "cursor" | "top" | "bottom" | "replace" }): Promise` Applies a template to the active note without creating a new file. The template runs through the full QuickAdd format pipeline (`{{TITLE}}` and the unnamed `{{VALUE}}`/`{{NAME}}` resolve to the note's basename), and Templater syntax is processed. See [Apply Template to Note](/docs/ApplyTemplateToNote/) for the full behavior, including frontmatter merging. @@ -488,6 +521,19 @@ await quickAddApi.applyTemplateToActiveFile("templates/meeting.md", { }); ``` +## Packages + +### `importPackage(packageJson: string): Promise<{ addedChoiceIds: string[]; skippedChoiceIds: string[]; writtenAssets: string[]; skippedAssets: string[] }>` +Imports a [package](/docs/Choices/Packages/) without the **Import package** review, so your plugin can install a ready-made workflow it ships. `packageJson` is the text of a `.quickadd.json` package. QuickAdd adds only what the vault doesn't have yet. It skips a choice whose id is already in the vault and a file that already exists, and never overwrites them, so a second import of the same package changes nothing. QuickAdd registers the commands of the imported choices right away, and the promise resolves after QuickAdd saves its settings. + +If `packageJson` isn't a valid package, or the package runs code, the promise rejects and nothing changes. A package with scripts can only be imported from QuickAdd's settings, where the user reviews it. + +**Example:** +```javascript +const { addedChoiceIds, skippedChoiceIds } = await quickAddApi.importPackage(packageJson); +const choice = quickAddApi.getChoice({ id: "my-plugin-capture" }); +``` + ## Formatting ### `format(input: string, variables?: {[key: string]: any}, shouldClearVariables?: boolean): Promise` From 827f928dd3bb7abdc821bef942041dbf265971ec Mon Sep 17 00:00:00 2001 From: Christian Bager Bach Houmann Date: Sat, 24 Oct 2026 17:35:05 +0200 Subject: [PATCH 2/3] docs(api): name every package importPackage refuses, and the CLI path --- docs/src/content/docs/docs/QuickAddAPI.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/content/docs/docs/QuickAddAPI.md b/docs/src/content/docs/docs/QuickAddAPI.md index 0d975ee6d..fb33702d8 100644 --- a/docs/src/content/docs/docs/QuickAddAPI.md +++ b/docs/src/content/docs/docs/QuickAddAPI.md @@ -526,7 +526,7 @@ await quickAddApi.applyTemplateToActiveFile("templates/meeting.md", { ### `importPackage(packageJson: string): Promise<{ addedChoiceIds: string[]; skippedChoiceIds: string[]; writtenAssets: string[]; skippedAssets: string[] }>` Imports a [package](/docs/Choices/Packages/) without the **Import package** review, so your plugin can install a ready-made workflow it ships. `packageJson` is the text of a `.quickadd.json` package. QuickAdd adds only what the vault doesn't have yet. It skips a choice whose id is already in the vault and a file that already exists, and never overwrites them, so a second import of the same package changes nothing. QuickAdd registers the commands of the imported choices right away, and the promise resolves after QuickAdd saves its settings. -If `packageJson` isn't a valid package, or the package runs code, the promise rejects and nothing changes. A package with scripts can only be imported from QuickAdd's settings, where the user reviews it. +If `packageJson` isn't a valid package, or the package can run code or runs a choice when Obsidian starts, the promise rejects and nothing changes. This API can't import such a package. The user can review and import it with **Import package…** in QuickAdd's settings, or review it with `quickadd:package-preview` and import it with `quickadd:package-import acknowledge=true`. **Example:** ```javascript From 22af1a00e92503eb002e850b6b50d04ee656b2a2 Mon Sep 17 00:00:00 2001 From: Christian Bager Bach Houmann Date: Sat, 24 Oct 2026 17:40:49 +0200 Subject: [PATCH 3/3] docs(api): include the path argument in the package CLI hint --- docs/src/content/docs/docs/QuickAddAPI.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/content/docs/docs/QuickAddAPI.md b/docs/src/content/docs/docs/QuickAddAPI.md index fb33702d8..5e58a4b9b 100644 --- a/docs/src/content/docs/docs/QuickAddAPI.md +++ b/docs/src/content/docs/docs/QuickAddAPI.md @@ -526,7 +526,7 @@ await quickAddApi.applyTemplateToActiveFile("templates/meeting.md", { ### `importPackage(packageJson: string): Promise<{ addedChoiceIds: string[]; skippedChoiceIds: string[]; writtenAssets: string[]; skippedAssets: string[] }>` Imports a [package](/docs/Choices/Packages/) without the **Import package** review, so your plugin can install a ready-made workflow it ships. `packageJson` is the text of a `.quickadd.json` package. QuickAdd adds only what the vault doesn't have yet. It skips a choice whose id is already in the vault and a file that already exists, and never overwrites them, so a second import of the same package changes nothing. QuickAdd registers the commands of the imported choices right away, and the promise resolves after QuickAdd saves its settings. -If `packageJson` isn't a valid package, or the package can run code or runs a choice when Obsidian starts, the promise rejects and nothing changes. This API can't import such a package. The user can review and import it with **Import package…** in QuickAdd's settings, or review it with `quickadd:package-preview` and import it with `quickadd:package-import acknowledge=true`. +If `packageJson` isn't a valid package, or the package can run code or runs a choice when Obsidian starts, the promise rejects and nothing changes. This API can't import such a package. The user can review and import it with **Import package…** in QuickAdd's settings, or review it with `quickadd:package-preview path=` and import it with `quickadd:package-import path= acknowledge=true`, where `` is the package's path in the vault. **Example:** ```javascript