-
-
Notifications
You must be signed in to change notification settings - Fork 198
feat: add inbox GPS capture example package #1722
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
3755c68
feat: add inbox GPS capture example package
cursoragent 433dc0d
test: put GPS package specs on the default Vitest include path
cursoragent 418c2f4
test: fix GPS package CI on Windows and tsc
cursoragent c417f99
test: type GPS example script entry without Function
cursoragent 29db430
test: match GPS example entry arity for tsc
cursoragent File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| { | ||
| "schemaVersion": 1, | ||
| "quickAddVersion": "2.23.0", | ||
| "createdAt": "2026-08-31T00:00:00.000Z", | ||
| "rootChoiceIds": [ | ||
| "qa-pkg-capture-inbox-gps" | ||
| ], | ||
| "choices": [ | ||
| { | ||
| "choice": { | ||
| "id": "qa-pkg-capture-inbox-gps", | ||
| "name": "Capture to Inbox with GPS", | ||
| "type": "Macro", | ||
| "command": true, | ||
| "runOnStartup": false, | ||
| "macro": { | ||
| "id": "qa-pkg-capture-inbox-gps-macro", | ||
| "name": "Capture to Inbox with GPS", | ||
| "commands": [ | ||
| { | ||
| "id": "qa-pkg-capture-inbox-gps-script", | ||
| "name": "captureInboxGps", | ||
| "type": "UserScript", | ||
| "path": "scripts/captureInboxGps.js", | ||
| "settings": {} | ||
| } | ||
| ] | ||
| } | ||
| }, | ||
| "pathHint": [ | ||
| "Capture to Inbox with GPS" | ||
| ], | ||
| "parentChoiceId": null | ||
| } | ||
| ], | ||
| "assets": [ | ||
| { | ||
| "kind": "user-script", | ||
| "originalPath": "scripts/captureInboxGps.js", | ||
| "contentEncoding": "base64", | ||
| "content": "Y29uc3QgSU5CT1hfUEFUSCA9ICJJbmJveCBwYXRoIjsKY29uc3QgQ1JFQVRFX0lGX01JU1NJTkcgPSAiQ3JlYXRlIEluYm94IGlmIG1pc3NpbmciOwoKbW9kdWxlLmV4cG9ydHMgPSB7CgllbnRyeTogc3RhcnQsCglzZXR0aW5nczogewoJCW5hbWU6ICJDYXB0dXJlIHRvIEluYm94IHdpdGggR1BTIiwKCQlhdXRob3I6ICJRdWlja0FkZCIsCgkJb3B0aW9uczogewoJCQlbSU5CT1hfUEFUSF06IHsKCQkJCXR5cGU6ICJ0ZXh0IiwKCQkJCWRlZmF1bHRWYWx1ZTogIkluYm94Lm1kIiwKCQkJCXBsYWNlaG9sZGVyOiAiSW5ib3gubWQiLAoJCQkJZGVzY3JpcHRpb246ICJWYXVsdCBwYXRoIG9mIHRoZSBub3RlIHRvIGFwcGVuZCB0byIsCgkJCX0sCgkJCVtDUkVBVEVfSUZfTUlTU0lOR106IHsKCQkJCXR5cGU6ICJ0b2dnbGUiLAoJCQkJZGVmYXVsdFZhbHVlOiB0cnVlLAoJCQkJZGVzY3JpcHRpb246ICJDcmVhdGUgdGhlIEluYm94IG5vdGUgd2hlbiBpdCBkb2VzIG5vdCBleGlzdCIsCgkJCX0sCgkJfSwKCX0sCn07Cgphc3luYyBmdW5jdGlvbiBzdGFydChwYXJhbXMsIHNldHRpbmdzKSB7Cgljb25zdCB7IE5vdGljZSwgVEZpbGUsIG5vcm1hbGl6ZVBhdGggfSA9IHBhcmFtcy5vYnNpZGlhbjsKCWNvbnN0IGluYm94UGF0aCA9IG5vcm1hbGl6ZVBhdGgoCgkJU3RyaW5nKHNldHRpbmdzPy5bSU5CT1hfUEFUSF0gfHwgIkluYm94Lm1kIikudHJpbSgpIHx8ICJJbmJveC5tZCIsCgkpOwoJY29uc3QgY3JlYXRlSWZNaXNzaW5nID0gc2V0dGluZ3M/LltDUkVBVEVfSUZfTUlTU0lOR10gIT09IGZhbHNlOwoKCWNvbnN0IGNvb3Jkc1Byb21pc2UgPSByZXNvbHZlQ29vcmRpbmF0ZXMocGFyYW1zLnZhcmlhYmxlcyk7Cgljb25zdCB0ZXh0ID0gYXdhaXQgcmVzb2x2ZU5vdGVUZXh0KHBhcmFtcyk7CglpZiAoIXRleHQpIHJldHVybjsKCgljb25zdCBjb29yZHMgPSBhd2FpdCBjb29yZHNQcm9taXNlOwoJY29uc3Qgc3RhbXAgPSBmb3JtYXRTdGFtcCgpOwoJY29uc3Qgc3VmZml4ID0gY29vcmRzID8gYCAoJHtjb29yZHN9KWAgOiAiIjsKCWNvbnN0IGxpbmUgPSBgLSAke3N0YW1wfSAke3RleHR9JHtzdWZmaXh9XG5gOwoKCWNvbnN0IGV4aXN0aW5nID0gcGFyYW1zLmFwcC52YXVsdC5nZXRBYnN0cmFjdEZpbGVCeVBhdGgoaW5ib3hQYXRoKTsKCWlmIChleGlzdGluZyBpbnN0YW5jZW9mIFRGaWxlKSB7CgkJYXdhaXQgcGFyYW1zLmFwcC52YXVsdC5hcHBlbmQoZXhpc3RpbmcsIGxpbmUpOwoJfSBlbHNlIGlmIChleGlzdGluZykgewoJCW5ldyBOb3RpY2UoYFF1aWNrQWRkOiAke2luYm94UGF0aH0gaXMgYSBmb2xkZXIsIG5vdCBhIG5vdGVgKTsKCQlyZXR1cm47Cgl9IGVsc2UgaWYgKGNyZWF0ZUlmTWlzc2luZykgewoJCWF3YWl0IGVuc3VyZVBhcmVudEZvbGRlcnMocGFyYW1zLmFwcCwgaW5ib3hQYXRoKTsKCQlhd2FpdCBwYXJhbXMuYXBwLnZhdWx0LmNyZWF0ZShpbmJveFBhdGgsIGxpbmUpOwoJfSBlbHNlIHsKCQluZXcgTm90aWNlKGBRdWlja0FkZDogJHtpbmJveFBhdGh9IG5vdCBmb3VuZGApOwoJCXJldHVybjsKCX0KCglpZiAoIWNvb3JkcykgewoJCW5ldyBOb3RpY2UoIlNhdmVkIHdpdGhvdXQgR1BTIChubyBmaXgsIHBlcm1pc3Npb24gZGVuaWVkLCBvciBkZXNrdG9wKSIpOwoJfQp9Cgphc3luYyBmdW5jdGlvbiByZXNvbHZlTm90ZVRleHQocGFyYW1zKSB7Cgljb25zdCBwcmVzZXQgPSBwYXJhbXMudmFyaWFibGVzPy52YWx1ZTsKCWlmICh0eXBlb2YgcHJlc2V0ID09PSAic3RyaW5nIikgewoJCXJldHVybiBwcmVzZXQudHJpbSgpOwoJfQoJY29uc3QgdHlwZWQgPSBhd2FpdCBwYXJhbXMucXVpY2tBZGRBcGkuaW5wdXRQcm9tcHQoIkluYm94Iik7CglyZXR1cm4gdHlwZW9mIHR5cGVkID09PSAic3RyaW5nIiA/IHR5cGVkLnRyaW0oKSA6ICIiOwp9CgpmdW5jdGlvbiByZXNvbHZlQ29vcmRpbmF0ZXModmFyaWFibGVzKSB7Cgljb25zdCBwcmVzZXQgPSB2YXJpYWJsZXM/LmNvb3JkaW5hdGVzOwoJaWYgKHR5cGVvZiBwcmVzZXQgPT09ICJzdHJpbmciICYmIHByZXNldC50cmltKCkpIHsKCQlyZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHByZXNldC50cmltKCkpOwoJfQoKCXJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gewoJCWlmICh0eXBlb2YgbmF2aWdhdG9yID09PSAidW5kZWZpbmVkIiB8fCAhbmF2aWdhdG9yLmdlb2xvY2F0aW9uKSB7CgkJCXJlc29sdmUoIiIpOwoJCQlyZXR1cm47CgkJfQoKCQluYXZpZ2F0b3IuZ2VvbG9jYXRpb24uZ2V0Q3VycmVudFBvc2l0aW9uKAoJCQkocG9zKSA9PiB7CgkJCQlyZXNvbHZlKAoJCQkJCWAke3Bvcy5jb29yZHMubGF0aXR1ZGUudG9GaXhlZCg2KX0sICR7cG9zLmNvb3Jkcy5sb25naXR1ZGUudG9GaXhlZCg2KX1gLAoJCQkJKTsKCQkJfSwKCQkJKCkgPT4gcmVzb2x2ZSgiIiksCgkJCXsKCQkJCWVuYWJsZUhpZ2hBY2N1cmFjeTogdHJ1ZSwKCQkJCXRpbWVvdXQ6IDMwMDAwLAoJCQkJbWF4aW11bUFnZTogNjAwMDAsCgkJCX0sCgkJKTsKCX0pOwp9CgpmdW5jdGlvbiBmb3JtYXRTdGFtcCgpIHsKCWlmICh0eXBlb2Ygd2luZG93ICE9PSAidW5kZWZpbmVkIiAmJiB3aW5kb3cubW9tZW50KSB7CgkJcmV0dXJuIHdpbmRvdy5tb21lbnQoKS5mb3JtYXQoIllZWVktTU0tREQgSEg6bW0iKTsKCX0KCXJldHVybiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCkuc2xpY2UoMCwgMTYpLnJlcGxhY2UoIlQiLCAiICIpOwp9Cgphc3luYyBmdW5jdGlvbiBlbnN1cmVQYXJlbnRGb2xkZXJzKGFwcCwgZmlsZVBhdGgpIHsKCWNvbnN0IHBhcnRzID0gZmlsZVBhdGguc3BsaXQoIi8iKS5maWx0ZXIoQm9vbGVhbik7CglwYXJ0cy5wb3AoKTsKCWxldCBmb2xkZXIgPSAiIjsKCWZvciAoY29uc3QgcGFydCBvZiBwYXJ0cykgewoJCWZvbGRlciA9IGZvbGRlciA/IGAke2ZvbGRlcn0vJHtwYXJ0fWAgOiBwYXJ0OwoJCWlmICghYXBwLnZhdWx0LmdldEFic3RyYWN0RmlsZUJ5UGF0aChmb2xkZXIpKSB7CgkJCWF3YWl0IGFwcC52YXVsdC5jcmVhdGVGb2xkZXIoZm9sZGVyKTsKCQl9Cgl9Cn0K" | ||
| } | ||
| ] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| const INBOX_PATH = "Inbox path"; | ||
| const CREATE_IF_MISSING = "Create Inbox if missing"; | ||
|
|
||
| module.exports = { | ||
| entry: start, | ||
| settings: { | ||
| name: "Capture to Inbox with GPS", | ||
| author: "QuickAdd", | ||
| options: { | ||
| [INBOX_PATH]: { | ||
| type: "text", | ||
| defaultValue: "Inbox.md", | ||
| placeholder: "Inbox.md", | ||
| description: "Vault path of the note to append to", | ||
| }, | ||
| [CREATE_IF_MISSING]: { | ||
| type: "toggle", | ||
| defaultValue: true, | ||
| description: "Create the Inbox note when it does not exist", | ||
| }, | ||
| }, | ||
| }, | ||
| }; | ||
|
|
||
| async function start(params, settings) { | ||
| const { Notice, TFile, normalizePath } = params.obsidian; | ||
| const inboxPath = normalizePath( | ||
| String(settings?.[INBOX_PATH] || "Inbox.md").trim() || "Inbox.md", | ||
| ); | ||
| const createIfMissing = settings?.[CREATE_IF_MISSING] !== false; | ||
|
|
||
| const coordsPromise = resolveCoordinates(params.variables); | ||
| const text = await resolveNoteText(params); | ||
| if (!text) return; | ||
|
|
||
| const coords = await coordsPromise; | ||
| const stamp = formatStamp(); | ||
| const suffix = coords ? ` (${coords})` : ""; | ||
| const line = `- ${stamp} ${text}${suffix}\n`; | ||
|
|
||
| const existing = params.app.vault.getAbstractFileByPath(inboxPath); | ||
| if (existing instanceof TFile) { | ||
| await params.app.vault.append(existing, line); | ||
| } else if (existing) { | ||
| new Notice(`QuickAdd: ${inboxPath} is a folder, not a note`); | ||
| return; | ||
| } else if (createIfMissing) { | ||
| await ensureParentFolders(params.app, inboxPath); | ||
| await params.app.vault.create(inboxPath, line); | ||
| } else { | ||
| new Notice(`QuickAdd: ${inboxPath} not found`); | ||
| return; | ||
| } | ||
|
|
||
| if (!coords) { | ||
| new Notice("Saved without GPS (no fix, permission denied, or desktop)"); | ||
| } | ||
| } | ||
|
|
||
| async function resolveNoteText(params) { | ||
| const preset = params.variables?.value; | ||
| if (typeof preset === "string") { | ||
| return preset.trim(); | ||
| } | ||
| const typed = await params.quickAddApi.inputPrompt("Inbox"); | ||
| return typeof typed === "string" ? typed.trim() : ""; | ||
| } | ||
|
|
||
| function resolveCoordinates(variables) { | ||
| const preset = variables?.coordinates; | ||
| if (typeof preset === "string" && preset.trim()) { | ||
| return Promise.resolve(preset.trim()); | ||
| } | ||
|
|
||
| return new Promise((resolve) => { | ||
| if (typeof navigator === "undefined" || !navigator.geolocation) { | ||
| resolve(""); | ||
| return; | ||
| } | ||
|
|
||
| navigator.geolocation.getCurrentPosition( | ||
| (pos) => { | ||
| resolve( | ||
| `${pos.coords.latitude.toFixed(6)}, ${pos.coords.longitude.toFixed(6)}`, | ||
| ); | ||
| }, | ||
| () => resolve(""), | ||
| { | ||
| enableHighAccuracy: true, | ||
| timeout: 30000, | ||
| maximumAge: 60000, | ||
| }, | ||
| ); | ||
| }); | ||
| } | ||
|
|
||
| function formatStamp() { | ||
| if (typeof window !== "undefined" && window.moment) { | ||
| return window.moment().format("YYYY-MM-DD HH:mm"); | ||
| } | ||
| return new Date().toISOString().slice(0, 16).replace("T", " "); | ||
| } | ||
|
|
||
| async function ensureParentFolders(app, filePath) { | ||
| const parts = filePath.split("/").filter(Boolean); | ||
| parts.pop(); | ||
| let folder = ""; | ||
| for (const part of parts) { | ||
| folder = folder ? `${folder}/${part}` : part; | ||
| if (!app.vault.getAbstractFileByPath(folder)) { | ||
| await app.vault.createFolder(folder); | ||
| } | ||
| } | ||
| } | ||
57 changes: 57 additions & 0 deletions
57
docs/src/content/docs/docs/Examples/Macro_CaptureInboxGps.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| --- | ||
| title: "Macro: Capture to Inbox with GPS" | ||
| description: Append a timestamped inbox line with device GPS coordinates, for offline capture on Obsidian mobile 1.11+ | ||
| slug: docs/Examples/Macro_CaptureInboxGps | ||
| --- | ||
|
|
||
| This macro asks for a quick note, looks up your device location at the same | ||
| time, and appends a timestamped line to `Inbox.md`. It is meant for capture on | ||
| the go: voice-to-text in the prompt, GPS in the background, one line waiting | ||
| when you get home. | ||
|
|
||
| GPS works on **Obsidian mobile 1.11 or newer**. The first run asks Android or | ||
| iOS for location permission. Desktop cannot read GPS, so the line is still | ||
| saved, just without coordinates. A cold satellite lock while offline can take | ||
| a while; if it times out, the note is saved without GPS. | ||
|
|
||
| This is not a built-in `{{coordinates}}` token. A capture format that calls | ||
| `{{MACRO:...}}` would wait for GPS *before* opening the prompt, which fights | ||
| voice-to-text. The script starts the location lookup first, then prompts. | ||
|
|
||
| ## Install from a package {#install-from-a-package} | ||
|
|
||
| 1. Download <a href="/packages/capture-inbox-gps.quickadd.json" download>capture-inbox-gps.quickadd.json</a>. | ||
| 2. Open **Settings → QuickAdd** and click **Import package…**. | ||
| 3. Paste the file contents. Review the script (it is marked executable), tick | ||
| the acknowledgement, and import. | ||
| 4. Assign a hotkey to **Capture to Inbox with GPS**, or run it from the command | ||
| palette. | ||
|
|
||
| The package writes `scripts/captureInboxGps.js` and a Macro choice that runs | ||
| it. Open the cog on the script step to change the Inbox path (default | ||
| `Inbox.md`) or to turn off creating the note when it is missing. | ||
|
|
||
| See [Share QuickAdd Packages](/docs/Choices/Packages/) for the import review | ||
| screen. | ||
|
|
||
| ## Install by hand {#install-by-hand} | ||
|
|
||
| 1. Save <a href="/scripts/captureInboxGps.js" download>captureInboxGps.js</a> | ||
| anywhere in your vault except `.obsidian` or a hidden folder. | ||
| 2. **Settings → QuickAdd → Add Choice → Macro**. Name it | ||
| `Capture to Inbox with GPS`. | ||
| 3. In the Macro Builder, add that script as a **User Script**. | ||
| 4. Enable **Command** on the choice so it appears in the palette. | ||
|
|
||
| ## What you get | ||
|
|
||
| Each run appends one line: | ||
|
|
||
| ```markdown | ||
| - 2026-08-31 15:42 Saw the trail marker at the ridge (55.676098, 12.568337) | ||
| ``` | ||
|
|
||
| If GPS is unavailable, the same line is written without the coordinates. | ||
|
|
||
| A run that already has `value` and `coordinates` set (URI, CLI, or an earlier | ||
| macro step) skips the prompt and the location lookup. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| import { readFileSync } from "node:fs"; | ||
| import path from "node:path"; | ||
| import { fileURLToPath } from "node:url"; | ||
| import { describe, expect, it, vi } from "vitest"; | ||
| import type { App } from "obsidian"; | ||
| import type IMacroChoice from "../src/types/choices/IMacroChoice"; | ||
| import { decodeFromBase64 } from "../src/utils/base64"; | ||
| import { buildPackagePreview } from "../src/services/packagePreview"; | ||
| import { | ||
| applyPackageImport, | ||
| parseQuickAddPackage, | ||
| } from "../src/services/packageImportService"; | ||
|
|
||
| const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); | ||
| const packagePath = path.join( | ||
| root, | ||
| "docs/public/packages/capture-inbox-gps.quickadd.json", | ||
| ); | ||
| const scriptPath = path.join(root, "docs/public/scripts/captureInboxGps.js"); | ||
|
|
||
| function lf(value: string): string { | ||
| return value.replace(/\r\n/g, "\n"); | ||
| } | ||
|
|
||
| function createMockApp(initialFiles: Record<string, string> = {}): { | ||
| app: App; | ||
| files: Map<string, string>; | ||
| } { | ||
| const files = new Map(Object.entries(initialFiles)); | ||
| const app = { | ||
| vault: { | ||
| adapter: { | ||
| exists: vi.fn(async (filePath: string) => files.has(filePath)), | ||
| read: vi.fn(async (filePath: string) => { | ||
| const content = files.get(filePath); | ||
| if (content === undefined) throw new Error(`Missing file: ${filePath}`); | ||
| return content; | ||
| }), | ||
| write: vi.fn(async (filePath: string, content: string) => { | ||
| files.set(filePath, content); | ||
| }), | ||
| }, | ||
| configDir: ".obsidian", | ||
| createFolder: vi.fn(async (folderPath: string) => { | ||
| files.set(folderPath, ""); | ||
| }), | ||
| }, | ||
| } as unknown as App; | ||
|
|
||
| return { app, files }; | ||
| } | ||
|
|
||
| describe("Capture to Inbox with GPS package", () => { | ||
| const raw = readFileSync(packagePath, "utf8"); | ||
| const script = lf(readFileSync(scriptPath, "utf8")); | ||
| const pkg = parseQuickAddPackage(raw); | ||
|
|
||
| it("bundles the published script and a command-palette Macro", () => { | ||
| expect(pkg.quickAddVersion).toBe("2.23.0"); | ||
| expect(pkg.rootChoiceIds).toEqual(["qa-pkg-capture-inbox-gps"]); | ||
| expect(pkg.assets).toHaveLength(1); | ||
| expect(pkg.assets[0]?.originalPath).toBe("scripts/captureInboxGps.js"); | ||
| expect(lf(decodeFromBase64(pkg.assets[0]?.content ?? ""))).toBe(script); | ||
|
|
||
| const choice = pkg.choices[0]?.choice as IMacroChoice; | ||
| expect(choice.name).toBe("Capture to Inbox with GPS"); | ||
| expect(choice.command).toBe(true); | ||
| expect(choice.runOnStartup).toBe(false); | ||
| expect(choice.macro.commands[0]?.type).toBe("UserScript"); | ||
| expect( | ||
| (choice.macro.commands[0] as { path?: string }).path, | ||
| ).toBe("scripts/captureInboxGps.js"); | ||
| }); | ||
|
|
||
| it("previews as an executable script that registers a command", () => { | ||
| const preview = buildPackagePreview([], pkg, new Set()); | ||
|
|
||
| expect(preview.summary.scriptCount).toBe(1); | ||
| expect(preview.summary.registersCommandCount).toBe(1); | ||
| expect(preview.criticalScriptPaths).toEqual(["scripts/captureInboxGps.js"]); | ||
| expect(preview.capabilityRows.some((row) => row.flag === "user-script")).toBe( | ||
| true, | ||
| ); | ||
| expect( | ||
| preview.capabilityRows.some((row) => row.flag === "registers-command"), | ||
| ).toBe(true); | ||
| }); | ||
|
|
||
| it("imports the script file and the Macro choice", async () => { | ||
| const { app, files } = createMockApp(); | ||
| const result = await applyPackageImport({ | ||
| app, | ||
| existingChoices: [], | ||
| pkg, | ||
| choiceDecisions: [ | ||
| { choiceId: "qa-pkg-capture-inbox-gps", mode: "import" }, | ||
| ], | ||
| assetDecisions: [ | ||
| { | ||
| originalPath: "scripts/captureInboxGps.js", | ||
| destinationPath: "scripts/captureInboxGps.js", | ||
| mode: "write", | ||
| }, | ||
| ], | ||
| }); | ||
|
|
||
| expect(result.addedChoiceIds).toEqual(["qa-pkg-capture-inbox-gps"]); | ||
| expect(result.writtenAssets).toEqual(["scripts/captureInboxGps.js"]); | ||
| expect(lf(files.get("scripts/captureInboxGps.js") ?? "")).toBe(script); | ||
| expect(result.updatedChoices[0]?.name).toBe("Capture to Inbox with GPS"); | ||
| }); | ||
| }); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When an existing inbox note does not end with a newline—for example, a newly created note containing only
# Inbox—vault.appendwrites this string directly after the final character, producing# Inbox- 2026-...instead of a separate Markdown list item. Read the existing file and conditionally prefix the appended entry with\n; also regenerate the package's embedded script copy when applying the fix.AGENTS.md reference: AGENTS.md:L31-L32
Useful? React with 👍 / 👎.