argsbarg 5.1.12 → 5.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,7 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
- ## [5.1.12] - 2026-07-05
10
+ ## [5.1.14] - 2026-07-06
11
+
12
+
13
+ ## [5.1.13] - 2026-07-06
14
+
15
+ ### Fixed
16
+
17
+ - **`configure --remove-all`** — skill uninstall actions no longer reinstall skills after printing "Removing …".
18
+ - **Interactive `configure`** — choosing `n` on an installed skill now removes the skill directory (same bug as `--remove-all`, different code path).
19
+
20
+ ### Changed
21
+
22
+ - **Homebrew formula `uninstall`** — generated formulae run `{key} configure --remove-all --yes` (skills, MCP, and app config).
11
23
 
12
24
  ### Changed
13
25
 
@@ -665,8 +677,9 @@ const cli = { ... } satisfies CliProgram; // or : CliProgram
665
677
  - Migrate schemas: rename every `children` property to **`commands`**; move positional definitions to **`CliPositional`** objects on `positionals` and strip `positional` / `argMin` / `argMax` from flag definitions under `options` (flags only carry `name`, `description`, `kind`, and optional `shortName`).
666
678
  - Imports: use `CliPositional` where needed; replace `CliOptionDef` with `CliOption` or `CliPositional` as appropriate.
667
679
 
