buzz-agent-skill 0.1.0 → 0.2.0

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/README.md CHANGED
@@ -8,7 +8,7 @@ Buzz Desktop or a source installation, so updating Buzz also updates the CLI.
8
8
  ## Install
9
9
 
10
10
  ```bash
11
- npx buzz-agent-skill install
11
+ npx buzz-agent-skill@latest install
12
12
  ```
13
13
 
14
14
  This installs the skill into:
@@ -22,14 +22,28 @@ This installs the skill into:
22
22
  npx buzz-agent-skill@latest update
23
23
  ```
24
24
 
25
+ ## Uninstall
26
+
27
+ ```bash
28
+ npx buzz-agent-skill@latest uninstall
29
+ ```
30
+
25
31
  ## Check
26
32
 
27
33
  ```bash
28
- npx buzz-agent-skill check
34
+ npx buzz-agent-skill@latest check
29
35
  ```
30
36
 
31
- The check reports skill versions, CLI availability, and whether Buzz
32
- authentication variables are set. It never prints secret values.
37
+ Commands print a concise, human-readable summary by default.
38
+
39
+ Add `--json` to any command for machine-readable output:
40
+
41
+ ```bash
42
+ npx buzz-agent-skill@latest install --json
43
+ npx buzz-agent-skill@latest update --json
44
+ npx buzz-agent-skill@latest uninstall --json
45
+ npx buzz-agent-skill@latest check --json
46
+ ```
33
47
 
34
48
  ## CLI installation
35
49
 
@@ -44,4 +58,3 @@ For source builds:
44
58
  ```bash
45
59
  cargo build --release -p buzz-cli
