@tealbrick/kit 0.3.0-rc.7 → 0.3.0-rc.8
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/BOOTSTRAP.md +3 -3
- package/BUZZ.md +135 -0
- package/NATIVE.md +2 -2
- package/README.md +65 -2
- package/assets/buzz/buzz-backend-provider.py +99 -0
- package/assets/buzz/buzz-plist.py +22 -0
- package/assets/buzz/buzz-run.sh +39 -0
- package/assets/buzz/tb-provider-apply.py +97 -0
- package/dist/buzz.d.ts +63 -0
- package/dist/buzz.js +262 -0
- package/dist/cli.js +6 -1
- package/dist/index.d.ts +14 -14
- package/dist/native-acp.d.ts +36 -0
- package/dist/native-acp.js +219 -0
- package/dist/native-buzz.d.ts +128 -0
- package/dist/native-buzz.js +508 -0
- package/dist/native-claude.d.ts +31 -1
- package/dist/native-claude.js +199 -16
- package/dist/native-serve-config.d.ts +18 -0
- package/dist/native-serve-config.js +38 -5
- package/dist/native.d.ts +1 -1
- package/dist/native.js +11 -1
- package/package.json +9 -7
package/dist/buzz.js
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { chmod, copyFile, lstat, mkdir, readFile, readdir, rename, stat, unlink, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { execFile } from 'node:child_process';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import { delimiter, dirname, isAbsolute, join, resolve } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { promisify } from 'node:util';
|
|
8
|
+
/** Buzz Desktop managed-agent provider (client Mac) and its agent host (Mac running buzz-acp + kit native acp). */
|
|
9
|
+
const run = promisify(execFile);
|
|
10
|
+
const assets = fileURLToPath(new URL('../assets/buzz/', import.meta.url));
|
|
11
|
+
export const PROVIDER_MARKER = 'tealbrick-buzz-provider';
|
|
12
|
+
export const buzzUsage = `Usage: tealbrick buzz provider install [--name NAME] [--bin-dir DIRECTORY] [--force]
|
|
13
|
+
tealbrick buzz host setup [--owners-dir DIRECTORY] [--buzz-app PATH] [--node PATH] [--kit-cli PATH] [--respond-to-default owner-only|anyone]
|
|
14
|
+
tealbrick buzz host remove <label>`;
|
|
15
|
+
async function kitVersion() { return JSON.parse(await readFile(new URL('../package.json', import.meta.url), 'utf8')).version; }
|
|
16
|
+
function flagsOf(args, values, switches) {
|
|
17
|
+
const flags = {};
|
|
18
|
+
for (let i = 0; i < args.length; i++) {
|
|
19
|
+
const name = /^--([a-z-]+)$/.exec(args[i])?.[1];
|
|
20
|
+
if (!name || flags[name] !== undefined)
|
|
21
|
+
throw Error('kit_buzz_invalid_arguments');
|
|
22
|
+
if (switches.includes(name)) {
|
|
23
|
+
flags[name] = true;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (!values.includes(name) || !args[i + 1] || args[i + 1].startsWith('--'))
|
|
27
|
+
throw Error('kit_buzz_invalid_arguments');
|
|
28
|
+
flags[name] = args[++i];
|
|
29
|
+
}
|
|
30
|
+
return flags;
|
|
31
|
+
}
|
|
32
|
+
function expand(path, home) { return resolve(path === '~' ? home : path.startsWith('~/') ? join(home, path.slice(2)) : path); }
|
|
33
|
+
async function exists(path) { try {
|
|
34
|
+
await stat(path);
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return false;
|
|
39
|
+
} }
|
|
40
|
+
async function writeAtomic(path, body, mode) {
|
|
41
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
42
|
+
await writeFile(tmp, body, { mode });
|
|
43
|
+
await chmod(tmp, mode);
|
|
44
|
+
await rename(tmp, path);
|
|
45
|
+
}
|
|
46
|
+
/** Paths end up in a shell script and in buzz-acp's comma-separated BUZZ_ACP_AGENT_ARGS. */
|
|
47
|
+
function hostPath(name, path) {
|
|
48
|
+
if (!isAbsolute(path) || /[,\x00-\x1f\x7f]/.test(path))
|
|
49
|
+
throw Error(`kit_buzz_${name}_path_invalid`);
|
|
50
|
+
return path;
|
|
51
|
+
}
|
|
52
|
+
function shellQuote(value) { return `'${value.replace(/'/g, `'\\''`)}'`; }
|
|
53
|
+
async function python3Ok() { try {
|
|
54
|
+
await run('/usr/bin/python3', ['-c', 'import json, plistlib']);
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return false;
|
|
59
|
+
} }
|
|
60
|
+
export async function installProvider(options = {}) {
|
|
61
|
+
const home = options.home ?? homedir(), name = options.name ?? 'tealbrick-mac';
|
|
62
|
+
if (!/^[a-z0-9-]{3,40}$/.test(name))
|
|
63
|
+
throw Error('kit_buzz_provider_name_invalid');
|
|
64
|
+
const binDir = expand(options.binDir ?? '~/.local/bin', home), path = join(binDir, `buzz-backend-${name}`);
|
|
65
|
+
let existing;
|
|
66
|
+
try {
|
|
67
|
+
existing = await readFile(path, 'utf8');
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (error?.code !== 'ENOENT')
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
if (existing !== undefined && !existing.split('\n', 3).some(line => line.includes(PROVIDER_MARKER)) && !options.force)
|
|
74
|
+
throw Error('kit_buzz_provider_foreign_file');
|
|
75
|
+
const version = await kitVersion();
|
|
76
|
+
const body = (await readFile(join(assets, 'buzz-backend-provider.py'), 'utf8')).replaceAll('__TB_PROVIDER_ID__', name).replaceAll('__TB_KIT_VERSION__', version);
|
|
77
|
+
await mkdir(binDir, { recursive: true });
|
|
78
|
+
await writeAtomic(path, body, 0o755);
|
|
79
|
+
const onPath = (process.env.PATH ?? '').split(delimiter).some(entry => entry && resolve(entry) === binDir);
|
|
80
|
+
return { path, name, version, updated: existing !== undefined, discoverable: onPath || binDir === join(home, '.local', 'bin'), python3: await python3Ok() };
|
|
81
|
+
}
|
|
82
|
+
async function npmInstallKit(prefix, version) {
|
|
83
|
+
const local = join(dirname(process.execPath), 'npm');
|
|
84
|
+
const npm = await exists(local) ? local : 'npm';
|
|
85
|
+
try {
|
|
86
|
+
await run(npm, ['install', '--prefix', prefix, '--no-audit', '--no-fund', '--save-exact', `@tealbrick/kit@${version}`], { maxBuffer: 16 * 1024 * 1024 });
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
throw Error('kit_buzz_kit_install_failed');
|
|
90
|
+
}
|
|
91
|
+
return join(prefix, 'node_modules', '@tealbrick', 'kit', 'dist', 'cli.js');
|
|
92
|
+
}
|
|
93
|
+
async function bundleVersion(app) {
|
|
94
|
+
const plist = join(app, 'Contents', 'Info.plist');
|
|
95
|
+
try {
|
|
96
|
+
const { stdout } = await run('/usr/bin/plutil', ['-extract', 'CFBundleShortVersionString', 'raw', '-o', '-', plist]);
|
|
97
|
+
if (stdout.trim())
|
|
98
|
+
return stdout.trim();
|
|
99
|
+
}
|
|
100
|
+
catch { }
|
|
101
|
+
try {
|
|
102
|
+
const text = await readFile(plist, 'utf8');
|
|
103
|
+
return /<key>CFBundleShortVersionString<\/key>\s*<string>([^<]+)<\/string>/.exec(text)?.[1] ?? 'unknown';
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return 'unknown';
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async function sha256(path) { return createHash('sha256').update(await readFile(path)).digest('hex'); }
|
|
110
|
+
export async function setupBuzzHost(options = {}) {
|
|
111
|
+
const home = options.home ?? homedir(), version = await kitVersion();
|
|
112
|
+
if (options.respondToDefault !== undefined && !['owner-only', 'anyone'].includes(options.respondToDefault))
|
|
113
|
+
throw Error('kit_buzz_respond_to_default_invalid');
|
|
114
|
+
const ownersDir = hostPath('owners_dir', expand(options.ownersDir ?? '~/agents/tealbrick-connections', home));
|
|
115
|
+
const app = expand(options.buzzApp ?? '/Applications/Buzz.app', home);
|
|
116
|
+
const node = hostPath('node', expand(options.node ?? process.execPath, home));
|
|
117
|
+
if (!(await stat(node).catch(() => undefined))?.isFile())
|
|
118
|
+
throw Error('kit_buzz_node_missing');
|
|
119
|
+
const sources = { buzz: join(app, 'Contents', 'MacOS', 'buzz'), 'buzz-acp': join(app, 'Contents', 'MacOS', 'buzz-acp') };
|
|
120
|
+
for (const source of Object.values(sources))
|
|
121
|
+
if (!(await stat(source).catch(() => undefined))?.isFile())
|
|
122
|
+
throw Error('kit_buzz_app_binaries_missing');
|
|
123
|
+
const root = join(home, 'agents', 'buzz'), bin = join(root, 'bin'), runtime = join(root, 'runtime');
|
|
124
|
+
for (const dir of [root, bin, runtime]) {
|
|
125
|
+
await mkdir(dir, { recursive: true, mode: 0o700 });
|
|
126
|
+
await chmod(dir, 0o700);
|
|
127
|
+
}
|
|
128
|
+
const buzzBin = hostPath('buzz_bin', join(bin, 'buzz')), buzzAcpBin = hostPath('buzz_acp_bin', join(bin, 'buzz-acp'));
|
|
129
|
+
// Copy then rename, so a running buzz-acp keeps its inode and a Buzz.app update never changes agents silently.
|
|
130
|
+
for (const [source, target] of [[sources.buzz, buzzBin], [sources['buzz-acp'], buzzAcpBin]]) {
|
|
131
|
+
const tmp = `${target}.${process.pid}.tmp`;
|
|
132
|
+
await copyFile(source, tmp);
|
|
133
|
+
await chmod(tmp, 0o755);
|
|
134
|
+
await rename(tmp, target);
|
|
135
|
+
}
|
|
136
|
+
const kitCli = hostPath('kit_cli', options.kitCli ? expand(options.kitCli, home) : await (options.installKit ?? npmInstallKit)(runtime, version));
|
|
137
|
+
if (!(await stat(kitCli).catch(() => undefined))?.isFile())
|
|
138
|
+
throw Error('kit_buzz_kit_cli_missing');
|
|
139
|
+
const host = { version: 1, kitVersion: version, node, kitCli, ownersDir, buzzBin, buzzAcpBin, buzzAppVersion: await bundleVersion(app),
|
|
140
|
+
buzzSha256: { buzz: await sha256(buzzBin), 'buzz-acp': await sha256(buzzAcpBin) } };
|
|
141
|
+
await writeAtomic(join(root, 'host.json'), JSON.stringify(host, null, 1) + '\n', 0o600);
|
|
142
|
+
const values = { NODE: node, KIT_CLI: kitCli, OWNERS_DIR: ownersDir, BUZZ_BIN: buzzBin, BUZZ_ACP_BIN: buzzAcpBin };
|
|
143
|
+
const runner = (await readFile(join(assets, 'buzz-run.sh'), 'utf8')).replace(/@@([A-Z_]+)@@/g, (_, key) => { if (!Object.hasOwn(values, key))
|
|
144
|
+
throw Error('kit_buzz_asset_placeholder_unknown'); return shellQuote(values[key]); });
|
|
145
|
+
await writeAtomic(join(bin, 'buzz-run.sh'), runner, 0o700);
|
|
146
|
+
for (const script of ['buzz-plist.py', 'tb-provider-apply.py'])
|
|
147
|
+
await writeAtomic(join(bin, script), await readFile(join(assets, script)), 0o700);
|
|
148
|
+
if (options.respondToDefault)
|
|
149
|
+
await writeAtomic(join(root, 'fleet-defaults.json'), JSON.stringify({ respond_to: options.respondToDefault }) + '\n', 0o600);
|
|
150
|
+
const owners = [];
|
|
151
|
+
try {
|
|
152
|
+
for (const entry of await readdir(ownersDir, { withFileTypes: true }))
|
|
153
|
+
if (entry.isDirectory() && /^[a-z0-9-]{2,32}$/.test(entry.name) && await exists(join(ownersDir, entry.name, '.tealbrick', 'native-serve.json')))
|
|
154
|
+
owners.push(entry.name);
|
|
155
|
+
}
|
|
156
|
+
catch { }
|
|
157
|
+
const warnings = [];
|
|
158
|
+
if (!await python3Ok())
|
|
159
|
+
warnings.push('/usr/bin/python3 is not usable; install the Xcode Command Line Tools (xcode-select --install).');
|
|
160
|
+
if (!owners.length)
|
|
161
|
+
warnings.push(`No enrolled kit owners under ${ownersDir}; run \`tealbrick native setup\` and \`tealbrick native enroll\` in ${ownersDir}/<owner>.`);
|
|
162
|
+
return { hostJson: join(root, 'host.json'), ...host, scripts: ['buzz-run.sh', 'buzz-plist.py', 'tb-provider-apply.py'].map(name => join(bin, name)),
|
|
163
|
+
fleetDefaults: options.respondToDefault ?? null, owners, warnings };
|
|
164
|
+
}
|
|
165
|
+
const launchctl = args => run('/bin/launchctl', args).then(() => 0, (e) => typeof e?.code === 'number' ? e.code : 1);
|
|
166
|
+
const AGENT_LABEL = /^[a-z0-9][a-z0-9-]{2,62}$/;
|
|
167
|
+
/** Names under ~/agents/buzz that are host files, never agents. */
|
|
168
|
+
const RESERVED_LABELS = ['bin', 'runtime', 'logs'];
|
|
169
|
+
/**
|
|
170
|
+
* Remove one provider-managed agent from this host (Buzz Desktop has no undeploy operation): boot out its
|
|
171
|
+
* launchd unit, delete the plist and move ~/agents/buzz/<label> to ~/agents/buzz/.removed/<label>-<ts>
|
|
172
|
+
* (0700; it still holds the agent key until you delete it).
|
|
173
|
+
*/
|
|
174
|
+
export async function removeBuzzAgent(label, options = {}) {
|
|
175
|
+
if (!AGENT_LABEL.test(label) || RESERVED_LABELS.includes(label))
|
|
176
|
+
throw Error('kit_buzz_label_invalid');
|
|
177
|
+
const home = options.home ?? homedir(), uid = options.uid ?? process.getuid?.() ?? 0, unit = `com.tealbrick.buzz-acp.${label}`, service = `gui/${uid}/${unit}`;
|
|
178
|
+
const root = join(home, 'agents', 'buzz'), dir = join(root, label), plist = join(home, 'Library', 'LaunchAgents', `${unit}.plist`);
|
|
179
|
+
const exec = options.launchctl ?? launchctl;
|
|
180
|
+
const loaded = await exec(['print', service]) === 0;
|
|
181
|
+
if (loaded && await exec(['bootout', service]) !== 0)
|
|
182
|
+
throw Error('kit_buzz_bootout_failed');
|
|
183
|
+
const plistStat = await lstat(plist).catch(() => undefined);
|
|
184
|
+
if (plistStat) {
|
|
185
|
+
if (!plistStat.isFile() || plistStat.isSymbolicLink())
|
|
186
|
+
throw Error('kit_buzz_plist_unsafe');
|
|
187
|
+
await unlink(plist);
|
|
188
|
+
}
|
|
189
|
+
const dirStat = await lstat(dir).catch(() => undefined);
|
|
190
|
+
let movedTo;
|
|
191
|
+
if (dirStat) {
|
|
192
|
+
if (!dirStat.isDirectory() || dirStat.isSymbolicLink())
|
|
193
|
+
throw Error('kit_buzz_agent_dir_unsafe');
|
|
194
|
+
const removed = join(root, '.removed');
|
|
195
|
+
await mkdir(removed, { recursive: true, mode: 0o700 });
|
|
196
|
+
const removedStat = await lstat(removed);
|
|
197
|
+
if (!removedStat.isDirectory() || removedStat.isSymbolicLink())
|
|
198
|
+
throw Error('kit_buzz_removed_dir_unsafe');
|
|
199
|
+
await chmod(removed, 0o700);
|
|
200
|
+
movedTo = join(removed, `${label}-${(options.now?.() ?? new Date()).toISOString().replace(/[:.]/g, '-')}`);
|
|
201
|
+
await rename(dir, movedTo);
|
|
202
|
+
await chmod(movedTo, 0o700);
|
|
203
|
+
}
|
|
204
|
+
if (!loaded && !plistStat && !dirStat)
|
|
205
|
+
throw Error('kit_buzz_agent_not_found');
|
|
206
|
+
return { label, service, bootedOut: loaded, plistRemoved: !!plistStat, movedTo };
|
|
207
|
+
}
|
|
208
|
+
export async function buzzCommand(args) {
|
|
209
|
+
const [group, action, ...rest] = args;
|
|
210
|
+
if (!group || group === 'help' || group === '--help' || group === '-h') {
|
|
211
|
+
console.log(buzzUsage);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (group === 'provider' && action === 'install') {
|
|
215
|
+
const flags = flagsOf(rest, ['name', 'bin-dir'], ['force']);
|
|
216
|
+
const result = await installProvider({ ...(typeof flags.name === 'string' ? { name: flags.name } : {}), ...(typeof flags['bin-dir'] === 'string' ? { binDir: flags['bin-dir'] } : {}), force: flags.force === true });
|
|
217
|
+
console.log(`${result.updated ? 'Updated' : 'Installed'} Buzz Desktop provider ${result.name} (kit ${result.version}):\n ${result.path}`);
|
|
218
|
+
if (!result.discoverable)
|
|
219
|
+
console.log(`Warning: ${dirname(result.path)} is not on PATH; Buzz Desktop looks in ~/.local/bin and on PATH.`);
|
|
220
|
+
if (!result.python3)
|
|
221
|
+
console.log('Warning: /usr/bin/python3 is not usable; install the Xcode Command Line Tools (xcode-select --install).');
|
|
222
|
+
console.log(`Next, in Buzz Desktop:
|
|
223
|
+
1. Restart Buzz Desktop so it finds the new provider.
|
|
224
|
+
2. Open Agents > New agent.
|
|
225
|
+
3. Set "Run on" to ${result.name} (Teal Brick · ${result.name}).
|
|
226
|
+
4. Enter owner (the kit owner directory on the host) and host (the ssh alias or user@host of the agent host).
|
|
227
|
+
5. Create the agent. Desktop deploys it over ssh; the host must have run \`tealbrick buzz host setup\`.`);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
if (group === 'host' && action === 'setup') {
|
|
231
|
+
const flags = flagsOf(rest, ['owners-dir', 'buzz-app', 'node', 'kit-cli', 'respond-to-default'], []);
|
|
232
|
+
const str = (name) => typeof flags[name] === 'string' ? flags[name] : undefined;
|
|
233
|
+
const respond = str('respond-to-default');
|
|
234
|
+
if (respond !== undefined && respond !== 'owner-only' && respond !== 'anyone')
|
|
235
|
+
throw Error('kit_buzz_respond_to_default_invalid');
|
|
236
|
+
const result = await setupBuzzHost({ ownersDir: str('owners-dir'), buzzApp: str('buzz-app'), node: str('node'), kitCli: str('kit-cli'), respondToDefault: respond });
|
|
237
|
+
console.log(`Buzz agent host ready (kit ${result.kitVersion}, Buzz ${result.buzzAppVersion}).
|
|
238
|
+
host.json: ${result.hostJson}
|
|
239
|
+
node: ${result.node}
|
|
240
|
+
kit cli: ${result.kitCli}
|
|
241
|
+
owners dir: ${result.ownersDir}${result.owners.length ? ` (enrolled: ${result.owners.join(', ')})` : ''}
|
|
242
|
+
buzz: ${result.buzzBin}
|
|
243
|
+
buzz-acp: ${result.buzzAcpBin}
|
|
244
|
+
fleet respond_to default: ${result.fleetDefaults ?? '(none; Desktop choice applies)'}`);
|
|
245
|
+
for (const warning of result.warnings)
|
|
246
|
+
console.log(`Warning: ${warning}`);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
if (group === 'host' && action === 'remove') {
|
|
250
|
+
if (rest.length !== 1)
|
|
251
|
+
throw Error('kit_buzz_invalid_arguments');
|
|
252
|
+
const result = await removeBuzzAgent(rest[0]);
|
|
253
|
+
console.log(`Removed Buzz agent ${result.label}:
|
|
254
|
+
launchd unit: ${result.bootedOut ? `booted out (${result.service})` : 'was not loaded'}
|
|
255
|
+
plist: ${result.plistRemoved ? 'deleted' : 'not present'}
|
|
256
|
+
agent dir: ${result.movedTo ? `moved to ${result.movedTo} (still holds the agent key; delete it when no longer needed)` : 'not present'}
|
|
257
|
+
Also delete the agent in Buzz Desktop so it is not deployed again.`);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
console.error(buzzUsage);
|
|
261
|
+
process.exitCode = 2;
|
|
262
|
+
}
|
package/dist/cli.js
CHANGED
|
@@ -20,6 +20,11 @@ async function main() {
|
|
|
20
20
|
await nativeCommand(process.argv.slice(3), root);
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
|
+
if (command === 'buzz') {
|
|
24
|
+
const { buzzCommand } = await import('./buzz.js');
|
|
25
|
+
await buzzCommand(process.argv.slice(3));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
23
28
|
if (command === 'connect') {
|
|
24
29
|
await runtimeOnboarding('connect', process.argv.slice(3), root);
|
|
25
30
|
return;
|
|
@@ -41,7 +46,7 @@ async function main() {
|
|
|
41
46
|
return;
|
|
42
47
|
}
|
|
43
48
|
if (command !== 'setup') {
|
|
44
|
-
console.log('Usage: tealbrick setup | status | apply <config.json>\n tealbrick connect --workspace ID --node ID --agent ID [--issuer URL]\n tealbrick app claim --workspace ID --node ID --binding REF --endpoint HTTPS_ORIGIN --company PARTITION [--issuer URL]\nInstalled dependencies expose nothing until activated. Rebuild/restart Eve after changing selection.');
|
|
49
|
+
console.log('Usage: tealbrick setup | status | apply <config.json>\n tealbrick connect --workspace ID --node ID --agent ID [--issuer URL]\n tealbrick app claim --workspace ID --node ID --binding REF --endpoint HTTPS_ORIGIN --company PARTITION [--issuer URL]\n tealbrick buzz provider install | buzz host setup (Buzz Desktop agents on a Mac host; see BUZZ.md)\nInstalled dependencies expose nothing until activated. Rebuild/restart Eve after changing selection.');
|
|
45
50
|
return;
|
|
46
51
|
}
|
|
47
52
|
console.log('Setup requires Portal sign-in and saves an agent card in your chosen workspace. Other capabilities are optional.');
|
package/dist/index.d.ts
CHANGED
|
@@ -67,7 +67,7 @@ declare const schema: z.ZodObject<{
|
|
|
67
67
|
}[] | undefined;
|
|
68
68
|
spawns?: {
|
|
69
69
|
worker: string;
|
|
70
|
-
profile: "
|
|
70
|
+
profile: "small" | "light" | "standard" | "browser";
|
|
71
71
|
mode: "ephemeral" | "durable";
|
|
72
72
|
harnesses?: string[] | undefined;
|
|
73
73
|
bundles?: string[] | undefined;
|
|
@@ -150,7 +150,7 @@ declare const schema: z.ZodObject<{
|
|
|
150
150
|
kind: "user";
|
|
151
151
|
id: string;
|
|
152
152
|
};
|
|
153
|
-
allow: ("capabilities" | "auth" | "start" | "stop" | "wake" | "schedule" | "cool" | "status" | "exec" | "ssh" | "
|
|
153
|
+
allow: ("logs" | "capabilities" | "auth" | "start" | "stop" | "wake" | "schedule" | "cool" | "status" | "exec" | "ssh" | "events" | "runs" | "assignments" | "leases" | "resident" | "list" | "inventory" | "monitor" | "roles" | "ingress")[];
|
|
154
154
|
} | {
|
|
155
155
|
operation: "shareRevoke";
|
|
156
156
|
worker: string;
|
|
@@ -194,7 +194,7 @@ declare const schema: z.ZodObject<{
|
|
|
194
194
|
}[] | undefined;
|
|
195
195
|
spawns?: {
|
|
196
196
|
worker: string;
|
|
197
|
-
profile: "
|
|
197
|
+
profile: "small" | "light" | "standard" | "browser";
|
|
198
198
|
mode: "ephemeral" | "durable";
|
|
199
199
|
harnesses?: string[] | undefined;
|
|
200
200
|
bundles?: string[] | undefined;
|
|
@@ -277,7 +277,7 @@ declare const schema: z.ZodObject<{
|
|
|
277
277
|
kind: "user";
|
|
278
278
|
id: string;
|
|
279
279
|
};
|
|
280
|
-
allow: ("capabilities" | "auth" | "start" | "stop" | "wake" | "schedule" | "cool" | "status" | "exec" | "ssh" | "
|
|
280
|
+
allow: ("logs" | "capabilities" | "auth" | "start" | "stop" | "wake" | "schedule" | "cool" | "status" | "exec" | "ssh" | "events" | "runs" | "assignments" | "leases" | "resident" | "list" | "inventory" | "monitor" | "roles" | "ingress")[];
|
|
281
281
|
} | {
|
|
282
282
|
operation: "shareRevoke";
|
|
283
283
|
worker: string;
|
|
@@ -320,7 +320,7 @@ declare const schema: z.ZodObject<{
|
|
|
320
320
|
}[] | undefined;
|
|
321
321
|
spawns?: {
|
|
322
322
|
worker: string;
|
|
323
|
-
profile: "
|
|
323
|
+
profile: "small" | "light" | "standard" | "browser";
|
|
324
324
|
mode: "ephemeral" | "durable";
|
|
325
325
|
harnesses?: string[] | undefined;
|
|
326
326
|
bundles?: string[] | undefined;
|
|
@@ -403,7 +403,7 @@ declare const schema: z.ZodObject<{
|
|
|
403
403
|
kind: "user";
|
|
404
404
|
id: string;
|
|
405
405
|
};
|
|
406
|
-
allow: ("capabilities" | "auth" | "start" | "stop" | "wake" | "schedule" | "cool" | "status" | "exec" | "ssh" | "
|
|
406
|
+
allow: ("logs" | "capabilities" | "auth" | "start" | "stop" | "wake" | "schedule" | "cool" | "status" | "exec" | "ssh" | "events" | "runs" | "assignments" | "leases" | "resident" | "list" | "inventory" | "monitor" | "roles" | "ingress")[];
|
|
407
407
|
} | {
|
|
408
408
|
operation: "shareRevoke";
|
|
409
409
|
worker: string;
|
|
@@ -447,7 +447,7 @@ declare const schema: z.ZodObject<{
|
|
|
447
447
|
}[] | undefined;
|
|
448
448
|
spawns?: {
|
|
449
449
|
worker: string;
|
|
450
|
-
profile: "
|
|
450
|
+
profile: "small" | "light" | "standard" | "browser";
|
|
451
451
|
mode: "ephemeral" | "durable";
|
|
452
452
|
harnesses?: string[] | undefined;
|
|
453
453
|
bundles?: string[] | undefined;
|
|
@@ -530,7 +530,7 @@ declare const schema: z.ZodObject<{
|
|
|
530
530
|
kind: "user";
|
|
531
531
|
id: string;
|
|
532
532
|
};
|
|
533
|
-
allow: ("capabilities" | "auth" | "start" | "stop" | "wake" | "schedule" | "cool" | "status" | "exec" | "ssh" | "
|
|
533
|
+
allow: ("logs" | "capabilities" | "auth" | "start" | "stop" | "wake" | "schedule" | "cool" | "status" | "exec" | "ssh" | "events" | "runs" | "assignments" | "leases" | "resident" | "list" | "inventory" | "monitor" | "roles" | "ingress")[];
|
|
534
534
|
} | {
|
|
535
535
|
operation: "shareRevoke";
|
|
536
536
|
worker: string;
|
|
@@ -575,7 +575,7 @@ declare const schema: z.ZodObject<{
|
|
|
575
575
|
}[] | undefined;
|
|
576
576
|
spawns?: {
|
|
577
577
|
worker: string;
|
|
578
|
-
profile: "
|
|
578
|
+
profile: "small" | "light" | "standard" | "browser";
|
|
579
579
|
mode: "ephemeral" | "durable";
|
|
580
580
|
harnesses?: string[] | undefined;
|
|
581
581
|
bundles?: string[] | undefined;
|
|
@@ -658,7 +658,7 @@ declare const schema: z.ZodObject<{
|
|
|
658
658
|
kind: "user";
|
|
659
659
|
id: string;
|
|
660
660
|
};
|
|
661
|
-
allow: ("capabilities" | "auth" | "start" | "stop" | "wake" | "schedule" | "cool" | "status" | "exec" | "ssh" | "
|
|
661
|
+
allow: ("logs" | "capabilities" | "auth" | "start" | "stop" | "wake" | "schedule" | "cool" | "status" | "exec" | "ssh" | "events" | "runs" | "assignments" | "leases" | "resident" | "list" | "inventory" | "monitor" | "roles" | "ingress")[];
|
|
662
662
|
} | {
|
|
663
663
|
operation: "shareRevoke";
|
|
664
664
|
worker: string;
|
|
@@ -704,7 +704,7 @@ declare const schema: z.ZodObject<{
|
|
|
704
704
|
}[] | undefined;
|
|
705
705
|
spawns?: {
|
|
706
706
|
worker: string;
|
|
707
|
-
profile: "
|
|
707
|
+
profile: "small" | "light" | "standard" | "browser";
|
|
708
708
|
mode: "ephemeral" | "durable";
|
|
709
709
|
harnesses?: string[] | undefined;
|
|
710
710
|
bundles?: string[] | undefined;
|
|
@@ -787,7 +787,7 @@ declare const schema: z.ZodObject<{
|
|
|
787
787
|
kind: "user";
|
|
788
788
|
id: string;
|
|
789
789
|
};
|
|
790
|
-
allow: ("capabilities" | "auth" | "start" | "stop" | "wake" | "schedule" | "cool" | "status" | "exec" | "ssh" | "
|
|
790
|
+
allow: ("logs" | "capabilities" | "auth" | "start" | "stop" | "wake" | "schedule" | "cool" | "status" | "exec" | "ssh" | "events" | "runs" | "assignments" | "leases" | "resident" | "list" | "inventory" | "monitor" | "roles" | "ingress")[];
|
|
791
791
|
} | {
|
|
792
792
|
operation: "shareRevoke";
|
|
793
793
|
worker: string;
|
|
@@ -831,7 +831,7 @@ declare const schema: z.ZodObject<{
|
|
|
831
831
|
}[] | undefined;
|
|
832
832
|
spawns?: {
|
|
833
833
|
worker: string;
|
|
834
|
-
profile: "
|
|
834
|
+
profile: "small" | "light" | "standard" | "browser";
|
|
835
835
|
mode: "ephemeral" | "durable";
|
|
836
836
|
harnesses?: string[] | undefined;
|
|
837
837
|
bundles?: string[] | undefined;
|
|
@@ -914,7 +914,7 @@ declare const schema: z.ZodObject<{
|
|
|
914
914
|
kind: "user";
|
|
915
915
|
id: string;
|
|
916
916
|
};
|
|
917
|
-
allow: ("capabilities" | "auth" | "start" | "stop" | "wake" | "schedule" | "cool" | "status" | "exec" | "ssh" | "
|
|
917
|
+
allow: ("logs" | "capabilities" | "auth" | "start" | "stop" | "wake" | "schedule" | "cool" | "status" | "exec" | "ssh" | "events" | "runs" | "assignments" | "leases" | "resident" | "list" | "inventory" | "monitor" | "roles" | "ingress")[];
|
|
918
918
|
} | {
|
|
919
919
|
operation: "shareRevoke";
|
|
920
920
|
worker: string;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type ClaudeSdk } from './native-claude.js';
|
|
2
|
+
import { type BuzzDownload, type BuzzRun } from './native-buzz.js';
|
|
3
|
+
/**
|
|
4
|
+
* Agent Client Protocol (ACP, JSON-RPC 2.0 over stdio) agent for this kit root, for chat harnesses
|
|
5
|
+
* such as Buzz's `buzz-acp`. It runs the SAME owner harness as `native serve` (profile, expert
|
|
6
|
+
* contracts, Portal grants, PreToolUse gate, traces) in-process; no HTTP, no extra credential.
|
|
7
|
+
* Messages are treated as untrusted. Payload approvals have no surface here: they are declined and
|
|
8
|
+
* the owner is told to continue in TBD, so a chat message can never approve an outward write.
|
|
9
|
+
* With a Buzz CLI, the owner session also gets the in-process `buzz` MCP tools (agent↔agent
|
|
10
|
+
* messaging) and each final answer is auto-posted with request/answer mention rules and a
|
|
11
|
+
* per-thread loop breaker. ACP `session/new` mcpServers are never attached (they could grant a shell).
|
|
12
|
+
*/
|
|
13
|
+
export { buzzRoute, buzzTrigger } from './native-buzz.js';
|
|
14
|
+
export interface AcpDependencies {
|
|
15
|
+
claudeSdk?: ClaudeSdk;
|
|
16
|
+
log?: (event: Record<string, unknown>) => void;
|
|
17
|
+
env?: NodeJS.ProcessEnv;
|
|
18
|
+
input?: NodeJS.ReadableStream;
|
|
19
|
+
output?: NodeJS.WritableStream;
|
|
20
|
+
runtimeSync?: false;
|
|
21
|
+
/** Buzz CLI path: enables the buzz tools and posts each turn's final answer (identity comes from buzz-acp's injected BUZZ_* env). */
|
|
22
|
+
buzzCli?: string;
|
|
23
|
+
/** Injectable Buzz CLI runner (tests); behaves like buzzCli. */
|
|
24
|
+
buzz?: BuzzRun;
|
|
25
|
+
/** Injectable media downloader (tests); default `buzz media get` through buzzCli. */
|
|
26
|
+
download?: BuzzDownload;
|
|
27
|
+
/** Relay base URL for attachment URLs (default BUZZ_RELAY_URL). */
|
|
28
|
+
relayUrl?: string;
|
|
29
|
+
/** Overrides the auto-post transport only (legacy hook). */
|
|
30
|
+
send?: (args: string[], text: string) => Promise<boolean>;
|
|
31
|
+
/** Identity overrides (tests). Defaults: owner from BUZZ_AUTH_TAG, self derived from BUZZ_PRIVATE_KEY. */
|
|
32
|
+
ownerPubkey?: string;
|
|
33
|
+
selfPubkey?: string;
|
|
34
|
+
now?: () => number;
|
|
35
|
+
}
|
|
36
|
+
export declare function serveAcp(root: string, deps?: AcpDependencies): Promise<void>;
|