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 +120 -13
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
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 [
|
|
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
|
|
3633
|
-
return [...splitCmd(bridgeCmd), "
|
|
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:
|
|
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({
|
|
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(
|
|
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({
|
|
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,
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arp-tui",
|
|
3
|
-
"version": "0.0.
|
|
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.
|
|
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