arp-tui 0.0.8 → 0.0.10

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/dist/index.js CHANGED
@@ -3619,6 +3619,7 @@ unknown profile command "${args2.sub}".`);
3619
3619
  import { spawn as spawn2 } from "child_process";
3620
3620
  var DEFAULT_BRIDGE_CMD = "npx -y @snowyroad/braid";
3621
3621
  var ENROLL_TIMEOUT_MS = 12e4;
3622
+ var STATUS_TIMEOUT_MS = 6e4;
3622
3623
  var STDERR_TAIL_CHARS = 600;
3623
3624
  function resolveBridgeCmd(flag, env = process.env) {
3624
3625
  return flag ?? env["ARP_TUI_BRIDGE_CMD"] ?? DEFAULT_BRIDGE_CMD;
@@ -3626,14 +3627,30 @@ function resolveBridgeCmd(flag, env = process.env) {
3626
3627
  function splitCmd(cmd) {
3627
3628
  return cmd.trim().split(/\s+/).filter(Boolean);
3628
3629
  }
3629
- function enrollArgv(bridgeCmd) {
3630
- return [...splitCmd(bridgeCmd), "enroll", "--invite-stdin", "--json"];
3630
+ function enrollArgv(bridgeCmd, opts) {
3631
+ return [
3632
+ ...splitCmd(bridgeCmd),
3633
+ "enroll",
3634
+ "--invite-stdin",
3635
+ "--json",
3636
+ ...opts?.provider ? ["--provider", opts.provider] : [],
3637
+ ...opts?.model ? ["--model", opts.model] : []
3638
+ ];
3639
+ }
3640
+ function startArgv(bridgeCmd, name, provider, model) {
3641
+ return [
3642
+ ...splitCmd(bridgeCmd),
3643
+ "start",
3644
+ name,
3645
+ ...provider ? ["--provider", provider] : [],
3646
+ ...model ? ["--model", model] : []
3647
+ ];
3631
3648
  }
3632
- function startArgv(bridgeCmd, name, provider) {
3633
- return [...splitCmd(bridgeCmd), "start", name, ...provider ? ["--provider", provider] : []];
3649
+ function statusArgv(bridgeCmd) {
3650
+ return [...splitCmd(bridgeCmd), "status", "--json"];
3634
3651
  }
3635
3652
  function enrollAgent(opts) {
3636
- const [cmd, ...argv] = enrollArgv(opts.bridgeCmd);
3653
+ const [cmd, ...argv] = enrollArgv(opts.bridgeCmd, { provider: opts.provider, model: opts.model });
3637
3654
  if (!cmd) {
3638
3655
  return Promise.resolve({ ok: false, exitCode: null, message: "empty bridge command", stderrTail: "" });
3639
3656
  }
@@ -3722,8 +3739,60 @@ function parseReceipt(stdout) {
3722
3739
  }
3723
3740
  return null;
3724
3741
  }
3742
+ function fetchLocalPosture(opts) {
3743
+ const [cmd, ...argv] = statusArgv(opts.bridgeCmd);
3744
+ if (!cmd) return Promise.resolve(null);
3745
+ return new Promise((resolve) => {
3746
+ const child = spawn2(cmd, argv, { stdio: ["pipe", "pipe", "pipe"] });
3747
+ let stdout = "";
3748
+ let settled = false;
3749
+ const finish = (r) => {
3750
+ if (settled) return;
3751
+ settled = true;
3752
+ clearTimeout(timer);
3753
+ resolve(r);
3754
+ };
3755
+ const timer = setTimeout(() => {
3756
+ finish(null);
3757
+ child.kill("SIGKILL");
3758
+ }, opts.timeoutMs ?? STATUS_TIMEOUT_MS);
3759
+ child.on("error", () => finish(null));
3760
+ child.stdout.setEncoding("utf8");
3761
+ child.stdout.on("data", (d) => stdout += d);
3762
+ child.stderr.resume();
3763
+ child.stdin.on("error", () => {
3764
+ });
3765
+ child.stdin.end();
3766
+ child.on("close", (code) => {
3767
+ if (code !== 0) {
3768
+ finish(null);
3769
+ return;
3770
+ }
3771
+ const agents = parseStatusAgents(stdout);
3772
+ finish(agents?.find((a) => a.name === opts.agentName) ?? null);
3773
+ });
3774
+ });
3775
+ }
3776
+ function parseStatusAgents(stdout) {
3777
+ const lines = stdout.split("\n").map((l) => l.trim()).filter(Boolean);
3778
+ for (let i = lines.length - 1; i >= 0; i--) {
3779
+ if (!lines[i].startsWith("{")) continue;
3780
+ for (const candidate of [lines[i], lines.slice(i).join("\n")]) {
3781
+ try {
3782
+ const data = JSON.parse(candidate);
3783
+ if (data && typeof data === "object" && Array.isArray(data.agents)) {
3784
+ return data.agents.filter(
3785
+ (a) => !!a && typeof a === "object" && typeof a.name === "string"
3786
+ );
3787
+ }
3788
+ } catch {
3789
+ }
3790
+ }
3791
+ }
3792
+ return null;
3793
+ }
3725
3794
  function startAgentProcess(opts) {
3726
- const [cmd, ...argv] = startArgv(opts.bridgeCmd, opts.name, opts.provider);
3795
+ const [cmd, ...argv] = startArgv(opts.bridgeCmd, opts.name, opts.provider, opts.model);
3727
3796
  if (!cmd) return Promise.resolve(1);
3728
3797
  return new Promise((resolve) => {
3729
3798
  const child = spawn2(cmd, argv, { stdio: "inherit" });
@@ -3738,19 +3807,24 @@ var AGENT_USAGE = `usage: braid agent <add|status|reissue|revoke|remove> <name>
3738
3807
 
