diff --git a/TODO.md b/TODO.md index 8c62307..54a7da3 100644 --- a/TODO.md +++ b/TODO.md @@ -152,101 +152,22 @@ worth doing carefully, and worth a design conversation before the first PR. --- -## Importer: bring snips in from SnipCommand and friends +## Importer: more source formats -**Problem.** `CLAUDE.md` already parks SnipCommand import as a "future nicety": -read a SnipCommand JSON, auto-suggest the CLI from the first token of each -command. Worth doing — SnipCommand is the obvious migration path. And there -are other shapes worth ingesting later (VS Code snippets, espanso, Alfred, -TextExpander, ad-hoc shell-history dumps). +**Shipped (PR #34).** The `snipdeck-importer` console tool imports from +**SnipCommand** end-to-end — see `tools/Snipdeck.Importer/`. It auto-suggests a +CLI per command, translates `[sc_choice]` / `[sc_variable]` markup into +`{token}` placeholders plus structured parameters, and merges into the store +(dry-run by default; `--write` backs up, dedupes, and creates CLIs on demand). -**Decision: this is a separate CLI tool, not a feature inside the WinUI app.** +**Remaining.** Additional source adapters, each a new subcommand implementing +`ISnippetSource`: -Reasons: +- **VS Code snippets** (`*.code-snippets`) and **espanso** (`*.yml`) are the + obvious next two — each has its own placeholder syntax to translate. +- Alfred, TextExpander and ad-hoc shell-history dumps are further candidates. -- Import is a rare / one-off operation. It doesn't deserve UI surface area - in the main app, where it'd compete for visual real estate with everyday - workflows. -- A CLI tool is cross-platform — useful for users who want to bulk-prep an - import on a Linux box or in CI before bringing the JSON over to a Windows - Snipdeck install. -- Adding a new source format (espanso, TextExpander, …) is then a new - subcommand in the importer, not a new dialog in the main app. -- Distribution is independent: shipped as a `dotnet tool` for trivial - install (`dotnet tool install -g snipdeck-importer`) and versioned - separately from the desktop app. -- Spectre.Console.Cli is the established pattern in the wider - StuartMeeks toolbox — fits naturally. - -**Sketch.** - -- New project at `tools/Snipdeck.Importer/` in this solution, targeting - `net10.0` (NOT `-windows`), depending on `Snipdeck.Core`. Re-uses - `SnipStoreDocument`, `Cli`, `Snip`, `Parameter`, `JsonSnipStore`, - `BackupService` — exactly the surface Core was carved off for. -- Packaged as a .NET tool (`true`, - `ToolCommandName=snipdeck-importer`). -- Subcommand per source: `snipdeck-importer snipcommand `, - later `snipdeck-importer vscode `, etc. Each source adapter - implements an `ISnippetSource` that yields `Snip` candidates plus - a suggested `Cli` name. -- Defaults to **dry-run**: parses the source, prints the planned - additions (Snips grouped by suggested CLI, parameter summary), exits - without touching the store. `--write` actually merges into the store. -- `--store ` lets the user point at an arbitrary store file; - defaults to the same path the desktop app uses - (`IPathProvider`'s default, factored down into Core). -- `--cli ` forces every imported Snip into a named CLI, overriding - the per-command auto-suggestion. -- `--into ` is the per-command equivalent — apply only to - Snips that didn't get a confident auto-suggestion. - -**SnipCommand specifics.** - -- SnipCommand stores a flat list — Snipdeck groups by CLI. Auto-suggest - the CLI from the first whitespace-separated token of each command - (`pl-app orgs list` → `pl-app`). When the leading token is `sudo`, - `npx`, or similar, peel it off and use the next token. -- SnipCommand uses inline markup: `[sc_choice ...]`, `[sc_variable ...]`. - Snipdeck uses `{token}` placeholders plus a structured `Parameter[]` - list. The importer: - 1. Parses the markup, mints a placeholder name (the variable / choice - name, with collisions disambiguated). - 2. Replaces the inline markup with `{name}` in the command template. - 3. Emits a `Parameter` entry of the right `Type` (Choice with options, - or Text) into the Snip. -- Description / tags carry across one-for-one where present. - -**Merge semantics.** - -- Always write a backup of the existing store before modifying it - (call `BackupService` so the desktop app's retention policy stays in - charge). -- New Snips always mint fresh GUIDs — SnipCommand IDs aren't reused. -- De-duplication: if a Snip with the same `(Title, CommandTemplate)` - already exists, skip by default. `--allow-duplicates` opts in to - importing them anyway. -- New CLIs are created on demand when an imported Snip's suggested CLI - doesn't already exist in the target store. - -**Open questions** to settle when scheduled: - -- **Where the docs live.** The importer's README probably belongs in - the tool's project folder, with a pointer from the desktop app's - README so users discover it. -- **Velopack interaction.** The desktop app should never be running - against a store the importer is concurrently rewriting. The atomic - temp-file-then-rename write the JsonSnipStore already does avoids - corruption, but a running desktop instance won't *see* the changes - until it next reloads. Worth surfacing in `--write` output: - "Snipdeck is running — restart it to see the imported Snips." -- **Adversarial sources.** A SnipCommand JSON crafted to overflow a - parameter name, embed escape sequences in the command preview, or - similar — be defensive when parsing. Treat the input as untrusted. -- **Future sources.** VS Code snippets (`*.code-snippets`) and espanso - (`*.yml`) are the obvious next two. Each has its own placeholder - syntax to translate. Add them when there's actual demand, not - speculatively. +Add these on actual demand, not speculatively. ---