arp-tui 0.0.10 → 0.0.11
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 +234 -193
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2229,6 +2229,14 @@ function createStore(opts) {
|
|
|
2229
2229
|
pendingAttentionAck = null;
|
|
2230
2230
|
set({ mode: "attention_level", attentionDraft: "", error: null });
|
|
2231
2231
|
}
|
|
2232
|
+
function noteHandoffIneligible() {
|
|
2233
|
+
set({ error: "that attention item wasn't raised by an agent" });
|
|
2234
|
+
}
|
|
2235
|
+
function noteHandoffExit(code) {
|
|
2236
|
+
set({ error: code === 0 ? null : `handoff exited with code ${code}` });
|
|
2237
|
+
void refreshChannelAttention();
|
|
2238
|
+
void pollAttention();
|
|
2239
|
+
}
|
|
2232
2240
|
function beginAttentionAck(all) {
|
|
2233
2241
|
if (state.attentionBusy) return;
|
|
2234
2242
|
if (all) pendingAttentionAck = "all";
|
|
@@ -2627,6 +2635,7 @@ function createStore(opts) {
|
|
|
2627
2635
|
else if (state.connection !== "connected") ws.reconnectNow();
|
|
2628
2636
|
}
|
|
2629
2637
|
async function init() {
|
|
2638
|
+
if (initialized) return;
|
|
2630
2639
|
if (!creds || !creds.token && !clerkSupplier) {
|
|
2631
2640
|
enterTokenPrompt("no token found \u2014 paste a fresh one to connect");
|
|
2632
2641
|
return;
|
|
@@ -2784,6 +2793,8 @@ function createStore(opts) {
|
|
|
2784
2793
|
moveAttentionSelection,
|
|
2785
2794
|
beginAttentionRaise,
|
|
2786
2795
|
beginAttentionAck,
|
|
2796
|
+
noteHandoffIneligible,
|
|
2797
|
+
noteHandoffExit,
|
|
2787
2798
|
setAttentionDraft,
|
|
2788
2799
|
submitAttentionInput,
|
|
2789
2800
|
jumpNextActive: () => {
|
|
@@ -2796,6 +2807,207 @@ function createStore(opts) {
|
|
|
2796
2807
|
};
|
|
2797
2808
|
}
|
|
2798
2809
|
|
|
2810
|
+
// src/api/bridgeProcess.ts
|
|
2811
|
+
import { spawn as spawn2 } from "child_process";
|
|
2812
|
+
var DEFAULT_BRIDGE_CMD = "npx -y @snowyroad/braid";
|
|
2813
|
+
var ENROLL_TIMEOUT_MS = 12e4;
|
|
2814
|
+
var STATUS_TIMEOUT_MS = 6e4;
|
|
2815
|
+
var STDERR_TAIL_CHARS = 600;
|
|
2816
|
+
function resolveBridgeCmd(flag, env = process.env) {
|
|
2817
|
+
return flag ?? env["ARP_TUI_BRIDGE_CMD"] ?? DEFAULT_BRIDGE_CMD;
|
|
2818
|
+
}
|
|
2819
|
+
function splitCmd(cmd) {
|
|
2820
|
+
return cmd.trim().split(/\s+/).filter(Boolean);
|
|
2821
|
+
}
|
|
2822
|
+
function enrollArgv(bridgeCmd2, opts) {
|
|
2823
|
+
return [
|
|
2824
|
+
...splitCmd(bridgeCmd2),
|
|
2825
|
+
"enroll",
|
|
2826
|
+
"--invite-stdin",
|
|
2827
|
+
"--json",
|
|
2828
|
+
...opts?.provider ? ["--provider", opts.provider] : [],
|
|
2829
|
+
...opts?.model ? ["--model", opts.model] : []
|
|
2830
|
+
];
|
|
2831
|
+
}
|
|
2832
|
+
function startArgv(bridgeCmd2, name, provider, model) {
|
|
2833
|
+
return [
|
|
2834
|
+
...splitCmd(bridgeCmd2),
|
|
2835
|
+
"start",
|
|
2836
|
+
name,
|
|
2837
|
+
...provider ? ["--provider", provider] : [],
|
|
2838
|
+
...model ? ["--model", model] : []
|
|
2839
|
+
];
|
|
2840
|
+
}
|
|
2841
|
+
function statusArgv(bridgeCmd2) {
|
|
2842
|
+
return [...splitCmd(bridgeCmd2), "status", "--json"];
|
|
2843
|
+
}
|
|
2844
|
+
function enrollAgent(opts) {
|
|
2845
|
+
const [cmd, ...argv] = enrollArgv(opts.bridgeCmd, { provider: opts.provider, model: opts.model });
|
|
2846
|
+
if (!cmd) {
|
|
2847
|
+
return Promise.resolve({ ok: false, exitCode: null, message: "empty bridge command", stderrTail: "" });
|
|
2848
|
+
}
|
|
2849
|
+
return new Promise((resolve) => {
|
|
2850
|
+
const child = spawn2(cmd, argv, { stdio: ["pipe", "pipe", "pipe"] });
|
|
2851
|
+
let stdout = "";
|
|
2852
|
+
let stderr = "";
|
|
2853
|
+
let settled = false;
|
|
2854
|
+
const timeoutMs = opts.timeoutMs ?? ENROLL_TIMEOUT_MS;
|
|
2855
|
+
const finish = (r) => {
|
|
2856
|
+
if (settled) return;
|
|
2857
|
+
settled = true;
|
|
2858
|
+
clearTimeout(timer);
|
|
2859
|
+
resolve(r);
|
|
2860
|
+
};
|
|
2861
|
+
const timer = setTimeout(() => {
|
|
2862
|
+
finish({
|
|
2863
|
+
ok: false,
|
|
2864
|
+
exitCode: null,
|
|
2865
|
+
message: `bridge enrollment timed out after ${Math.round(timeoutMs / 1e3)}s`,
|
|
2866
|
+
stderrTail: tail(stderr)
|
|
2867
|
+
});
|
|
2868
|
+
child.kill("SIGKILL");
|
|
2869
|
+
}, timeoutMs);
|
|
2870
|
+
child.on("error", (err) => {
|
|
2871
|
+
finish({
|
|
2872
|
+
ok: false,
|
|
2873
|
+
exitCode: null,
|
|
2874
|
+
message: `could not run the bridge (${cmd}): ${sanitizeForTty(err.message)}`,
|
|
2875
|
+
stderrTail: ""
|
|
2876
|
+
});
|
|
2877
|
+
});
|
|
2878
|
+
child.stdout.setEncoding("utf8");
|
|
2879
|
+
child.stdout.on("data", (d) => stdout += d);
|
|
2880
|
+
child.stderr.setEncoding("utf8");
|
|
2881
|
+
child.stderr.on("data", (d) => stderr += d);
|
|
2882
|
+
child.stdin.on("error", () => {
|
|
2883
|
+
});
|
|
2884
|
+
child.stdin.write(opts.connectBlob);
|
|
2885
|
+
child.stdin.end();
|
|
2886
|
+
child.on("close", (code) => {
|
|
2887
|
+
if (code !== 0) {
|
|
2888
|
+
finish({
|
|
2889
|
+
ok: false,
|
|
2890
|
+
exitCode: code,
|
|
2891
|
+
message: `bridge enroll exited ${code ?? "on a signal"}`,
|
|
2892
|
+
stderrTail: tail(stderr)
|
|
2893
|
+
});
|
|
2894
|
+
return;
|
|
2895
|
+
}
|
|
2896
|
+
const receipt = parseReceipt(stdout);
|
|
2897
|
+
if (!receipt) {
|
|
2898
|
+
finish({
|
|
2899
|
+
ok: false,
|
|
2900
|
+
exitCode: 0,
|
|
2901
|
+
message: "the bridge exited 0 but printed no parseable enrollment receipt",
|
|
2902
|
+
stderrTail: tail(stderr)
|
|
2903
|
+
});
|
|
2904
|
+
return;
|
|
2905
|
+
}
|
|
2906
|
+
finish({ ok: true, receipt });
|
|
2907
|
+
});
|
|
2908
|
+
});
|
|
2909
|
+
}
|
|
2910
|
+
function tail(stderr) {
|
|
2911
|
+
return sanitizeForTty(stderr).trim().slice(-STDERR_TAIL_CHARS);
|
|
2912
|
+
}
|
|
2913
|
+
function parseReceipt(stdout) {
|
|
2914
|
+
const lines = stdout.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
2915
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
2916
|
+
const line = lines[i];
|
|
2917
|
+
if (!line.startsWith("{")) continue;
|
|
2918
|
+
try {
|
|
2919
|
+
const data = JSON.parse(line);
|
|
2920
|
+
if (data && typeof data === "object" && data["ok"] === true && typeof data["agentName"] === "string" && typeof data["agentUuid"] === "string") {
|
|
2921
|
+
return {
|
|
2922
|
+
ok: true,
|
|
2923
|
+
agentName: data["agentName"],
|
|
2924
|
+
agentUuid: data["agentUuid"],
|
|
2925
|
+
relayUrl: typeof data["relayUrl"] === "string" ? data["relayUrl"] : "",
|
|
2926
|
+
keystoreFile: typeof data["keystoreFile"] === "string" ? data["keystoreFile"] : ""
|
|
2927
|
+
};
|
|
2928
|
+
}
|
|
2929
|
+
} catch {
|
|
2930
|
+
}
|
|
2931
|
+
}
|
|
2932
|
+
return null;
|
|
2933
|
+
}
|
|
2934
|
+
function fetchLocalPosture(opts) {
|
|
2935
|
+
const [cmd, ...argv] = statusArgv(opts.bridgeCmd);
|
|
2936
|
+
if (!cmd) return Promise.resolve(null);
|
|
2937
|
+
return new Promise((resolve) => {
|
|
2938
|
+
const child = spawn2(cmd, argv, { stdio: ["pipe", "pipe", "pipe"] });
|
|
2939
|
+
let stdout = "";
|
|
2940
|
+
let settled = false;
|
|
2941
|
+
const finish = (r) => {
|
|
2942
|
+
if (settled) return;
|
|
2943
|
+
settled = true;
|
|
2944
|
+
clearTimeout(timer);
|
|
2945
|
+
resolve(r);
|
|
2946
|
+
};
|
|
2947
|
+
const timer = setTimeout(() => {
|
|
2948
|
+
finish(null);
|
|
2949
|
+
child.kill("SIGKILL");
|
|
2950
|
+
}, opts.timeoutMs ?? STATUS_TIMEOUT_MS);
|
|
2951
|
+
child.on("error", () => finish(null));
|
|
2952
|
+
child.stdout.setEncoding("utf8");
|
|
2953
|
+
child.stdout.on("data", (d) => stdout += d);
|
|
2954
|
+
child.stderr.resume();
|
|
2955
|
+
child.stdin.on("error", () => {
|
|
2956
|
+
});
|
|
2957
|
+
child.stdin.end();
|
|
2958
|
+
child.on("close", (code) => {
|
|
2959
|
+
if (code !== 0) {
|
|
2960
|
+
finish(null);
|
|
2961
|
+
return;
|
|
2962
|
+
}
|
|
2963
|
+
const agents = parseStatusAgents(stdout);
|
|
2964
|
+
finish(agents?.find((a) => a.name === opts.agentName) ?? null);
|
|
2965
|
+
});
|
|
2966
|
+
});
|
|
2967
|
+
}
|
|
2968
|
+
function parseStatusAgents(stdout) {
|
|
2969
|
+
const lines = stdout.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
2970
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
2971
|
+
if (!lines[i].startsWith("{")) continue;
|
|
2972
|
+
for (const candidate of [lines[i], lines.slice(i).join("\n")]) {
|
|
2973
|
+
try {
|
|
2974
|
+
const data = JSON.parse(candidate);
|
|
2975
|
+
if (data && typeof data === "object" && Array.isArray(data.agents)) {
|
|
2976
|
+
return data.agents.filter(
|
|
2977
|
+
(a) => !!a && typeof a === "object" && typeof a.name === "string"
|
|
2978
|
+
);
|
|
2979
|
+
}
|
|
2980
|
+
} catch {
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
}
|
|
2984
|
+
return null;
|
|
2985
|
+
}
|
|
2986
|
+
function startAgentProcess(opts) {
|
|
2987
|
+
const [cmd, ...argv] = startArgv(opts.bridgeCmd, opts.name, opts.provider, opts.model);
|
|
2988
|
+
if (!cmd) return Promise.resolve(1);
|
|
2989
|
+
return new Promise((resolve) => {
|
|
2990
|
+
const child = spawn2(cmd, argv, { stdio: "inherit" });
|
|
2991
|
+
child.on("error", () => resolve(1));
|
|
2992
|
+
child.on("close", (code) => resolve(code ?? 1));
|
|
2993
|
+
});
|
|
2994
|
+
}
|
|
2995
|
+
function handoffArgv(bridgeCmd2, agent, channelId) {
|
|
2996
|
+
return [...splitCmd(bridgeCmd2), "handoff", agent, "--channel", channelId];
|
|
2997
|
+
}
|
|
2998
|
+
function runHandoffProcess(opts) {
|
|
2999
|
+
const [cmd, ...argv] = handoffArgv(opts.bridgeCmd, opts.agent, opts.channelId);
|
|
3000
|
+
if (!cmd) return Promise.resolve(1);
|
|
3001
|
+
return new Promise((resolve) => {
|
|
3002
|
+
const child = spawn2(cmd, argv, { stdio: "inherit" });
|
|
3003
|
+
child.on("error", () => resolve(1));
|
|
3004
|
+
child.on("close", (code) => resolve(code ?? 1));
|
|
3005
|
+
});
|
|
3006
|
+
}
|
|
3007
|
+
function handoffTarget(item) {
|
|
3008
|
+
return item?.raisedByType === "bot" && item.raisedBy ? item.raisedBy : null;
|
|
3009
|
+
}
|
|
3010
|
+
|
|
2799
3011
|
// src/ui/ActivityLine.tsx
|
|
2800
3012
|
import { Text } from "ink";
|
|
2801
3013
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -2958,7 +3170,7 @@ function AttentionPanel({
|
|
|
2958
3170
|
": ",
|
|
2959
3171
|
sanitizeForTty(draft),
|
|
2960
3172
|
"\u258C"
|
|
2961
|
-
] }) : /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: busy ? "working\u2026" : "j/k select \xB7 r raise \xB7 x ack selected \xB7 X ack all \xB7 Esc close" })
|
|
3173
|
+
] }) : /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: busy ? "working\u2026" : "j/k select \xB7 r raise \xB7 x ack selected \xB7 X ack all \xB7 h take over agent \xB7 Esc close" })
|
|
2962
3174
|
] });
|
|
2963
3175
|
}
|
|
2964
3176
|
|
|
@@ -3365,7 +3577,7 @@ var ACTIVITY_SETTLE_MS2 = 4e3;
|
|
|
3365
3577
|
function cleanInput(input) {
|
|
3366
3578
|
return input.replace(/\r\n|[\r\n]/g, " ").replace(/[\x00-\x1f\x7f]/g, "");
|
|
3367
3579
|
}
|
|
3368
|
-
function App({ store: store2 }) {
|
|
3580
|
+
function App({ store: store2, onHandoff: onHandoff2 }) {
|
|
3369
3581
|
const { exit } = useApp();
|
|
3370
3582
|
const { isRawModeSupported } = useStdin();
|
|
3371
3583
|
const interactive = isRawModeSupported === true;
|
|
@@ -3421,6 +3633,12 @@ function App({ store: store2 }) {
|
|
|
3421
3633
|
else if (input === "r") store2.beginAttentionRaise();
|
|
3422
3634
|
else if (input === "x") store2.beginAttentionAck(false);
|
|
3423
3635
|
else if (input === "X") store2.beginAttentionAck(true);
|
|
3636
|
+
else if (input === "h") {
|
|
3637
|
+
const item = s.channelAttention[s.attentionSelected];
|
|
3638
|
+
const agent = handoffTarget(item);
|
|
3639
|
+
if (!agent || !item) store2.noteHandoffIneligible();
|
|
3640
|
+
else onHandoff2(agent, item.channelId);
|
|
3641
|
+
}
|
|
3424
3642
|
return;
|
|
3425
3643
|
}
|
|
3426
3644
|
if (s.mode === "switcher") {
|
|
@@ -3615,192 +3833,6 @@ unknown profile command "${args2.sub}".`);
|
|
|
3615
3833
|
}
|
|
3616
3834
|
}
|
|
3617
3835
|
|
|
3618
|
-
// src/api/bridgeProcess.ts
|
|
3619
|
-
import { spawn as spawn2 } from "child_process";
|
|
3620
|
-
var DEFAULT_BRIDGE_CMD = "npx -y @snowyroad/braid";
|
|
3621
|
-
var ENROLL_TIMEOUT_MS = 12e4;
|
|
3622
|
-
var STATUS_TIMEOUT_MS = 6e4;
|
|
3623
|
-
var STDERR_TAIL_CHARS = 600;
|
|
3624
|
-
function resolveBridgeCmd(flag, env = process.env) {
|
|
3625
|
-
return flag ?? env["ARP_TUI_BRIDGE_CMD"] ?? DEFAULT_BRIDGE_CMD;
|
|
3626
|
-
}
|
|
3627
|
-
function splitCmd(cmd) {
|
|
3628
|
-
return cmd.trim().split(/\s+/).filter(Boolean);
|
|
3629
|
-
}
|
|
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
|
-
];
|
|
3648
|
-
}
|
|
3649
|
-
function statusArgv(bridgeCmd) {
|
|
3650
|
-
return [...splitCmd(bridgeCmd), "status", "--json"];
|
|
3651
|
-
}
|
|
3652
|
-
function enrollAgent(opts) {
|
|
3653
|
-
const [cmd, ...argv] = enrollArgv(opts.bridgeCmd, { provider: opts.provider, model: opts.model });
|
|
3654
|
-
if (!cmd) {
|
|
3655
|
-
return Promise.resolve({ ok: false, exitCode: null, message: "empty bridge command", stderrTail: "" });
|
|
3656
|
-
}
|
|
3657
|
-
return new Promise((resolve) => {
|
|
3658
|
-
const child = spawn2(cmd, argv, { stdio: ["pipe", "pipe", "pipe"] });
|
|
3659
|
-
let stdout = "";
|
|
3660
|
-
let stderr = "";
|
|
3661
|
-
let settled = false;
|
|
3662
|
-
const timeoutMs = opts.timeoutMs ?? ENROLL_TIMEOUT_MS;
|
|
3663
|
-
const finish = (r) => {
|
|
3664
|
-
if (settled) return;
|
|
3665
|
-
settled = true;
|
|
3666
|
-
clearTimeout(timer);
|
|
3667
|
-
resolve(r);
|
|
3668
|
-
};
|
|
3669
|
-
const timer = setTimeout(() => {
|
|
3670
|
-
finish({
|
|
3671
|
-
ok: false,
|
|
3672
|
-
exitCode: null,
|
|
3673
|
-
message: `bridge enrollment timed out after ${Math.round(timeoutMs / 1e3)}s`,
|
|
3674
|
-
stderrTail: tail(stderr)
|
|
3675
|
-
});
|
|
3676
|
-
child.kill("SIGKILL");
|
|
3677
|
-
}, timeoutMs);
|
|
3678
|
-
child.on("error", (err) => {
|
|
3679
|
-
finish({
|
|
3680
|
-
ok: false,
|
|
3681
|
-
exitCode: null,
|
|
3682
|
-
message: `could not run the bridge (${cmd}): ${sanitizeForTty(err.message)}`,
|
|
3683
|
-
stderrTail: ""
|
|
3684
|
-
});
|
|
3685
|
-
});
|
|
3686
|
-
child.stdout.setEncoding("utf8");
|
|
3687
|
-
child.stdout.on("data", (d) => stdout += d);
|
|
3688
|
-
child.stderr.setEncoding("utf8");
|
|
3689
|
-
child.stderr.on("data", (d) => stderr += d);
|
|
3690
|
-
child.stdin.on("error", () => {
|
|
3691
|
-
});
|
|
3692
|
-
child.stdin.write(opts.connectBlob);
|
|
3693
|
-
child.stdin.end();
|
|
3694
|
-
child.on("close", (code) => {
|
|
3695
|
-
if (code !== 0) {
|
|
3696
|
-
finish({
|
|
3697
|
-
ok: false,
|
|
3698
|
-
exitCode: code,
|
|
3699
|
-
message: `bridge enroll exited ${code ?? "on a signal"}`,
|
|
3700
|
-
stderrTail: tail(stderr)
|
|
3701
|
-
});
|
|
3702
|
-
return;
|
|
3703
|
-
}
|
|
3704
|
-
const receipt = parseReceipt(stdout);
|
|
3705
|
-
if (!receipt) {
|
|
3706
|
-
finish({
|
|
3707
|
-
ok: false,
|
|
3708
|
-
exitCode: 0,
|
|
3709
|
-
message: "the bridge exited 0 but printed no parseable enrollment receipt",
|
|
3710
|
-
stderrTail: tail(stderr)
|
|
3711
|
-
});
|
|
3712
|
-
return;
|
|
3713
|
-
}
|
|
3714
|
-
finish({ ok: true, receipt });
|
|
3715
|
-
});
|
|
3716
|
-
});
|
|
3717
|
-
}
|
|
3718
|
-
function tail(stderr) {
|
|
3719
|
-
return sanitizeForTty(stderr).trim().slice(-STDERR_TAIL_CHARS);
|
|
3720
|
-
}
|
|
3721
|
-
function parseReceipt(stdout) {
|
|
3722
|
-
const lines = stdout.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
3723
|
-
for (let i = lines.length - 1; i >= 0; i--) {
|
|
3724
|
-
const line = lines[i];
|
|
3725
|
-
if (!line.startsWith("{")) continue;
|
|
3726
|
-
try {
|
|
3727
|
-
const data = JSON.parse(line);
|
|
3728
|
-
if (data && typeof data === "object" && data["ok"] === true && typeof data["agentName"] === "string" && typeof data["agentUuid"] === "string") {
|
|
3729
|
-
return {
|
|
3730
|
-
ok: true,
|
|
3731
|
-
agentName: data["agentName"],
|
|
3732
|
-
agentUuid: data["agentUuid"],
|
|
3733
|
-
relayUrl: typeof data["relayUrl"] === "string" ? data["relayUrl"] : "",
|
|
3734
|
-
keystoreFile: typeof data["keystoreFile"] === "string" ? data["keystoreFile"] : ""
|
|
3735
|
-
};
|
|
3736
|
-
}
|
|
3737
|
-
} catch {
|
|
3738
|
-
}
|
|
3739
|
-
}
|
|
3740
|
-
return null;
|
|
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
|
-
}
|
|
3794
|
-
function startAgentProcess(opts) {
|
|
3795
|
-
const [cmd, ...argv] = startArgv(opts.bridgeCmd, opts.name, opts.provider, opts.model);
|
|
3796
|
-
if (!cmd) return Promise.resolve(1);
|
|
3797
|
-
return new Promise((resolve) => {
|
|
3798
|
-
const child = spawn2(cmd, argv, { stdio: "inherit" });
|
|
3799
|
-
child.on("error", () => resolve(1));
|
|
3800
|
-
child.on("close", (code) => resolve(code ?? 1));
|
|
3801
|
-
});
|
|
3802
|
-
}
|
|
3803
|
-
|
|
3804
3836
|
// src/commands/agent.ts
|
|
3805
3837
|
import readline from "readline/promises";
|
|
3806
3838
|
var AGENT_USAGE = `usage: braid agent <add|status|reissue|revoke|remove> <name> [options]
|
|
@@ -3998,7 +4030,7 @@ async function enrollAndMaybeStart(args2, deps, opts) {
|
|
|
3998
4030
|
async function runAgentAdd(instance2, args2, deps) {
|
|
3999
4031
|
const name = requireName2(args2, deps);
|
|
4000
4032
|
if (!name) return 1;
|
|
4001
|
-
const
|
|
4033
|
+
const bridgeCmd2 = resolveBridgeCmd(args2.bridgeCmd, deps.env);
|
|
4002
4034
|
const creds = await ensureSignedIn(deps);
|
|
4003
4035
|
const rest = oneShotRest(instance2, creds);
|
|
4004
4036
|
let invite;
|
|
@@ -4012,7 +4044,7 @@ async function runAgentAdd(instance2, args2, deps) {
|
|
|
4012
4044
|
}
|
|
4013
4045
|
deps.err(`\u2713 ${sanitizeLabel(name)} created on Braid \u2014 enrolling on this machine\u2026`);
|
|
4014
4046
|
return enrollAndMaybeStart(args2, deps, {
|
|
4015
|
-
bridgeCmd,
|
|
4047
|
+
bridgeCmd: bridgeCmd2,
|
|
4016
4048
|
connectBlob: invite.connectBlob,
|
|
4017
4049
|
successLine: (n) => `\u2714 ${n} is enrolled with Braid`
|
|
4018
4050
|
});
|
|
@@ -4069,7 +4101,7 @@ async function runAgentStatus(instance2, args2, deps) {
|
|
|
4069
4101
|
async function runAgentReissue(instance2, args2, deps) {
|
|
4070
4102
|
const name = requireName2(args2, deps);
|
|
4071
4103
|
if (!name) return 1;
|
|
4072
|
-
const
|
|
4104
|
+
const bridgeCmd2 = resolveBridgeCmd(args2.bridgeCmd, deps.env);
|
|
4073
4105
|
const creds = await ensureSignedIn(deps);
|
|
4074
4106
|
const rest = oneShotRest(instance2, creds);
|
|
4075
4107
|
const agent = await findMyAgent(rest, name, args2, deps);
|
|
@@ -4085,7 +4117,7 @@ async function runAgentReissue(instance2, args2, deps) {
|
|
|
4085
4117
|
}
|
|
4086
4118
|
deps.err(`\u2713 fresh credential minted \u2014 re-enrolling ${sanitizeLabel(name)} on this machine\u2026`);
|
|
4087
4119
|
return enrollAndMaybeStart(args2, deps, {
|
|
4088
|
-
bridgeCmd,
|
|
4120
|
+
bridgeCmd: bridgeCmd2,
|
|
4089
4121
|
connectBlob: invite.connectBlob,
|
|
4090
4122
|
successLine: (n) => `\u2714 ${n} reconnected to Braid`
|
|
4091
4123
|
});
|
|
@@ -5145,4 +5177,13 @@ if (credentials?.tokenType === "dev-jwt" && credentials.token && !credentials.cl
|
|
|
5145
5177
|
);
|
|
5146
5178
|
}
|
|
5147
5179
|
var store = createStore({ instance, credentials });
|
|
5148
|
-
|
|
5180
|
+
var bridgeCmd = resolveBridgeCmd(args.bridgeCmd, process.env);
|
|
5181
|
+
var onHandoff = (agent, channelId) => {
|
|
5182
|
+
void (async () => {
|
|
5183
|
+
inkInstance.unmount();
|
|
5184
|
+
const code = await runHandoffProcess({ bridgeCmd, agent, channelId });
|
|
5185
|
+
store.noteHandoffExit(code);
|
|
5186
|
+
inkInstance = render(/* @__PURE__ */ jsx13(App, { store, onHandoff }));
|
|
5187
|
+
})();
|
|
5188
|
+
};
|
|
5189
|
+
var inkInstance = render(/* @__PURE__ */ jsx13(App, { store, onHandoff }));
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arp-tui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
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.11",
|
|
10
10
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"ink": "^5.2.0",
|
package/package.json
CHANGED