@wrongstack/webui 0.3.4 → 0.3.7
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/assets/index-B-u6omip.css +1 -0
- package/dist/assets/{index-C0CgRrvX.js → index-Do84Z2Fv.js} +31 -31
- package/dist/index.css +3 -0
- package/dist/index.css.map +1 -1
- package/dist/index.html +2 -2
- package/dist/index.js +46 -15
- package/dist/index.js.map +1 -1
- package/dist/server/entry.js +53 -17
- package/dist/server/entry.js.map +1 -1
- package/dist/server/index.js +53 -17
- package/dist/server/index.js.map +1 -1
- package/package.json +5 -5
- package/dist/assets/index-TCwASaz8.css +0 -1
package/dist/index.js
CHANGED
|
@@ -108,6 +108,11 @@ function playCompletionChime() {
|
|
|
108
108
|
tone(659.25, 0, 0.18);
|
|
109
109
|
tone(880, 0.12, 0.24);
|
|
110
110
|
}
|
|
111
|
+
function playPermissionChime() {
|
|
112
|
+
tone(523.25, 0, 0.15);
|
|
113
|
+
tone(659.25, 0.1, 0.15);
|
|
114
|
+
tone(783.99, 0.2, 0.25);
|
|
115
|
+
}
|
|
111
116
|
|
|
112
117
|
// src/lib/favicon.ts
|
|
113
118
|
var BASE_BG = "#4f46e5";
|
|
@@ -119,6 +124,8 @@ function buildSvg(status) {
|
|
|
119
124
|
return '<circle cx="50" cy="14" r="14" fill="#ef4444" stroke="#fff" stroke-width="3" />';
|
|
120
125
|
if (status === "running")
|
|
121
126
|
return '<circle cx="50" cy="14" r="14" fill="#f59e0b" stroke="#fff" stroke-width="3" />';
|
|
127
|
+
if (status === "attention")
|
|
128
|
+
return '<circle cx="50" cy="14" r="14" fill="#eab308" stroke="#fff" stroke-width="3"><animate attributeName="opacity" values="1;0.3;1" dur="1s" repeatCount="indefinite"/></circle>';
|
|
122
129
|
return "";
|
|
123
130
|
})();
|
|
124
131
|
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
|
@@ -153,7 +160,7 @@ function installFaviconVisibilityReset() {
|
|
|
153
160
|
if (visibilityHookInstalled || typeof document === "undefined") return;
|
|
154
161
|
visibilityHookInstalled = true;
|
|
155
162
|
document.addEventListener("visibilitychange", () => {
|
|
156
|
-
if (!document.hidden && (currentStatus === "ready" || currentStatus === "error")) {
|
|
163
|
+
if (!document.hidden && (currentStatus === "ready" || currentStatus === "error" || currentStatus === "attention")) {
|
|
157
164
|
setFaviconStatus("idle");
|
|
158
165
|
}
|
|
159
166
|
});
|
|
@@ -178,7 +185,7 @@ async function ensureNotificationPermission() {
|
|
|
178
185
|
return "denied";
|
|
179
186
|
}
|
|
180
187
|
}
|
|
181
|
-
function notifyIfHidden(title, body) {
|
|
188
|
+
function notifyIfHidden(title, body, tag) {
|
|
182
189
|
if (typeof document === "undefined" || !document.hidden) return;
|
|
183
190
|
if (permissionState !== "granted") return;
|
|
184
191
|
try {
|
|
@@ -186,10 +193,13 @@ function notifyIfHidden(title, body) {
|
|
|
186
193
|
body,
|
|
187
194
|
icon: "/favicon.ico",
|
|
188
195
|
// Tag-collapse: if multiple notifications stack while the tab is
|
|
189
|
-
// hidden, only the latest
|
|
190
|
-
// litter the OS notification center.
|
|
191
|
-
tag
|
|
192
|
-
|
|
196
|
+
// hidden, only the latest with the same tag shows up so we don't
|
|
197
|
+
// litter the OS notification center. Permission alerts use a
|
|
198
|
+
// separate tag so they don't get swallowed by run-completion.
|
|
199
|
+
tag: tag ?? "wrongstack-run",
|
|
200
|
+
// Require interaction for permission alerts — the agent is stuck
|
|
201
|
+
// until the user responds, so auto-dismiss would be harmful.
|
|
202
|
+
requireInteraction: tag === "wrongstack-confirm"
|
|
193
203
|
});
|
|
194
204
|
n.onclick = () => {
|
|
195
205
|
window.focus();
|
|
@@ -1172,6 +1182,19 @@ function installHandlers(ws) {
|
|
|
1172
1182
|
input: payload.input,
|
|
1173
1183
|
suggestedPattern: payload.suggestedPattern
|
|
1174
1184
|
});
|
|
1185
|
+
try {
|
|
1186
|
+
playPermissionChime();
|
|
1187
|
+
} catch {
|
|
1188
|
+
}
|
|
1189
|
+
void ensureNotificationPermission();
|
|
1190
|
+
notifyIfHidden(
|
|
1191
|
+
"WrongStack needs approval",
|
|
1192
|
+
`Tool "${payload.toolName}" is waiting for your decision.`,
|
|
1193
|
+
"wrongstack-confirm"
|
|
1194
|
+
);
|
|
1195
|
+
if (typeof document !== "undefined" && document.hidden) {
|
|
1196
|
+
setFaviconStatus("attention");
|
|
1197
|
+
}
|
|
1175
1198
|
});
|
|
1176
1199
|
on("run.result", (msg) => {
|
|
1177
1200
|
const payload = msg.payload;
|
|
@@ -5384,7 +5407,7 @@ function ChatView() {
|
|
|
5384
5407
|
|
|
5385
5408
|
// src/components/ConfirmDialog.tsx
|
|
5386
5409
|
import { AlertTriangle as AlertTriangle2, FileEdit, Globe, ShieldAlert, Terminal as Terminal3, Wrench as Wrench3 } from "lucide-react";
|
|
5387
|
-
import { useEffect as useEffect13 } from "react";
|
|
5410
|
+
import { useEffect as useEffect13, useRef as useRef10 } from "react";
|
|
5388
5411
|
|
|
5389
5412
|
// src/components/ui/dialog.tsx
|
|
5390
5413
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
@@ -5512,6 +5535,7 @@ function SmartInputPreview({
|
|
|
5512
5535
|
function ConfirmDialog() {
|
|
5513
5536
|
const { showConfirmDialog, confirmInfo, hideConfirm } = useUIStore();
|
|
5514
5537
|
const { sendConfirm } = useWebSocket();
|
|
5538
|
+
const dialogRef = useRef10(null);
|
|
5515
5539
|
const handleConfirm = (decision) => {
|
|
5516
5540
|
if (confirmInfo) {
|
|
5517
5541
|
sendConfirm(confirmInfo.id, decision);
|
|
@@ -5533,9 +5557,13 @@ function ConfirmDialog() {
|
|
|
5533
5557
|
} else if (e.key === "a" || e.key === "A") {
|
|
5534
5558
|
e.preventDefault();
|
|
5535
5559
|
handleConfirm("always");
|
|
5560
|
+
} else if (e.key === "d" || e.key === "D") {
|
|
5561
|
+
e.preventDefault();
|
|
5562
|
+
handleConfirm("deny");
|
|
5536
5563
|
}
|
|
5537
5564
|
};
|
|
5538
5565
|
window.addEventListener("keydown", onKey);
|
|
5566
|
+
dialogRef.current?.focus();
|
|
5539
5567
|
return () => window.removeEventListener("keydown", onKey);
|
|
5540
5568
|
}, [showConfirmDialog, confirmInfo?.id]);
|
|
5541
5569
|
if (!confirmInfo) {
|
|
@@ -5543,11 +5571,11 @@ function ConfirmDialog() {
|
|
|
5543
5571
|
}
|
|
5544
5572
|
const Icon2 = pickToolIcon(confirmInfo.toolName);
|
|
5545
5573
|
const isEdit = /edit|write/i.test(confirmInfo.toolName);
|
|
5546
|
-
return /* @__PURE__ */ jsx19(Dialog, { open: showConfirmDialog, onOpenChange: () => hideConfirm(), children: /* @__PURE__ */ jsxs18(DialogContent, { className: "sm:max-w-2xl", children: [
|
|
5574
|
+
return /* @__PURE__ */ jsx19(Dialog, { open: showConfirmDialog, onOpenChange: () => hideConfirm(), children: /* @__PURE__ */ jsxs18(DialogContent, { className: "sm:max-w-2xl border-yellow-500/50", ref: dialogRef, tabIndex: -1, children: [
|
|
5547
5575
|
/* @__PURE__ */ jsxs18(DialogHeader, { children: [
|
|
5548
5576
|
/* @__PURE__ */ jsxs18(DialogTitle, { className: "flex items-center gap-2", children: [
|
|
5549
|
-
/* @__PURE__ */ jsx19(ShieldAlert, { className: "h-5 w-5 text-yellow-500" }),
|
|
5550
|
-
"
|
|
5577
|
+
/* @__PURE__ */ jsx19(ShieldAlert, { className: "h-5 w-5 text-yellow-500 animate-pulse" }),
|
|
5578
|
+
"Approval required: ",
|
|
5551
5579
|
confirmInfo.toolName
|
|
5552
5580
|
] }),
|
|
5553
5581
|
/* @__PURE__ */ jsxs18(DialogDescription, { children: [
|
|
@@ -5582,14 +5610,17 @@ function ConfirmDialog() {
|
|
|
5582
5610
|
] })
|
|
5583
5611
|
] }),
|
|
5584
5612
|
/* @__PURE__ */ jsxs18(DialogFooter, { className: "gap-2 sm:gap-2 flex-wrap", children: [
|
|
5585
|
-
/* @__PURE__ */
|
|
5613
|
+
/* @__PURE__ */ jsxs18(
|
|
5586
5614
|
Button,
|
|
5587
5615
|
{
|
|
5588
5616
|
variant: "outline",
|
|
5589
5617
|
size: "sm",
|
|
5590
5618
|
onClick: () => handleConfirm("deny"),
|
|
5591
|
-
title: "Reject this and all future calls matching the pattern",
|
|
5592
|
-
children:
|
|
5619
|
+
title: "Reject this and all future calls matching the pattern (d)",
|
|
5620
|
+
children: [
|
|
5621
|
+
"Deny always ",
|
|
5622
|
+
/* @__PURE__ */ jsx19("kbd", { className: "ml-1 text-[10px] border rounded px-1 bg-background", children: "d" })
|
|
5623
|
+
]
|
|
5593
5624
|
}
|
|
5594
5625
|
),
|
|
5595
5626
|
/* @__PURE__ */ jsxs18(
|
|
@@ -5740,7 +5771,7 @@ var ErrorBoundary = class extends Component {
|
|
|
5740
5771
|
|
|
5741
5772
|
// src/components/QuickModelSwitcher.tsx
|
|
5742
5773
|
import { ArrowRight as ArrowRight2, Cpu as Cpu3, Search as Search4 } from "lucide-react";
|
|
5743
|
-
import { useEffect as useEffect15, useMemo as useMemo5, useRef as
|
|
5774
|
+
import { useEffect as useEffect15, useMemo as useMemo5, useRef as useRef11, useState as useState15 } from "react";
|
|
5744
5775
|
import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
5745
5776
|
function QuickModelSwitcher() {
|
|
5746
5777
|
const open = useUIStore((s) => s.modelSwitcherOpen);
|
|
@@ -5749,7 +5780,7 @@ function QuickModelSwitcher() {
|
|
|
5749
5780
|
const [selected, setSelected] = useState15(0);
|
|
5750
5781
|
const [saved, setSaved] = useState15([]);
|
|
5751
5782
|
const [modelsByProvider, setModelsByProvider] = useState15({});
|
|
5752
|
-
const inputRef =
|
|
5783
|
+
const inputRef = useRef11(null);
|
|
5753
5784
|
const wsUrl = useConfigStore((s) => s.wsUrl);
|
|
5754
5785
|
const currentProvider = useConfigStore((s) => s.provider);
|
|
5755
5786
|
const currentModel = useConfigStore((s) => s.model);
|