From a3c6e5af113a2129a3191c2f2a9d17ad2431dcac Mon Sep 17 00:00:00 2001 From: Theo Ephraim Date: Tue, 14 Jul 2026 17:25:51 -0700 Subject: [PATCH 1/3] =?UTF-8?q?refactor(completion):=20use=20@gunshi/plugi?= =?UTF-8?q?n-completion;=20upgrade=20gunshi=200.34=E2=86=920.36?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the hand-rolled @bomb.sh/tab shell completion with gunshi's official completion plugin. Subcommands and every flag are now derived automatically from each command's `args` schema, so the duplicated FLAGS / JSR_FLAGS tables (which could silently drift from the real command definitions) are gone. - Bump gunshi 0.34.0 β†’ 0.36.0, drop the direct @bomb.sh/tab dependency, add @gunshi/plugin-completion (pulls @bomb.sh/tab + @gunshi/plugin transitively). - Register the plugin via `plugins: [completionPlugin()]` and remove the manual `maybeHandleCompletion` argv intercept in cli.ts. - completion.ts now only supplies the dynamic-value handlers (workspace package names, --provider, --permissions). - Declare the `packages` positional in npmArgs / jsrArgs so the plugin can complete it; commands still read selectors via `selectorsOf(ctx)`. Bonus: it's now documented in --help under ARGUMENTS. Verified: typecheck + build clean; package/--provider/--permissions/jsr completions and shell-script generation work; runtime selector parsing unchanged. --- bun.lock | 14 ++-- package.json | 4 +- src/args.ts | 3 + src/cli.ts | 10 ++- src/commands/jsr.command.ts | 1 + src/completion.ts | 133 +++++++++++------------------------- 6 files changed, 60 insertions(+), 105 deletions(-) diff --git a/bun.lock b/bun.lock index f51a726..00f7af6 100644 --- a/bun.lock +++ b/bun.lock @@ -5,9 +5,9 @@ "": { "name": "newdle", "dependencies": { - "@bomb.sh/tab": "^0.0.16", "@clack/prompts": "^1.5.1", - "gunshi": "^0.34.0", + "@gunshi/plugin-completion": "^0.36.0", + "gunshi": "^0.36.0", "picocolors": "^1.1.1", "tinyglobby": "^0.2.10", }, @@ -30,7 +30,7 @@ "@babel/types": ["@babel/types@8.0.0-rc.6", "", { "dependencies": { "@babel/helper-string-parser": "^8.0.0-rc.6", "@babel/helper-validator-identifier": "^8.0.0-rc.6" } }, "sha512-p7/ABylAYlexb31wtRdIfH9L9A0Z2T/9H6zAqzqndkY2PLkvNNc580wGhp/gGKN4Sp9sQvSkhc6Oga8/O+wTyw=="], - "@bomb.sh/tab": ["@bomb.sh/tab@0.0.16", "", { "peerDependencies": { "cac": "^6.7.14", "citty": "^0.1.6 || ^0.2.0", "commander": "^13.1.0" }, "optionalPeers": ["cac", "citty", "commander"], "bin": { "tab": "dist/bin/cli.mjs" } }, "sha512-xFtIH6JYVdXgkSft97gsQyJODZbjGXw+l+wkT06lBiBPuaF0CFYNulQNsgnYud7rURI7D4lyLmOQeAzRkvl1Fg=="], + "@bomb.sh/tab": ["@bomb.sh/tab@0.0.17", "", { "peerDependencies": { "cac": "^6.7.14", "citty": "^0.1.6 || ^0.2.0", "commander": "^13.1.0" }, "optionalPeers": ["cac", "citty", "commander"], "bin": { "tab": "dist/bin/cli.mjs" } }, "sha512-rGhqfWwaSF6qN5Gm5P9EH9eybrwLEowHTkV+wsRgFewT6aQCQWVWXLclVk0McgVIlWCGX+W9mYYC1Egsg+Znsw=="], "@clack/core": ["@clack/core@1.4.1", "", { "dependencies": { "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" } }, "sha512-FILJa1gGKEFTGZAJE9RpVhrjKz3c3h4ar60dSv6cGuDqufQ84YEIS3GAGvZiN+H6yaLbbvTFNejjCC4tXpZEuw=="], @@ -42,6 +42,12 @@ "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="], + "@gunshi/plugin": ["@gunshi/plugin@0.36.0", "", {}, "sha512-y0/lUz7k1kSF9pbINqmz1VoG7lkvMDzw/onbHtf0Ot2cteLQkncplJFLo1qQWterwtduYfRjYeYZRlj4kZc5pg=="], + + "@gunshi/plugin-completion": ["@gunshi/plugin-completion@0.36.0", "", { "dependencies": { "@bomb.sh/tab": "^0.0.17", "@gunshi/plugin": "0.36.0" }, "peerDependencies": { "@gunshi/plugin-i18n": "0.36.0" } }, "sha512-79EIxM3KIksBNHEzl1dW3ZQcjLuKxz2LYMK/gF/wRri+z/SlkqcpS3gqv/p3HiIK+2pegpTd5o5AKznko5kDXw=="], + + "@gunshi/plugin-i18n": ["@gunshi/plugin-i18n@0.36.0", "", { "dependencies": { "@gunshi/plugin": "0.36.0" }, "peerDependencies": { "@gunshi/plugin-global": "0.36.0" }, "optionalPeers": ["@gunshi/plugin-global"] }, "sha512-T4IZh6lWApMiQ6UnBku5oGUgFgcv07GoZNF8v8aRoqcbmW9FQ6UVW8Em6s/oSFLMuIthR5B6OgcgI3ptZlgrZw=="], + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], @@ -124,7 +130,7 @@ "get-tsconfig": ["get-tsconfig@5.0.0-beta.5", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-/6gFNr0N04nob252sTQxyFLi3eKFRqIg1I87YcqAMT1i6SQrSF6KujUEQrtrjMV0H/eejTCltLdDSTEMzHbnsQ=="], - "gunshi": ["gunshi@0.34.0", "", {}, "sha512-X2iHMotAKK143WNWyatb1y+sBoIqIeXNNc9ul5oMVqyxTpN/8LVJ+YWQZ8wT35r8RzMFO3nUi+Fnt7c4QzE34g=="], + "gunshi": ["gunshi@0.36.0", "", {}, "sha512-LJhM/2YiC4GfsaT2fnvccNkGXzbtMCBkgXpyLSM+1QVal2n7k8VJZol8qm1qgm2wmaQ6NBVmcGZIOkB/ms+6uQ=="], "hookable": ["hookable@6.1.1", "", {}, "sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ=="], diff --git a/package.json b/package.json index 5fcf400..fdea2e3 100644 --- a/package.json +++ b/package.json @@ -37,9 +37,9 @@ "start": "node dist/cli.mjs" }, "dependencies": { - "@bomb.sh/tab": "^0.0.16", "@clack/prompts": "^1.5.1", - "gunshi": "^0.34.0", + "@gunshi/plugin-completion": "^0.36.0", + "gunshi": "^0.36.0", "picocolors": "^1.1.1", "tinyglobby": "^0.2.10" }, diff --git a/src/args.ts b/src/args.ts index 1adf881..a2fa728 100644 --- a/src/args.ts +++ b/src/args.ts @@ -9,6 +9,9 @@ export const selectorsOf = (ctx: Ctx): string[] => (ctx.positionals ?? []).slice /** The npm-shaped flag set shared by the default, `add`, and `sync` commands. */ export const npmArgs = { + // positional package selectors β€” declared so the completion plugin can complete + // them; the commands still read them via `selectorsOf(ctx)` (i.e. `ctx.positionals`). + packages: { type: 'positional', multiple: true, required: false, description: 'Package name(s) or glob(s) to target (default: all workspace packages)' }, // run options (per invocation) yes: { type: 'boolean', short: 'y', description: 'Apply changes without prompting (default: interactive / dry run)' }, 'dry-run': { type: 'boolean', description: 'Print a plan without prompts (non-interactive)' }, diff --git a/src/cli.ts b/src/cli.ts index e6d32ea..8a278df 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -1,7 +1,7 @@ #!/usr/bin/env node import { cli } from 'gunshi'; import pc from 'picocolors'; -import { maybeHandleCompletion } from './completion.js'; +import { completionPlugin } from './completion.js'; import { entryCommand, addCommand } from './commands/add.command.js'; import { syncCommand } from './commands/sync.command.js'; import { initCommand } from './commands/init.command.js'; @@ -12,17 +12,15 @@ const VERSION = __VERSION__; const rawArgv = process.argv.slice(2); -// shell completion (`fledgling complete …`) is handled by @bomb.sh/tab, before gunshi -if (maybeHandleCompletion(rawArgv)) { - process.exit(0); -} - try { await cli(rawArgv, entryCommand, { name: 'fledgling', version: VERSION, description: '🐣 Create and set up packages on npm with trusted publishing', subCommands: { add: addCommand, sync: syncCommand, init: initCommand, jsr: jsrCommand }, + // shell completion (`fledgling complete `) β€” subcommands + flags are derived + // from each command's `args`; see completion.ts for the dynamic-value handlers. + plugins: [completionPlugin()], renderHeader: null, // no auto-printed banner on every run }); } catch (e) { diff --git a/src/commands/jsr.command.ts b/src/commands/jsr.command.ts index e760ad6..0214881 100644 --- a/src/commands/jsr.command.ts +++ b/src/commands/jsr.command.ts @@ -24,6 +24,7 @@ import { /** `fledgling jsr`'s own flags β€” JSR needs none of the npm-shaped `args` (no npm * CLI, no OTP, no provider/workflow/environment config). */ export const jsrArgs = { + packages: { type: 'positional', multiple: true, required: false, description: 'Package name(s) or glob(s) to target (default: all workspace packages)' }, yes: { type: 'boolean', short: 'y', description: 'Apply changes without prompting (default: interactive / dry run)' }, 'dry-run': { type: 'boolean', description: 'Print a plan without prompts (non-interactive)' }, scope: { type: 'string', description: '[config] JSR scope for packages whose npm name has none (or to override it)' }, diff --git a/src/completion.ts b/src/completion.ts index 79949a2..01c6260 100644 --- a/src/completion.ts +++ b/src/completion.ts @@ -1,102 +1,49 @@ -import t from '@bomb.sh/tab'; +import completion from '@gunshi/plugin-completion'; import { workspacePackages } from './core.js'; -const FLAGS: [string, string][] = [ - ['--yes', 'apply changes without prompting'], - ['--new', 'claim brand-new names not in the repo'], - ['--skip-publish', 'only set up trusted publishing'], - ['--skip-trust', 'only claim names'], - ['--force', 'replace an existing trusted publisher'], - ['--dry-run', 'print a plan without prompting'], - ['--placeholder-version', 'placeholder version'], - ['--tag', 'dist-tag for placeholders'], - ['--otp', 'npm 2FA one-time password'], - ['--otp-secret', 'TOTP secret to generate 2FA codes from'], - ['--registry', 'npm registry URL'], - ['--repo', 'trusted-publisher repo (owner/repo)'], - ['--workflow', 'publishing workflow filename'], - ['--env', 'CI environment'], - ['--org-id', 'CircleCI organization UUID'], - ['--project-id', 'CircleCI project UUID'], - ['--pipeline-definition-id', 'CircleCI pipeline definition UUID'], - ['--vcs-origin', 'CircleCI VCS origin (github/owner/repo)'], - ['--context-id', 'CircleCI context UUID (repeatable)'], -]; - -type Cmd = { - argument(name: string, handler: (complete: (v: string, d?: string) => void) => void, variadic?: boolean): Cmd; - option(flag: string, desc: string, handler?: (complete: (v: string, d?: string) => void) => void): Cmd; -}; +type Completion = { value: string; description?: string }; -/** Wire the package-name positional + every flag onto a command. */ -function withPackageArgsAndFlags(cmd: Cmd): void { - cmd.argument( - 'packages', - complete => { - for (const p of workspacePackages()) complete(p.name, 'package'); - }, - true, - ); - cmd.option('--provider', 'CI provider', complete => { - complete('github', ''); - complete('gitlab', ''); - complete('circleci', ''); - }); - cmd.option('--permissions', 'trust permissions', complete => { - complete('publish', ''); - complete('stage', ''); - complete('both', ''); - }); - for (const [flag, desc] of FLAGS) cmd.option(flag, desc); -} +/** Complete workspace package names for the `packages` positional. */ +const completePackages = (): Completion[] => + workspacePackages().map(p => ({ value: p.name, description: 'package' })); -const JSR_FLAGS: [string, string][] = [ - ['--yes', 'apply changes without prompting'], - ['--dry-run', 'print a plan without prompting'], - ['--scope', 'JSR scope for unscoped packages'], - ['--repo', 'GitHub repo to link (owner/repo)'], - ['--token', 'JSR personal access token (full access)'], - ['--skip-manifest', "don't scaffold missing jsr.json manifests"], - ['--skip-link', "only claim names β€” don't link the repo"], - ['--skip-metadata', "don't sync description / runtime compat to JSR"], +/** Static value completions for the enum-ish string options. */ +const completeProvider = (): Completion[] => [ + { value: 'github' }, + { value: 'gitlab' }, + { value: 'circleci' }, +]; +const completePermissions = (): Completion[] => [ + { value: 'publish' }, + { value: 'stage' }, + { value: 'both' }, ]; -function defineCompletions(): void { - // subcommands: `add` / `sync` take package selectors + flags, `init` takes nothing - withPackageArgsAndFlags(t.command('add', 'claim names + set up trusted publishing') as unknown as Cmd); - withPackageArgsAndFlags(t.command('sync', 'reconcile trusted publishing with your config') as unknown as Cmd); - const jsr = t.command('jsr', 'claim packages on JSR + link the repo for OIDC') as unknown as Cmd; - jsr.argument( - 'packages', - complete => { - for (const p of workspacePackages()) complete(p.name, 'package'); - }, - true, - ); - for (const [flag, desc] of JSR_FLAGS) jsr.option(flag, desc); - t.command('init', 'write trusted-publishing config to package.json'); - - // bare `fledgling …` (default command) also accepts selectors + flags - withPackageArgsAndFlags(t as unknown as Cmd); -} +/** Handlers for the npm-shaped commands (default / add / sync). */ +const npmConfig = { + args: { + packages: { handler: completePackages }, + provider: { handler: completeProvider }, + permissions: { handler: completePermissions }, + }, +}; /** - * Handle the hidden `complete` subcommand (shell completion). - * `fledgling complete ` prints an install script; the shell calls - * `fledgling complete -- ` to get dynamic completions. - * Returns true if it handled the invocation. + * Shell completion plugin. Subcommands and every flag are derived automatically + * from the commands' `args` schemas; we only supply handlers for the dynamic + * values (workspace package names + the enum-ish `--provider` / `--permissions`). + * + * Installs via the auto-generated `complete` subcommand: + * fledgling complete zsh >> ~/.zshrc (or bash | fish | powershell) */ -export function maybeHandleCompletion(argv: string[]): boolean { - if (argv[0] !== 'complete') return false; - defineCompletions(); - const arg = argv[1]; - if (arg === '--') { - t.parse(argv.slice(2)); - } else if (arg) { - t.setup('fledgling', 'fledgling', arg); // arg = bash | zsh | fish | powershell - } else { - console.log('Usage: fledgling complete '); - console.log('e.g. fledgling complete zsh >> ~/.zshrc'); - } - return true; -} +export const completionPlugin = () => + completion({ + config: { + entry: npmConfig, + subCommands: { + add: npmConfig, + sync: npmConfig, + jsr: { args: { packages: { handler: completePackages } } }, + }, + }, + }); From fe9f8e5ec6470ab9c5f569786794fc6e1215d57d Mon Sep 17 00:00:00 2001 From: Theo Ephraim Date: Tue, 14 Jul 2026 17:40:23 -0700 Subject: [PATCH 2/3] chore: add lefthook git hooks (pre-push: typecheck + bumpy check) Mirrors the bumpy repo's pre-push setup, scoped to fledgling's tooling (no oxlint/oxfmt here). `postinstall: lefthook install` registers the hook on `bun install`. --- bun.lock | 23 +++++++++++++++++++++++ lefthook.yml | 6 ++++++ package.json | 4 +++- 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 lefthook.yml diff --git a/bun.lock b/bun.lock index 00f7af6..20475d8 100644 --- a/bun.lock +++ b/bun.lock @@ -14,6 +14,7 @@ "devDependencies": { "@types/node": "^25.0.0", "@varlock/bumpy": "^1.15.0", + "lefthook": "^2.1.10", "tsdown": "^0.22.2", "typescript": "^6.0.3", }, @@ -138,6 +139,28 @@ "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], + "lefthook": ["lefthook@2.1.10", "", { "optionalDependencies": { "lefthook-darwin-arm64": "2.1.10", "lefthook-darwin-x64": "2.1.10", "lefthook-freebsd-arm64": "2.1.10", "lefthook-freebsd-x64": "2.1.10", "lefthook-linux-arm64": "2.1.10", "lefthook-linux-x64": "2.1.10", "lefthook-openbsd-arm64": "2.1.10", "lefthook-openbsd-x64": "2.1.10", "lefthook-windows-arm64": "2.1.10", "lefthook-windows-x64": "2.1.10" }, "bin": { "lefthook": "bin/index.js" } }, "sha512-K7mM4WoqMwqfXYK11EHy+lSH1uW8XHni3Yn/bSqyerPkUPygGdf3xn18JoV5HyA06xuQL3ofGAOjG01QX9oJ4w=="], + + "lefthook-darwin-arm64": ["lefthook-darwin-arm64@2.1.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-nw+X8wRNDoUUV6WSteyKBbcLySq+fsmZt5WV/s50ZJpysmsDKJOUMln6SllNfP+60dzUahAO7REco/2633BsLg=="], + + "lefthook-darwin-x64": ["lefthook-darwin-x64@2.1.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-KQ/bHmvpkFdHMn4pZnUdTf+GuSC+aBBgBTxZT4GW+6cSf+qbErKZBhK7cH6BmILsvx43+VzEArvHYY7YOfRFOQ=="], + + "lefthook-freebsd-arm64": ["lefthook-freebsd-arm64@2.1.10", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-8su6DwydP7+pv7kG0zCtjphqsw4ouOnfexRUErapy5GTxYBoUOhYz3RSHTSWNRsK6W4jva7FPUh2Lp5/PSn30w=="], + + "lefthook-freebsd-x64": ["lefthook-freebsd-x64@2.1.10", "", { "os": "freebsd", "cpu": "x64" }, "sha512-GeAJEFxko3Lk+AsnS3NleAFrpyMLFUKOlgJvPKuU0xHwVEI/z+ZoCcmuO0BX+4CS0NLbZhC/YQAvBASqDvvVdQ=="], + + "lefthook-linux-arm64": ["lefthook-linux-arm64@2.1.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-1sHTCmpTWjVMs+yKPBLRNT1kuuIr1yjietlk7rCB6wFPVOS6Ph3o2zPFH2AvW1UymHlqwyHXzBr9EtDpQ7j1mQ=="], + + "lefthook-linux-x64": ["lefthook-linux-x64@2.1.10", "", { "os": "linux", "cpu": "x64" }, "sha512-z/VlRB3bh6mBvW3r1rwnJ5vP8z+Krx5gJzkZ4veDXh+6FlRTx8wtd3g3fllOv/yZMxkgmL3fQoFXv05Esa7vBQ=="], + + "lefthook-openbsd-arm64": ["lefthook-openbsd-arm64@2.1.10", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-430zL8sSIKw5P0YXGG6PB+eAhHa06n0PXuaERaAQE4Ss3odfqwnl5Mq9hQmkEnOS1EGiQEKkd0UHv/i4PtMNIQ=="], + + "lefthook-openbsd-x64": ["lefthook-openbsd-x64@2.1.10", "", { "os": "openbsd", "cpu": "x64" }, "sha512-bgkO8PphGZVDhQgCJ524aYYPI5491pVmCiLPGjBIo1AvOSlIyw4N1Y+1C3QfqwEmechzw+Aq16SNc8pqv6UuXg=="], + + "lefthook-windows-arm64": ["lefthook-windows-arm64@2.1.10", "", { "os": "win32", "cpu": "arm64" }, "sha512-5Q6etF0Fla2DDA4ilDySrdNgiR5+W7cJZwnZ69Je3kvWCaWm4wnkuc8FEdjp3kiL2x3ZXipdI00f5vpO8aWmog=="], + + "lefthook-windows-x64": ["lefthook-windows-x64@2.1.10", "", { "os": "win32", "cpu": "x64" }, "sha512-c/XH8YZtylG4XaxzqFfXluvq2LXq2W/p54Bnzn3+Z7E5X2Fk3JlFJAibulMbIt2+w8T7UI/r97ok5GqE4kGaeA=="], + "obug": ["obug@2.1.3", "", {}, "sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg=="], "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], diff --git a/lefthook.yml b/lefthook.yml new file mode 100644 index 0000000..24c7923 --- /dev/null +++ b/lefthook.yml @@ -0,0 +1,6 @@ +pre-push: + jobs: + - name: typecheck + run: bun run typecheck + - name: bumpy-check + run: bunx @varlock/bumpy check --hook pre-push diff --git a/package.json b/package.json index fdea2e3..404bed9 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,8 @@ "build": "tsdown", "dev": "tsdown --watch", "typecheck": "tsc --noEmit", - "start": "node dist/cli.mjs" + "start": "node dist/cli.mjs", + "postinstall": "lefthook install" }, "dependencies": { "@clack/prompts": "^1.5.1", @@ -46,6 +47,7 @@ "devDependencies": { "@types/node": "^25.0.0", "@varlock/bumpy": "^1.15.0", + "lefthook": "^2.1.10", "tsdown": "^0.22.2", "typescript": "^6.0.3" }, From 92bb181466d3c3864915efcbb5a34171d8d78c75 Mon Sep 17 00:00:00 2001 From: Theo Ephraim Date: Tue, 14 Jul 2026 17:40:23 -0700 Subject: [PATCH 3/3] chore: add bump file for the gunshi completion-plugin migration --- .bumpy/gunshi-completion-plugin.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .bumpy/gunshi-completion-plugin.md diff --git a/.bumpy/gunshi-completion-plugin.md b/.bumpy/gunshi-completion-plugin.md new file mode 100644 index 0000000..524b275 --- /dev/null +++ b/.bumpy/gunshi-completion-plugin.md @@ -0,0 +1,5 @@ +--- +'fledgling': patch +--- + +Upgrade gunshi to 0.36 and switch shell completion to the official `@gunshi/plugin-completion` (replacing the hand-rolled `@bomb.sh/tab` integration). Completion behaves the same β€” package names, `--provider`, and `--permissions` still complete β€” and the `packages` argument is now documented in `--help`.