668
- [Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v5.1.12...HEAD
669
- [5.1.12]: https://github.com/bdombro/bun-argsbarg/releases/tag/v5.1.12
680
+ [Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v5.1.14...HEAD
681
+ [5.1.14]: https://github.com/bdombro/bun-argsbarg/releases/tag/v5.1.14
682
+ [5.1.13]: https://github.com/bdombro/bun-argsbarg/releases/tag/v5.1.13
670
683
  [5.1.11]: https://github.com/bdombro/bun-argsbarg/releases/tag/v5.1.11
671
684
  [5.1.10]: https://github.com/bdombro/bun-argsbarg/releases/tag/v5.1.10
672
685
  [5.1.9]: https://github.com/bdombro/bun-argsbarg/releases/tag/v5.1.9
package/docs/configure.md CHANGED
@@ -16,14 +16,15 @@ brew install <tap>/<key>
16
16
 
17
17
  Upgrade with `brew upgrade <key>`. Shell completions are installed by Homebrew during `brew install`. Users must configure their shell per [Homebrew Shell Completion](https://docs.brew.sh/Shell-Completion).
18
18
 
19
- **Uninstall the binary:** remove agent artifacts first (while the CLI is still on PATH), then `brew uninstall`:
19
+ **Uninstall the binary:**
20
20
 
21
21
  ```bash
22
- <key> configure --remove-all --yes
23
22
  brew uninstall <tap>/<key>
24
23
  ```
25
24
 
26
- `brew uninstall` runs the formula `uninstall` hook, which removes app config (`configure --remove-config --yes`). Skills and MCP entries are not removed by Homebrew — use `--remove-all` before uninstall when you want those gone too.
25
+ `brew uninstall` runs the formula `uninstall` hook (`configure --remove-all --yes`), which removes detected skills, MCP entries, and app config while the binary is still on PATH.
26
+
27
+ To remove app config only (keep skills/MCP), run `configure --remove-config --yes` before uninstall.
27
28
 
28
29
  ## Developer install
29
30
 
@@ -177,11 +178,11 @@ Release formulae should run:
177
178
 
178
179
  ```ruby
179
180
  def uninstall
180
- system bin/"myapp", "configure", "--remove-config", "--yes"
181
+ system bin/"myapp", "configure", "--remove-all", "--yes"
181
182
  end
182
183
  ```
183
184
 
184
- Homebrew calls this before removing the keg, so the binary is still on PATH. Safe no-op when app config was never created or `program.appConfig` is unset.
185
+ Removes detected skills, MCP entries, and app config while the binary is still on PATH. Safe no-op when nothing was installed.
185
186
 
186
187
  ## Bootstrapping a new CLI
187
188
 
@@ -10,7 +10,7 @@ Argsbarg apps distribute the **binary and shell completions** through Homebrew,
10
10
  | Skills + MCP | Formula `post_install` → `{key} configure --sync --yes` |
11
11
  | App config file | Bootstrapped as `{}` on `post_install` via `--sync` (`~/.local/lib/<key>/config.json`) |
12
12
  | App config values | User opt-in: `{key} configure` (interactive wizard when `program.appConfig` has entries) |
13
- | App config cleanup | Formula `uninstall` → `{key} configure --remove-config --yes` |
13
+ | App config cleanup | Formula `uninstall` → `{key} configure --remove-all --yes` |
14
14
 
15
15
  **Only tap-from-repo** — in-repo `Formula/` or GitHub tap. Not Homebrew core.
16
16
 
@@ -62,13 +62,13 @@ If `brew install` fails, run `bun scripts/dev-formula.ts reset` manually to rest
62
62
 
63
63
  | Recipe | Removes |
64
64
  | --- | --- |
65
- | `just uninstall` | Formula `{key}` + tap symlink + skills/MCP; app config via formula `uninstall` |
65
+ | `just uninstall` | Formula `{key}` + tap symlink + skills/MCP + app config via formula `uninstall` |
66
66
  | `just uninstall-config` | App config file only (`configure --remove-config --yes`) |
67
- | `just uninstall-release` | Release formula from `{tap}` (keeps tap; app config via formula `uninstall`) |
68
- | `just uninstall-release-tap` | Release formula + `brew untap {tap}` (app config via formula `uninstall`) |
67
+ | `just uninstall-release` | Release formula from `{tap}` (keeps tap; agent artifacts via formula `uninstall`) |
68
+ | `just uninstall-release-tap` | Release formula + `brew untap {tap}` (agent artifacts via formula `uninstall`) |
69
69
  | `just test-release` | Install release formula and run formula test |
70
70
 
71
- End users: `<key> configure --remove-all --yes` then `brew uninstall <tap>/<key>`. `brew uninstall` also removes app config via the formula `uninstall` hook (skills/MCP are not removed automatically).
71
+ End users: `brew uninstall <tap>/<key>`. The formula `uninstall` hook runs `configure --remove-all --yes` (skills, MCP, and app config).
72
72
 
73
73
  ## Formula pattern
74
74
 
@@ -83,7 +83,7 @@ def post_install
83
83
  end
84
84
 
85
85
  def uninstall
86
- system bin/"{key}", "configure", "--remove-config", "--yes"
86
+ system bin/"{key}", "configure", "--remove-all", "--yes"
87
87
  end
88
88
  ```
89
89
 
@@ -43,7 +43,7 @@ Production CLIs with several JSON commands tend to use **codegen** so types, han
43
43
 
44
44
  ## Recommended pipeline (copy per repo)
45
45
 
46
- No shared npm package — each app copies the same **contract**. Reference implementations: **sqsp-qa-manager-poc**, **idp-trees**, **sqsp-i18n-tools-poc** (see each repo’s `docs/architecture.md` for which commands use which schema root).
46
+ No shared npm package — each app copies the same **contract**. Reference implementations: **sqsp-qa-manager-poc**, **sqsp-workspaces**, **sqsp-i18n-tools-poc** (see each repo’s `docs/architecture.md` for which commands use which schema root).
47
47
 
48
48
  ```mermaid
49
49
  flowchart LR
@@ -24,7 +24,7 @@ export const formulaPostInstallRuby = `def post_install
24
24
  end`;
25
25
 
26
26
  export const formulaUninstallRuby = `def uninstall
27
- system bin/"${key}", "configure", "--remove-config", "--yes"
27
+ system bin/"${key}", "configure", "--remove-all", "--yes"
28
28
  end`;
29
29
 
30
30
  export const formulaCaveatsRuby = `def caveats
@@ -80,7 +80,10 @@ export function selectStaleReleaseTags(releases: ReleaseTag[]): string[] {
80
80
  export const releaseRepoSlug = releaseRepo;
81
81
 
82
82
  /** Resolves private GitHub release assets via the API at download time. */
83
- export const githubPrivateReleaseDownloadStrategyRuby = ` class GitHubPrivateReleaseDownloadStrategy < CurlDownloadStrategy
83
+ export const githubPrivateReleaseDownloadStrategyRuby = ` # Private/internal releases: default CurlDownloadStrategy cannot fetch non-public
84
+ # GitHub release assets. Resolve the asset via the API and authenticate with
85
+ # GitHub::API.credentials (set up via \`gh auth login\` or HOMEBREW_GITHUB_API_TOKEN).
86
+ class GitHubPrivateReleaseDownloadStrategy < CurlDownloadStrategy
84
87
  def initialize(url, name, version, **meta)
85
88
  super
86
89
  pattern = %r{https://github\\.com/([^/]+)/([^/]+)/releases/download/([^/]+)/(\\S+)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "argsbarg",
3
- "version": "5.1.12",
3
+ "version": "5.1.14",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "bun": ">=1.3"
@@ -68,11 +68,10 @@ export function configureCommandNotes(program: CliProgram, _caps: CliCapabilitie
68
68
  "See what is installed:",
69
69
  ` ${app} configure --status`,
70
70
  "",
71
- "Remove agent artifacts before brew uninstall:",
72
- ` ${app} configure --remove-all --yes`,
71
+ "Uninstall:",
73
72
  ` brew uninstall <tap>/${app}`,
74
73
  "",
75
- "App config is removed automatically by the formula uninstall hook during brew uninstall.",
74
+ "The formula uninstall hook runs `configure --remove-all --yes` (skills, MCP, and app config).",
76
75
  "",
77
76
  ];
78
77
  if (program.appConfig) {
@@ -3,7 +3,7 @@ Tests for configure/configure module behavior.
3
3
  */
4
4
 
5
5
  import { afterEach, beforeEach, describe, expect, test } from "bun:test";
6
- import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
6
+ import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
7
7
  import { tmpdir } from "node:os";
8
8
  import { join } from "node:path";
9
9
  import { appConfigFileExists } from "../config/file.ts";
@@ -13,6 +13,8 @@ import { detectInstalledArtifacts } from "../install/detect-installed.ts";
13
13
  import { parseInstallOpts } from "../install/opts.ts";
14
14
  import { resolveClaudeDesktopMcpPath, resolveInstallPaths } from "../install/paths.ts";
15
15
  import { buildInstallPlan, buildUpdatePlan } from "../install/plan.ts";
16
+ import { installTargetForKey } from "../install/target-registry.ts";
17
+ import { buildDetectedSnapshot, buildTargetPlanContext } from "../install/target-scope.ts";
16
18
  import { buildUninstallPlan } from "../install/uninstall.ts";
17
19
  import type { CliProgram } from "../types.ts";
18
20
 
@@ -137,6 +139,45 @@ describe("remove plan", () => {
137
139
  const plan = buildUninstallPlan(fixture, paths, parseInstallOpts({ uninstall: "1", all: "1" }));
138
140
  expect(plan.length).toBe(0);
139
141
  });
142
+
143
+ test("configure --remove-all removes installed cursor skill", async () => {
144
+ const skillApp: CliProgram = {
145
+ ...fixture,
146
+ configure: { agentIntegration: "skill" },
147
+ };
148
+ const paths = resolveInstallPaths(skillApp);
149
+ mkdirSync(paths.cursorSkillDir, { recursive: true });
150
+ writeFileSync(join(paths.cursorSkillDir, "SKILL.md"), "# test\n", "utf8");
151
+
152
+ expect(detectInstalledArtifacts(paths, skillApp).cursorSkill).toBe(true);
153
+
154
+ const result = await new Cli(skillApp).invoke(["configure", "--remove-all", "--yes"]);
155
+ expect(result.exitCode).toBe(0);
156
+ expect(existsSync(paths.cursorSkillDir)).toBe(false);
157
+ });
158
+
159
+ test("scoped skill uninstall action removes directory without global uninstall flag", () => {
160
+ const skillApp: CliProgram = {
161
+ ...fixture,
162
+ configure: { agentIntegration: "skill" },
163
+ };
164
+ const paths = resolveInstallPaths(skillApp);
165
+ mkdirSync(paths.cursorSkillDir, { recursive: true });
166
+ writeFileSync(join(paths.cursorSkillDir, "SKILL.md"), "# test\n", "utf8");
167
+
168
+ const detected = buildDetectedSnapshot(skillApp, paths);
169
+ const ctx = buildTargetPlanContext(skillApp, paths, {}, detected);
170
+ const target = installTargetForKey("cursorSkill");
171
+ expect(target).toBeDefined();
172
+ const actions = target!.planUninstall({
173
+ ...ctx,
174
+ mode: "uninstall-scoped",
175
+ include: (key) => key === "cursorSkill",
176
+ });
177
+ expect(actions).toHaveLength(1);
178
+ expect(actions[0]!.run().length).toBeGreaterThan(0);
179
+ expect(existsSync(paths.cursorSkillDir)).toBe(false);
180
+ });
140
181
  });
141
182
 
142
183
  /** Tests for app config wizard. */
@@ -121,7 +121,17 @@ function executePlan(
121
121
  if ("kind" in action && action.kind) {
122
122
  const skillTarget = skillTargetFromActionKind(action.kind);
123
123
  if (skillTarget) {
124
- changed.push(...runSkillAction(root, action.kind as InstallActionKind, opts));
124
+ const runResult = action.run();
125
+ if (runResult.length > 0) {
126
+ changed.push(...runResult);
127
+ } else if (opts.uninstall) {
128
+ const skillDir = skillDirFromUninstallSummary(action.summary, paths);
129
+ if (skillDir) {
130
+ changed.push(...uninstallSkillDir(skillDir, !!opts.dry));
131
+ }
132
+ } else {
133
+ changed.push(...runSkillAction(root, action.kind as InstallActionKind, opts));
134
+ }
125
135
  continue;
126
136
  }
127
137
  }
@@ -221,7 +231,7 @@ async function runInteractiveConfigure(root: CliProgram, opts: ConfigureOpts): P
221
231
  runTargetPreflight(root, paths, mutationOpts, installActions);
222
232
  }
223
233
 
224
- changed.push(...executePlan(root, actions, mutationOpts, true));
234
+ changed.push(...executePlan(root, actions, { ...mutationOpts, uninstall: choice === "uninstall" }, true));
225
235
  }
226
236
 
227
237
  return changed;
@@ -12,6 +12,7 @@ import type {
12
12
  TargetPlanContext,
13
13
  UninstallAction,
14
14
  } from "./target-types.ts";
15
+ import { uninstallSkillDir } from "./uninstall.ts";
15
16
 
16
17
  export interface SkillHostSpec {
17
18
  key: CliInstallArtifactKey;
@@ -97,7 +98,7 @@ export class SkillInstallTarget extends InstallTarget {
97
98
  kind: this.actionKind,
98
99
  summary: `${this.uninstallPrefix}: ${displayInstallPath(dir)}/`,
99
100
  message: `Removing ${this.spec.label} skill ${displayInstallPath(dir)}/`,
100
- run: () => [],
101
+ run: () => uninstallSkillDir(dir, ctx.dry),
101
102
  },
102
103
  ];
103
104
  }