@bivy/bivy 0.2.0 → 0.2.1-staging.34
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/bin/bivy.mjs +49 -1
- package/dist/server.js +18 -2
- package/package.json +1 -1
package/bin/bivy.mjs
CHANGED
|
@@ -1527,7 +1527,7 @@ async function cmdExec(args = []) {
|
|
|
1527
1527
|
function cmdCompletions(args = []) {
|
|
1528
1528
|
const shell = (args[0] || "").toLowerCase();
|
|
1529
1529
|
const commands = [
|
|
1530
|
-
"run", "sessions", "ls", "resume", "promote", "nodes", "agents", "agents:install", "shim", "takeover", "token", "exec",
|
|
1530
|
+
"run", "sessions", "ls", "resume", "promote", "rename", "nodes", "agents", "agents:install", "shim", "takeover", "token", "exec",
|
|
1531
1531
|
"send", "kill", "setup", "start", "stop", "restart", "status", "doctor", "logs", "login",
|
|
1532
1532
|
"update", "update:log", "open", "service", "secrets", "voice", "link", "relay:setup",
|
|
1533
1533
|
"github:connect", "github:app-create", "github:app-connect", "github:app-sync", "prune", "uninstall", "help", "version",
|
|
@@ -1908,6 +1908,49 @@ async function cmdPromote(args = []) {
|
|
|
1908
1908
|
}
|
|
1909
1909
|
}
|
|
1910
1910
|
|
|
1911
|
+
// `bivy rename <name>` — rename THIS node. Runs against the local daemon, which
|
|
1912
|
+
// persists the name to .bivy/node.json and live-updates relay/work-queue routing
|
|
1913
|
+
// (no restart needed). If the name collides on your account the control plane
|
|
1914
|
+
// auto-adjusts it for uniqueness, so we re-read the node info afterward to show
|
|
1915
|
+
// the name that actually stuck. Alias: node:rename.
|
|
1916
|
+
async function cmdRename(args = []) {
|
|
1917
|
+
if (args.includes("-h") || args.includes("--help")) {
|
|
1918
|
+
console.log('Usage: bivy rename <name>\n\nRename this node. Takes effect immediately (no restart). If the name is already used by another node on your account, it is auto-adjusted to stay unique.');
|
|
1919
|
+
return;
|
|
1920
|
+
}
|
|
1921
|
+
if (!(await ensureDeps())) process.exit(1);
|
|
1922
|
+
// Node names may contain spaces, so join all positional (non-flag) args rather
|
|
1923
|
+
// than taking only the first. The daemon trims/collapses whitespace and caps
|
|
1924
|
+
// the length; we just forward the raw text.
|
|
1925
|
+
const name = args.filter((a) => !a.startsWith("-")).join(" ").trim();
|
|
1926
|
+
if (!name) { console.error(c.red("Usage: bivy rename <name>")); process.exit(1); return; }
|
|
1927
|
+
|
|
1928
|
+
const config = loadConfig();
|
|
1929
|
+
if (!(await ensureNodeRunning(config))) { console.error(c.red(`Could not start the Bivy node at ${url(config)}.`)); process.exit(1); return; }
|
|
1930
|
+
let token;
|
|
1931
|
+
try { token = await localDeviceToken(config); }
|
|
1932
|
+
catch (error) { console.error(c.red(error?.message || String(error))); process.exit(1); return; }
|
|
1933
|
+
|
|
1934
|
+
const base = url(config);
|
|
1935
|
+
const prev = await fetchJson(base, "/api/node/info", token).then((d) => d?.name).catch(() => undefined);
|
|
1936
|
+
const res = await fetch(`${base}/api/node/name`, {
|
|
1937
|
+
method: "POST",
|
|
1938
|
+
headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
|
|
1939
|
+
body: JSON.stringify({ name }),
|
|
1940
|
+
});
|
|
1941
|
+
if (!res.ok) {
|
|
1942
|
+
const data = await res.json().catch(() => ({}));
|
|
1943
|
+
console.error(c.red(`Rename failed (${res.status}): ${data.error || "unknown error"}`));
|
|
1944
|
+
process.exit(1);
|
|
1945
|
+
return;
|
|
1946
|
+
}
|
|
1947
|
+
const data = await res.json().catch(() => ({}));
|
|
1948
|
+
const applied = data.name || name;
|
|
1949
|
+
if (prev && prev !== applied) console.log(c.green(`Renamed node: ${c.dim(prev)} → ${applied}`));
|
|
1950
|
+
else console.log(c.green(`Node name set to "${applied}".`));
|
|
1951
|
+
if (applied !== name) console.log(c.dim(`(Adjusted from "${name}" to stay unique on your account.)`));
|
|
1952
|
+
}
|
|
1953
|
+
|
|
1911
1954
|
// `bivy send <id> "<message>"` — send a prompt to an existing session and stream
|
|
1912
1955
|
// the reply. Thin wrapper over the headless exec client with --session.
|
|
1913
1956
|
// Deliberately does NOT intercept -h/--help (see cmdExec above) — the message
|
|
@@ -3968,6 +4011,7 @@ ${c.bold("bivy")} — Bivy node CLI
|
|
|
3968
4011
|
${c.cyan("bivy run <agent> --node <name>")} Start the session on another registered node
|
|
3969
4012
|
${c.cyan("bivy run <agent> --clone [remote]")} Start in a fresh clone (current repo, or a given remote)
|
|
3970
4013
|
${c.cyan("bivy run <agent> --workspace <dir>")} Start in an existing directory (default: current repo, else the configured workspace)
|
|
4014
|
+
${c.cyan("bivy rename <name>")} Rename this node (takes effect immediately, no restart)
|
|
3971
4015
|
${c.cyan("bivy nodes")} List/add/remove other nodes (add <name> <url> --token <t>)
|
|
3972
4016
|
${c.cyan("bivy agents")} List the supported agents and which are installed (--json)
|
|
3973
4017
|
${c.cyan("bivy shim install <agent>")} Make interactive '<agent>' launch its native TUI in a Bivy PTY (remote-visible)
|
|
@@ -4051,6 +4095,10 @@ An agent's own --help passes through, e.g. 'bivy run claude --help'.`);
|
|
|
4051
4095
|
case "promote":
|
|
4052
4096
|
await cmdPromote(args);
|
|
4053
4097
|
break;
|
|
4098
|
+
case "rename":
|
|
4099
|
+
case "node:rename":
|
|
4100
|
+
await cmdRename(args);
|
|
4101
|
+
break;
|
|
4054
4102
|
case "nodes":
|
|
4055
4103
|
await cmdNodes(args);
|
|
4056
4104
|
break;
|
package/dist/server.js
CHANGED
|
@@ -1344,7 +1344,11 @@ async function runTerminalList() {
|
|
|
1344
1344
|
const out = [];
|
|
1345
1345
|
for (const t of runs) {
|
|
1346
1346
|
let sessionRef = t.meta.sessionId;
|
|
1347
|
-
|
|
1347
|
+
// Discover the on-disk session for agents that assign their id lazily (Pi,
|
|
1348
|
+
// Codex). Runs whenever there's no pinned id — not just for auto-named
|
|
1349
|
+
// terminals — so the takeover-readiness flag below is accurate even for a
|
|
1350
|
+
// run launched with an explicit --name.
|
|
1351
|
+
if (!sessionRef) {
|
|
1348
1352
|
try {
|
|
1349
1353
|
sessionRef = await SESSION_DISCOVERY_BY_AGENT[t.meta.agent ?? ""]?.(t.workspace, t.createdAt);
|
|
1350
1354
|
}
|
|
@@ -1355,7 +1359,11 @@ async function runTerminalList() {
|
|
|
1355
1359
|
if (t.meta.autoName && nativeName && !isEmptyUntitledTitle(nativeName))
|
|
1356
1360
|
t.meta.name = nativeName;
|
|
1357
1361
|
const { autoName: _autoName, ...publicMeta } = t.meta;
|
|
1358
|
-
|
|
1362
|
+
// "Continue as chat" can only adopt a session that exists: a pinned id, or a
|
|
1363
|
+
// session discovered on disk. Surface that so the client can disable the
|
|
1364
|
+
// affordance (with guidance) until the agent has actually started its
|
|
1365
|
+
// session, instead of letting the user tap it and hit a 409.
|
|
1366
|
+
out.push({ termId: t.id, workspace: t.workspace, createdAt: t.createdAt, lastActivityAt: t.lastActivityAt, pid: terminals.pid(t.id), ...publicMeta, takeoverReady: Boolean(sessionRef) });
|
|
1359
1367
|
}
|
|
1360
1368
|
return out;
|
|
1361
1369
|
}
|
|
@@ -2581,6 +2589,7 @@ const RELAY_COMMANDS = {
|
|
|
2581
2589
|
agent: meta?.runtimeId ?? s.agent,
|
|
2582
2590
|
agentName: meta?.agentName ?? s.agentName,
|
|
2583
2591
|
source: rec?.source ?? meta?.source,
|
|
2592
|
+
forkedFrom: rec?.forkedFrom ?? meta?.forkedFrom,
|
|
2584
2593
|
branch: rec?.worktree?.branch ?? meta?.branch,
|
|
2585
2594
|
sandbox: rec?.sandbox ?? normalizeSandboxTier(meta?.sandbox),
|
|
2586
2595
|
prUrl: rec?.prUrl ?? meta?.prUrl,
|
|
@@ -5350,6 +5359,11 @@ async function standUpFork(opts) {
|
|
|
5350
5359
|
const record = plan.kind === "resume"
|
|
5351
5360
|
? await createSession(cwd, plan.sessionFile, { runtimeId: targetRuntimeId, source: bundle.record.source, makeActive: false })
|
|
5352
5361
|
: await createSession(cwd, undefined, { runtimeId: targetRuntimeId, source: bundle.record.source, makeActive: false });
|
|
5362
|
+
// Mark the new session as a fork of its source, so the run card can show
|
|
5363
|
+
// "Forked from …" and the lineage survives a reload (persisted below). Just
|
|
5364
|
+
// the parent's session id — an identifier, not content, so it's safe to
|
|
5365
|
+
// carry into metadata the same way branch/prUrl already are.
|
|
5366
|
+
record.forkedFrom = bundle.record.sourceSessionId;
|
|
5353
5367
|
// Attach the reconstructed worktree to the record. createSession only
|
|
5354
5368
|
// populates record.worktree when it provisions one itself (fresh repo session)
|
|
5355
5369
|
// or restores it from stored metadata (resume) — neither happens for a fork,
|
|
@@ -5703,6 +5717,7 @@ function persistSessionMetadata(record, status = sessionStatus(record)) {
|
|
|
5703
5717
|
name: record.session.getName(),
|
|
5704
5718
|
workspace: record.workspace,
|
|
5705
5719
|
source: record.source ?? "manual",
|
|
5720
|
+
forkedFrom: record.forkedFrom,
|
|
5706
5721
|
runtimeId: record.runtimeId,
|
|
5707
5722
|
sandbox: record.sandbox,
|
|
5708
5723
|
agentName: getRuntime(record.runtimeId).displayName,
|
|
@@ -8421,6 +8436,7 @@ app.get("/api/sessions", async (_req, res, next) => {
|
|
|
8421
8436
|
agent: meta?.runtimeId ?? s.agent,
|
|
8422
8437
|
agentName: meta?.agentName ?? s.agentName,
|
|
8423
8438
|
source: rec?.source ?? meta?.source,
|
|
8439
|
+
forkedFrom: rec?.forkedFrom ?? meta?.forkedFrom,
|
|
8424
8440
|
branch: rec?.worktree?.branch ?? meta?.branch,
|
|
8425
8441
|
prUrl: rec?.prUrl ?? meta?.prUrl,
|
|
8426
8442
|
prs: rec?.prs ?? meta?.prs,
|