@aiaiai-pt/martha-cli 0.53.0 → 0.54.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/CHANGELOG.md +31 -0
- package/dist/index.js +87 -19
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@aiaiai-pt/martha-cli`. Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). This project adheres to semver — `0.x` releases may include breaking changes between minor versions.
|
|
4
4
|
|
|
5
|
+
## [0.54.0] — 2026-08-03
|
|
6
|
+
|
|
7
|
+
### Added — `channels` uses the Buzz binaries Desktop already ships
|
|
8
|
+
|
|
9
|
+
- `buzz` and `buzz-acp` are now resolved from the user's PATH **or** from Buzz
|
|
10
|
+
Desktop's own bundle (`Buzz.app/Contents/MacOS` and the platform
|
|
11
|
+
equivalents), and `connect` prepends that directory to the harness's PATH so
|
|
12
|
+
`acp-serve --post-reply` can reach `buzz` to deliver. Desktop ships both as
|
|
13
|
+
Tauri sidecars and does exactly this for the agents it spawns itself
|
|
14
|
+
(`runtime/path.rs`); doing the same means a machine with Buzz Desktop
|
|
15
|
+
installed needs nothing on PATH and nothing built. Telling someone to
|
|
16
|
+
`cargo build` a binary sitting in their Applications folder was a
|
|
17
|
+
prerequisite we invented.
|
|
18
|
+
- The two checks now read `buzz-acp` / `buzz CLI` rather than `… on PATH`,
|
|
19
|
+
since PATH is no longer the only place they can come from, and the detail
|
|
20
|
+
says which copy is in use. When neither has it, the fix leads with installing
|
|
21
|
+
Buzz Desktop and keeps the build-from-source path as the alternative.
|
|
22
|
+
|
|
23
|
+
## [0.53.1] — 2026-08-03
|
|
24
|
+
|
|
25
|
+
### Fixed — `channels install-harness` told a Buzz-less machine to "launch Buzz once"
|
|
26
|
+
|
|
27
|
+
- The command registers Martha as a runtime *inside* Buzz Desktop, so with no
|
|
28
|
+
Desktop on the machine there is nothing to register with. It correctly
|
|
29
|
+
refused and wrote nothing, but the remedy assumed the app was installed and
|
|
30
|
+
merely unopened. It now probes for the application itself and says which of
|
|
31
|
+
the two situations it is: **not installed** (with the release link, and a
|
|
32
|
+
pointer to `martha channels connect buzz`, which needs no Desktop at all) or
|
|
33
|
+
**installed but never launched** (open it once). Both still name the exact
|
|
34
|
+
app-data paths so `--app-data` stays actionable.
|
|
35
|
+
|
|
5
36
|
## [0.53.0] — 2026-08-02
|
|
6
37
|
|
|
7
38
|
### Added — `martha channels`: connect an agent to a channel from either side (#1140)
|
package/dist/index.js
CHANGED
|
@@ -11129,7 +11129,7 @@ init_config();
|
|
|
11129
11129
|
init_errors();
|
|
11130
11130
|
|
|
11131
11131
|
// src/version.ts
|
|
11132
|
-
var CLI_VERSION = "0.
|
|
11132
|
+
var CLI_VERSION = "0.54.0";
|
|
11133
11133
|
|
|
11134
11134
|
// src/commands/sessions.ts
|
|
11135
11135
|
function relativeTime(iso) {
|
|
@@ -14770,6 +14770,62 @@ function buzzAppDataCandidates(platform, env2, home) {
|
|
|
14770
14770
|
function chooseAppDataDir(candidates, exists) {
|
|
14771
14771
|
return candidates.find((c) => exists(c.dir)) ?? null;
|
|
14772
14772
|
}
|
|
14773
|
+
function buzzAppCandidates(platform, env2, home) {
|
|
14774
|
+
if (platform === "darwin") {
|
|
14775
|
+
return ["/Applications/Buzz.app", join3(home, "Applications", "Buzz.app")];
|
|
14776
|
+
}
|
|
14777
|
+
if (platform === "win32") {
|
|
14778
|
+
const base = env2.LOCALAPPDATA ?? join3(home, "AppData", "Local");
|
|
14779
|
+
return [join3(base, "Programs", "Buzz")];
|
|
14780
|
+
}
|
|
14781
|
+
return [
|
|
14782
|
+
"/opt/Buzz",
|
|
14783
|
+
"/usr/bin/buzz-desktop",
|
|
14784
|
+
join3(home, ".local", "bin", "buzz-desktop")
|
|
14785
|
+
];
|
|
14786
|
+
}
|
|
14787
|
+
var BUZZ_RELEASES_URL = "https://github.com/block/buzz/releases/latest";
|
|
14788
|
+
function buzzSidecarDirs(platform, env2, home) {
|
|
14789
|
+
if (platform === "darwin") {
|
|
14790
|
+
return buzzAppCandidates(platform, env2, home).map((app) => join3(app, "Contents", "MacOS"));
|
|
14791
|
+
}
|
|
14792
|
+
if (platform === "win32") {
|
|
14793
|
+
return buzzAppCandidates(platform, env2, home);
|
|
14794
|
+
}
|
|
14795
|
+
return ["/opt/Buzz"];
|
|
14796
|
+
}
|
|
14797
|
+
function resolveBuzzBinary(bin, opts) {
|
|
14798
|
+
const onPath = resolveOnPath(bin, opts.env, opts.platform, opts.isExecutable);
|
|
14799
|
+
if (onPath)
|
|
14800
|
+
return { path: onPath, source: "path" };
|
|
14801
|
+
if (bin.includes("/") || bin.includes("\\"))
|
|
14802
|
+
return null;
|
|
14803
|
+
for (const dir of buzzSidecarDirs(opts.platform, opts.env, opts.home)) {
|
|
14804
|
+
const candidate = join3(dir, bin);
|
|
14805
|
+
if (opts.isExecutable(candidate))
|
|
14806
|
+
return { path: candidate, source: "desktop" };
|
|
14807
|
+
}
|
|
14808
|
+
return null;
|
|
14809
|
+
}
|
|
14810
|
+
function missingAppDataMessage(candidates, appInstalled) {
|
|
14811
|
+
const looked = candidates.map((c) => ` ${c.dir} (${c.build})`).join(`
|
|
14812
|
+
`);
|
|
14813
|
+
if (appInstalled) {
|
|
14814
|
+
return `Buzz Desktop is installed but has never been launched — it creates its ` + `data directory on first run.
|
|
14815
|
+
|
|
14816
|
+
Looked for:
|
|
14817
|
+
${looked}
|
|
14818
|
+
` + `Open Buzz Desktop once, then re-run this. Or pass --app-data <dir>.`;
|
|
14819
|
+
}
|
|
14820
|
+
return `Buzz Desktop is not installed on this machine. This command registers ` + `Martha as a runtime INSIDE Desktop, so there is nothing to register with.
|
|
14821
|
+
|
|
14822
|
+
` + `Looked for:
|
|
14823
|
+
${looked}
|
|
14824
|
+
` + `Install it: ${BUZZ_RELEASES_URL}
|
|
14825
|
+
|
|
14826
|
+
` + `If you do not want Desktop at all, you do not need this command — run the ` + `adapter yourself instead:
|
|
14827
|
+
martha channels connect buzz --agent <name> --relay <url>`;
|
|
14828
|
+
}
|
|
14773
14829
|
var DEFAULT_BUZZ_KINDS = "9,46010,40007,7";
|
|
14774
14830
|
function buzzAcpEnv(opts) {
|
|
14775
14831
|
const env2 = {
|
|
@@ -14810,6 +14866,14 @@ function executableOnDisk(p) {
|
|
|
14810
14866
|
function which(bin) {
|
|
14811
14867
|
return resolveOnPath(bin, process.env, process.platform, executableOnDisk);
|
|
14812
14868
|
}
|
|
14869
|
+
function whichBuzz(bin) {
|
|
14870
|
+
return resolveBuzzBinary(bin, {
|
|
14871
|
+
platform: process.platform,
|
|
14872
|
+
env: process.env,
|
|
14873
|
+
home: homedir(),
|
|
14874
|
+
isExecutable: executableOnDisk
|
|
14875
|
+
});
|
|
14876
|
+
}
|
|
14813
14877
|
function runBin(bin, args, env2) {
|
|
14814
14878
|
return new Promise((resolve2) => {
|
|
14815
14879
|
execFile2(bin, args, { env: env2, timeout: 15000, maxBuffer: 4 * 1024 * 1024 }, (err, stdout, stderr) => {
|
|
@@ -14855,20 +14919,22 @@ async function preflightBuzz(ctx, opts) {
|
|
|
14855
14919
|
fix: supported ? undefined : "upgrade the CLI that is FIRST on PATH: npm i -g @aiaiai-pt/martha-cli@latest (or point --martha-bin at the right one)"
|
|
14856
14920
|
});
|
|
14857
14921
|
}
|
|
14858
|
-
const
|
|
14922
|
+
const resolveBin = opts.resolveBin ?? whichBuzz;
|
|
14923
|
+
const acp = resolveBin(opts.buzzAcpBin);
|
|
14859
14924
|
checks.push({
|
|
14860
|
-
ok: !!
|
|
14861
|
-
label: "buzz-acp
|
|
14862
|
-
detail:
|
|
14863
|
-
fix:
|
|
14925
|
+
ok: !!acp,
|
|
14926
|
+
label: "buzz-acp",
|
|
14927
|
+
detail: acp ? acp.source === "desktop" ? `${acp.path} (bundled with Buzz Desktop)` : acp.path : `'${opts.buzzAcpBin}' not found on PATH or in Buzz Desktop`,
|
|
14928
|
+
fix: acp ? undefined : `install Buzz Desktop (${BUZZ_RELEASES_URL}) — it ships this binary — or build it: cargo build -p buzz-acp (or pass --buzz-acp-bin)`
|
|
14864
14929
|
});
|
|
14865
|
-
const
|
|
14930
|
+
const buzz = resolveBin(opts.buzzBin);
|
|
14866
14931
|
checks.push({
|
|
14867
|
-
ok: !!
|
|
14868
|
-
label: "buzz CLI
|
|
14869
|
-
detail:
|
|
14870
|
-
fix:
|
|
14932
|
+
ok: !!buzz,
|
|
14933
|
+
label: "buzz CLI",
|
|
14934
|
+
detail: buzz ? buzz.source === "desktop" ? `${buzz.path} (bundled with Buzz Desktop)` : buzz.path : `'${opts.buzzBin}' not found on PATH or in Buzz Desktop`,
|
|
14935
|
+
fix: buzz ? undefined : `install Buzz Desktop (${BUZZ_RELEASES_URL}) — it ships this binary — or build it: cargo build -p buzz-cli. acp-serve --post-reply shells it to deliver the answer`
|
|
14871
14936
|
});
|
|
14937
|
+
const buzzPath = buzz?.path ?? null;
|
|
14872
14938
|
let whoami = null;
|
|
14873
14939
|
try {
|
|
14874
14940
|
whoami = await ctx.api.get("/api/tasks/whoami");
|
|
@@ -15116,10 +15182,8 @@ function registerChannelCommands(program2) {
|
|
|
15116
15182
|
const chosen = opts.appData ? { build: "release", dir: String(opts.appData) } : chooseAppDataDir(buzzAppDataCandidates(process.platform, process.env, homedir()), (d) => existsSync(d));
|
|
15117
15183
|
if (!chosen) {
|
|
15118
15184
|
const candidates = buzzAppDataCandidates(process.platform, process.env, homedir());
|
|
15119
|
-
|
|
15120
|
-
|
|
15121
|
-
`)}
|
|
15122
|
-
Launch Buzz Desktop once so it creates one, or pass --app-data <dir>.`);
|
|
15185
|
+
const appInstalled = buzzAppCandidates(process.platform, process.env, homedir()).some((p) => existsSync(p));
|
|
15186
|
+
throw new CLIError(appInstalled ? "Buzz Desktop has no data directory yet." : "Buzz Desktop is not installed.", 3 /* NotFound */, missingAppDataMessage(candidates, appInstalled));
|
|
15123
15187
|
}
|
|
15124
15188
|
const dir = join3(chosen.dir, "custom_harnesses");
|
|
15125
15189
|
const file = join3(dir, `${def.id}.json`);
|
|
@@ -15190,21 +15254,25 @@ Launch Buzz Desktop once so it creates one, or pass --app-data <dir>.`);
|
|
|
15190
15254
|
process.exitCode = 1 /* Error */;
|
|
15191
15255
|
return;
|
|
15192
15256
|
}
|
|
15193
|
-
const acp =
|
|
15257
|
+
const acp = whichBuzz(opts.buzzAcpBin);
|
|
15258
|
+
const childPath = [
|
|
15259
|
+
...buzzSidecarDirs(process.platform, process.env, homedir()).filter((d) => existsSync(d)),
|
|
15260
|
+
process.env.PATH ?? ""
|
|
15261
|
+
].filter(Boolean).join(process.platform === "win32" ? ";" : ":");
|
|
15194
15262
|
if (opts.dryRun) {
|
|
15195
15263
|
console.log(source_default.bold(`Would launch:
|
|
15196
15264
|
`));
|
|
15197
15265
|
for (const [k, v] of Object.entries(env2))
|
|
15198
15266
|
console.log(` ${k}=${v}`);
|
|
15199
|
-
console.log(` ${acp}
|
|
15267
|
+
console.log(` ${acp.path}
|
|
15200
15268
|
`);
|
|
15201
15269
|
return;
|
|
15202
15270
|
}
|
|
15203
15271
|
console.log(source_default.bold(`
|
|
15204
15272
|
Connecting '${opts.agent}' to ${opts.relay} …
|
|
15205
15273
|
`));
|
|
15206
|
-
const child = spawn3(acp, [], {
|
|
15207
|
-
env: { ...process.env, ...env2 },
|
|
15274
|
+
const child = spawn3(acp.path, [], {
|
|
15275
|
+
env: { ...process.env, PATH: childPath, ...env2 },
|
|
15208
15276
|
stdio: "inherit"
|
|
15209
15277
|
});
|
|
15210
15278
|
await new Promise((resolve2) => {
|