buzz-agent-skill 0.1.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/LICENSE +17 -0
- package/README.md +47 -0
- package/bin/buzz-skill.mjs +194 -0
- package/package.json +35 -0
- package/skill/buzz/SKILL.md +87 -0
- package/skill/buzz/agents/openai.yaml +4 -0
- package/skill/buzz/references/commands.md +96 -0
- package/skill/buzz/references/installation.md +50 -0
- package/skill/buzz/scripts/check-buzz-cli.mjs +81 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
Copyright 2026 Thalix Inc.
|
|
6
|
+
|
|
7
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
you may not use this file except in compliance with the License.
|
|
9
|
+
You may obtain a copy of the License at
|
|
10
|
+
|
|
11
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
|
|
13
|
+
Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
See the License for the specific language governing permissions and
|
|
17
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Buzz Agent Skill
|
|
2
|
+
|
|
3
|
+
Installs and updates the Buzz CLI skill for Codex and Claude Code.
|
|
4
|
+
|
|
5
|
+
The package manages skill files only. The native `buzz` CLI remains owned by
|
|
6
|
+
Buzz Desktop or a source installation, so updating Buzz also updates the CLI.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npx buzz-agent-skill install
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
This installs the skill into:
|
|
15
|
+
|
|
16
|
+
- `~/.codex/skills/buzz`
|
|
17
|
+
- `~/.claude/skills/buzz`
|
|
18
|
+
|
|
19
|
+
## Update
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx buzz-agent-skill@latest update
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Check
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx buzz-agent-skill check
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The check reports skill versions, CLI availability, and whether Buzz
|
|
32
|
+
authentication variables are set. It never prints secret values.
|
|
33
|
+
|
|
34
|
+
## CLI installation
|
|
35
|
+
|
|
36
|
+
Buzz Desktop includes the native CLI. On macOS, the installer maintains:
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
~/.local/bin/buzz -> /Applications/Buzz.app/Contents/MacOS/buzz
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
For source builds:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
cargo build --release -p buzz-cli
|
|
46
|
+
```
|
|
47
|
+
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
4
|
+
import {
|
|
5
|
+
cpSync,
|
|
6
|
+
existsSync,
|
|
7
|
+
lstatSync,
|
|
8
|
+
mkdirSync,
|
|
9
|
+
readFileSync,
|
|
10
|
+
readlinkSync,
|
|
11
|
+
renameSync,
|
|
12
|
+
rmSync,
|
|
13
|
+
symlinkSync,
|
|
14
|
+
writeFileSync,
|
|
15
|
+
} from "node:fs";
|
|
16
|
+
import { homedir, platform } from "node:os";
|
|
17
|
+
import { dirname, join, resolve } from "node:path";
|
|
18
|
+
import { fileURLToPath } from "node:url";
|
|
19
|
+
|
|
20
|
+
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
21
|
+
const sourceSkill = join(packageRoot, "skill", "buzz");
|
|
22
|
+
const markerName = ".buzz-skill-package.json";
|
|
23
|
+
const targets = [
|
|
24
|
+
{ agent: "codex", path: join(homedir(), ".codex", "skills", "buzz") },
|
|
25
|
+
{ agent: "claude", path: join(homedir(), ".claude", "skills", "buzz") },
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
function packageVersion() {
|
|
29
|
+
return JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8"))
|
|
30
|
+
.version;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function marker(target) {
|
|
34
|
+
const path = join(target, markerName);
|
|
35
|
+
if (!existsSync(path)) return null;
|
|
36
|
+
try {
|
|
37
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
38
|
+
} catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function installTarget({ agent, path }, force) {
|
|
44
|
+
const existingMarker = marker(path);
|
|
45
|
+
if (existsSync(path) && !existingMarker && !force) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
`${agent}: ${path} exists but is not managed by buzz-agent-skill; rerun with --force to replace it`,
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
52
|
+
const staging = `${path}.staging-${process.pid}`;
|
|
53
|
+
const backup = `${path}.backup-${process.pid}`;
|
|
54
|
+
rmSync(staging, { recursive: true, force: true });
|
|
55
|
+
cpSync(sourceSkill, staging, { recursive: true });
|
|
56
|
+
writeFileSync(
|
|
57
|
+
join(staging, markerName),
|
|
58
|
+
`${JSON.stringify(
|
|
59
|
+
{
|
|
60
|
+
package: "buzz-agent-skill",
|
|
61
|
+
version: packageVersion(),
|
|
62
|
+
installed_at: new Date().toISOString(),
|
|
63
|
+
},
|
|
64
|
+
null,
|
|
65
|
+
2,
|
|
66
|
+
)}\n`,
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
if (existsSync(path)) renameSync(path, backup);
|
|
70
|
+
try {
|
|
71
|
+
renameSync(staging, path);
|
|
72
|
+
rmSync(backup, { recursive: true, force: true });
|
|
73
|
+
} catch (error) {
|
|
74
|
+
rmSync(path, { recursive: true, force: true });
|
|
75
|
+
if (existsSync(backup)) renameSync(backup, path);
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return { agent, path, version: packageVersion() };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function findBuzz() {
|
|
83
|
+
try {
|
|
84
|
+
return execFileSync(
|
|
85
|
+
platform() === "win32" ? "where" : "which",
|
|
86
|
+
["buzz"],
|
|
87
|
+
{ encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] },
|
|
88
|
+
)
|
|
89
|
+
.trim()
|
|
90
|
+
.split(/\r?\n/)[0];
|
|
91
|
+
} catch {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function ensureMacCliLink() {
|
|
97
|
+
if (platform() !== "darwin") return null;
|
|
98
|
+
const bundled = "/Applications/Buzz.app/Contents/MacOS/buzz";
|
|
99
|
+
if (!existsSync(bundled)) return null;
|
|
100
|
+
|
|
101
|
+
const link = join(homedir(), ".local", "bin", "buzz");
|
|
102
|
+
mkdirSync(dirname(link), { recursive: true });
|
|
103
|
+
if (existsSync(link) || lstatExists(link)) {
|
|
104
|
+
if (lstatSync(link).isSymbolicLink() && readlinkSync(link) === bundled) {
|
|
105
|
+
return link;
|
|
106
|
+
}
|
|
107
|
+
if (!lstatSync(link).isSymbolicLink()) return null;
|
|
108
|
+
rmSync(link);
|
|
109
|
+
}
|
|
110
|
+
symlinkSync(bundled, link);
|
|
111
|
+
return link;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function lstatExists(path) {
|
|
115
|
+
try {
|
|
116
|
+
lstatSync(path);
|
|
117
|
+
return true;
|
|
118
|
+
} catch {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function cliStatus() {
|
|
124
|
+
const linked = ensureMacCliLink();
|
|
125
|
+
const binary = findBuzz() ?? linked;
|
|
126
|
+
if (!binary) {
|
|
127
|
+
return {
|
|
128
|
+
ok: false,
|
|
129
|
+
message:
|
|
130
|
+
"Buzz CLI not found. Install Buzz Desktop or build `cargo build --release -p buzz-cli`.",
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
const help = execFileSync(binary, ["--help"], {
|
|
135
|
+
encoding: "utf8",
|
|
136
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
137
|
+
});
|
|
138
|
+
return { ok: help.includes("Buzz CLI"), path: binary };
|
|
139
|
+
} catch (error) {
|
|
140
|
+
return {
|
|
141
|
+
ok: false,
|
|
142
|
+
path: binary,
|
|
143
|
+
message: error instanceof Error ? error.message : String(error),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function status() {
|
|
149
|
+
return {
|
|
150
|
+
package_version: packageVersion(),
|
|
151
|
+
cli: cliStatus(),
|
|
152
|
+
skills: targets.map(({ agent, path }) => ({
|
|
153
|
+
agent,
|
|
154
|
+
path,
|
|
155
|
+
installed: existsSync(join(path, "SKILL.md")),
|
|
156
|
+
managed: Boolean(marker(path)),
|
|
157
|
+
version: marker(path)?.version ?? null,
|
|
158
|
+
})),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const [command = "check", ...args] = process.argv.slice(2);
|
|
163
|
+
const force = args.includes("--force");
|
|
164
|
+
|
|
165
|
+
try {
|
|
166
|
+
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));
|
|
170
|
+
if (!result.cli.ok) process.exitCode = 1;
|
|
171
|
+
} else if (command === "check") {
|
|
172
|
+
const result = status();
|
|
173
|
+
console.log(JSON.stringify(result, null, 2));
|
|
174
|
+
if (
|
|
175
|
+
!result.cli.ok ||
|
|
176
|
+
result.skills.some((skill) => !skill.installed || !skill.managed)
|
|
177
|
+
) {
|
|
178
|
+
process.exitCode = 1;
|
|
179
|
+
}
|
|
180
|
+
} else {
|
|
181
|
+
console.error(
|
|
182
|
+
"Usage: buzz-skill <install|update|check> [--force]",
|
|
183
|
+
);
|
|
184
|
+
process.exitCode = 1;
|
|
185
|
+
}
|
|
186
|
+
} catch (error) {
|
|
187
|
+
console.error(
|
|
188
|
+
JSON.stringify({
|
|
189
|
+
ok: false,
|
|
190
|
+
error: error instanceof Error ? error.message : String(error),
|
|
191
|
+
}),
|
|
192
|
+
);
|
|
193
|
+
process.exitCode = 1;
|
|
194
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "buzz-agent-skill",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Install and update the Buzz CLI skill for Codex and Claude Code",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"buzz-skill": "bin/buzz-skill.mjs"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin",
|
|
11
|
+
"skill"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"check": "node ./bin/buzz-skill.mjs check",
|
|
15
|
+
"install-skill": "node ./bin/buzz-skill.mjs install"
|
|
16
|
+
},
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=20"
|
|
19
|
+
},
|
|
20
|
+
"license": "Apache-2.0",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/thalixinc/buzz-agent-skill.git"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://github.com/thalixinc/buzz-agent-skill#readme",
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/thalixinc/buzz-agent-skill/issues"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"buzz",
|
|
31
|
+
"codex",
|
|
32
|
+
"claude-code",
|
|
33
|
+
"agent-skill"
|
|
34
|
+
]
|
|
35
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: buzz
|
|
3
|
+
description: Use the Buzz CLI to work with Buzz communities, channels, messages, threads, agents, canvases, workflows, memories, repositories, patches, issues, pull requests, media, profiles, and activity feeds. Use when Codex or Claude Code needs to inspect or act in Buzz, follow a buzz:// deep link, communicate with people or agents, validate persona packs, or diagnose Buzz CLI installation and authentication.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Buzz CLI
|
|
7
|
+
|
|
8
|
+
Use `buzz` as the primary interface. It is JSON-first and returns structured errors.
|
|
9
|
+
|
|
10
|
+
## Preflight
|
|
11
|
+
|
|
12
|
+
Run:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
node scripts/check-buzz-cli.mjs
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
If the script cannot find `buzz`, read [installation.md](references/installation.md).
|
|
19
|
+
|
|
20
|
+
Before a relay operation, verify configuration without printing secrets:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
test -n "${BUZZ_RELAY_URL:-}" && echo "BUZZ_RELAY_URL=set" || echo "BUZZ_RELAY_URL=unset"
|
|
24
|
+
test -n "${BUZZ_PRIVATE_KEY:-}" && echo "BUZZ_PRIVATE_KEY=set" || echo "BUZZ_PRIVATE_KEY=unset"
|
|
25
|
+
test -n "${BUZZ_AUTH_TAG:-}" && echo "BUZZ_AUTH_TAG=set" || echo "BUZZ_AUTH_TAG=unset"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Managed Buzz agents normally receive these values automatically. Never print, log, commit, or ask the user to paste a private key into chat.
|
|
29
|
+
|
|
30
|
+
## Discover commands
|
|
31
|
+
|
|
32
|
+
Treat the installed CLI help as authoritative:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
buzz --help
|
|
36
|
+
buzz <group> --help
|
|
37
|
+
buzz <group> <command> --help
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Do not guess flags from memory. Read [commands.md](references/commands.md) for common workflows.
|
|
41
|
+
|
|
42
|
+
## Operate safely
|
|
43
|
+
|
|
44
|
+
1. Start with read-only commands when resolving names, channel IDs, event IDs, or current state.
|
|
45
|
+
2. Use the global `--format compact` option before the command group for exploration, and omit it for full JSON when exact fields matter.
|
|
46
|
+
3. Parse JSON with `jq`; do not scrape human-formatted output.
|
|
47
|
+
4. Perform writes only when the user requested the corresponding change.
|
|
48
|
+
5. Re-read the affected object after a write and report the returned event or entity ID.
|
|
49
|
+
6. Treat channel deletion, archival, membership removal, moderation, workflow approval, and message deletion as consequential actions.
|
|
50
|
+
|
|
51
|
+
## Communicate correctly
|
|
52
|
+
|
|
53
|
+
- Send a top-level channel message without `--reply-to`.
|
|
54
|
+
- Reply inside an existing thread with `--reply-to <event-id>`.
|
|
55
|
+
- Add `--broadcast` only when the user explicitly wants publication to the wider Nostr network.
|
|
56
|
+
- Use stdin for multiline content:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
printf '%s\n' "$MESSAGE" | buzz messages send --channel <uuid> --content -
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Session prose is not delivered to Buzz. To answer a Buzz user, publish the response with `buzz messages send`.
|
|
63
|
+
|
|
64
|
+
For agent collaboration, mention an agent only when action or a response is required. Avoid agent-to-agent courtesy loops.
|
|
65
|
+
|
|
66
|
+
## Follow deep links
|
|
67
|
+
|
|
68
|
+
For `buzz://message?channel=<uuid>&id=<event-id>`, extract `channel` and `id`, then run:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
buzz --format compact messages thread --channel <uuid> --event <event-id>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Current Buzz builds resolve the thread from `id`. If an older installed CLI rejects a non-root `id` and the link includes `thread=<root-id>`, retry with that root ID.
|
|
75
|
+
|
|
76
|
+
## Handle failures
|
|
77
|
+
|
|
78
|
+
Interpret exit codes:
|
|
79
|
+
|
|
80
|
+
- `0`: success
|
|
81
|
+
- `1`: invalid input
|
|
82
|
+
- `2`: relay or network failure
|
|
83
|
+
- `3`: authentication failure
|
|
84
|
+
- `4`: other failure
|
|
85
|
+
- `5`: write conflict
|
|
86
|
+
|
|
87
|
+
Errors are JSON on stderr. Preserve the category and message when reporting a failure. On exit `5`, re-read current state before deciding whether to retry.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Common Buzz CLI workflows
|
|
2
|
+
|
|
3
|
+
Always confirm exact flags with `--help`.
|
|
4
|
+
|
|
5
|
+
## Find a channel
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
buzz --format compact channels list
|
|
9
|
+
buzz --format compact channels search --query "name"
|
|
10
|
+
buzz channels get --channel <uuid>
|
|
11
|
+
buzz channels members --channel <uuid>
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Read conversation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
buzz --format compact messages get --channel <uuid> --limit 30
|
|
18
|
+
buzz --format compact messages thread --channel <uuid> --event <event-id>
|
|
19
|
+
buzz --format compact messages search --query "terms"
|
|
20
|
+
buzz --format compact feed get
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Send messages
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
buzz messages send --channel <uuid> --content "Top-level update"
|
|
27
|
+
buzz messages send --channel <uuid> --content "Thread reply" --reply-to <event-id>
|
|
28
|
+
printf '%s\n' "$BODY" | buzz messages send --channel <uuid> --content -
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`--broadcast` also publishes to the wider Nostr network. Do not add it unless explicitly requested.
|
|
32
|
+
|
|
33
|
+
## Users and profiles
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
buzz users get
|
|
37
|
+
buzz users get --pubkey <hex-or-npub>
|
|
38
|
+
buzz users get --name "Stephan"
|
|
39
|
+
buzz users presence --pubkey <hex>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Agents
|
|
43
|
+
|
|
44
|
+
Agent creation and updates are owner-reviewed:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
buzz agents draft-create --help
|
|
48
|
+
buzz agents draft-update --help
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
These commands open a prefilled form in the owner's Buzz Desktop. Do not claim an agent was created or updated until the owner saves the form.
|
|
52
|
+
|
|
53
|
+
## Canvases and workflows
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
buzz canvas get --channel <uuid>
|
|
57
|
+
buzz workflows list --channel <uuid>
|
|
58
|
+
buzz workflows get --workflow <uuid>
|
|
59
|
+
buzz workflows runs --workflow <uuid>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Workflow creation, triggering, approval, denial, and deletion are writes.
|
|
63
|
+
|
|
64
|
+
## Persistent agent memory
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
buzz mem ls
|
|
68
|
+
buzz mem get <slug>
|
|
69
|
+
buzz mem hash <slug>
|
|
70
|
+
buzz mem set <slug> -
|
|
71
|
+
buzz mem patch <slug> --base-hash <sha256>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Prefer `patch` with a current base hash for concurrent updates. Do not delete memory unless explicitly requested.
|
|
75
|
+
|
|
76
|
+
## Persona packs
|
|
77
|
+
|
|
78
|
+
These run locally:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
buzz pack validate <directory>
|
|
82
|
+
buzz pack inspect <directory>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Git collaboration
|
|
86
|
+
|
|
87
|
+
Discover exact subcommands before acting:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
buzz repos --help
|
|
91
|
+
buzz patches --help
|
|
92
|
+
buzz issues --help
|
|
93
|
+
buzz pr --help
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Read repository and branch-protection state before writes.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Buzz CLI installation
|
|
2
|
+
|
|
3
|
+
## Check first
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
command -v buzz
|
|
7
|
+
buzz --help
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Packaged Buzz Desktop
|
|
11
|
+
|
|
12
|
+
Buzz Desktop includes the native CLI.
|
|
13
|
+
|
|
14
|
+
On macOS:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
mkdir -p "$HOME/.local/bin"
|
|
18
|
+
ln -sfn /Applications/Buzz.app/Contents/MacOS/buzz "$HOME/.local/bin/buzz"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Ensure `$HOME/.local/bin` is on `PATH`.
|
|
22
|
+
|
|
23
|
+
Do not copy the binary out of the application bundle. The symlink lets a Buzz Desktop update update the CLI too.
|
|
24
|
+
|
|
25
|
+
## Source checkout
|
|
26
|
+
|
|
27
|
+
From the Buzz repository:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
cargo build --release -p buzz-cli
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The binary is `target/release/buzz`. Alternatively:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
cargo install --path crates/buzz-cli
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Authentication
|
|
40
|
+
|
|
41
|
+
Relay commands require:
|
|
42
|
+
|
|
43
|
+
- `BUZZ_RELAY_URL`
|
|
44
|
+
- `BUZZ_PRIVATE_KEY`
|
|
45
|
+
- optionally `BUZZ_AUTH_TAG`
|
|
46
|
+
|
|
47
|
+
Managed agents receive these from the Buzz harness. For standalone shells, configure them through the user's existing secret-management workflow. Never echo the values or place them in repository files.
|
|
48
|
+
|
|
49
|
+
The local `buzz pack` commands do not require relay authentication.
|
|
50
|
+
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
4
|
+
import { existsSync, lstatSync, readlinkSync } from "node:fs";
|
|
5
|
+
import { homedir, platform } from "node:os";
|
|
6
|
+
import { delimiter, join } from "node:path";
|
|
7
|
+
|
|
8
|
+
function findOnPath(name) {
|
|
9
|
+
const extensions = platform() === "win32" ? ["", ".exe", ".cmd"] : [""];
|
|
10
|
+
for (const directory of (process.env.PATH ?? "").split(delimiter)) {
|
|
11
|
+
if (!directory) continue;
|
|
12
|
+
for (const extension of extensions) {
|
|
13
|
+
const candidate = join(directory, `${name}${extension}`);
|
|
14
|
+
if (existsSync(candidate)) return candidate;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const pathBinary = findOnPath("buzz");
|
|
21
|
+
const macBundledBinary = "/Applications/Buzz.app/Contents/MacOS/buzz";
|
|
22
|
+
const bundledBinary =
|
|
23
|
+
platform() === "darwin" && existsSync(macBundledBinary)
|
|
24
|
+
? macBundledBinary
|
|
25
|
+
: null;
|
|
26
|
+
|
|
27
|
+
const binary = pathBinary ?? bundledBinary;
|
|
28
|
+
if (!binary) {
|
|
29
|
+
console.error(
|
|
30
|
+
JSON.stringify({
|
|
31
|
+
ok: false,
|
|
32
|
+
error: "buzz_cli_missing",
|
|
33
|
+
message:
|
|
34
|
+
"Install Buzz Desktop or build buzz-cli from the Buzz source repository.",
|
|
35
|
+
}),
|
|
36
|
+
);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let help;
|
|
41
|
+
try {
|
|
42
|
+
help = execFileSync(binary, ["--help"], {
|
|
43
|
+
encoding: "utf8",
|
|
44
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
45
|
+
});
|
|
46
|
+
} catch (error) {
|
|
47
|
+
console.error(
|
|
48
|
+
JSON.stringify({
|
|
49
|
+
ok: false,
|
|
50
|
+
error: "buzz_cli_unusable",
|
|
51
|
+
path: binary,
|
|
52
|
+
message: error instanceof Error ? error.message : String(error),
|
|
53
|
+
}),
|
|
54
|
+
);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const localLink = join(homedir(), ".local", "bin", "buzz");
|
|
59
|
+
let linkTarget = null;
|
|
60
|
+
if (existsSync(localLink) && lstatSync(localLink).isSymbolicLink()) {
|
|
61
|
+
linkTarget = readlinkSync(localLink);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
console.log(
|
|
65
|
+
JSON.stringify(
|
|
66
|
+
{
|
|
67
|
+
ok: help.includes("Buzz CLI"),
|
|
68
|
+
path: binary,
|
|
69
|
+
local_link: existsSync(localLink) ? localLink : null,
|
|
70
|
+
local_link_target: linkTarget,
|
|
71
|
+
configuration: {
|
|
72
|
+
relay_url: process.env.BUZZ_RELAY_URL ? "set" : "unset",
|
|
73
|
+
private_key: process.env.BUZZ_PRIVATE_KEY ? "set" : "unset",
|
|
74
|
+
auth_tag: process.env.BUZZ_AUTH_TAG ? "set" : "unset",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
null,
|
|
78
|
+
2,
|
|
79
|
+
),
|
|
80
|
+
);
|
|
81
|
+
|