3739
3808
  add <name> create a personal agent on Braid, enroll it on this machine
3740
3809
  via the local bridge, and start it (Ctrl-C stops it)
3741
- status <name> detail card: presence, credential, health, service mode
3810
+ status <name> detail card: presence, credential, health, service mode,
3811
+ plus this machine's local provider/model posture (via the bridge)
3742
3812
  reissue <name> mint a fresh credential and re-enroll here \u2014 recovers an
3743
3813
  agent whose credential is broken or revoked
3744
3814
  revoke <name> revoke the agent's credential \u2014 it cannot connect until reissued
3745
3815
  remove <name> permanently delete the agent from Braid
3746
3816
 
3747
3817
  --provider <p> agent CLI the bridge runs (claude-code, codex, gemini, \u2026)
3818
+ --model <name> model pin for the provider; persists to the enrolled agent
3748
3819
  --no-start enroll only \u2014 prints the exact start command instead
3749
- --bridge-cmd <cmd> bridge command to spawn (default: npx -y arp-bridge@latest;
3820
+ --bridge-cmd <cmd> bridge command to spawn (default: ${DEFAULT_BRIDGE_CMD};
3750
3821
  also ARP_TUI_BRIDGE_CMD env)
3751
3822
  --yes skip the confirmation prompt (required with --json on
3752
3823
  revoke/remove)
3753
- --json machine-readable result on stdout`;
3824
+ --json machine-readable result on stdout
3825
+
3826
+ deeper per-agent knobs (--tools, --auth, --scope, --fallback-model, sandbox
3827
+ widenings, \u2026) belong to the bridge \u2014 see: ${DEFAULT_BRIDGE_CMD} --help`;
3754
3828
  async function promptOnTty(question) {
3755
3829
  if (!process.stdin.isTTY || !process.stderr.isTTY) return null;
3756
3830
  const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
@@ -3803,6 +3877,7 @@ async function runAgentCli(instance2, args2, overrides = {}) {
3803
3877
  runLogin: async () => (await login(instance2)).credentials,
3804
3878
  enroll: enrollAgent,
3805
3879
  startAgent: startAgentProcess,
3880
+ fetchPosture: fetchLocalPosture,
3806
3881
  env: process.env,
3807
3882
  out: (line) => console.log(line),
3808
3883
  err: (line) => console.error(line),
@@ -3879,7 +3954,12 @@ async function confirmDestructive(args2, deps, name, actionLine) {
3879
3954
  return true;
3880
3955
  }
3881
3956
  async function enrollAndMaybeStart(args2, deps, opts) {
3882
- const result = await deps.enroll({ bridgeCmd: opts.bridgeCmd, connectBlob: opts.connectBlob });
3957
+ const result = await deps.enroll({
3958
+ bridgeCmd: opts.bridgeCmd,
3959
+ connectBlob: opts.connectBlob,
3960
+ provider: args2.provider,
3961
+ model: args2.model
3962
+ });
3883
3963
  if (!result.ok) {
3884
3964
  const msg = sanitizeForTty(result.message);
3885
3965
  if (args2.json) deps.out(JSON.stringify({ ok: false, error: msg }));
@@ -3902,11 +3982,18 @@ async function enrollAndMaybeStart(args2, deps, opts) {
3902
3982
  }
3903
3983
  deps.err(opts.successLine(sanitizeLabel(agentName)));
3904
3984
  if (!started) {
3905
- deps.err(` start it with: ${sanitizeForTty(startArgv(opts.bridgeCmd, agentName, args2.provider).join(" "))}`);
3985
+ deps.err(
3986
+ ` start it with: ${sanitizeForTty(startArgv(opts.bridgeCmd, agentName, args2.provider, args2.model).join(" "))}`
3987
+ );
3906
3988
  return 0;
3907
3989
  }
3908
3990
  deps.err(`\u2192 starting ${sanitizeLabel(agentName)} now \u2014 press Ctrl-C to stop it`);
3909
- return deps.startAgent({ bridgeCmd: opts.bridgeCmd, name: agentName, provider: args2.provider });
3991
+ return deps.startAgent({
3992
+ bridgeCmd: opts.bridgeCmd,
3993
+ name: agentName,
3994
+ provider: args2.provider,
3995
+ model: args2.model
3996
+ });
3910
3997
  }
3911
3998
  async function runAgentAdd(instance2, args2, deps) {
3912
3999
  const name = requireName2(args2, deps);
@@ -3936,8 +4023,12 @@ async function runAgentStatus(instance2, args2, deps) {
3936
4023
  const creds = await ensureSignedIn(deps);
3937
4024
  const agent = await findMyAgent(oneShotRest(instance2, creds), name, args2, deps);
3938
4025
  if (!agent) return 1;
4026
+ const posture = await deps.fetchPosture({
4027
+ bridgeCmd: resolveBridgeCmd(args2.bridgeCmd, deps.env),
4028
+ agentName: name
4029
+ });
3939
4030
  if (args2.json) {
3940
- deps.out(JSON.stringify(agent, null, 2));
4031
+ deps.out(JSON.stringify({ ...agent, localPosture: posture }, null, 2));
3941
4032
  return 0;
3942
4033
  }
3943
4034
  const row = (label, value) => deps.out(`${(label + ":").padEnd(14)}${value}`);
@@ -3957,6 +4048,22 @@ async function runAgentStatus(instance2, args2, deps) {
3957
4048
  );
3958
4049
  if (agent.runtimeVersion) row("runtime", sanitizeLabel(agent.runtimeVersion, 40));
3959
4050
  if (agent.daemonPosture) row("daemon", sanitizeLabel(agent.daemonPosture, 40));
4051
+ const knobRow = (label, knob, emptyValue = "") => {
4052
+ const value = sanitizeLabel(knob?.value ?? "", 48) || emptyValue;
4053
+ row(label, `${value} (${sanitizeLabel(knob?.origin ?? "unknown", 16)})`);
4054
+ };
4055
+ if (posture) {
4056
+ knobRow("provider", posture.provider);
4057
+ knobRow("model", posture.model, "(provider default)");
4058
+ knobRow("tools", posture.tools);
4059
+ knobRow("auth", posture.auth);
4060
+ row(
4061
+ "sandbox",
4062
+ `${posture.sandbox?.enabled ? "on" : "off"} (${sanitizeLabel(posture.sandbox?.origin ?? "unknown", 16)})`
4063
+ );
4064
+ } else {
4065
+ row("local", "not enrolled on this machine (or bridge unavailable)");
4066
+ }
3960
4067
  return 0;
3961
4068
  }
3962
4069
  async function runAgentReissue(instance2, args2, deps) {
@@ -4772,7 +4879,7 @@ commands:
4772
4879
  profile manage saved instances (list|add|switch|remove; run \`arp-tui profile\`)
4773
4880
  agent add <name> create a personal agent on Braid, enroll it on this machine
4774
4881
  via the local bridge, and start it (--no-start to skip;
4775
- --bridge-cmd/--provider/--json \u2014 run \`arp-tui agent\` for details)
4882
+ --bridge-cmd/--provider/--model/--json \u2014 run \`arp-tui agent\` for details)
4776
4883
  agent status|reissue|revoke|remove <name>
4777
4884
  inspect or recover an agent: detail card, fresh credential +
4778
4885
  re-enroll, credential revoke, permanent delete (revoke/remove
@@ -4832,6 +4939,7 @@ function parseCliArgs(argv) {
4832
4939
  "clerk-template": { type: "string" },
4833
4940
  "clerk-oauth-client-id": { type: "string" },
4834
4941
  provider: { type: "string" },
4942
+ model: { type: "string" },
4835
4943
  "no-start": { type: "boolean" },
4836
4944
  "bridge-cmd": { type: "string" },
4837
4945
  channel: { type: "string" },
@@ -4859,6 +4967,7 @@ function parseCliArgs(argv) {
4859
4967
  clerkTemplate: parsed.values["clerk-template"],
4860
4968
  clerkOAuthClientId: parsed.values["clerk-oauth-client-id"],
4861
4969
  provider: parsed.values.provider,
4970
+ model: parsed.values.model,
4862
4971
  noStart: parsed.values["no-start"] === true,
4863
4972
  bridgeCmd: parsed.values["bridge-cmd"],
4864
4973
  channel: parsed.values.channel,
@@ -4977,6 +5086,7 @@ if (args.cmd === "login") {
4977
5086
  sub: args.sub,
4978
5087
  name: args.name,
4979
5088
  provider: args.provider,
5089
+ model: args.model,
4980
5090
  noStart: args.noStart,
4981
5091
  bridgeCmd: args.bridgeCmd,
4982
5092
  yes: args.yes,
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "arp-tui",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "arp-tui",
9
- "version": "0.0.8",
9
+ "version": "0.0.10",
10
10
  "license": "SEE LICENSE IN LICENSE.md",
11
11
  "dependencies": {
12
12
  "ink": "^5.2.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arp-tui",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "description": "Human-facing terminal client for Agent Relay Protocol. Tail channels and post messages from your terminal.",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "author": "SnowyRoad",