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 +124 -14
- 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,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:
|
|
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({
|
|
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(
|
|
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({
|
|
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,
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arp-tui",
|
|
3
|
-
"version": "0.0.
|
|
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.
|
|
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