arp-tui 0.0.8 → 0.0.9

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,15 +3807,17 @@ 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)
@@ -3803,6 +3874,7 @@ async function runAgentCli(instance2, args2, overrides = {}) {
3803
3874
  runLogin: async () => (await login(instance2)).credentials,
3804
3875
  enroll: enrollAgent,
3805
3876
  startAgent: startAgentProcess,
3877
+ fetchPosture: fetchLocalPosture,
3806
3878
  env: process.env,
3807
3879
  out: (line) => console.log(line),
3808
3880
  err: (line) => console.error(line),
@@ -3879,7 +3951,12 @@ async function confirmDestructive(args2, deps, name, actionLine) {
3879
3951
  return true;
3880
3952
  }
3881
3953
  async function enrollAndMaybeStart(args2, deps, opts) {
3882
- const result = await deps.enroll({ bridgeCmd: opts.bridgeCmd, connectBlob: opts.connectBlob });
3954
+ const result = await deps.enroll({
3955
+ bridgeCmd: opts.bridgeCmd,
3956
+ connectBlob: opts.connectBlob,
3957
+ provider: args2.provider,
3958
+ model: args2.model
3959
+ });
3883
3960
  if (!result.ok) {
3884
3961
  const msg = sanitizeForTty(result.message);
3885
3962
  if (args2.json) deps.out(JSON.stringify({ ok: false, error: msg }));
@@ -3902,11 +3979,18 @@ async function enrollAndMaybeStart(args2, deps, opts) {
3902
3979
  }
3903
3980
  deps.err(opts.successLine(sanitizeLabel(agentName)));
3904
3981
  if (!started) {
3905
- deps.err(` start it with: ${sanitizeForTty(startArgv(opts.bridgeCmd, agentName, args2.provider).join(" "))}`);
3982
+ deps.err(
3983
+ ` start it with: ${sanitizeForTty(startArgv(opts.bridgeCmd, agentName, args2.provider, args2.model).join(" "))}`
3984
+ );
3906
3985
  return 0;
3907
3986
  }
3908
3987
  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 });
3988
+ return deps.startAgent({
3989
+ bridgeCmd: opts.bridgeCmd,
3990
+ name: agentName,
3991
+ provider: args2.provider,
3992
+ model: args2.model
3993
+ });
3910
3994
  }
3911
3995
  async function runAgentAdd(instance2, args2, deps) {
3912
3996
  const name = requireName2(args2, deps);
@@ -3936,8 +4020,12 @@ async function runAgentStatus(instance2, args2, deps) {
3936
4020
  const creds = await ensureSignedIn(deps);
3937
4021
  const agent = await findMyAgent(oneShotRest(instance2, creds), name, args2, deps);
3938
4022
  if (!agent) return 1;
4023
+ const posture = await deps.fetchPosture({
4024
+ bridgeCmd: resolveBridgeCmd(args2.bridgeCmd, deps.env),
4025
+ agentName: name
4026
+ });
3939
4027
  if (args2.json) {
3940
- deps.out(JSON.stringify(agent, null, 2));
4028
+ deps.out(JSON.stringify({ ...agent, localPosture: posture }, null, 2));
3941
4029
  return 0;
3942
4030
  }
3943
4031
  const row = (label, value) => deps.out(`${(label + ":").padEnd(14)}${value}`);
@@ -3957,6 +4045,22 @@ async function runAgentStatus(instance2, args2, deps) {
3957
4045
  );
3958
4046
  if (agent.runtimeVersion) row("runtime", sanitizeLabel(agent.runtimeVersion, 40));
3959
4047
  if (agent.daemonPosture) row("daemon", sanitizeLabel(agent.daemonPosture, 40));
4048
+ const knobRow = (label, knob, emptyValue = "") => {
4049
+ const value = sanitizeLabel(knob?.value ?? "", 48) || emptyValue;
4050
+ row(label, `${value} (${sanitizeLabel(knob?.origin ?? "unknown", 16)})`);
4051
+ };
4052
+ if (posture) {
4053
+ knobRow("provider", posture.provider);
4054
+ knobRow("model", posture.model, "(provider default)");
4055
+ knobRow("tools", posture.tools);
4056
+ knobRow("auth", posture.auth);
4057
+ row(
4058
+ "sandbox",
4059
+ `${posture.sandbox?.enabled ? "on" : "off"} (${sanitizeLabel(posture.sandbox?.origin ?? "unknown", 16)})`
4060
+ );
4061
+ } else {
4062
+ row("local", "not enrolled on this machine (or bridge unavailable)");
4063
+ }
3960
4064
  return 0;
3961
4065
  }
3962
4066
  async function runAgentReissue(instance2, args2, deps) {
@@ -4772,7 +4876,7 @@ commands:
4772
4876
  profile manage saved instances (list|add|switch|remove; run \`arp-tui profile\`)
4773
4877
  agent add <name> create a personal agent on Braid, enroll it on this machine
4774
4878
  via the local bridge, and start it (--no-start to skip;
4775
- --bridge-cmd/--provider/--json \u2014 run \`arp-tui agent\` for details)
4879
+ --bridge-cmd/--provider/--model/--json \u2014 run \`arp-tui agent\` for details)
4776
4880
  agent status|reissue|revoke|remove <name>
4777
4881
  inspect or recover an agent: detail card, fresh credential +
4778
4882
  re-enroll, credential revoke, permanent delete (revoke/remove
@@ -4832,6 +4936,7 @@ function parseCliArgs(argv) {
4832
4936
  "clerk-template": { type: "string" },
4833
4937
  "clerk-oauth-client-id": { type: "string" },
4834
4938
  provider: { type: "string" },
4939
+ model: { type: "string" },
4835
4940
  "no-start": { type: "boolean" },
4836
4941
  "bridge-cmd": { type: "string" },
4837
4942
  channel: { type: "string" },
@@ -4859,6 +4964,7 @@ function parseCliArgs(argv) {
4859
4964
  clerkTemplate: parsed.values["clerk-template"],
4860
4965
  clerkOAuthClientId: parsed.values["clerk-oauth-client-id"],
4861
4966
  provider: parsed.values.provider,
4967
+ model: parsed.values.model,
4862
4968
  noStart: parsed.values["no-start"] === true,
4863
4969
  bridgeCmd: parsed.values["bridge-cmd"],
4864
4970
  channel: parsed.values.channel,
@@ -4977,6 +5083,7 @@ if (args.cmd === "login") {
4977
5083
  sub: args.sub,
4978
5084
  name: args.name,
4979
5085
  provider: args.provider,
5086
+ model: args.model,
4980
5087
  noStart: args.noStart,
4981
5088
  bridgeCmd: args.bridgeCmd,
4982
5089
  yes: args.yes,
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "arp-tui",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
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.9",
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.9",
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",