bazilion 0.9.0 → 0.11.0
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/cli.js +1257 -150
- package/dist/cli.js.map +1 -1
- package/dist/daemon.js +3049 -471
- package/dist/daemon.js.map +1 -1
- package/dist/migrations/0001_init.sql +20 -0
- package/dist/web/client/assets/AgentTabs-B3hq5a3e.js +1 -0
- package/dist/web/client/assets/ConfigPage-BCwfgyjD.js +1 -0
- package/dist/web/client/assets/FieldRow-avAFLgYW.js +1 -0
- package/dist/web/client/assets/Page-CwNuDhWz.js +1 -0
- package/dist/web/client/assets/ProductionTeamPolicyEditor-B6dbpuYy.js +7 -0
- package/dist/web/client/assets/{ProfileCommunicationEditor-D1OZ8WE5.js → ProfileCommunicationEditor-Bf8UvmZT.js} +1 -1
- package/dist/web/client/assets/SectionTabs-DZzy01az.js +1 -0
- package/dist/web/client/assets/TeamTabs-sQBHChtd.js +1 -0
- package/dist/web/client/assets/TemplatesTabs-DPsuwsWB.js +1 -0
- package/dist/web/client/assets/_id-C9rkCclz.js +1 -0
- package/dist/web/client/assets/_id-D65IzC8H.js +1 -0
- package/dist/web/client/assets/_id-DE4IY5bL.js +1 -0
- package/dist/web/client/assets/_id-DYASsGQ8.js +1 -0
- package/dist/web/client/assets/activity-C7o6-xHg.js +1 -0
- package/dist/web/client/assets/agents-UroO4d25.js +1 -0
- package/dist/web/client/assets/agents-h8yWXQ2H.js +1 -0
- package/dist/web/client/assets/approvals-DKhF0YLC.js +1 -0
- package/dist/web/client/assets/chevron-down-BK6NPMMP.js +1 -0
- package/dist/web/client/assets/config-q8JDresK.js +3 -0
- package/dist/web/client/assets/context-CBucAoi6.js +1 -0
- package/dist/web/client/assets/inbox-BwoRikj1.js +1 -0
- package/dist/web/client/assets/index-DUXAevpZ.js +12 -0
- package/dist/web/client/assets/login-CNAV9Wer.js +1 -0
- package/dist/web/client/assets/mcp-BKdEFwHO.js +1 -0
- package/dist/web/client/assets/members-BDqZQh26.js +1 -0
- package/dist/web/client/assets/memory-DVdEVr6L.js +1 -0
- package/dist/web/client/assets/plus-b4yFXP0O.js +1 -0
- package/dist/web/client/assets/policy-DdDctqvg.js +1 -0
- package/dist/web/client/assets/preload-helper-mNuBjNXU.js +1 -0
- package/dist/web/client/assets/react-3W8R1pOO.js +1 -0
- package/dist/web/client/assets/routes-BEfALSZv.js +1 -0
- package/dist/web/client/assets/services-DZP2ybzb.js +1 -0
- package/dist/web/client/assets/skills-DoeIjITs.js +1 -0
- package/dist/web/client/assets/styles-BYM0UGdF.css +2 -0
- package/dist/web/client/assets/team-policy-D0jpnn2b.js +1 -0
- package/dist/web/client/assets/teams-DlHRnrQw.js +1 -0
- package/dist/web/client/assets/teams-W3j-UoJ9.js +1 -0
- package/dist/web/client/assets/telegram-2OdeGv4E.js +1 -0
- package/dist/web/client/assets/tokens-MuBfmgue.js +1 -0
- package/dist/web/client/assets/triggers-CX7RMQFQ.js +1 -0
- package/dist/web/client/assets/welcome-CvNr5IMi.js +1 -0
- package/dist/web/client/assets/wire-constants-BhVKOCQa.js +74 -0
- package/dist/web/server/assets/{AgentTabs-BOjTN7QF.js → AgentTabs-DoMDJBXH.js} +10 -7
- package/dist/web/server/assets/{ChatPane-Dh3qxzdb.js → ChatPane-Ba5wTsVk.js} +340 -44
- package/dist/web/server/assets/ConfigPage-BKlh5vOU.js +68 -0
- package/dist/web/server/assets/{FieldRow-DwyqycWI.js → FieldRow-B4eTegH9.js} +5 -5
- package/dist/web/server/assets/Page-LENulSXY.js +111 -0
- package/dist/web/server/assets/{ProductionTeamPolicyEditor-Bke5doyl.js → ProductionTeamPolicyEditor-Y4mzFFvR.js} +4 -4
- package/dist/web/server/assets/SectionTabs-BJTPr5nU.js +8 -0
- package/dist/web/server/assets/{Sidebar-CGmtCnYU.js → Sidebar-DsRVCszF.js} +229 -118
- package/dist/web/server/assets/{TeamTabs-BPxDBfqy.js → TeamTabs-zZzbP1t_.js} +9 -8
- package/dist/web/server/assets/{TemplatesTabs-zf4YhStd.js → TemplatesTabs-CcRxZhJe.js} +5 -4
- package/dist/web/server/assets/{_id-fpFQ9_Ya.js → _id-BhOB8Umi.js} +1 -1
- package/dist/web/server/assets/{_id-CCHA0gdR.js → _id-C3HY4lWg.js} +7 -10
- package/dist/web/server/assets/{_id-B6g9wmPR.js → _id-Cg7x6q3g.js} +22 -28
- package/dist/web/server/assets/{_id-B04VaQlh.js → _id-CwyGjJeP.js} +2 -2
- package/dist/web/server/assets/{_id-_nFwi9gD.js → _id-D27T85mU.js} +1 -1
- package/dist/web/server/assets/{_id-5lLzLwcv.js → _id-D3Ap7zZA.js} +142 -144
- package/dist/web/server/assets/{_id-ButXHnRH.js → _id-DinTp_7X.js} +2 -2
- package/dist/web/server/assets/{_id-DdC9wpNN.js → _id-Dj1yZ3zJ.js} +2 -2
- package/dist/web/server/assets/{_id-DkFgCIb-.js → _id-DqON-59C.js} +2 -2
- package/dist/web/server/assets/{_id-CUWgTqMS.js → _id-IzadFZV9.js} +1 -1
- package/dist/web/server/assets/{_id-C4AOhstq.js → _id-LrvXU4Nr.js} +6 -5
- package/dist/web/server/assets/{_id-DJkzwHjM.js → _id-tB47Vsfp.js} +1 -1
- package/dist/web/server/assets/{_tanstack-start-manifest_v-Div-TukY.js → _tanstack-start-manifest_v-BXauUXg6.js} +96 -51
- package/dist/web/server/assets/{activity-C2ZKg1Q9.js → activity-BCI4mfNS.js} +28 -30
- package/dist/web/server/assets/{activity-DedraoFj.js → activity-D9SMqBhy.js} +2 -2
- package/dist/web/server/assets/{activity-GPx8NCeB.js → activity-DohitgwW.js} +1 -1
- package/dist/web/server/assets/{agents-BR2qXlXF.js → agents-BPKOshR5.js} +1 -1
- package/dist/web/server/assets/{agents-LHowEI6S.js → agents-BY74v7fM.js} +1 -1
- package/dist/web/server/assets/{agents-B8kinIPW.js → agents-BvttypqB.js} +2 -2
- package/dist/web/server/assets/{agents-Bp1nsVs2.js → agents-C9xlWK0Z.js} +2 -2
- package/dist/web/server/assets/agents-CgZMHj80.js +265 -0
- package/dist/web/server/assets/{agents-CUQmWhTp.js → agents-DZuFEj0D.js} +59 -77
- package/dist/web/server/assets/{approvals-VPc0YpLN.js → approvals-BGU-XGIO.js} +1 -1
- package/dist/web/server/assets/{approvals-Dw2LJoSA.js → approvals-CWcFHlor.js} +2 -2
- package/dist/web/server/assets/{approvals-DHgARzd8.js → approvals-DCaVw1Mz.js} +116 -78
- package/dist/web/server/assets/{auth-l-Vf8wlu.js → auth-byfSx6Ja.js} +1 -1
- package/dist/web/server/assets/{config-CHaCv89D.js → config-BDCJdtj2.js} +1 -1
- package/dist/web/server/assets/{config-BvKctDOX.js → config-D2LAsud2.js} +28 -49
- package/dist/web/server/assets/{config-QvHaxGlP.js → config-TeIoyYYc.js} +2 -2
- package/dist/web/server/assets/{context-5lrf2ame.js → context-B-XDf6Ym.js} +1 -1
- package/dist/web/server/assets/{context-D3Egm-vY.js → context-BXGo5Vfi.js} +2 -2
- package/dist/web/server/assets/context-DrkrIWun.js +47 -0
- package/dist/web/server/assets/{createServerRpc-CeKECg65.js → createServerRpc-pU-IQV2Y.js} +1 -1
- package/dist/web/server/assets/{createSsrRpc-ZBGxhl8t.js → createSsrRpc-DFsIAfFd.js} +1 -1
- package/dist/web/server/assets/{empty-plugin-adapters-DKUlnwwl.js → empty-plugin-adapters-Cq4--YW-.js} +1 -1
- package/dist/web/server/assets/{inbox-CkiSvD14.js → inbox-B3-TRsNI.js} +1 -1
- package/dist/web/server/assets/{inbox-Bxb3W04M.js → inbox-BardsGyy.js} +2 -2
- package/dist/web/server/assets/inbox-CUIyf9MT.js +131 -0
- package/dist/web/server/assets/login-Bx5LEyGP.js +118 -0
- package/dist/web/server/assets/login-CmWvxfTK.js +136 -0
- package/dist/web/server/assets/{mcp-BsFKEoXt.js → mcp-2pwT9HU8.js} +1 -1
- package/dist/web/server/assets/{mcp-BU_kKENi.js → mcp-BJjLIdP0.js} +105 -112
- package/dist/web/server/assets/{mcp-CKqwG4mt.js → mcp-DIWTogHM.js} +2 -2
- package/dist/web/server/assets/members-CCv17cjQ.js +46 -0
- package/dist/web/server/assets/{members-DlGBKZNl.js → members-CW5aBe81.js} +1 -1
- package/dist/web/server/assets/{members-ksELRsyk.js → members-VdPwD6CE.js} +2 -2
- package/dist/web/server/assets/{memory-CO0jKGzJ.js → memory-Dngc13Nw.js} +1 -1
- package/dist/web/server/assets/memory-a8Kz57Kh.js +287 -0
- package/dist/web/server/assets/{memory-B5moRnnp.js → memory-pZ4pZT7p.js} +2 -2
- package/dist/web/server/assets/{policy-Dxs78_GO.js → policy-Bb-vEgqg.js} +1 -1
- package/dist/web/server/assets/{policy-Dr55y-Mh.js → policy-BcGELcc9.js} +16 -22
- package/dist/web/server/assets/{policy-DNcGZLOB.js → policy-C30AeFIb.js} +2 -2
- package/dist/web/server/assets/{router-_izWQUeG.js → router-C5_NjTsP.js} +100 -111
- package/dist/web/server/assets/{routes-BSSKp3Rv.js → routes-B6cMLIPk.js} +16 -13
- package/dist/web/server/assets/{routes-BrTOoeth.js → routes-BrA-U_Hm.js} +2 -2
- package/dist/web/server/assets/{routes-DOj6ljcm.js → routes-C19CMLZt.js} +2 -2
- package/dist/web/server/assets/services-B9yBWDX0.js +79 -0
- package/dist/web/server/assets/{services-Pv_V88VA.js → services-C4szdhPx.js} +2 -2
- package/dist/web/server/assets/{services-DhRiNeq0.js → services-wG8I06oS.js} +1 -1
- package/dist/web/server/assets/skills-BZdqiDig.js +358 -0
- package/dist/web/server/assets/{skills-l2cyQ3zS.js → skills-C-UgkuCW.js} +2 -2
- package/dist/web/server/assets/{skills-CFIWVg32.js → skills-a9VSWHWq.js} +1 -1
- package/dist/web/server/assets/{start-DlHq0RaQ.js → start-WH8WzTL_.js} +1 -1
- package/dist/web/server/assets/{team-policy-Csvc5EDd.js → team-policy-vPG01onj.js} +3 -3
- package/dist/web/server/assets/{teams-B9O-WDH5.js → teams-CpQ0YgWf.js} +38 -34
- package/dist/web/server/assets/{teams-35Oprf6e.js → teams-DEpQR2QA.js} +2 -2
- package/dist/web/server/assets/{teams-DFkN7ic7.js → teams-DqfrEoH6.js} +1 -1
- package/dist/web/server/assets/{teams-B5IF65p2.js → teams-MjqgsmC3.js} +1 -1
- package/dist/web/server/assets/{teams-DH1CvWmT.js → teams-OIkHuxy1.js} +2 -2
- package/dist/web/server/assets/teams-jBtvnk59.js +193 -0
- package/dist/web/server/assets/{telegram-C9sQFwWj.js → telegram-CBF8SJzB.js} +36 -71
- package/dist/web/server/assets/{telegram-BdaUIjvs.js → telegram-DNgCWebD.js} +1 -1
- package/dist/web/server/assets/{telegram-mTnJCOmn.js → telegram-XwyKSEtj.js} +2 -2
- package/dist/web/server/assets/{tokens-DdpnfV_Y.js → tokens-BnwFbV7T.js} +2 -2
- package/dist/web/server/assets/{tokens-BCz3PSoT.js → tokens-DPDMSN5O.js} +1 -1
- package/dist/web/server/assets/tokens-yyTSfBSN.js +186 -0
- package/dist/web/server/assets/{triggers-BcTTwMfy.js → triggers-CBl4yMyw.js} +2 -2
- package/dist/web/server/assets/{triggers-BcH_6PW1.js → triggers-D79NoSXk.js} +4 -3
- package/dist/web/server/assets/{triggers-BzJG1nN5.js → triggers-_3rdhwSN.js} +31 -6
- package/dist/web/server/assets/{welcome-CDGE2Sdk.js → welcome-IYHGurWx.js} +21 -13
- package/dist/web/server/server.js +82 -73
- package/dist/worker.js +1614 -153
- package/dist/worker.js.map +1 -1
- package/package.json +5 -3
- package/dist/web/client/assets/AgentTabs-DioGqUVR.js +0 -1
- package/dist/web/client/assets/ConfigTabs-pY-V0Rie.js +0 -1
- package/dist/web/client/assets/FieldRow-DmwAFfbF.js +0 -1
- package/dist/web/client/assets/ProductionTeamPolicyEditor-1a5jQqUB.js +0 -7
- package/dist/web/client/assets/TeamTabs-BViZ4sti.js +0 -1
- package/dist/web/client/assets/TemplatesTabs-DVcY9pMD.js +0 -1
- package/dist/web/client/assets/_id-8P7brhGy.js +0 -1
- package/dist/web/client/assets/_id-C3o3MHq8.js +0 -1
- package/dist/web/client/assets/_id-DGRrSF1e.js +0 -1
- package/dist/web/client/assets/_id-KnJe-aW9.js +0 -1
- package/dist/web/client/assets/activity-WWvJSo4t.js +0 -1
- package/dist/web/client/assets/agents-C32T1voV.js +0 -1
- package/dist/web/client/assets/agents-nH4m4gZ1.js +0 -1
- package/dist/web/client/assets/approvals-l8jIZjqz.js +0 -1
- package/dist/web/client/assets/config-C7wvi1nR.js +0 -3
- package/dist/web/client/assets/context-BEGWE3RC.js +0 -1
- package/dist/web/client/assets/inbox--4aBaAgG.js +0 -1
- package/dist/web/client/assets/index-BCXoh1c8.js +0 -12
- package/dist/web/client/assets/login-Bk2wwIHQ.js +0 -1
- package/dist/web/client/assets/mcp-vM7xgh9e.js +0 -1
- package/dist/web/client/assets/members-cPKfnrSL.js +0 -1
- package/dist/web/client/assets/memory-BOcsaemD.js +0 -1
- package/dist/web/client/assets/policy-BGLCJYvS.js +0 -1
- package/dist/web/client/assets/preload-helper-eOOCz1Fu.js +0 -1
- package/dist/web/client/assets/routes-DnrP3dwv.js +0 -1
- package/dist/web/client/assets/services-C2_O3ifw.js +0 -1
- package/dist/web/client/assets/skills-B__fLZjx.js +0 -1
- package/dist/web/client/assets/styles-Dn24-ZvP.css +0 -2
- package/dist/web/client/assets/team-policy-BdX340m4.js +0 -1
- package/dist/web/client/assets/teams-DZMB4_iw.js +0 -1
- package/dist/web/client/assets/teams-rpaYKNIb.js +0 -1
- package/dist/web/client/assets/telegram-B1O4Ko0V.js +0 -1
- package/dist/web/client/assets/tokens-D7FH9VgA.js +0 -1
- package/dist/web/client/assets/triggers-3PLy2_Fo.js +0 -1
- package/dist/web/client/assets/welcome-B-QQobzq.js +0 -1
- package/dist/web/client/assets/wire-constants-BY9Q9Z7d.js +0 -74
- package/dist/web/server/assets/ConfigTabs-CyuxzesF.js +0 -41
- package/dist/web/server/assets/agents-DU9Hqs58.js +0 -249
- package/dist/web/server/assets/context-CEr4-xiA.js +0 -49
- package/dist/web/server/assets/inbox-DU27iHv_.js +0 -133
- package/dist/web/server/assets/login-CNznncgA.js +0 -58
- package/dist/web/server/assets/login-CQybKk7Y.js +0 -74
- package/dist/web/server/assets/members-40DxRdVj.js +0 -48
- package/dist/web/server/assets/memory-CiTl4cN9.js +0 -289
- package/dist/web/server/assets/services-CHe4ihJk.js +0 -94
- package/dist/web/server/assets/skills-D89ND2kR.js +0 -321
- package/dist/web/server/assets/teams-zcm9XaQU.js +0 -174
- package/dist/web/server/assets/tokens-CkKqrtk-.js +0 -193
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { t as Button } from "./Button-Dsnw22OF.js";
|
|
1
2
|
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
2
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
4
|
import DOMPurify from "dompurify";
|
|
4
5
|
import { marked } from "marked";
|
|
5
6
|
//#region src/lib/md.ts
|
|
@@ -40,6 +41,30 @@ var AUTOSCROLL_THRESHOLD_PX = 40;
|
|
|
40
41
|
var SESSION_POLL_MS = 1e4;
|
|
41
42
|
var TOOL_GROUP_MAX_HEIGHT_PX = 320;
|
|
42
43
|
var MAX_INPUT_HEIGHT = 200;
|
|
44
|
+
/** Keep one inline card per ephemeral shell approval while preserving its first position. */
|
|
45
|
+
function upsertCommandApprovalEntry(entries, approval) {
|
|
46
|
+
const index = entries.findIndex((entry) => entry.type === "command_approval" && entry.approval.id === approval.id);
|
|
47
|
+
if (index === -1) return [...entries, {
|
|
48
|
+
type: "command_approval",
|
|
49
|
+
approval
|
|
50
|
+
}];
|
|
51
|
+
const next = [...entries];
|
|
52
|
+
next[index] = {
|
|
53
|
+
type: "command_approval",
|
|
54
|
+
approval
|
|
55
|
+
};
|
|
56
|
+
return next;
|
|
57
|
+
}
|
|
58
|
+
function interactiveChatRequest(message, attachments) {
|
|
59
|
+
return {
|
|
60
|
+
message,
|
|
61
|
+
attachments,
|
|
62
|
+
bashApprovalMode: "interactive"
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function shellApprovalsUrl(agentId) {
|
|
66
|
+
return `/api/shell-approvals?agentId=${encodeURIComponent(agentId)}`;
|
|
67
|
+
}
|
|
43
68
|
var SLASH_HELP = "slash commands:\n /context — context breakdown (system prompt, tools, skills, history)\n /compact [N] — summarize the head; keep the last N messages verbatim (default 10)\n /reset — reset chat history for this agent\n /help — show this list";
|
|
44
69
|
function prettyArgs(raw) {
|
|
45
70
|
if (!raw) return "";
|
|
@@ -141,10 +166,16 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
|
|
|
141
166
|
const [attachments, setAttachments] = useState([]);
|
|
142
167
|
const [dragging, setDragging] = useState(false);
|
|
143
168
|
const [staleBanner, setStaleBanner] = useState(false);
|
|
169
|
+
const [recoveredTurn, setRecoveredTurn] = useState(false);
|
|
170
|
+
const [approvalBusy, setApprovalBusy] = useState({});
|
|
171
|
+
const [approvalErrors, setApprovalErrors] = useState({});
|
|
144
172
|
const messagesRef = useRef(null);
|
|
145
173
|
const fileInputRef = useRef(null);
|
|
146
174
|
const inputRef = useRef(null);
|
|
147
175
|
const currentAbortRef = useRef(null);
|
|
176
|
+
const currentAgentIdRef = useRef(agentId);
|
|
177
|
+
const commandApprovalTurnRef = useRef(false);
|
|
178
|
+
currentAgentIdRef.current = agentId;
|
|
148
179
|
const systemIdRef = useRef(0);
|
|
149
180
|
const visibleEntryCountRef = useRef(0);
|
|
150
181
|
const knownHeadRef = useRef(initialSessionHead ?? {
|
|
@@ -153,7 +184,11 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
|
|
|
153
184
|
});
|
|
154
185
|
const streamingRef = useRef(false);
|
|
155
186
|
streamingRef.current = streaming;
|
|
187
|
+
const turnBusy = streaming || recoveredTurn;
|
|
156
188
|
useEffect(() => {
|
|
189
|
+
currentAbortRef.current?.abort();
|
|
190
|
+
currentAbortRef.current = null;
|
|
191
|
+
commandApprovalTurnRef.current = false;
|
|
157
192
|
setServerMessages(initialMessages);
|
|
158
193
|
setLiveEntries([]);
|
|
159
194
|
setSystemBubbles([]);
|
|
@@ -162,11 +197,37 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
|
|
|
162
197
|
setThinking(false);
|
|
163
198
|
setStreaming(false);
|
|
164
199
|
setStaleBanner(false);
|
|
200
|
+
setRecoveredTurn(false);
|
|
201
|
+
setApprovalBusy({});
|
|
202
|
+
setApprovalErrors({});
|
|
165
203
|
knownHeadRef.current = initialSessionHead ?? {
|
|
166
204
|
file: null,
|
|
167
205
|
size: 0
|
|
168
206
|
};
|
|
169
207
|
}, [agentId]);
|
|
208
|
+
useEffect(() => {
|
|
209
|
+
const controller = new AbortController();
|
|
210
|
+
let stopped = false;
|
|
211
|
+
async function recoverPendingCommandApprovals() {
|
|
212
|
+
try {
|
|
213
|
+
const response = await fetch(shellApprovalsUrl(agentId), { signal: controller.signal });
|
|
214
|
+
if (!response.ok) return;
|
|
215
|
+
const pending = (await response.json()).approvals.filter((approval) => approval.agentId === agentId && approval.status === "pending");
|
|
216
|
+
if (stopped || pending.length === 0) return;
|
|
217
|
+
sessionStorage.removeItem(`bz_pending_${agentId}`);
|
|
218
|
+
commandApprovalTurnRef.current = true;
|
|
219
|
+
setLiveEntries((entries) => pending.reduce(upsertCommandApprovalEntry, entries));
|
|
220
|
+
setRecoveredTurn(true);
|
|
221
|
+
} catch (error) {
|
|
222
|
+
if (error.name === "AbortError") return;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
recoverPendingCommandApprovals();
|
|
226
|
+
return () => {
|
|
227
|
+
stopped = true;
|
|
228
|
+
controller.abort();
|
|
229
|
+
};
|
|
230
|
+
}, [agentId]);
|
|
170
231
|
const wasNearBottomRef = useRef(true);
|
|
171
232
|
useLayoutEffect(() => {
|
|
172
233
|
const el = messagesRef.current;
|
|
@@ -227,11 +288,12 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
|
|
|
227
288
|
staleBanner
|
|
228
289
|
]);
|
|
229
290
|
async function refreshKnownHead() {
|
|
291
|
+
if (currentAgentIdRef.current !== agentId) return;
|
|
230
292
|
try {
|
|
231
293
|
const res = await fetch(`/api/agents/${encodeURIComponent(agentId)}/sessions/head`);
|
|
232
294
|
if (!res.ok) return;
|
|
233
295
|
const body = await res.json();
|
|
234
|
-
if (typeof body.size === "number") knownHeadRef.current = {
|
|
296
|
+
if (currentAgentIdRef.current === agentId && typeof body.size === "number") knownHeadRef.current = {
|
|
235
297
|
file: body.file ?? null,
|
|
236
298
|
size: body.size
|
|
237
299
|
};
|
|
@@ -369,7 +431,7 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
|
|
|
369
431
|
return -1;
|
|
370
432
|
}
|
|
371
433
|
function enterEditMode() {
|
|
372
|
-
if (liveEntries.length > 0 ||
|
|
434
|
+
if (liveEntries.length > 0 || turnBusy) return;
|
|
373
435
|
const idx = findLastUserIdx();
|
|
374
436
|
if (idx === -1) return;
|
|
375
437
|
const userMsg = serverMessages[idx];
|
|
@@ -382,7 +444,7 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
|
|
|
382
444
|
setEditIdx(null);
|
|
383
445
|
}
|
|
384
446
|
async function addFiles(files) {
|
|
385
|
-
if (!files ||
|
|
447
|
+
if (!files || turnBusy) return;
|
|
386
448
|
const arr = Array.from(files);
|
|
387
449
|
if (arr.length === 0) return;
|
|
388
450
|
const encoded = await Promise.all(arr.map(fileToAttachment));
|
|
@@ -398,7 +460,7 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
|
|
|
398
460
|
function onDragOver(e) {
|
|
399
461
|
if (!Array.from(e.dataTransfer.types).includes("Files")) return;
|
|
400
462
|
e.preventDefault();
|
|
401
|
-
if (
|
|
463
|
+
if (turnBusy) {
|
|
402
464
|
setDragging(false);
|
|
403
465
|
return;
|
|
404
466
|
}
|
|
@@ -411,12 +473,12 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
|
|
|
411
473
|
if (e.dataTransfer.files.length === 0) return;
|
|
412
474
|
e.preventDefault();
|
|
413
475
|
setDragging(false);
|
|
414
|
-
if (
|
|
476
|
+
if (turnBusy) return;
|
|
415
477
|
addFiles(e.dataTransfer.files);
|
|
416
478
|
}
|
|
417
479
|
const send = useCallback(async (text) => {
|
|
418
480
|
const atts = attachments;
|
|
419
|
-
if (!text.trim() && atts.length === 0 ||
|
|
481
|
+
if (!text.trim() && atts.length === 0 || turnBusy) return;
|
|
420
482
|
setInput("");
|
|
421
483
|
if (await maybeHandleSlashCommand(text)) return;
|
|
422
484
|
setAttachments([]);
|
|
@@ -456,19 +518,21 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
|
|
|
456
518
|
...previewImages.length > 0 ? { images: previewImages } : {},
|
|
457
519
|
...previewFiles.length > 0 ? { files: previewFiles.map((f) => ({ name: f.name ?? "file" })) } : {}
|
|
458
520
|
}]);
|
|
521
|
+
setRecoveredTurn(false);
|
|
522
|
+
setApprovalBusy({});
|
|
523
|
+
setApprovalErrors({});
|
|
524
|
+
commandApprovalTurnRef.current = false;
|
|
459
525
|
sessionStorage.setItem(`bz_pending_${agentId}`, "1");
|
|
460
526
|
const abort = new AbortController();
|
|
461
527
|
currentAbortRef.current = abort;
|
|
462
528
|
setStreaming(true);
|
|
463
529
|
setThinking(true);
|
|
530
|
+
let terminalFrameReceived = false;
|
|
464
531
|
try {
|
|
465
532
|
const res = await fetch(`/api/agents/${encodeURIComponent(agentId)}/chat`, {
|
|
466
533
|
method: "POST",
|
|
467
534
|
headers: { "content-type": "application/json" },
|
|
468
|
-
body: JSON.stringify(
|
|
469
|
-
message: text,
|
|
470
|
-
attachments: atts
|
|
471
|
-
}),
|
|
535
|
+
body: JSON.stringify(interactiveChatRequest(text, atts)),
|
|
472
536
|
signal: abort.signal
|
|
473
537
|
});
|
|
474
538
|
if (res.status === 202) {
|
|
@@ -508,11 +572,14 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
|
|
|
508
572
|
} catch {
|
|
509
573
|
continue;
|
|
510
574
|
}
|
|
575
|
+
if (frame.kind === "done" || frame.kind === "fatal") terminalFrameReceived = true;
|
|
511
576
|
handleFrame(frame);
|
|
512
577
|
}
|
|
513
578
|
}
|
|
514
579
|
if (buffer.trim()) try {
|
|
515
|
-
|
|
580
|
+
const frame = JSON.parse(buffer);
|
|
581
|
+
if (frame.kind === "done" || frame.kind === "fatal") terminalFrameReceived = true;
|
|
582
|
+
handleFrame(frame);
|
|
516
583
|
} catch {}
|
|
517
584
|
await refreshKnownHead();
|
|
518
585
|
sessionStorage.removeItem(`bz_pending_${agentId}`);
|
|
@@ -523,28 +590,44 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
|
|
|
523
590
|
}]);
|
|
524
591
|
sessionStorage.removeItem(`bz_pending_${agentId}`);
|
|
525
592
|
} finally {
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
593
|
+
if (currentAgentIdRef.current === agentId && currentAbortRef.current === abort) {
|
|
594
|
+
if (!terminalFrameReceived && commandApprovalTurnRef.current) setRecoveredTurn(true);
|
|
595
|
+
setThinking(false);
|
|
596
|
+
setStreaming(false);
|
|
597
|
+
currentAbortRef.current = null;
|
|
598
|
+
}
|
|
529
599
|
}
|
|
530
600
|
}, [
|
|
531
601
|
agentId,
|
|
532
602
|
editIdx,
|
|
533
603
|
serverMessages,
|
|
534
|
-
|
|
604
|
+
turnBusy,
|
|
535
605
|
attachments
|
|
536
606
|
]);
|
|
537
607
|
function handleFrame(frame) {
|
|
608
|
+
if (currentAgentIdRef.current !== agentId) return;
|
|
538
609
|
if (frame.kind === "fatal") {
|
|
539
|
-
|
|
610
|
+
commandApprovalTurnRef.current = false;
|
|
611
|
+
setLiveEntries((prev) => [...prev.map((entry) => entry.type === "command_approval" && entry.approval.status === "pending" ? {
|
|
612
|
+
type: "command_approval",
|
|
613
|
+
approval: {
|
|
614
|
+
...entry.approval,
|
|
615
|
+
status: "cancelled"
|
|
616
|
+
}
|
|
617
|
+
} : entry), {
|
|
540
618
|
type: "error",
|
|
541
619
|
content: `[fatal] ${frame.error}`
|
|
542
620
|
}]);
|
|
621
|
+
setRecoveredTurn(false);
|
|
543
622
|
return;
|
|
544
623
|
}
|
|
545
624
|
if (frame.kind === "done") {
|
|
625
|
+
commandApprovalTurnRef.current = false;
|
|
546
626
|
setServerMessages(frame.messages);
|
|
547
627
|
setLiveEntries([]);
|
|
628
|
+
setRecoveredTurn(false);
|
|
629
|
+
setApprovalBusy({});
|
|
630
|
+
setApprovalErrors({});
|
|
548
631
|
return;
|
|
549
632
|
}
|
|
550
633
|
if (frame.kind !== "event") return;
|
|
@@ -584,6 +667,13 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
|
|
|
584
667
|
});
|
|
585
668
|
return;
|
|
586
669
|
}
|
|
670
|
+
if (ev.type === "command_approval") {
|
|
671
|
+
if (ev.approval.agentId !== agentId) return;
|
|
672
|
+
commandApprovalTurnRef.current = true;
|
|
673
|
+
setThinking(ev.approval.status !== "pending" && ev.approval.status !== "cancelled");
|
|
674
|
+
setLiveEntries((entries) => upsertCommandApprovalEntry(entries, ev.approval));
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
587
677
|
if (ev.type === "tool_call" || ev.type === "tool_result" || ev.type === "tool_error") {
|
|
588
678
|
setThinking(ev.type !== "tool_call");
|
|
589
679
|
const item = ev.type === "tool_call" ? {
|
|
@@ -636,12 +726,92 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
|
|
|
636
726
|
content: `[error] ${ev.error}`
|
|
637
727
|
}]);
|
|
638
728
|
}
|
|
729
|
+
async function reconcileCommandApproval(approvalId) {
|
|
730
|
+
if (currentAgentIdRef.current !== agentId) return null;
|
|
731
|
+
try {
|
|
732
|
+
const response = await fetch(shellApprovalsUrl(agentId));
|
|
733
|
+
if (!response.ok) return null;
|
|
734
|
+
const body = await response.json();
|
|
735
|
+
if (currentAgentIdRef.current !== agentId) return null;
|
|
736
|
+
const approval = body.approvals.find((item) => item.id === approvalId && item.agentId === agentId);
|
|
737
|
+
if (approval) setLiveEntries((entries) => upsertCommandApprovalEntry(entries, approval));
|
|
738
|
+
return approval ?? null;
|
|
739
|
+
} catch {
|
|
740
|
+
return null;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
async function decideCommandApproval(approval, decision) {
|
|
744
|
+
if (approval.agentId !== agentId || approval.status !== "pending") return;
|
|
745
|
+
setApprovalBusy((current) => ({
|
|
746
|
+
...current,
|
|
747
|
+
[approval.id]: true
|
|
748
|
+
}));
|
|
749
|
+
setApprovalErrors((current) => {
|
|
750
|
+
const next = { ...current };
|
|
751
|
+
delete next[approval.id];
|
|
752
|
+
return next;
|
|
753
|
+
});
|
|
754
|
+
try {
|
|
755
|
+
const response = await fetch(`/api/shell-approvals/${encodeURIComponent(approval.id)}`, {
|
|
756
|
+
method: "POST",
|
|
757
|
+
headers: { "content-type": "application/json" },
|
|
758
|
+
body: JSON.stringify({ decision })
|
|
759
|
+
});
|
|
760
|
+
const body = await response.json().catch(() => null);
|
|
761
|
+
if (currentAgentIdRef.current !== agentId) return;
|
|
762
|
+
if (body?.approval?.agentId === agentId) setLiveEntries((entries) => upsertCommandApprovalEntry(entries, body.approval));
|
|
763
|
+
if (!response.ok) {
|
|
764
|
+
const message = body?.error ?? `Decision failed (${response.status})`;
|
|
765
|
+
const terminalStatus = commandApprovalStatusFromConflict(message);
|
|
766
|
+
if (terminalStatus) {
|
|
767
|
+
setLiveEntries((entries) => upsertCommandApprovalEntry(entries, {
|
|
768
|
+
...approval,
|
|
769
|
+
status: terminalStatus
|
|
770
|
+
}));
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
throw new Error(message);
|
|
774
|
+
}
|
|
775
|
+
} catch (error) {
|
|
776
|
+
const reconciled = await reconcileCommandApproval(approval.id);
|
|
777
|
+
if (currentAgentIdRef.current !== agentId) return;
|
|
778
|
+
if (!reconciled || reconciled.status === "pending") setApprovalErrors((current) => ({
|
|
779
|
+
...current,
|
|
780
|
+
[approval.id]: error instanceof Error ? error.message : String(error)
|
|
781
|
+
}));
|
|
782
|
+
} finally {
|
|
783
|
+
if (currentAgentIdRef.current === agentId) setApprovalBusy((current) => ({
|
|
784
|
+
...current,
|
|
785
|
+
[approval.id]: false
|
|
786
|
+
}));
|
|
787
|
+
}
|
|
788
|
+
}
|
|
639
789
|
async function cancel() {
|
|
790
|
+
const hasLocalStream = currentAbortRef.current !== null;
|
|
640
791
|
try {
|
|
641
792
|
const res = await fetch(`/api/agents/${encodeURIComponent(agentId)}/cancel`, { method: "POST" });
|
|
642
|
-
if (
|
|
793
|
+
if (currentAgentIdRef.current !== agentId) return;
|
|
794
|
+
if (res.ok || res.status === 204) {
|
|
795
|
+
if (!hasLocalStream) {
|
|
796
|
+
commandApprovalTurnRef.current = false;
|
|
797
|
+
setLiveEntries((entries) => entries.map((entry) => entry.type === "command_approval" && entry.approval.status === "pending" ? {
|
|
798
|
+
type: "command_approval",
|
|
799
|
+
approval: {
|
|
800
|
+
...entry.approval,
|
|
801
|
+
status: "cancelled"
|
|
802
|
+
}
|
|
803
|
+
} : entry));
|
|
804
|
+
setRecoveredTurn(false);
|
|
805
|
+
}
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
643
808
|
} catch {}
|
|
644
|
-
|
|
809
|
+
if (currentAgentIdRef.current !== agentId) return;
|
|
810
|
+
if (hasLocalStream) currentAbortRef.current?.abort();
|
|
811
|
+
else setLiveEntries((entries) => [...entries, {
|
|
812
|
+
type: "error",
|
|
813
|
+
content: "[cancel failed] could not reach the active turn"
|
|
814
|
+
}]);
|
|
645
815
|
}
|
|
646
816
|
function onKeyDown(e) {
|
|
647
817
|
if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
|
|
@@ -652,7 +822,7 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
|
|
|
652
822
|
const baseEntries = projectMessages(serverMessages);
|
|
653
823
|
visibleEntryCountRef.current = baseEntries.length + liveEntries.length;
|
|
654
824
|
const lastUserIdx = (() => {
|
|
655
|
-
if (liveEntries.length > 0 ||
|
|
825
|
+
if (liveEntries.length > 0 || turnBusy) return -1;
|
|
656
826
|
for (let i = baseEntries.length - 1; i >= 0; i--) if (baseEntries[i]?.type === "user") return i;
|
|
657
827
|
return -1;
|
|
658
828
|
})();
|
|
@@ -676,13 +846,20 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
|
|
|
676
846
|
children: "drop images or files to attach"
|
|
677
847
|
}),
|
|
678
848
|
/* @__PURE__ */ jsxs("div", {
|
|
679
|
-
className: "flex items-
|
|
680
|
-
children: [/* @__PURE__ */
|
|
681
|
-
className: "
|
|
682
|
-
children:
|
|
849
|
+
className: "flex items-center justify-between gap-3 border-b border-frost px-4 py-2.5",
|
|
850
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
851
|
+
className: "flex min-w-0 items-center gap-2",
|
|
852
|
+
children: [/* @__PURE__ */ jsx("a", {
|
|
853
|
+
href: "/",
|
|
854
|
+
className: "inline-flex h-7 items-center rounded-md border border-frost px-2 text-xs font-semibold text-mocha lg:hidden",
|
|
855
|
+
children: "← agents"
|
|
856
|
+
}), /* @__PURE__ */ jsx("h1", {
|
|
857
|
+
className: "truncate font-display text-[1.2rem] text-charcoal",
|
|
858
|
+
children: agentName
|
|
859
|
+
})]
|
|
683
860
|
}), /* @__PURE__ */ jsx("a", {
|
|
684
861
|
href: `/agents/${agentId}`,
|
|
685
|
-
className: "text-xs text-mocha-light hover:text-sapphire",
|
|
862
|
+
className: "shrink-0 text-xs text-mocha-light hover:text-sapphire",
|
|
686
863
|
children: "settings →"
|
|
687
864
|
})]
|
|
688
865
|
}),
|
|
@@ -695,7 +872,7 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
|
|
|
695
872
|
}),
|
|
696
873
|
/* @__PURE__ */ jsx("span", {
|
|
697
874
|
className: "flex-1",
|
|
698
|
-
children: "new activity from another source — reload to see it"
|
|
875
|
+
children: recoveredTurn ? "the recovered turn has new activity — reload to see it" : "new activity from another source — reload to see it"
|
|
699
876
|
}),
|
|
700
877
|
/* @__PURE__ */ jsx("button", {
|
|
701
878
|
type: "button",
|
|
@@ -727,10 +904,13 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
|
|
|
727
904
|
const flushSysUpTo = (idx) => {
|
|
728
905
|
while (sysIdx < systemBubbles.length && systemBubbles[sysIdx].afterIdx <= idx) {
|
|
729
906
|
const sb = systemBubbles[sysIdx];
|
|
730
|
-
out.push(/* @__PURE__ */ jsx(Bubble, {
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
907
|
+
out.push(/* @__PURE__ */ jsx(Bubble, {
|
|
908
|
+
entry: {
|
|
909
|
+
type: "system",
|
|
910
|
+
content: sb.content
|
|
911
|
+
},
|
|
912
|
+
onCommandApprovalDecision: decideCommandApproval
|
|
913
|
+
}, `y-${sb.id}`));
|
|
734
914
|
sysIdx++;
|
|
735
915
|
}
|
|
736
916
|
};
|
|
@@ -741,21 +921,32 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
|
|
|
741
921
|
entry,
|
|
742
922
|
isLastUser: i === lastUserIdx && editIdx === null,
|
|
743
923
|
isWillDrop: willDropFromIdx !== -1 && i >= willDropFromIdx,
|
|
744
|
-
onEdit: enterEditMode
|
|
924
|
+
onEdit: enterEditMode,
|
|
925
|
+
onCommandApprovalDecision: decideCommandApproval,
|
|
926
|
+
commandApprovalBusy: entry.type === "command_approval" && Boolean(approvalBusy[entry.approval.id]),
|
|
927
|
+
commandApprovalError: entry.type === "command_approval" ? approvalErrors[entry.approval.id] : void 0
|
|
745
928
|
}, `s-${i}`));
|
|
746
929
|
flushSysUpTo(i + 1);
|
|
747
930
|
}
|
|
748
931
|
for (let i = 0; i < liveEntries.length; i++) {
|
|
749
932
|
const entry = liveEntries[i];
|
|
750
|
-
out.push(/* @__PURE__ */ jsx(Bubble, {
|
|
933
|
+
out.push(/* @__PURE__ */ jsx(Bubble, {
|
|
934
|
+
entry,
|
|
935
|
+
onCommandApprovalDecision: decideCommandApproval,
|
|
936
|
+
commandApprovalBusy: entry.type === "command_approval" && Boolean(approvalBusy[entry.approval.id]),
|
|
937
|
+
commandApprovalError: entry.type === "command_approval" ? approvalErrors[entry.approval.id] : void 0
|
|
938
|
+
}, `l-${i}`));
|
|
751
939
|
flushSysUpTo(baseEntries.length + i + 1);
|
|
752
940
|
}
|
|
753
941
|
while (sysIdx < systemBubbles.length) {
|
|
754
942
|
const sb = systemBubbles[sysIdx];
|
|
755
|
-
out.push(/* @__PURE__ */ jsx(Bubble, {
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
943
|
+
out.push(/* @__PURE__ */ jsx(Bubble, {
|
|
944
|
+
entry: {
|
|
945
|
+
type: "system",
|
|
946
|
+
content: sb.content
|
|
947
|
+
},
|
|
948
|
+
onCommandApprovalDecision: decideCommandApproval
|
|
949
|
+
}, `y-${sb.id}`));
|
|
759
950
|
sysIdx++;
|
|
760
951
|
}
|
|
761
952
|
return out;
|
|
@@ -836,7 +1027,7 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
|
|
|
836
1027
|
/* @__PURE__ */ jsx("button", {
|
|
837
1028
|
type: "button",
|
|
838
1029
|
onClick: () => fileInputRef.current?.click(),
|
|
839
|
-
disabled:
|
|
1030
|
+
disabled: turnBusy,
|
|
840
1031
|
title: "attach images or files",
|
|
841
1032
|
"aria-label": "attach files",
|
|
842
1033
|
className: "rounded-md border-[1.5px] border-frost bg-snow px-3 py-2 text-[1em] text-mocha transition-colors hover:border-sapphire hover:text-sapphire disabled:cursor-not-allowed disabled:opacity-50",
|
|
@@ -849,18 +1040,18 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
|
|
|
849
1040
|
onChange: (e) => setInput(e.target.value),
|
|
850
1041
|
onKeyDown,
|
|
851
1042
|
onPaste,
|
|
852
|
-
disabled:
|
|
1043
|
+
disabled: turnBusy,
|
|
853
1044
|
placeholder: "say something… (Shift+Enter for newline; paste or 📎 to attach images/files)",
|
|
854
1045
|
autoComplete: "off",
|
|
855
1046
|
className: "max-h-[200px] min-h-[2.4rem] flex-1 resize-none overflow-y-auto rounded-md border-[1.5px] border-frost bg-snow px-3 py-2 text-[0.93em] leading-[1.45] text-chocolate outline-none transition-colors focus:border-sapphire focus:shadow-[0_0_0_3px_var(--color-sapphire-glow)]"
|
|
856
1047
|
}),
|
|
857
1048
|
/* @__PURE__ */ jsx("button", {
|
|
858
1049
|
type: "submit",
|
|
859
|
-
disabled:
|
|
1050
|
+
disabled: turnBusy || !input.trim() && attachments.length === 0,
|
|
860
1051
|
className: "rounded-md bg-sapphire px-4 py-2 text-[0.92em] font-semibold text-snow transition-colors hover:bg-sapphire-deep disabled:cursor-not-allowed disabled:opacity-50",
|
|
861
1052
|
children: "send"
|
|
862
1053
|
}),
|
|
863
|
-
|
|
1054
|
+
turnBusy && /* @__PURE__ */ jsx("button", {
|
|
864
1055
|
type: "button",
|
|
865
1056
|
onClick: cancel,
|
|
866
1057
|
className: "rounded-md border-[1.5px] border-frost bg-transparent px-3 py-1.5 text-[0.92em] font-medium text-mocha hover:border-sapphire-light hover:bg-sapphire-glow hover:text-sapphire",
|
|
@@ -871,7 +1062,7 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
|
|
|
871
1062
|
]
|
|
872
1063
|
});
|
|
873
1064
|
}
|
|
874
|
-
function Bubble({ entry, isLastUser, isWillDrop, onEdit }) {
|
|
1065
|
+
function Bubble({ entry, isLastUser, isWillDrop, onEdit, onCommandApprovalDecision, commandApprovalBusy, commandApprovalError }) {
|
|
875
1066
|
const dropCls = isWillDrop ? "opacity-40 [&_.bubble-content]:line-through" : "";
|
|
876
1067
|
if (entry.type === "user") {
|
|
877
1068
|
if (entry.content.startsWith(INBOX_WAKE_PREFIX)) {
|
|
@@ -943,10 +1134,10 @@ function Bubble({ entry, isLastUser, isWillDrop, onEdit }) {
|
|
|
943
1134
|
if (entry.content.startsWith("[error]") || entry.content.startsWith("[fatal]") || entry.content.startsWith("[network error]")) return /* @__PURE__ */ jsxs("div", {
|
|
944
1135
|
className: `my-4 flex flex-col items-start ${dropCls}`,
|
|
945
1136
|
children: [/* @__PURE__ */ jsx("span", {
|
|
946
|
-
className: "mb-1 text-[0.72em] font-semibold uppercase tracking-wider text-
|
|
1137
|
+
className: "mb-1 text-[0.72em] font-semibold uppercase tracking-wider text-danger",
|
|
947
1138
|
children: "error"
|
|
948
1139
|
}), /* @__PURE__ */ jsx("div", {
|
|
949
|
-
className: "bubble-content rounded-r-sm border-l-[3px] border-l-
|
|
1140
|
+
className: "bubble-content rounded-r-sm border-l-[3px] border-l-danger bg-danger/10 py-1 pl-3 pr-2 leading-[1.55]",
|
|
950
1141
|
dangerouslySetInnerHTML: { __html: renderMd(entry.content) }
|
|
951
1142
|
})]
|
|
952
1143
|
});
|
|
@@ -1000,6 +1191,12 @@ function Bubble({ entry, isLastUser, isWillDrop, onEdit }) {
|
|
|
1000
1191
|
})]
|
|
1001
1192
|
});
|
|
1002
1193
|
}
|
|
1194
|
+
if (entry.type === "command_approval") return /* @__PURE__ */ jsx(CommandApprovalCard, {
|
|
1195
|
+
approval: entry.approval,
|
|
1196
|
+
busy: commandApprovalBusy,
|
|
1197
|
+
error: commandApprovalError,
|
|
1198
|
+
onDecision: onCommandApprovalDecision
|
|
1199
|
+
});
|
|
1003
1200
|
if (entry.type === "system") return /* @__PURE__ */ jsxs("div", {
|
|
1004
1201
|
className: `my-3 rounded-r-sm border-l-[3px] border-sapphire bg-sapphire-glow px-3 py-1 font-mono text-[0.88em] text-sapphire-deep ${dropCls}`,
|
|
1005
1202
|
children: [/* @__PURE__ */ jsx("span", {
|
|
@@ -1011,11 +1208,110 @@ function Bubble({ entry, isLastUser, isWillDrop, onEdit }) {
|
|
|
1011
1208
|
})]
|
|
1012
1209
|
});
|
|
1013
1210
|
if (entry.type === "error") return /* @__PURE__ */ jsx("div", {
|
|
1014
|
-
className: `my-3 rounded-r-sm border-l-[3px] border-
|
|
1211
|
+
className: `my-3 rounded-r-sm border-l-[3px] border-danger bg-danger/10 px-3 py-1 text-[0.92em] text-danger ${dropCls}`,
|
|
1015
1212
|
children: entry.content
|
|
1016
1213
|
});
|
|
1017
1214
|
return null;
|
|
1018
1215
|
}
|
|
1216
|
+
function CommandApprovalCard({ approval, busy = false, error, onDecision }) {
|
|
1217
|
+
const pending = approval.status === "pending";
|
|
1218
|
+
return /* @__PURE__ */ jsxs("section", {
|
|
1219
|
+
className: "my-3 rounded-lg border border-danger/50 bg-danger/5 p-4 text-chocolate",
|
|
1220
|
+
"aria-label": "Shell command approval",
|
|
1221
|
+
children: [
|
|
1222
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1223
|
+
className: "flex flex-wrap items-start justify-between gap-2",
|
|
1224
|
+
children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
|
|
1225
|
+
className: "m-0 text-[0.72em] font-semibold uppercase tracking-wider text-danger",
|
|
1226
|
+
children: "Shell command approval"
|
|
1227
|
+
}), /* @__PURE__ */ jsx("h2", {
|
|
1228
|
+
className: "m-0 mt-1 font-body text-[0.95em] font-semibold",
|
|
1229
|
+
children: pending ? "A risky command is waiting for you" : "Command decision recorded"
|
|
1230
|
+
})] }), /* @__PURE__ */ jsx("span", {
|
|
1231
|
+
className: "rounded-full border border-danger/30 px-2 py-0.5 text-[0.75em] font-semibold uppercase tracking-wide text-danger",
|
|
1232
|
+
children: approval.status.replaceAll("_", " ")
|
|
1233
|
+
})]
|
|
1234
|
+
}),
|
|
1235
|
+
/* @__PURE__ */ jsx("pre", {
|
|
1236
|
+
className: "mt-3 max-h-48 overflow-auto whitespace-pre-wrap break-words rounded-md border border-fawn bg-snow p-3 font-mono text-[0.82em] leading-[1.45] text-charcoal",
|
|
1237
|
+
children: approval.command
|
|
1238
|
+
}),
|
|
1239
|
+
/* @__PURE__ */ jsx("ul", {
|
|
1240
|
+
className: "mt-3 space-y-1.5 pl-5 text-[0.84em] leading-[1.4] text-mocha",
|
|
1241
|
+
children: approval.risks.map((risk) => /* @__PURE__ */ jsxs("li", { children: [
|
|
1242
|
+
/* @__PURE__ */ jsx("span", {
|
|
1243
|
+
className: "font-medium text-chocolate",
|
|
1244
|
+
children: risk.message
|
|
1245
|
+
}),
|
|
1246
|
+
" ",
|
|
1247
|
+
/* @__PURE__ */ jsx("code", {
|
|
1248
|
+
className: "text-[0.9em]",
|
|
1249
|
+
children: risk.code
|
|
1250
|
+
})
|
|
1251
|
+
] }, `${risk.code}:${risk.span.start}:${risk.span.end}`))
|
|
1252
|
+
}),
|
|
1253
|
+
pending ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1254
|
+
/* @__PURE__ */ jsxs("p", {
|
|
1255
|
+
className: "mt-3 text-[0.78em] text-mocha-light",
|
|
1256
|
+
children: [
|
|
1257
|
+
"This approval expires",
|
|
1258
|
+
" ",
|
|
1259
|
+
/* @__PURE__ */ jsx("time", {
|
|
1260
|
+
dateTime: new Date(approval.expiresAt).toISOString(),
|
|
1261
|
+
children: new Date(approval.expiresAt).toLocaleString()
|
|
1262
|
+
}),
|
|
1263
|
+
". Deny blocks only this command; cancel stops the whole turn."
|
|
1264
|
+
]
|
|
1265
|
+
}),
|
|
1266
|
+
error && /* @__PURE__ */ jsx("p", {
|
|
1267
|
+
role: "alert",
|
|
1268
|
+
className: "mt-2 rounded-md bg-danger/10 px-3 py-2 text-[0.82em] text-danger",
|
|
1269
|
+
children: error
|
|
1270
|
+
}),
|
|
1271
|
+
onDecision && /* @__PURE__ */ jsxs("div", {
|
|
1272
|
+
className: "mt-3 flex flex-wrap gap-2",
|
|
1273
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
1274
|
+
variant: "primary",
|
|
1275
|
+
disabled: busy,
|
|
1276
|
+
onClick: () => onDecision(approval, "deny"),
|
|
1277
|
+
children: "Deny"
|
|
1278
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
1279
|
+
variant: "danger",
|
|
1280
|
+
disabled: busy,
|
|
1281
|
+
onClick: () => onDecision(approval, "allow"),
|
|
1282
|
+
children: "Allow once"
|
|
1283
|
+
})]
|
|
1284
|
+
})
|
|
1285
|
+
] }) : /* @__PURE__ */ jsx("p", {
|
|
1286
|
+
role: "status",
|
|
1287
|
+
className: "mt-3 text-[0.84em] font-medium text-mocha",
|
|
1288
|
+
children: commandApprovalStatusCopy(approval.status)
|
|
1289
|
+
})
|
|
1290
|
+
]
|
|
1291
|
+
});
|
|
1292
|
+
}
|
|
1293
|
+
function commandApprovalStatusCopy(status) {
|
|
1294
|
+
switch (status) {
|
|
1295
|
+
case "pending": return "Waiting for a decision.";
|
|
1296
|
+
case "allowed": return "Allowed once — the command may run for this tool call only.";
|
|
1297
|
+
case "denied": return "Denied — the command was not run.";
|
|
1298
|
+
case "auto_denied": return "Automatically denied — no interactive approval path was available.";
|
|
1299
|
+
case "expired": return "Expired — the command was not run.";
|
|
1300
|
+
case "cancelled": return "Cancelled — the command was not run.";
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
function commandApprovalStatusFromConflict(message) {
|
|
1304
|
+
if (!message.startsWith("shell approval already decided: ")) return null;
|
|
1305
|
+
const status = message.slice(32);
|
|
1306
|
+
switch (status) {
|
|
1307
|
+
case "allowed":
|
|
1308
|
+
case "denied":
|
|
1309
|
+
case "auto_denied":
|
|
1310
|
+
case "expired":
|
|
1311
|
+
case "cancelled": return status;
|
|
1312
|
+
default: return null;
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1019
1315
|
function ToolGroup({ items, dropCls }) {
|
|
1020
1316
|
const [expanded, setExpanded] = useState(false);
|
|
1021
1317
|
const contentRef = useRef(null);
|