46
60
  ```
47
-
@@ -20,9 +20,10 @@ import { fileURLToPath } from "node:url";
20
20
  const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
21
21
  const sourceSkill = join(packageRoot, "skill", "buzz");
22
22
  const markerName = ".buzz-skill-package.json";
23
+ const skillHome = process.env.BUZZ_SKILL_HOME || homedir();
23
24
  const targets = [
24
- { agent: "codex", path: join(homedir(), ".codex", "skills", "buzz") },
25
- { agent: "claude", path: join(homedir(), ".claude", "skills", "buzz") },
25
+ { agent: "codex", path: join(skillHome, ".codex", "skills", "buzz") },
26
+ { agent: "claude", path: join(skillHome, ".claude", "skills", "buzz") },
26
27
  ];
27
28
 
28
29
  function packageVersion() {
@@ -79,6 +80,20 @@ function installTarget({ agent, path }, force) {
79
80
  return { agent, path, version: packageVersion() };
80
81
  }
81
82
 
83
+ function uninstallTarget({ agent, path }, force) {
84
+ if (!existsSync(path)) {
85
+ return { agent, path, removed: false, reason: "not installed" };
86
+ }
87
+ if (!marker(path) && !force) {
88
+ throw new Error(
89
+ `${agent}: ${path} is not managed by buzz-agent-skill; rerun with --force to remove it`,
90
+ );
91
+ }
92
+
93
+ rmSync(path, { recursive: true, force: true });
94
+ return { agent, path, removed: true };
95
+ }
96
+
82
97
  function findBuzz() {
83
98
  try {
84
99
  return execFileSync(
@@ -98,7 +113,7 @@ function ensureMacCliLink() {
98
113
  const bundled = "/Applications/Buzz.app/Contents/MacOS/buzz";
99
114
  if (!existsSync(bundled)) return null;
100
115
 
101
- const link = join(homedir(), ".local", "bin", "buzz");
116
+ const link = join(skillHome, ".local", "bin", "buzz");
102
117
  mkdirSync(dirname(link), { recursive: true });
103
118
  if (existsSync(link) || lstatExists(link)) {
104
119
  if (lstatSync(link).isSymbolicLink() && readlinkSync(link) === bundled) {
@@ -159,36 +174,142 @@ function status() {
159
174
  };
160
175
  }
161
176
 
177
+ function formatStatus(result) {
178
+ const lines = [
179
+ `Buzz Agent Skill v${result.package_version}`,
180
+ "",
181
+ `${result.cli.ok ? "✓" : "✗"} Buzz CLI${
182
+ result.cli.path ? ` ${result.cli.path}` : ""
183
+ }`,
184
+ ];
185
+
186
+ if (!result.cli.ok && result.cli.message) {
187
+ lines.push(` ${result.cli.message}`);
188
+ }
189
+
190
+ lines.push("", "Agent skills");
191
+ for (const skill of result.skills) {
192
+ const ok = skill.installed && skill.managed;
193
+ const details = [
194
+ skill.installed ? "installed" : "not installed",
195
+ skill.managed ? "managed" : "not managed",
196
+ skill.version ? `v${skill.version}` : null,
197
+ ]
198
+ .filter(Boolean)
199
+ .join(" · ");
200
+ lines.push(
201
+ `${ok ? "✓" : "✗"} ${skill.agent.padEnd(7)} ${details}`,
202
+ ` ${skill.path}`,
203
+ );
204
+ }
205
+
206
+ const healthy =
207
+ result.cli.ok &&
208
+ result.skills.every((skill) => skill.installed && skill.managed);
209
+ lines.push("", healthy ? "Everything looks good." : "Some items need attention.");
210
+ return lines.join("\n");
211
+ }
212
+
213
+ function formatChange(result) {
214
+ const verbs = {
215
+ install: "Installed",
216
+ update: "Updated",
217
+ uninstall: "Uninstalled",
218
+ };
219
+ const lines = [
220
+ `${verbs[result.action]} Buzz Agent Skill v${result.package_version}`,
221
+ "",
222
+ ];
223
+
224
+ for (const skill of result.skills) {
225
+ const changed =
226
+ result.action === "uninstall" ? skill.removed : Boolean(skill.version);
227
+ const detail = changed
228
+ ? result.action === "uninstall"
229
+ ? "removed"
230
+ : `v${skill.version}`
231
+ : skill.reason;
232
+ lines.push(
233
+ `${changed ? "✓" : "–"} ${skill.agent.padEnd(7)} ${detail}`,
234
+ ` ${skill.path}`,
235
+ );
236
+ }
237
+
238
+ if (result.cli) {
239
+ lines.push(
240
+ "",
241
+ `${result.cli.ok ? "✓" : "✗"} Buzz CLI${
242
+ result.cli.path ? ` ${result.cli.path}` : ""
243
+ }`,
244
+ );
245
+ if (!result.cli.ok && result.cli.message) {
246
+ lines.push(` ${result.cli.message}`);
247
+ }
248
+ }
249
+
250
+ lines.push("", "Done.");
251
+ return lines.join("\n");
252
+ }
253
+
254
+ function usage() {
255
+ return [
256
+ "Buzz Agent Skill",
257
+ "",
258
+ "Usage:",
259
+ " buzz-skill install [--force] [--json]",
260
+ " buzz-skill update [--force] [--json]",
261
+ " buzz-skill uninstall [--force] [--json]",
262
+ " buzz-skill check [--json]",
263
+ "",
264
+ "Options:",
265
+ " --force Replace or remove skill folders not managed by this package",
266
+ " --json Print machine-readable JSON",
267
+ " --help Show this help",
268
+ ].join("\n");
269
+ }
270
+
162
271
  const [command = "check", ...args] = process.argv.slice(2);
163
272
  const force = args.includes("--force");
273
+ const json = args.includes("--json");
164
274
 
165
275
  try {
166
276
  if (command === "install" || command === "update") {
167
- const installed = targets.map((target) => installTarget(target, force));
168
- const result = { installed, cli: cliStatus() };
169
- console.log(JSON.stringify(result, null, 2));
277
+ const result = {
278
+ action: command,
279
+ package_version: packageVersion(),
280
+ skills: targets.map((target) => installTarget(target, force)),
281
+ cli: cliStatus(),
282
+ };
283
+ console.log(json ? JSON.stringify(result, null, 2) : formatChange(result));
170
284
  if (!result.cli.ok) process.exitCode = 1;
285
+ } else if (command === "uninstall") {
286
+ const result = {
287
+ action: command,
288
+ package_version: packageVersion(),
289
+ skills: targets.map((target) => uninstallTarget(target, force)),
290
+ };
291
+ console.log(json ? JSON.stringify(result, null, 2) : formatChange(result));
171
292
  } else if (command === "check") {
172
293
  const result = status();
173
- console.log(JSON.stringify(result, null, 2));
294
+ console.log(json ? JSON.stringify(result, null, 2) : formatStatus(result));
174
295
  if (
175
296
  !result.cli.ok ||
176
297
  result.skills.some((skill) => !skill.installed || !skill.managed)
177
298
  ) {
178
299
  process.exitCode = 1;
179
300
  }
301
+ } else if (command === "help" || command === "--help" || command === "-h") {
302
+ console.log(usage());
180
303
  } else {
181
- console.error(
182
- "Usage: buzz-skill <install|update|check> [--force]",
183
- );
304
+ console.error(usage());
184
305
  process.exitCode = 1;
185
306
  }
186
307
  } catch (error) {
308
+ const message = error instanceof Error ? error.message : String(error);
187
309
  console.error(
188
- JSON.stringify({
189
- ok: false,
190
- error: error instanceof Error ? error.message : String(error),
191
- }),
310
+ json
311
+ ? JSON.stringify({ ok: false, command, error: message }, null, 2)
312
+ : `✗ ${command} failed\n\n${message}`,
192
313
  );
193
314
  process.exitCode = 1;
194
315
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "buzz-agent-skill",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Install and update the Buzz CLI skill for Codex and Claude Code",
5
5
  "type": "module",
6
6
  "bin": {
@@ -12,7 +12,8 @@
12
12
  ],
13
13
  "scripts": {
14
14
  "check": "node ./bin/buzz-skill.mjs check",
15
- "install-skill": "node ./bin/buzz-skill.mjs install"
15
+ "install-skill": "node ./bin/buzz-skill.mjs install",
16
+ "uninstall-skill": "node ./bin/buzz-skill.mjs uninstall"
16
17
  },
17
18
  "engines": {
18
19
  "node": ">=20"