@bivy/bivy 0.16.25-staging.9 → 0.17.0-staging.1
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 +4 -0
- package/bin/acp-shim.mjs +7 -0
- package/bin/agent-manifest.json +2 -2
- package/bin/bivy.mjs +55 -0
- package/bin/codex-app-server-shim.mjs +10 -0
- package/bin/patch-pi-dependencies.mjs +2 -2
- package/dist/agents/claude-code/integration.js +9 -1
- package/dist/agents/codex/integration.js +9 -1
- package/dist/agents/pi/integration.js +1 -1
- package/dist/agents/pi/runtime.js +27 -3
- package/dist/agents/profiles.js +27 -6
- package/dist/apps/gateway.js +357 -0
- package/dist/apps/preview-shell.js +55 -0
- package/dist/apps/preview-stream.js +58 -0
- package/dist/apps/registry.js +160 -0
- package/dist/apps/remote-preview.js +70 -0
- package/dist/apps/service.js +62 -0
- package/dist/apps/styles.css +3165 -0
- package/dist/apps/tokens.css +203 -0
- package/dist/apps/types.js +9 -0
- package/dist/automation-cli.js +26 -3
- package/dist/automation-config.js +14 -2
- package/dist/automation-filter-gate.js +32 -0
- package/dist/automation-filter.js +118 -0
- package/dist/automation-template.js +18 -4
- package/dist/certification/generated.js +5 -4
- package/dist/control-plane-tasks.js +14 -0
- package/dist/controllers/app-commands.js +28 -0
- package/dist/controllers/credential-commands.js +8 -3
- package/dist/credentials/document.js +35 -10
- package/dist/credentials/store.js +17 -0
- package/dist/hosted-custody.js +30 -0
- package/dist/protocol/client-command-routes.js +1 -0
- package/dist/protocol/client-command-schemas.js +4 -0
- package/dist/remote/relay-client.js +14 -0
- package/dist/runtime/cli-parsers.js +29 -2
- package/dist/runtime/index.js +43 -1
- package/dist/runtime/protocol.js +32 -2
- package/dist/server.js +112 -15
- package/dist/session/event-log.js +131 -10
- package/dist/session/fork-matrix.js +12 -0
- package/dist/session/transcript-persistence.js +8 -1
- package/dist/worktree.js +9 -1
- package/package.json +16 -15
package/README.md
CHANGED
|
@@ -206,6 +206,10 @@ answer questions, approve supported tool calls, or stop the agent.
|
|
|
206
206
|
|
|
207
207
|
- Send screenshots, images, logs, and other files from your phone.
|
|
208
208
|
- Download reports and artifacts the agent creates.
|
|
209
|
+
- Publish [session apps](docs/apps.md) with web and CLI/TUI views using
|
|
210
|
+
`bivy app publish bivy.app.json`. Linked machines automatically discover web
|
|
211
|
+
preview delivery through Bivy's relay—no per-machine domains, certificates or
|
|
212
|
+
public ports. Terminal views use the existing connection.
|
|
209
213
|
- Use voice input and read-aloud where supported; provider-backed voice may
|
|
210
214
|
send audio or text to the selected provider.
|
|
211
215
|
- Keep a native terminal workflow or use structured chat, depending on the agent.
|
package/bin/acp-shim.mjs
CHANGED
|
@@ -313,6 +313,13 @@ function onSessionUpdate(params) {
|
|
|
313
313
|
if (!content) return "";
|
|
314
314
|
if (typeof content === "string") return content;
|
|
315
315
|
if (Array.isArray(content)) return content.map(textOf).join("");
|
|
316
|
+
// ACP's ToolCallContent wraps a ContentBlock: `{ type: "content", content:
|
|
317
|
+
// { type: "text", text } }`. Unwrap it (recursively) so a tool's real output
|
|
318
|
+
// — a command's stdout, a fetched document, a read's text — isn't dropped,
|
|
319
|
+
// which collapsed the tool_result to the bare status ("completed"). opencode
|
|
320
|
+
// and most spec-compliant ACP agents deliver tool output in this wrapped
|
|
321
|
+
// shape, so reading only the bare `{type:"text"}` form lost it in production.
|
|
322
|
+
if (content.type === "content" && content.content != null) return textOf(content.content);
|
|
316
323
|
if (content.type === "text" && typeof content.text === "string") return content.text;
|
|
317
324
|
if (typeof content.text === "string") return content.text;
|
|
318
325
|
return "";
|
package/bin/agent-manifest.json
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"hidden": false,
|
|
23
23
|
"supportTier": "supported",
|
|
24
24
|
"certification": "release-tested",
|
|
25
|
-
"testedVersion": "1.18.
|
|
25
|
+
"testedVersion": "1.18.32",
|
|
26
26
|
"headlessFlags": [
|
|
27
27
|
"run",
|
|
28
28
|
"-s"
|
|
@@ -191,7 +191,7 @@
|
|
|
191
191
|
"hidden": false,
|
|
192
192
|
"supportTier": "supported",
|
|
193
193
|
"certification": "release-tested",
|
|
194
|
-
"testedVersion": "1.0.
|
|
194
|
+
"testedVersion": "1.0.41",
|
|
195
195
|
"headlessFlags": [
|
|
196
196
|
"--always-approve",
|
|
197
197
|
"-p",
|
package/bin/bivy.mjs
CHANGED
|
@@ -2418,6 +2418,57 @@ async function cmdAttach(args = []) {
|
|
|
2418
2418
|
console.log(c.green(`Attached ${body.name} (${body.kind}, ${body.size} bytes) to the chat.`));
|
|
2419
2419
|
}
|
|
2420
2420
|
|
|
2421
|
+
// Universal app publishing: every agent that can write JSON and run a command
|
|
2422
|
+
// uses the same contract. Relative static directories are manifest-relative.
|
|
2423
|
+
async function cmdApp(args = []) {
|
|
2424
|
+
const [action, ...rest] = args;
|
|
2425
|
+
if (!action || rest.some((arg) => arg === "--help" || arg === "-h") || ["help", "--help", "-h"].includes(action)) {
|
|
2426
|
+
console.log(`Usage: bivy app publish <manifest.json> [--session <id>]
|
|
2427
|
+
bivy app list [--session <id>]
|
|
2428
|
+
bivy app remove <app-id> [--session <id>]
|
|
2429
|
+
|
|
2430
|
+
Manifest: {"version":1,"name":"My app","views":[
|
|
2431
|
+
{"kind":"web","name":"Website","source":{"kind":"service","port":3000}},
|
|
2432
|
+
{"kind":"terminal","name":"Console","command":"bin/rails","args":["console"]}
|
|
2433
|
+
]}
|
|
2434
|
+
|
|
2435
|
+
Static web source: {"kind":"static","directory":"./dist"}
|
|
2436
|
+
Publishing does not start commands. Open Apps in the session menu to view or run.
|
|
2437
|
+
Terminal commands run with the node user's permissions, not in a new sandbox.
|
|
2438
|
+
Web previews require operator setup; see docs/apps.md.`);
|
|
2439
|
+
return;
|
|
2440
|
+
}
|
|
2441
|
+
if (!["publish", "list", "remove"].includes(action)) throw new Error("Unknown app command. Run bivy app --help.");
|
|
2442
|
+
const sessionIndex = rest.indexOf("--session");
|
|
2443
|
+
if (sessionIndex >= 0 && (!rest[sessionIndex + 1] || rest[sessionIndex + 1].startsWith("--"))) throw new Error("--session requires an id.");
|
|
2444
|
+
const sessionId = resolveAttachSessionId({ sessionFlag: sessionIndex >= 0 ? rest[sessionIndex + 1] : undefined, env: process.env });
|
|
2445
|
+
if (!sessionId) throw new Error("Set --session <id> or run inside a Bivy agent session.");
|
|
2446
|
+
const positional = rest.filter((_, i) => i !== sessionIndex && (sessionIndex < 0 || i !== sessionIndex + 1));
|
|
2447
|
+
if (positional.some((a) => a.startsWith("-")) || positional.length !== (action === "list" ? 0 : 1)) throw new Error("Invalid arguments. Run bivy app --help.");
|
|
2448
|
+
const body = { sessionId };
|
|
2449
|
+
if (action === "publish") {
|
|
2450
|
+
const file = path.resolve(positional[0]);
|
|
2451
|
+
if (fs.statSync(file).size > 64 * 1024) throw new Error("App manifest exceeds 64 KiB.");
|
|
2452
|
+
const manifest = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
2453
|
+
if (!manifest || typeof manifest !== "object") throw new Error("App manifest must be a JSON object.");
|
|
2454
|
+
if (Array.isArray(manifest.views)) for (const view of manifest.views) {
|
|
2455
|
+
if (view?.kind === "web" && view.source?.kind === "static" && typeof view.source.directory === "string") {
|
|
2456
|
+
view.source.directory = path.resolve(path.dirname(file), view.source.directory);
|
|
2457
|
+
}
|
|
2458
|
+
}
|
|
2459
|
+
body.manifest = manifest;
|
|
2460
|
+
} else if (action === "remove") body.appId = positional[0];
|
|
2461
|
+
const config = loadConfig();
|
|
2462
|
+
if (!(await ensureNodeRunning(config))) throw new Error("Could not reach the Bivy node.");
|
|
2463
|
+
const token = await localDeviceToken(config);
|
|
2464
|
+
const response = await fetch(`${url(config)}/api/apps/${action}`, {
|
|
2465
|
+
method: "POST", headers: { authorization: `Bearer ${token}`, "content-type": "application/json" }, body: JSON.stringify(body),
|
|
2466
|
+
});
|
|
2467
|
+
const result = await response.json();
|
|
2468
|
+
if (!response.ok || result.error) throw new Error(result.error || `App command failed (${response.status}).`);
|
|
2469
|
+
console.log(JSON.stringify(result, null, 2));
|
|
2470
|
+
}
|
|
2471
|
+
|
|
2421
2472
|
// Map a saved session's runtime id to the `bivy run` agent whose native CLI can
|
|
2422
2473
|
// resume it in a terminal. Only agents with a real native resume qualify; other
|
|
2423
2474
|
// runtimes (generic-cli, SDK-only) have no terminal resume and open in the web app.
|
|
@@ -5045,6 +5096,7 @@ ${c.bold("bivy")} — Bivy node CLI
|
|
|
5045
5096
|
${c.cyan("bivy token")} Print a device token for this node (for 'bivy nodes add' elsewhere)
|
|
5046
5097
|
${c.cyan("bivy sessions")} List recent sessions (live + saved) and resume one (alias: ls)
|
|
5047
5098
|
${c.cyan("bivy resume")} [n|id] Resume a session directly (default: most recent)
|
|
5099
|
+
${c.cyan("bivy app")} Publish and list session apps (web and terminal views)
|
|
5048
5100
|
${c.cyan("bivy send <id>")} "..." Send a prompt to an existing session and stream the reply
|
|
5049
5101
|
${c.cyan("bivy kill <id>")} Stop a session/terminal (--delete also removes a saved session)
|
|
5050
5102
|
${c.cyan("bivy prune")} Delete old sessions/workspaces/worktrees (--keep N, --older-than 7d, --dry-run)
|
|
@@ -5167,6 +5219,9 @@ An agent's own --help passes through, e.g. 'bivy run claude --help'.`);
|
|
|
5167
5219
|
case "send":
|
|
5168
5220
|
await cmdSend(args);
|
|
5169
5221
|
break;
|
|
5222
|
+
case "app":
|
|
5223
|
+
await cmdApp(args);
|
|
5224
|
+
break;
|
|
5170
5225
|
case "attach":
|
|
5171
5226
|
await cmdAttach(args);
|
|
5172
5227
|
break;
|
|
@@ -415,6 +415,16 @@ function onNotification(m) {
|
|
|
415
415
|
bivy({ type: "session.status", status: "working" });
|
|
416
416
|
return;
|
|
417
417
|
case "turn/completed": {
|
|
418
|
+
// The completion event is authoritative about a terminal failure: a turn
|
|
419
|
+
// that hit a usage limit (or any provider error) arrives here as
|
|
420
|
+
// `status: "failed"` carrying `turn.error`. Capture it directly instead of
|
|
421
|
+
// depending on a separate `error` notification landing first — otherwise a
|
|
422
|
+
// completion that omits that notification seals as session.done and the
|
|
423
|
+
// user sees a silent empty turn (fail loud, never swallow the error).
|
|
424
|
+
const turnError =
|
|
425
|
+
params?.turn?.error?.message ||
|
|
426
|
+
(params?.turn?.status === "failed" ? params?.error?.message || params?.message || "Codex turn failed" : undefined);
|
|
427
|
+
if (turnError && !sawError) sawError = turnError;
|
|
418
428
|
// Codex 0.147 can publish turn/completed just before the final
|
|
419
429
|
// collabAgentToolCall item/completed notification. Sealing immediately
|
|
420
430
|
// leaves the sub-agent card running forever and drops its persisted
|
|
@@ -37,8 +37,8 @@ const piPackage = findDependency(path.join("@earendil-works", "pi-coding-agent")
|
|
|
37
37
|
if (!piPackage) process.exit(0);
|
|
38
38
|
|
|
39
39
|
const patches = [
|
|
40
|
-
{ name: "brace-expansion", version: "5.0.
|
|
41
|
-
{ name: "undici", version: "8.10.
|
|
40
|
+
{ name: "brace-expansion", version: "5.0.12" },
|
|
41
|
+
{ name: "undici", version: "8.10.2" },
|
|
42
42
|
];
|
|
43
43
|
|
|
44
44
|
for (const patch of patches) {
|
|
@@ -4,13 +4,21 @@ import { defineAgentIntegration } from "../definition.js";
|
|
|
4
4
|
import { withExactCapabilitySurface } from "../../runtime/types.js";
|
|
5
5
|
import { createCredentialStore } from "../../runtime/credentials.js";
|
|
6
6
|
import { ClaudeCodeRuntime, claudeRuntimeFromEnv, claudeSdkInstalled, } from "./runtime.js";
|
|
7
|
-
export const CLAUDE_TESTED_VERSION = "0.3.
|
|
7
|
+
export const CLAUDE_TESTED_VERSION = "0.3.281";
|
|
8
8
|
const CLAUDE_CAPABILITIES = withExactCapabilitySurface({
|
|
9
9
|
toolInterception: true,
|
|
10
10
|
modelSelection: true,
|
|
11
11
|
packages: false,
|
|
12
12
|
resume: true,
|
|
13
13
|
fork: true,
|
|
14
|
+
// Must mirror ClaudeCodeRuntime.capabilities (runtime.ts): the catalog is a
|
|
15
|
+
// consumed source of truth (the fork-fidelity matrix and any fork-target
|
|
16
|
+
// fidelity preview read these), so under-reporting here makes Claude look
|
|
17
|
+
// like a seeded-only fork target when its runtime actually delivers a
|
|
18
|
+
// byte-exact same-runtime fork (forkTransport) and a full cross-runtime
|
|
19
|
+
// transcript replay INTO it (forkHistoryImport, via importHistoryForFork).
|
|
20
|
+
forkTransport: true,
|
|
21
|
+
forkHistoryImport: true,
|
|
14
22
|
usageReporting: true,
|
|
15
23
|
nativeSessionDiscovery: true,
|
|
16
24
|
nativeSessionAdoption: true,
|
|
@@ -9,7 +9,7 @@ import { codexCredentialPreflight } from "../../runtime/codex-preflight.js";
|
|
|
9
9
|
import { deleteCodexSession, discoverNativeCodexSessions, loadCodexTranscript, writeCodexRollout, exportCodexRollout, importCodexRollout, } from "../../runtime/codex-sessions.js";
|
|
10
10
|
import { ProtocolRuntime } from "../../runtime/protocol.js";
|
|
11
11
|
import { codexSlashCommands } from "../../runtime/slash-commands.js";
|
|
12
|
-
export const CODEX_TESTED_VERSION = "0.
|
|
12
|
+
export const CODEX_TESTED_VERSION = "0.156.1";
|
|
13
13
|
const CODEX_AVAILABLE_CACHE = new Map();
|
|
14
14
|
function codexCommand() {
|
|
15
15
|
return process.env.BIVY_CODEX_BIN?.trim() || "codex";
|
|
@@ -146,6 +146,14 @@ export function codexIntegration(origin) {
|
|
|
146
146
|
resume: true,
|
|
147
147
|
packages: false,
|
|
148
148
|
fork: true,
|
|
149
|
+
// Mirror the ProtocolRuntime this integration builds (createCodexRuntime
|
|
150
|
+
// above wires exportForFork+importForFork and writeHistory, which flip
|
|
151
|
+
// capabilities.forkTransport/forkHistoryImport on). The catalog is a
|
|
152
|
+
// consumed source of truth (fork-fidelity matrix / fork-target preview),
|
|
153
|
+
// so omitting these made Codex look seeded-only when its runtime does a
|
|
154
|
+
// byte-exact codex→codex fork and a full transcript replay INTO it.
|
|
155
|
+
forkTransport: true,
|
|
156
|
+
forkHistoryImport: true,
|
|
149
157
|
usageReporting: true,
|
|
150
158
|
interactiveTui: installed,
|
|
151
159
|
nativeSessionDiscovery: true,
|
|
@@ -5,7 +5,7 @@ import os from "node:os";
|
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { defineAgentIntegration } from "../definition.js";
|
|
7
7
|
import { PI_CAPABILITIES } from "./capabilities.js";
|
|
8
|
-
export const PI_TESTED_VERSION = "0.
|
|
8
|
+
export const PI_TESTED_VERSION = "0.87.1";
|
|
9
9
|
export function piAgentDir() {
|
|
10
10
|
return process.env.PI_CODING_AGENT_DIR?.trim() || path.join(os.homedir(), ".pi", "agent");
|
|
11
11
|
}
|
|
@@ -268,8 +268,29 @@ class PiSession {
|
|
|
268
268
|
* reload. Async because that resolution reads the store.
|
|
269
269
|
*/
|
|
270
270
|
async getModels() {
|
|
271
|
-
const
|
|
272
|
-
|
|
271
|
+
const runtime = this.session.modelRuntime;
|
|
272
|
+
try {
|
|
273
|
+
const models = await runtime.getAvailable();
|
|
274
|
+
return models.map((model) => toModelInfo(model, true));
|
|
275
|
+
}
|
|
276
|
+
catch (error) {
|
|
277
|
+
// The runtime's availability refresh is a Promise.all across every
|
|
278
|
+
// provider's auth check, so one broken provider (an unreachable custom
|
|
279
|
+
// endpoint, a single failing credential read) rejects the whole catalog
|
|
280
|
+
// and the picker shows nothing. Degrade to per-provider listing and
|
|
281
|
+
// skip only the broken ones; rethrow only when truly nothing survives.
|
|
282
|
+
const models = [];
|
|
283
|
+
for (const provider of runtime.getProviders()) {
|
|
284
|
+
try {
|
|
285
|
+
for (const model of await runtime.getAvailable(provider.id))
|
|
286
|
+
models.push(toModelInfo(model, true));
|
|
287
|
+
}
|
|
288
|
+
catch { /* this provider is broken — the rest still list */ }
|
|
289
|
+
}
|
|
290
|
+
if (models.length)
|
|
291
|
+
return models;
|
|
292
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
293
|
+
}
|
|
273
294
|
}
|
|
274
295
|
/**
|
|
275
296
|
* Every model Pi knows about — built-in and custom, regardless of whether
|
|
@@ -281,7 +302,10 @@ class PiSession {
|
|
|
281
302
|
async getAllModels() {
|
|
282
303
|
const runtime = this.session.modelRuntime;
|
|
283
304
|
// Refresh availability first so `hasConfiguredAuth` reflects current creds.
|
|
284
|
-
|
|
305
|
+
// Best-effort: a failed refresh (one broken provider rejects the shared
|
|
306
|
+
// Promise.all) must not blank the full catalog — the flags then reflect
|
|
307
|
+
// the last successful refresh, which the picker can still act on.
|
|
308
|
+
await runtime.getAvailable().catch(() => { });
|
|
285
309
|
return runtime.getModels().map((model) => toModelInfo(model, runtime.hasConfiguredAuth(model.provider)));
|
|
286
310
|
}
|
|
287
311
|
/** Reload the projected models.json in-place so a live session immediately
|
package/dist/agents/profiles.js
CHANGED
|
@@ -43,7 +43,7 @@ export const AGENT_PROFILES = {
|
|
|
43
43
|
// Approve/Deny + session/load resume + a real model picker), the same bar Pi,
|
|
44
44
|
// Claude Code, and Codex clear. See `acp` below for the version fallback.
|
|
45
45
|
supportTier: "supported",
|
|
46
|
-
testedVersion: "1.18.
|
|
46
|
+
testedVersion: "1.18.32",
|
|
47
47
|
blurb: "The most widely used open-source coding harness (OpenCode CLI).",
|
|
48
48
|
// `opencode run -s <id> "<prompt>"` continues a prior session by its own id
|
|
49
49
|
// (`-s, --session session id to continue`, per `opencode run --help`).
|
|
@@ -356,8 +356,11 @@ export const AGENT_PROFILES = {
|
|
|
356
356
|
behaviors: { preflight: "grok", prepare: "grok-auth", nativeSessions: "grok" },
|
|
357
357
|
command: "grok",
|
|
358
358
|
packageName: "grok (curl -fsSL https://x.ai/cli/install.sh | bash)",
|
|
359
|
+
// Supported tier: Grok runs on the governed ACP path by default (per-tool
|
|
360
|
+
// Approve/Deny + native resume + live model state), the same bar Pi, Claude
|
|
361
|
+
// Code, Codex, and OpenCode clear. See `acp` below for the version fallback.
|
|
359
362
|
supportTier: "supported",
|
|
360
|
-
testedVersion: "1.0.
|
|
363
|
+
testedVersion: "1.0.41",
|
|
361
364
|
authOwner: "mixed",
|
|
362
365
|
blurb: "xAI's official Grok coding agent (Grok CLI) — SuperGrok/X subscription or API key.",
|
|
363
366
|
// Official CLI: `grok -p "<prompt>"` (alias `--single`) runs one headless
|
|
@@ -398,14 +401,32 @@ export const AGENT_PROFILES = {
|
|
|
398
401
|
flag: "-m",
|
|
399
402
|
models: [
|
|
400
403
|
// Official Grok CLI (1.x) advertises grok-4.6 as the default subscription
|
|
401
|
-
// model (verified against
|
|
402
|
-
//
|
|
403
|
-
//
|
|
404
|
-
//
|
|
404
|
+
// model (verified against the authenticated `~/.grok/models_cache.json`,
|
|
405
|
+
// origin cli-chat-proxy.grok.com/v1/models); the older grok-4.5 /
|
|
406
|
+
// grok-4-latest / grok-code-fast-1 ids now return "unknown model id".
|
|
407
|
+
// Keep the list honest; operators can override with BIVY_GROK_MODELS if
|
|
408
|
+
// their install exposes more.
|
|
405
409
|
{ id: "grok-4.6", name: "Grok 4.6", provider: "xai" },
|
|
406
410
|
],
|
|
407
411
|
},
|
|
412
|
+
// Grok's reasoning models expose a `--reasoning-effort <EFFORT>` flag
|
|
413
|
+
// (verified against `grok --help`, 1.0.0); the authenticated model catalog
|
|
414
|
+
// lists low/medium/high/xhigh with `high` as the default. `{level}` fills
|
|
415
|
+
// the value; insertAt: 0 keeps the trailing `-p` prompt flag last so the
|
|
416
|
+
// prompt still lands as its value. Threads through the resume path too, so a
|
|
417
|
+
// continued turn keeps the chosen effort. Override with BIVY_GROK_THINKING.
|
|
418
|
+
thinking: { levels: ["low", "medium", "high", "xhigh"], default: "high", template: ["--reasoning-effort", "{level}"], insertAt: 0 },
|
|
408
419
|
promptMode: "argv",
|
|
420
|
+
// `grok agent stdio` ("Run the agent over stdio") is a full ACP server
|
|
421
|
+
// (protocolVersion 1: session/new, session/prompt, session/request_permission,
|
|
422
|
+
// loadSession resume, live model state) — the governed ProtocolRuntime path
|
|
423
|
+
// that supersedes the `--always-approve` pipe above with real per-tool
|
|
424
|
+
// Approve/Deny. Validated against grok 1.0.41, so it is ON by default
|
|
425
|
+
// (`preferred`) — gated on the binary actually describing the `agent`
|
|
426
|
+
// subcommand ("Run Grok without the interactive UI" in `grok --help`), so an
|
|
427
|
+
// older CLI falls back to the pipe path rather than opening a dead session.
|
|
428
|
+
// Force the pipe path back with BIVY_GROK_ACP=0.
|
|
429
|
+
acp: { args: ["agent", "stdio"], helpToken: "without the interactive ui", preferred: true },
|
|
409
430
|
install: {
|
|
410
431
|
kind: "curl",
|
|
411
432
|
display: "curl -fsSL https://x.ai/cli/install.sh | bash",
|