agent-relay-server 0.11.5 → 0.11.6
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/package.json +4 -3
- package/public/index.html +300 -15
- package/runner/src/adapter.ts +4 -1
- package/src/routes.ts +13 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-relay-server",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.6",
|
|
4
4
|
"description": "Lightweight HTTP message relay for inter-agent communication across machines",
|
|
5
5
|
"module": "src/index.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -35,12 +35,13 @@
|
|
|
35
35
|
"agent-relay-sdk": "0.2.4"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
|
-
"prepack": "
|
|
38
|
+
"prepack": "bun run build:dashboard >&2",
|
|
39
39
|
"postinstall": "node scripts/install-bin-shim.cjs",
|
|
40
40
|
"start": "bun run src/index.ts",
|
|
41
41
|
"dev": "bun --watch run src/index.ts",
|
|
42
42
|
"dev:dashboard": "cd dashboard && npx vite",
|
|
43
|
-
"build:
|
|
43
|
+
"build:sdk": "cd sdk && bun run build",
|
|
44
|
+
"build:dashboard": "bun run build:sdk && cd dashboard && npx vite build",
|
|
44
45
|
"test": "bun test",
|
|
45
46
|
"smoke:spawn": "bun run scripts/orchestrator-spawn-smoke.ts",
|
|
46
47
|
"typecheck": "tsc --noEmit",
|
package/public/index.html
CHANGED
|
@@ -10753,13 +10753,23 @@ function providerPendingApproval(value) {
|
|
|
10753
10753
|
id: choice.id,
|
|
10754
10754
|
label: typeof choice.label === "string" ? choice.label : String(choice.id || "")
|
|
10755
10755
|
})).filter((choice) => (choice.id === "approve" || choice.id === "approve-session" || choice.id === "deny" || choice.id === "abort") && Boolean(choice.label)) : [];
|
|
10756
|
+
const questions = Array.isArray(value.questions) ? value.questions.filter(isRecord$2).map((q) => ({
|
|
10757
|
+
question: typeof q.question === "string" ? q.question : "",
|
|
10758
|
+
header: typeof q.header === "string" ? q.header : void 0,
|
|
10759
|
+
multiSelect: q.multiSelect === true,
|
|
10760
|
+
options: Array.isArray(q.options) ? q.options.filter(isRecord$2).map((o) => ({
|
|
10761
|
+
label: typeof o.label === "string" ? o.label : String(o.label ?? ""),
|
|
10762
|
+
description: typeof o.description === "string" ? o.description : void 0
|
|
10763
|
+
})).filter((o) => Boolean(o.label)) : []
|
|
10764
|
+
})).filter((q) => Boolean(q.question) && q.options.length > 0) : void 0;
|
|
10756
10765
|
return {
|
|
10757
10766
|
id: value.id,
|
|
10758
10767
|
provider: typeof value.provider === "string" ? value.provider : void 0,
|
|
10759
10768
|
kind: typeof value.kind === "string" ? value.kind : void 0,
|
|
10760
10769
|
title: typeof value.title === "string" && value.title ? value.title : "Permission request",
|
|
10761
10770
|
body: typeof value.body === "string" ? value.body : "",
|
|
10762
|
-
choices
|
|
10771
|
+
choices,
|
|
10772
|
+
...questions && questions.length ? { questions } : {}
|
|
10763
10773
|
};
|
|
10764
10774
|
}
|
|
10765
10775
|
function providerBlockedState(agent) {
|
|
@@ -12883,14 +12893,15 @@ var useRelayStore = create$1()(persist((set, get) => ({
|
|
|
12883
12893
|
}
|
|
12884
12894
|
set({ chatSending: false });
|
|
12885
12895
|
},
|
|
12886
|
-
async sendPermissionDecision(agentId, approvalId, decision) {
|
|
12896
|
+
async sendPermissionDecision(agentId, approvalId, decision, answers) {
|
|
12887
12897
|
try {
|
|
12888
12898
|
await api("POST", "/agents/" + encodeURIComponent(agentId) + "/permission-decision", {
|
|
12889
12899
|
approvalId,
|
|
12890
|
-
decision
|
|
12900
|
+
decision,
|
|
12901
|
+
...answers ? { answers } : {}
|
|
12891
12902
|
});
|
|
12892
|
-
const label = decision === "approve" ? "Approved" : decision === "approve-session" ? "Approved for session" : decision === "abort" ? "Aborted" : "Denied";
|
|
12893
|
-
get().showNotification(`${label} permission request`);
|
|
12903
|
+
const label = decision === "approve" ? "Approved" : decision === "approve-session" ? "Approved for session" : decision === "abort" ? "Aborted" : decision === "answer" ? "Answer sent for" : "Denied";
|
|
12904
|
+
get().showNotification(`${label} ${decision === "answer" ? "Claude's question" : "permission request"}`);
|
|
12894
12905
|
await get().fetchAgents();
|
|
12895
12906
|
} catch (e) {
|
|
12896
12907
|
get().showError("Permission Failed", e.message);
|
|
@@ -119805,6 +119816,15 @@ function FileOverlay() {
|
|
|
119805
119816
|
});
|
|
119806
119817
|
}
|
|
119807
119818
|
//#endregion
|
|
119819
|
+
//#region src/components/ui/textarea.tsx
|
|
119820
|
+
function Textarea({ className, ...props }) {
|
|
119821
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("textarea", {
|
|
119822
|
+
"data-slot": "textarea",
|
|
119823
|
+
className: cn$1("flex field-sizing-content min-h-16 w-full rounded-lg border border-input bg-transparent px-2.5 py-2 text-base transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40", className),
|
|
119824
|
+
...props
|
|
119825
|
+
});
|
|
119826
|
+
}
|
|
119827
|
+
//#endregion
|
|
119808
119828
|
//#region src/components/views/chat.tsx
|
|
119809
119829
|
function formatBytes(size) {
|
|
119810
119830
|
if (size < 1024) return `${size} B`;
|
|
@@ -120434,6 +120454,11 @@ function PermissionRequestBubble({ agentId, approval }) {
|
|
|
120434
120454
|
const sendPermissionDecision = useRelayStore((s) => s.sendPermissionDecision);
|
|
120435
120455
|
const [submitting, setSubmitting] = (0, import_react.useState)(null);
|
|
120436
120456
|
if (!approval) return null;
|
|
120457
|
+
if (approval.questions && approval.questions.length) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(QuestionForm, {
|
|
120458
|
+
agentId,
|
|
120459
|
+
approval,
|
|
120460
|
+
questions: approval.questions
|
|
120461
|
+
});
|
|
120437
120462
|
const currentApproval = approval;
|
|
120438
120463
|
const choices = approval.choices.length ? approval.choices : [{
|
|
120439
120464
|
id: "approve",
|
|
@@ -120485,6 +120510,217 @@ function PermissionRequestBubble({ agentId, approval }) {
|
|
|
120485
120510
|
})
|
|
120486
120511
|
});
|
|
120487
120512
|
}
|
|
120513
|
+
function questionAnswered(s) {
|
|
120514
|
+
if (!s) return false;
|
|
120515
|
+
if (s.otherActive && s.other.trim()) return true;
|
|
120516
|
+
return s.labels.length > 0;
|
|
120517
|
+
}
|
|
120518
|
+
function answerValue(s) {
|
|
120519
|
+
const parts = [...s.labels];
|
|
120520
|
+
if (s.otherActive && s.other.trim()) parts.push(s.other.trim());
|
|
120521
|
+
return parts.join(", ");
|
|
120522
|
+
}
|
|
120523
|
+
function QuestionForm({ agentId, approval, questions }) {
|
|
120524
|
+
const sendPermissionDecision = useRelayStore((s) => s.sendPermissionDecision);
|
|
120525
|
+
const [step, setStep] = (0, import_react.useState)(0);
|
|
120526
|
+
const [state, setState] = (0, import_react.useState)({});
|
|
120527
|
+
const [submitting, setSubmitting] = (0, import_react.useState)(null);
|
|
120528
|
+
const q = questions[Math.min(step, questions.length - 1)];
|
|
120529
|
+
const cur = state[step];
|
|
120530
|
+
if (!q) return null;
|
|
120531
|
+
const multi = Boolean(q.multiSelect);
|
|
120532
|
+
const total = questions.length;
|
|
120533
|
+
const isLast = step === total - 1;
|
|
120534
|
+
const answered = questionAnswered(cur);
|
|
120535
|
+
const allAnswered = questions.every((_, i) => questionAnswered(state[i]));
|
|
120536
|
+
const busy = Boolean(submitting);
|
|
120537
|
+
function update(patch) {
|
|
120538
|
+
setState((prev) => ({
|
|
120539
|
+
...prev,
|
|
120540
|
+
[step]: {
|
|
120541
|
+
labels: [],
|
|
120542
|
+
other: "",
|
|
120543
|
+
otherActive: false,
|
|
120544
|
+
...prev[step],
|
|
120545
|
+
...patch
|
|
120546
|
+
}
|
|
120547
|
+
}));
|
|
120548
|
+
}
|
|
120549
|
+
function pickOption(label) {
|
|
120550
|
+
if (multi) {
|
|
120551
|
+
const has = cur?.labels.includes(label);
|
|
120552
|
+
update({ labels: has ? (cur?.labels ?? []).filter((l) => l !== label) : [...cur?.labels ?? [], label] });
|
|
120553
|
+
} else update({
|
|
120554
|
+
labels: [label],
|
|
120555
|
+
otherActive: false
|
|
120556
|
+
});
|
|
120557
|
+
}
|
|
120558
|
+
function pickOther() {
|
|
120559
|
+
if (multi) update({ otherActive: !cur?.otherActive });
|
|
120560
|
+
else update({
|
|
120561
|
+
labels: [],
|
|
120562
|
+
otherActive: true
|
|
120563
|
+
});
|
|
120564
|
+
}
|
|
120565
|
+
async function submit() {
|
|
120566
|
+
if (!allAnswered || busy) return;
|
|
120567
|
+
setSubmitting("answer");
|
|
120568
|
+
try {
|
|
120569
|
+
const answers = {};
|
|
120570
|
+
questions.forEach((qq, i) => {
|
|
120571
|
+
const s = state[i];
|
|
120572
|
+
if (s) answers[qq.question] = answerValue(s);
|
|
120573
|
+
});
|
|
120574
|
+
await sendPermissionDecision(agentId, approval.id, "answer", answers);
|
|
120575
|
+
} finally {
|
|
120576
|
+
setSubmitting(null);
|
|
120577
|
+
}
|
|
120578
|
+
}
|
|
120579
|
+
async function dismiss() {
|
|
120580
|
+
if (busy) return;
|
|
120581
|
+
setSubmitting("dismiss");
|
|
120582
|
+
try {
|
|
120583
|
+
await sendPermissionDecision(agentId, approval.id, "deny");
|
|
120584
|
+
} finally {
|
|
120585
|
+
setSubmitting(null);
|
|
120586
|
+
}
|
|
120587
|
+
}
|
|
120588
|
+
const otherActive = Boolean(cur?.otherActive);
|
|
120589
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
120590
|
+
className: "flex justify-start mb-3",
|
|
120591
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
120592
|
+
className: "w-full max-w-[92%] md:max-w-[78%] rounded-2xl rounded-bl-sm bg-card ring-1 ring-amber-500/35 px-3.5 py-3 text-sm",
|
|
120593
|
+
children: [
|
|
120594
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
120595
|
+
className: "flex items-center gap-2",
|
|
120596
|
+
children: [
|
|
120597
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MessageCircleQuestionMark, { className: "h-4 w-4 shrink-0 text-amber-400" }),
|
|
120598
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
120599
|
+
className: "text-sm font-medium text-amber-100",
|
|
120600
|
+
children: approval.title
|
|
120601
|
+
}),
|
|
120602
|
+
total > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge$1, {
|
|
120603
|
+
variant: "outline",
|
|
120604
|
+
className: "ml-auto h-5 px-1.5 text-[10px] text-muted-foreground",
|
|
120605
|
+
children: [
|
|
120606
|
+
step + 1,
|
|
120607
|
+
" / ",
|
|
120608
|
+
total
|
|
120609
|
+
]
|
|
120610
|
+
})
|
|
120611
|
+
]
|
|
120612
|
+
}),
|
|
120613
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
120614
|
+
className: "mt-3",
|
|
120615
|
+
children: [
|
|
120616
|
+
q.header && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
120617
|
+
className: "text-[11px] font-semibold uppercase tracking-wide text-amber-300/80",
|
|
120618
|
+
children: q.header
|
|
120619
|
+
}),
|
|
120620
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
120621
|
+
className: "mt-0.5 text-sm text-foreground whitespace-pre-wrap break-words",
|
|
120622
|
+
children: q.question
|
|
120623
|
+
}),
|
|
120624
|
+
multi && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
120625
|
+
className: "mt-0.5 text-[11px] text-muted-foreground",
|
|
120626
|
+
children: "Select all that apply"
|
|
120627
|
+
}),
|
|
120628
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
120629
|
+
className: "mt-2 flex flex-col gap-1.5",
|
|
120630
|
+
children: [
|
|
120631
|
+
q.options.map((opt) => {
|
|
120632
|
+
const selected = Boolean(cur?.labels.includes(opt.label));
|
|
120633
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
|
|
120634
|
+
type: "button",
|
|
120635
|
+
disabled: busy,
|
|
120636
|
+
onClick: () => pickOption(opt.label),
|
|
120637
|
+
className: cn$1("flex items-start gap-2 rounded-lg border px-2.5 py-2 text-left transition-colors", selected ? "border-amber-500/60 bg-amber-500/10" : "border-border bg-background/60 hover:bg-background", busy && "opacity-60"),
|
|
120638
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
120639
|
+
className: cn$1("mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center border text-amber-300", multi ? "rounded" : "rounded-full", selected ? "border-amber-400 bg-amber-400/20" : "border-muted-foreground/40"),
|
|
120640
|
+
children: selected && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Check, { className: "h-3 w-3" })
|
|
120641
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
120642
|
+
className: "min-w-0",
|
|
120643
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
120644
|
+
className: "text-sm text-foreground",
|
|
120645
|
+
children: opt.label
|
|
120646
|
+
}), opt.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
120647
|
+
className: "block text-xs text-muted-foreground",
|
|
120648
|
+
children: opt.description
|
|
120649
|
+
})]
|
|
120650
|
+
})]
|
|
120651
|
+
}, opt.label);
|
|
120652
|
+
}),
|
|
120653
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
|
|
120654
|
+
type: "button",
|
|
120655
|
+
disabled: busy,
|
|
120656
|
+
onClick: pickOther,
|
|
120657
|
+
className: cn$1("flex items-start gap-2 rounded-lg border px-2.5 py-2 text-left transition-colors", otherActive ? "border-amber-500/60 bg-amber-500/10" : "border-border bg-background/60 hover:bg-background", busy && "opacity-60"),
|
|
120658
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
120659
|
+
className: cn$1("mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center border text-amber-300", multi ? "rounded" : "rounded-full", otherActive ? "border-amber-400 bg-amber-400/20" : "border-muted-foreground/40"),
|
|
120660
|
+
children: otherActive && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Check, { className: "h-3 w-3" })
|
|
120661
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
120662
|
+
className: "text-sm text-foreground",
|
|
120663
|
+
children: "Other…"
|
|
120664
|
+
})]
|
|
120665
|
+
}),
|
|
120666
|
+
otherActive && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Textarea, {
|
|
120667
|
+
autoFocus: true,
|
|
120668
|
+
rows: 2,
|
|
120669
|
+
disabled: busy,
|
|
120670
|
+
value: cur?.other ?? "",
|
|
120671
|
+
onChange: (e) => update({
|
|
120672
|
+
other: e.target.value,
|
|
120673
|
+
otherActive: true
|
|
120674
|
+
}),
|
|
120675
|
+
placeholder: "Type your answer",
|
|
120676
|
+
className: "mt-1 text-sm"
|
|
120677
|
+
})
|
|
120678
|
+
]
|
|
120679
|
+
})
|
|
120680
|
+
]
|
|
120681
|
+
}),
|
|
120682
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
120683
|
+
className: "mt-3 flex items-center gap-1.5",
|
|
120684
|
+
children: [
|
|
120685
|
+
step > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
120686
|
+
size: "sm",
|
|
120687
|
+
variant: "outline",
|
|
120688
|
+
disabled: busy,
|
|
120689
|
+
onClick: () => setStep((s) => s - 1),
|
|
120690
|
+
className: "h-7 px-2 text-xs",
|
|
120691
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronLeft, { className: "mr-1 h-3 w-3" }), "Back"]
|
|
120692
|
+
}),
|
|
120693
|
+
!isLast ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
120694
|
+
size: "sm",
|
|
120695
|
+
disabled: busy || !answered,
|
|
120696
|
+
onClick: () => setStep((s) => s + 1),
|
|
120697
|
+
className: "h-7 px-2 text-xs",
|
|
120698
|
+
children: ["Next", /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronRight, { className: "ml-1 h-3 w-3" })]
|
|
120699
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
120700
|
+
size: "sm",
|
|
120701
|
+
disabled: busy || !allAnswered,
|
|
120702
|
+
onClick: () => void submit(),
|
|
120703
|
+
className: "h-7 px-2 text-xs",
|
|
120704
|
+
children: [
|
|
120705
|
+
submitting === "answer" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoaderCircle, { className: "mr-1.5 h-3 w-3 animate-spin" }),
|
|
120706
|
+
"Send answer",
|
|
120707
|
+
total > 1 ? "s" : ""
|
|
120708
|
+
]
|
|
120709
|
+
}),
|
|
120710
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
120711
|
+
size: "sm",
|
|
120712
|
+
variant: "ghost",
|
|
120713
|
+
disabled: busy,
|
|
120714
|
+
onClick: () => void dismiss(),
|
|
120715
|
+
className: "ml-auto h-7 px-2 text-xs text-muted-foreground",
|
|
120716
|
+
children: [submitting === "dismiss" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoaderCircle, { className: "mr-1.5 h-3 w-3 animate-spin" }), "Dismiss"]
|
|
120717
|
+
})
|
|
120718
|
+
]
|
|
120719
|
+
})
|
|
120720
|
+
]
|
|
120721
|
+
})
|
|
120722
|
+
});
|
|
120723
|
+
}
|
|
120488
120724
|
function DateSeparator({ date }) {
|
|
120489
120725
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
120490
120726
|
className: "flex items-center justify-center gap-3 py-3 my-1",
|
|
@@ -124295,15 +124531,6 @@ function IntegrationsView() {
|
|
|
124295
124531
|
});
|
|
124296
124532
|
}
|
|
124297
124533
|
//#endregion
|
|
124298
|
-
//#region src/components/ui/textarea.tsx
|
|
124299
|
-
function Textarea({ className, ...props }) {
|
|
124300
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("textarea", {
|
|
124301
|
-
"data-slot": "textarea",
|
|
124302
|
-
className: cn$1("flex field-sizing-content min-h-16 w-full rounded-lg border border-input bg-transparent px-2.5 py-2 text-base transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40", className),
|
|
124303
|
-
...props
|
|
124304
|
-
});
|
|
124305
|
-
}
|
|
124306
|
-
//#endregion
|
|
124307
124534
|
//#region src/components/views/security.tsx
|
|
124308
124535
|
var scopeOptions = [
|
|
124309
124536
|
"admin:*",
|
|
@@ -153336,6 +153563,10 @@ if ("serviceWorker" in navigator) {
|
|
|
153336
153563
|
border-style: dashed;
|
|
153337
153564
|
}
|
|
153338
153565
|
|
|
153566
|
+
.border-amber-400 {
|
|
153567
|
+
border-color: var(--color-amber-400);
|
|
153568
|
+
}
|
|
153569
|
+
|
|
153339
153570
|
.border-amber-500\/15 {
|
|
153340
153571
|
border-color: #f99c0026;
|
|
153341
153572
|
}
|
|
@@ -153376,6 +153607,16 @@ if ("serviceWorker" in navigator) {
|
|
|
153376
153607
|
}
|
|
153377
153608
|
}
|
|
153378
153609
|
|
|
153610
|
+
.border-amber-500\/60 {
|
|
153611
|
+
border-color: #f99c0099;
|
|
153612
|
+
}
|
|
153613
|
+
|
|
153614
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
153615
|
+
.border-amber-500\/60 {
|
|
153616
|
+
border-color: color-mix(in oklab, var(--color-amber-500) 60%, transparent);
|
|
153617
|
+
}
|
|
153618
|
+
}
|
|
153619
|
+
|
|
153379
153620
|
.border-amber-800\/60 {
|
|
153380
153621
|
border-color: #953d0099;
|
|
153381
153622
|
}
|
|
@@ -153530,6 +153771,16 @@ if ("serviceWorker" in navigator) {
|
|
|
153530
153771
|
border-color: var(--input);
|
|
153531
153772
|
}
|
|
153532
153773
|
|
|
153774
|
+
.border-muted-foreground\/40 {
|
|
153775
|
+
border-color: var(--muted-foreground);
|
|
153776
|
+
}
|
|
153777
|
+
|
|
153778
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
153779
|
+
.border-muted-foreground\/40 {
|
|
153780
|
+
border-color: color-mix(in oklab, var(--muted-foreground) 40%, transparent);
|
|
153781
|
+
}
|
|
153782
|
+
}
|
|
153783
|
+
|
|
153533
153784
|
.border-orange-500\/20 {
|
|
153534
153785
|
border-color: #fe6e0033;
|
|
153535
153786
|
}
|
|
@@ -153784,6 +154035,16 @@ if ("serviceWorker" in navigator) {
|
|
|
153784
154035
|
background-color: var(--color-amber-400);
|
|
153785
154036
|
}
|
|
153786
154037
|
|
|
154038
|
+
.bg-amber-400\/20 {
|
|
154039
|
+
background-color: #fcbb0033;
|
|
154040
|
+
}
|
|
154041
|
+
|
|
154042
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
154043
|
+
.bg-amber-400\/20 {
|
|
154044
|
+
background-color: color-mix(in oklab, var(--color-amber-400) 20%, transparent);
|
|
154045
|
+
}
|
|
154046
|
+
}
|
|
154047
|
+
|
|
153787
154048
|
.bg-amber-500\/10 {
|
|
153788
154049
|
background-color: #f99c001a;
|
|
153789
154050
|
}
|
|
@@ -153804,7 +154065,17 @@ if ("serviceWorker" in navigator) {
|
|
|
153804
154065
|
}
|
|
153805
154066
|
}
|
|
153806
154067
|
|
|
153807
|
-
.bg-background, .bg-background\/
|
|
154068
|
+
.bg-background, .bg-background\/60 {
|
|
154069
|
+
background-color: var(--background);
|
|
154070
|
+
}
|
|
154071
|
+
|
|
154072
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
154073
|
+
.bg-background\/60 {
|
|
154074
|
+
background-color: color-mix(in oklab, var(--background) 60%, transparent);
|
|
154075
|
+
}
|
|
154076
|
+
}
|
|
154077
|
+
|
|
154078
|
+
.bg-background\/80 {
|
|
153808
154079
|
background-color: var(--background);
|
|
153809
154080
|
}
|
|
153810
154081
|
|
|
@@ -154830,6 +155101,16 @@ if ("serviceWorker" in navigator) {
|
|
|
154830
155101
|
color: var(--color-amber-300);
|
|
154831
155102
|
}
|
|
154832
155103
|
|
|
155104
|
+
.text-amber-300\/80 {
|
|
155105
|
+
color: #ffd236cc;
|
|
155106
|
+
}
|
|
155107
|
+
|
|
155108
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
155109
|
+
.text-amber-300\/80 {
|
|
155110
|
+
color: color-mix(in oklab, var(--color-amber-300) 80%, transparent);
|
|
155111
|
+
}
|
|
155112
|
+
}
|
|
155113
|
+
|
|
154833
155114
|
.text-amber-400 {
|
|
154834
155115
|
color: var(--color-amber-400);
|
|
154835
155116
|
}
|
|
@@ -155590,6 +155871,10 @@ if ("serviceWorker" in navigator) {
|
|
|
155590
155871
|
}
|
|
155591
155872
|
}
|
|
155592
155873
|
|
|
155874
|
+
.hover\:bg-background:hover {
|
|
155875
|
+
background-color: var(--background);
|
|
155876
|
+
}
|
|
155877
|
+
|
|
155593
155878
|
.hover\:bg-black\/80:hover {
|
|
155594
155879
|
background-color: #000c;
|
|
155595
155880
|
}
|
package/runner/src/adapter.ts
CHANGED
|
@@ -89,12 +89,15 @@ export interface TerminalAttachSpec {
|
|
|
89
89
|
ttlMs?: number;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
export type ProviderPermissionDecision = "approve" | "approve-session" | "deny" | "abort";
|
|
92
|
+
export type ProviderPermissionDecision = "approve" | "approve-session" | "deny" | "abort" | "answer";
|
|
93
93
|
|
|
94
94
|
export interface ProviderPermissionDecisionInput {
|
|
95
95
|
approvalId: string;
|
|
96
96
|
decision: ProviderPermissionDecision;
|
|
97
97
|
reason?: string;
|
|
98
|
+
// For "answer" decisions (Claude AskUserQuestion): maps each question's text
|
|
99
|
+
// to the chosen option label(s). Multi-select labels are comma-joined.
|
|
100
|
+
answers?: Record<string, string>;
|
|
98
101
|
}
|
|
99
102
|
|
|
100
103
|
export interface ProviderAdapter {
|
package/src/routes.ts
CHANGED
|
@@ -2416,9 +2416,20 @@ const postAgentPermissionDecision: Handler = async (req, params) => {
|
|
|
2416
2416
|
try {
|
|
2417
2417
|
if (!isRecord(parsed.body)) return error("permission decision required");
|
|
2418
2418
|
const approvalId = cleanString(parsed.body.approvalId, "approvalId", { required: true, max: 240 })!;
|
|
2419
|
-
const decision = cleanEnum(parsed.body.decision, "decision", ["approve", "approve-session", "deny", "abort"] as const);
|
|
2419
|
+
const decision = cleanEnum(parsed.body.decision, "decision", ["approve", "approve-session", "deny", "abort", "answer"] as const);
|
|
2420
2420
|
if (!decision) return error("decision required");
|
|
2421
2421
|
const reason = cleanString(parsed.body.reason, "reason", { max: 500 });
|
|
2422
|
+
// AskUserQuestion answers: { "<question text>": "<chosen label(s)>" }
|
|
2423
|
+
const answers = decision === "answer" && isRecord(parsed.body.answers)
|
|
2424
|
+
? Object.fromEntries(
|
|
2425
|
+
Object.entries(parsed.body.answers)
|
|
2426
|
+
.filter(([, v]) => typeof v === "string")
|
|
2427
|
+
.map(([k, v]) => [k.slice(0, 2000), (v as string).slice(0, 4000)]),
|
|
2428
|
+
)
|
|
2429
|
+
: undefined;
|
|
2430
|
+
if (decision === "answer" && (!answers || Object.keys(answers).length === 0)) {
|
|
2431
|
+
return error("answers required for answer decision");
|
|
2432
|
+
}
|
|
2422
2433
|
const agent = getAgent(params.id!);
|
|
2423
2434
|
if (!agent) return error("agent not found", 404);
|
|
2424
2435
|
if (!agentIsControlEligible(agent)) return error("agent cannot receive permission decisions", 400);
|
|
@@ -2445,6 +2456,7 @@ const postAgentPermissionDecision: Handler = async (req, params) => {
|
|
|
2445
2456
|
approvalId,
|
|
2446
2457
|
decision,
|
|
2447
2458
|
...(reason ? { reason } : {}),
|
|
2459
|
+
...(answers ? { answers } : {}),
|
|
2448
2460
|
requestedBy: "dashboard",
|
|
2449
2461
|
requestedAt: Date.now(),
|
|
2450
2462
|
},
|