arp-tui 0.0.7 → 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 +135 -21
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1822,6 +1822,9 @@ var RelayWs = class {
|
|
|
1822
1822
|
};
|
|
1823
1823
|
|
|
1824
1824
|
// src/state/store.ts
|
|
1825
|
+
function attentionConfirmTarget(channels, channelId) {
|
|
1826
|
+
return channels.find((c) => c.id === channelId)?.name ?? channelId.slice(0, 8);
|
|
1827
|
+
}
|
|
1825
1828
|
function filterChannels(channels, filter) {
|
|
1826
1829
|
const f = filter.trim().toLowerCase();
|
|
1827
1830
|
if (!f) return channels;
|
|
@@ -2234,7 +2237,7 @@ function createStore(opts) {
|
|
|
2234
2237
|
set({ mode: "attention_confirm", attentionDraft: "", error: null });
|
|
2235
2238
|
}
|
|
2236
2239
|
function setAttentionDraft(value) {
|
|
2237
|
-
const max = state.mode === "attention_level" ? 32 : state.mode === "attention_confirm" ?
|
|
2240
|
+
const max = state.mode === "attention_level" ? 32 : state.mode === "attention_confirm" ? 256 : 1024;
|
|
2238
2241
|
if (Buffer.byteLength(value, "utf8") <= max) set({ attentionDraft: value });
|
|
2239
2242
|
}
|
|
2240
2243
|
function submitAttentionInput() {
|
|
@@ -2260,8 +2263,9 @@ function createStore(opts) {
|
|
|
2260
2263
|
return;
|
|
2261
2264
|
}
|
|
2262
2265
|
if (state.mode === "attention_confirm") {
|
|
2263
|
-
if (state.
|
|
2264
|
-
|
|
2266
|
+
if (!state.activeChannelId) return;
|
|
2267
|
+
if (state.attentionDraft !== attentionConfirmTarget(state.channels, state.activeChannelId)) {
|
|
2268
|
+
set({ error: "confirmation did not match the channel name" });
|
|
2265
2269
|
return;
|
|
2266
2270
|
}
|
|
2267
2271
|
if (pendingAttentionAck) void performAttentionAck(pendingAttentionAck);
|
|
@@ -2909,18 +2913,20 @@ var LEVEL_COLOR = {
|
|
|
2909
2913
|
critical: "red"
|
|
2910
2914
|
};
|
|
2911
2915
|
function AttentionPanel({
|
|
2912
|
-
|
|
2916
|
+
channelName,
|
|
2917
|
+
channelKind,
|
|
2913
2918
|
items,
|
|
2914
2919
|
selected,
|
|
2915
2920
|
mode,
|
|
2916
2921
|
draft,
|
|
2917
2922
|
busy
|
|
2918
2923
|
}) {
|
|
2919
|
-
const prompt = mode === "attention_level" ? "level (info | action_required | critical)" : mode === "attention_reason" ? "reason" : mode === "attention_confirm" ? `type ${
|
|
2924
|
+
const prompt = mode === "attention_level" ? "level (info | action_required | critical)" : mode === "attention_reason" ? "reason" : mode === "attention_confirm" ? `type ${sanitizeForTty(channelName)} to confirm` : null;
|
|
2920
2925
|
return /* @__PURE__ */ jsxs3(Box2, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
2921
2926
|
/* @__PURE__ */ jsxs3(Text3, { bold: true, children: [
|
|
2922
|
-
"ATTENTION
|
|
2923
|
-
|
|
2927
|
+
"ATTENTION ",
|
|
2928
|
+
channelSigil(channelKind),
|
|
2929
|
+
sanitizeLabel(channelName)
|
|
2924
2930
|
] }),
|
|
2925
2931
|
items.length === 0 ? /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "no active attention" }) : items.map((item, index) => /* @__PURE__ */ jsxs3(Box2, { flexDirection: "column", children: [
|
|
2926
2932
|
/* @__PURE__ */ jsxs3(Text3, { children: [
|
|
@@ -3490,7 +3496,8 @@ function App({ store: store2 }) {
|
|
|
3490
3496
|
state.mode.startsWith("attention") && state.activeChannelId ? /* @__PURE__ */ jsx12(
|
|
3491
3497
|
AttentionPanel,
|
|
3492
3498
|
{
|
|
3493
|
-
|
|
3499
|
+
channelName: attentionConfirmTarget(state.channels, state.activeChannelId),
|
|
3500
|
+
channelKind: activeChannel?.kind,
|
|
3494
3501
|
items: state.channelAttention,
|
|
3495
3502
|
selected: state.attentionSelected,
|
|
3496
3503
|
mode: state.mode,
|
|
@@ -3612,6 +3619,7 @@ unknown profile command "${args2.sub}".`);
|
|
|
3612
3619
|
import { spawn as spawn2 } from "child_process";
|
|
3613
3620
|
var DEFAULT_BRIDGE_CMD = "npx -y @snowyroad/braid";
|
|
3614
3621
|
var ENROLL_TIMEOUT_MS = 12e4;
|
|
3622
|
+
var STATUS_TIMEOUT_MS = 6e4;
|
|
3615
3623
|
var STDERR_TAIL_CHARS = 600;
|
|
3616
3624
|
function resolveBridgeCmd(flag, env = process.env) {
|
|
3617
3625
|
return flag ?? env["ARP_TUI_BRIDGE_CMD"] ?? DEFAULT_BRIDGE_CMD;
|
|
@@ -3619,14 +3627,30 @@ function resolveBridgeCmd(flag, env = process.env) {
|
|
|
3619
3627
|
function splitCmd(cmd) {
|
|
3620
3628
|
return cmd.trim().split(/\s+/).filter(Boolean);
|
|
3621
3629
|
}
|
|
3622
|
-
function enrollArgv(bridgeCmd) {
|
|
3623
|
-
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
|
+
];
|
|
3624
3648
|
}
|
|
3625
|
-
function
|
|
3626
|
-
return [...splitCmd(bridgeCmd), "
|
|
3649
|
+
function statusArgv(bridgeCmd) {
|
|
3650
|
+
return [...splitCmd(bridgeCmd), "status", "--json"];
|
|
3627
3651
|
}
|
|
3628
3652
|
function enrollAgent(opts) {
|
|
3629
|
-
const [cmd, ...argv] = enrollArgv(opts.bridgeCmd);
|
|
3653
|
+
const [cmd, ...argv] = enrollArgv(opts.bridgeCmd, { provider: opts.provider, model: opts.model });
|
|
3630
3654
|
if (!cmd) {
|
|
3631
3655
|
return Promise.resolve({ ok: false, exitCode: null, message: "empty bridge command", stderrTail: "" });
|
|
3632
3656
|
}
|
|
@@ -3715,8 +3739,60 @@ function parseReceipt(stdout) {
|
|
|
3715
3739
|
}
|
|
3716
3740
|
return null;
|
|
3717
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
|
+
}
|
|
3718
3794
|
function startAgentProcess(opts) {
|
|
3719
|
-
const [cmd, ...argv] = startArgv(opts.bridgeCmd, opts.name, opts.provider);
|
|
3795
|
+
const [cmd, ...argv] = startArgv(opts.bridgeCmd, opts.name, opts.provider, opts.model);
|
|
3720
3796
|
if (!cmd) return Promise.resolve(1);
|
|
3721
3797
|
return new Promise((resolve) => {
|
|
3722
3798
|
const child = spawn2(cmd, argv, { stdio: "inherit" });
|
|
@@ -3731,15 +3807,17 @@ var AGENT_USAGE = `usage: braid agent <add|status|reissue|revoke|remove> <name>
|
|
|
3731
3807
|
|
|
3732
3808
|
add <name> create a personal agent on Braid, enroll it on this machine
|
|
3733
3809
|
via the local bridge, and start it (Ctrl-C stops it)
|
|
3734
|
-
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)
|
|
3735
3812
|
reissue <name> mint a fresh credential and re-enroll here \u2014 recovers an
|
|
3736
3813
|
agent whose credential is broken or revoked
|
|
3737
3814
|
revoke <name> revoke the agent's credential \u2014 it cannot connect until reissued
|
|
3738
3815
|
remove <name> permanently delete the agent from Braid
|
|
3739
3816
|
|
|
3740
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
|
|
3741
3819
|
--no-start enroll only \u2014 prints the exact start command instead
|
|
3742
|
-
--bridge-cmd <cmd> bridge command to spawn (default:
|
|
3820
|
+
--bridge-cmd <cmd> bridge command to spawn (default: ${DEFAULT_BRIDGE_CMD};
|
|
3743
3821
|
also ARP_TUI_BRIDGE_CMD env)
|
|
3744
3822
|
--yes skip the confirmation prompt (required with --json on
|
|
3745
3823
|
revoke/remove)
|
|
@@ -3796,6 +3874,7 @@ async function runAgentCli(instance2, args2, overrides = {}) {
|
|
|
3796
3874
|
runLogin: async () => (await login(instance2)).credentials,
|
|
3797
3875
|
enroll: enrollAgent,
|
|
3798
3876
|
startAgent: startAgentProcess,
|
|
3877
|
+
fetchPosture: fetchLocalPosture,
|
|
3799
3878
|
env: process.env,
|
|
3800
3879
|
out: (line) => console.log(line),
|
|
3801
3880
|
err: (line) => console.error(line),
|
|
@@ -3872,7 +3951,12 @@ async function confirmDestructive(args2, deps, name, actionLine) {
|
|
|
3872
3951
|
return true;
|
|
3873
3952
|
}
|
|
3874
3953
|
async function enrollAndMaybeStart(args2, deps, opts) {
|
|
3875
|
-
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
|
+
});
|
|
3876
3960
|
if (!result.ok) {
|
|
3877
3961
|
const msg = sanitizeForTty(result.message);
|
|
3878
3962
|
if (args2.json) deps.out(JSON.stringify({ ok: false, error: msg }));
|
|
@@ -3895,11 +3979,18 @@ async function enrollAndMaybeStart(args2, deps, opts) {
|
|
|
3895
3979
|
}
|
|
3896
3980
|
deps.err(opts.successLine(sanitizeLabel(agentName)));
|
|
3897
3981
|
if (!started) {
|
|
3898
|
-
deps.err(
|
|
3982
|
+
deps.err(
|
|
3983
|
+
` start it with: ${sanitizeForTty(startArgv(opts.bridgeCmd, agentName, args2.provider, args2.model).join(" "))}`
|
|
3984
|
+
);
|
|
3899
3985
|
return 0;
|
|
3900
3986
|
}
|
|
3901
3987
|
deps.err(`\u2192 starting ${sanitizeLabel(agentName)} now \u2014 press Ctrl-C to stop it`);
|
|
3902
|
-
return deps.startAgent({
|
|
3988
|
+
return deps.startAgent({
|
|
3989
|
+
bridgeCmd: opts.bridgeCmd,
|
|
3990
|
+
name: agentName,
|
|
3991
|
+
provider: args2.provider,
|
|
3992
|
+
model: args2.model
|
|
3993
|
+
});
|
|
3903
3994
|
}
|
|
3904
3995
|
async function runAgentAdd(instance2, args2, deps) {
|
|
3905
3996
|
const name = requireName2(args2, deps);
|
|
@@ -3929,8 +4020,12 @@ async function runAgentStatus(instance2, args2, deps) {
|
|
|
3929
4020
|
const creds = await ensureSignedIn(deps);
|
|
3930
4021
|
const agent = await findMyAgent(oneShotRest(instance2, creds), name, args2, deps);
|
|
3931
4022
|
if (!agent) return 1;
|
|
4023
|
+
const posture = await deps.fetchPosture({
|
|
4024
|
+
bridgeCmd: resolveBridgeCmd(args2.bridgeCmd, deps.env),
|
|
4025
|
+
agentName: name
|
|
4026
|
+
});
|
|
3932
4027
|
if (args2.json) {
|
|
3933
|
-
deps.out(JSON.stringify(agent, null, 2));
|
|
4028
|
+
deps.out(JSON.stringify({ ...agent, localPosture: posture }, null, 2));
|
|
3934
4029
|
return 0;
|
|
3935
4030
|
}
|
|
3936
4031
|
const row = (label, value) => deps.out(`${(label + ":").padEnd(14)}${value}`);
|
|
@@ -3950,6 +4045,22 @@ async function runAgentStatus(instance2, args2, deps) {
|
|
|
3950
4045
|
);
|
|
3951
4046
|
if (agent.runtimeVersion) row("runtime", sanitizeLabel(agent.runtimeVersion, 40));
|
|
3952
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
|
+
}
|
|
3953
4064
|
return 0;
|
|
3954
4065
|
}
|
|
3955
4066
|
async function runAgentReissue(instance2, args2, deps) {
|
|
@@ -4765,7 +4876,7 @@ commands:
|
|
|
4765
4876
|
profile manage saved instances (list|add|switch|remove; run \`arp-tui profile\`)
|
|
4766
4877
|
agent add <name> create a personal agent on Braid, enroll it on this machine
|
|
4767
4878
|
via the local bridge, and start it (--no-start to skip;
|
|
4768
|
-
--bridge-cmd/--provider/--json \u2014 run \`arp-tui agent\` for details)
|
|
4879
|
+
--bridge-cmd/--provider/--model/--json \u2014 run \`arp-tui agent\` for details)
|
|
4769
4880
|
agent status|reissue|revoke|remove <name>
|
|
4770
4881
|
inspect or recover an agent: detail card, fresh credential +
|
|
4771
4882
|
re-enroll, credential revoke, permanent delete (revoke/remove
|
|
@@ -4825,6 +4936,7 @@ function parseCliArgs(argv) {
|
|
|
4825
4936
|
"clerk-template": { type: "string" },
|
|
4826
4937
|
"clerk-oauth-client-id": { type: "string" },
|
|
4827
4938
|
provider: { type: "string" },
|
|
4939
|
+
model: { type: "string" },
|
|
4828
4940
|
"no-start": { type: "boolean" },
|
|
4829
4941
|
"bridge-cmd": { type: "string" },
|
|
4830
4942
|
channel: { type: "string" },
|
|
@@ -4852,6 +4964,7 @@ function parseCliArgs(argv) {
|
|
|
4852
4964
|
clerkTemplate: parsed.values["clerk-template"],
|
|
4853
4965
|
clerkOAuthClientId: parsed.values["clerk-oauth-client-id"],
|
|
4854
4966
|
provider: parsed.values.provider,
|
|
4967
|
+
model: parsed.values.model,
|
|
4855
4968
|
noStart: parsed.values["no-start"] === true,
|
|
4856
4969
|
bridgeCmd: parsed.values["bridge-cmd"],
|
|
4857
4970
|
channel: parsed.values.channel,
|
|
@@ -4970,6 +5083,7 @@ if (args.cmd === "login") {
|
|
|
4970
5083
|
sub: args.sub,
|
|
4971
5084
|
name: args.name,
|
|
4972
5085
|
provider: args.provider,
|
|
5086
|
+
model: args.model,
|
|
4973
5087
|
noStart: args.noStart,
|
|
4974
5088
|
bridgeCmd: args.bridgeCmd,
|
|
4975
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