@hachej/boring-agent 0.1.35 → 0.1.36
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/{agentPluginEvents-CAMp363h.d.ts → agentPluginEvents-DgNc3erX.d.ts} +39 -1
- package/dist/chunk-DGRKMMXO.js +8 -0
- package/dist/front/index.d.ts +16 -1
- package/dist/front/index.js +691 -356
- package/dist/front/styles.css +27 -0
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.js +103 -5
- package/dist/shared/index.d.ts +6 -6
- package/dist/shared/index.js +4 -2
- package/package.json +2 -2
- package/dist/chunk-NZN2PRET.js +0 -6
package/dist/front/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
-
WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT
|
|
3
|
-
|
|
2
|
+
WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT,
|
|
3
|
+
WORKSPACE_COMMAND_NOTIFY_EVENT
|
|
4
|
+
} from "../chunk-DGRKMMXO.js";
|
|
4
5
|
import {
|
|
5
6
|
CommandReceiptSchema,
|
|
6
7
|
ErrorCode,
|
|
@@ -56,7 +57,7 @@ async function uploadFile(file, opts = {}) {
|
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
// src/front/chat/PiChatPanel.tsx
|
|
59
|
-
import { lazy, Suspense, useCallback as
|
|
60
|
+
import { lazy, Suspense, useCallback as useCallback18, useEffect as useEffect21, useMemo as useMemo12, useRef as useRef16, useState as useState20 } from "react";
|
|
60
61
|
|
|
61
62
|
// src/front/ArtifactOpenContext.tsx
|
|
62
63
|
import { createContext, useContext } from "react";
|
|
@@ -234,6 +235,9 @@ function createCommandRegistry(initial) {
|
|
|
234
235
|
register(cmd) {
|
|
235
236
|
commands.set(cmd.name, cmd);
|
|
236
237
|
},
|
|
238
|
+
unregister(name) {
|
|
239
|
+
commands.delete(name);
|
|
240
|
+
},
|
|
237
241
|
get(name) {
|
|
238
242
|
return commands.get(name);
|
|
239
243
|
},
|
|
@@ -254,6 +258,13 @@ var builtinCommands = [
|
|
|
254
258
|
return "Session reset.";
|
|
255
259
|
}
|
|
256
260
|
},
|
|
261
|
+
{
|
|
262
|
+
name: "clear",
|
|
263
|
+
description: "Hide messages from display",
|
|
264
|
+
handler(_, ctx) {
|
|
265
|
+
ctx.clearMessages();
|
|
266
|
+
}
|
|
267
|
+
},
|
|
257
268
|
{
|
|
258
269
|
name: "reload",
|
|
259
270
|
description: "Reload agent plugins",
|
|
@@ -295,7 +306,12 @@ var builtinCommands = [
|
|
|
295
306
|
handler(_, ctx) {
|
|
296
307
|
const cmds = ctx.listCommands();
|
|
297
308
|
if (cmds.length === 0) return "No commands available.";
|
|
298
|
-
|
|
309
|
+
const escape = (text) => text.replace(/\|/g, "\\|").replace(/\n/g, " ");
|
|
310
|
+
return [
|
|
311
|
+
"| Command | Description |",
|
|
312
|
+
"| --- | --- |",
|
|
313
|
+
...cmds.map((c) => `| \`/${c.name}\` | ${escape(c.description ?? "")} |`)
|
|
314
|
+
].join("\n");
|
|
299
315
|
}
|
|
300
316
|
}
|
|
301
317
|
];
|
|
@@ -1976,17 +1992,18 @@ function usePickerKeyboard({
|
|
|
1976
1992
|
useEffect3(() => {
|
|
1977
1993
|
const handler = (e) => {
|
|
1978
1994
|
if (e.key === "ArrowDown") {
|
|
1979
|
-
if (count <= 0) return;
|
|
1980
1995
|
e.preventDefault();
|
|
1981
|
-
setActiveIdx((i) =>
|
|
1996
|
+
setActiveIdx((i) => count === 0 ? 0 : (i + 1) % count);
|
|
1982
1997
|
} else if (e.key === "ArrowUp") {
|
|
1983
|
-
if (count <= 0) return;
|
|
1984
1998
|
e.preventDefault();
|
|
1985
|
-
setActiveIdx((i) =>
|
|
1999
|
+
setActiveIdx((i) => count === 0 ? 0 : (i - 1 + count) % count);
|
|
1986
2000
|
} else if (e.key === "Enter" || e.key === "Tab") {
|
|
1987
|
-
if (count
|
|
1988
|
-
|
|
1989
|
-
|
|
2001
|
+
if (count > 0) {
|
|
2002
|
+
e.preventDefault();
|
|
2003
|
+
selectRef.current(activeIdx);
|
|
2004
|
+
} else {
|
|
2005
|
+
dismissRef.current();
|
|
2006
|
+
}
|
|
1990
2007
|
} else if (e.key === "Escape") {
|
|
1991
2008
|
e.preventDefault();
|
|
1992
2009
|
dismissRef.current();
|
|
@@ -2680,53 +2697,104 @@ function scopedHeaders2(headers, storageScope) {
|
|
|
2680
2697
|
return result;
|
|
2681
2698
|
}
|
|
2682
2699
|
|
|
2683
|
-
// src/front/hooks/
|
|
2684
|
-
import { useEffect as useEffect6, useState as useState8 } from "react";
|
|
2685
|
-
function
|
|
2686
|
-
|
|
2687
|
-
|
|
2700
|
+
// src/front/hooks/useServerCommands.ts
|
|
2701
|
+
import { useEffect as useEffect6, useRef as useRef7, useState as useState8 } from "react";
|
|
2702
|
+
function toSlashCommand(command, getSessionId, apiBaseUrl, requestHeaders, fetchImpl) {
|
|
2703
|
+
return {
|
|
2704
|
+
name: command.name,
|
|
2705
|
+
description: command.description ?? "",
|
|
2706
|
+
source: command.source,
|
|
2707
|
+
...command.sourcePlugin ? { sourcePlugin: command.sourcePlugin } : {},
|
|
2708
|
+
handler: async (args) => {
|
|
2709
|
+
const base = apiBaseUrl?.replace(/\/$/, "") ?? "";
|
|
2710
|
+
const params = new URLSearchParams({ sessionId: getSessionId() });
|
|
2711
|
+
const url = `${base}/api/v1/agent/commands/execute?${params.toString()}`;
|
|
2712
|
+
try {
|
|
2713
|
+
const res = await fetchImpl(url, {
|
|
2714
|
+
method: "POST",
|
|
2715
|
+
headers: { ...requestHeaders ?? {}, "content-type": "application/json" },
|
|
2716
|
+
body: JSON.stringify({ name: command.name, args })
|
|
2717
|
+
});
|
|
2718
|
+
if (!res.ok) {
|
|
2719
|
+
const body = await res.json().catch(() => ({}));
|
|
2720
|
+
if (typeof globalThis.dispatchEvent === "function") {
|
|
2721
|
+
globalThis.dispatchEvent(new CustomEvent(WORKSPACE_COMMAND_NOTIFY_EVENT, {
|
|
2722
|
+
detail: { message: body.error ?? `/${command.name} failed`, tone: "error", command: command.name }
|
|
2723
|
+
}));
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
} catch {
|
|
2727
|
+
if (typeof globalThis.dispatchEvent === "function") {
|
|
2728
|
+
globalThis.dispatchEvent(new CustomEvent(WORKSPACE_COMMAND_NOTIFY_EVENT, {
|
|
2729
|
+
detail: { message: `/${command.name} could not be reached`, tone: "error", command: command.name }
|
|
2730
|
+
}));
|
|
2731
|
+
}
|
|
2732
|
+
}
|
|
2733
|
+
}
|
|
2734
|
+
};
|
|
2735
|
+
}
|
|
2736
|
+
function useServerCommands({
|
|
2688
2737
|
registry,
|
|
2689
2738
|
requestHeaders,
|
|
2739
|
+
sessionId,
|
|
2740
|
+
apiBaseUrl,
|
|
2741
|
+
fetch: fetchImpl,
|
|
2690
2742
|
storageScope,
|
|
2691
|
-
|
|
2692
|
-
|
|
2743
|
+
enabled = true,
|
|
2744
|
+
refreshKey = 0
|
|
2693
2745
|
}) {
|
|
2694
|
-
const [
|
|
2746
|
+
const [stamp, setStamp] = useState8(0);
|
|
2747
|
+
const registeredNamesRef = useRef7(/* @__PURE__ */ new Set());
|
|
2748
|
+
const sessionIdRef = useRef7(sessionId);
|
|
2695
2749
|
useEffect6(() => {
|
|
2696
|
-
|
|
2750
|
+
sessionIdRef.current = sessionId;
|
|
2751
|
+
}, [sessionId]);
|
|
2752
|
+
useEffect6(() => {
|
|
2753
|
+
const clearRegistered = () => {
|
|
2754
|
+
if (registeredNamesRef.current.size === 0) return false;
|
|
2755
|
+
for (const name of registeredNamesRef.current) registry.unregister(name);
|
|
2756
|
+
registeredNamesRef.current = /* @__PURE__ */ new Set();
|
|
2757
|
+
return true;
|
|
2758
|
+
};
|
|
2759
|
+
if (!enabled) {
|
|
2760
|
+
if (clearRegistered()) setStamp((n) => n + 1);
|
|
2761
|
+
return;
|
|
2762
|
+
}
|
|
2697
2763
|
let aborted = false;
|
|
2698
2764
|
const nextFetch = fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
2699
|
-
const
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
if (
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2765
|
+
const base = apiBaseUrl?.replace(/\/$/, "") ?? "";
|
|
2766
|
+
const url = `${base}/api/v1/agent/commands?sessionId=${encodeURIComponent(sessionIdRef.current)}`;
|
|
2767
|
+
const headers = scopedHeaders3(requestHeaders, storageScope);
|
|
2768
|
+
nextFetch(url, { headers }).then(async (res) => {
|
|
2769
|
+
if (!res.ok) throw new Error(`commands request failed (${res.status})`);
|
|
2770
|
+
return await res.json();
|
|
2771
|
+
}).then((payload) => {
|
|
2772
|
+
if (aborted) return;
|
|
2773
|
+
const removed = clearRegistered();
|
|
2774
|
+
let added = false;
|
|
2775
|
+
for (const serverCommand of payload.commands ?? []) {
|
|
2776
|
+
const command = toSlashCommand(serverCommand, () => sessionIdRef.current, apiBaseUrl, headers, nextFetch);
|
|
2777
|
+
if (registry.get(command.name)) continue;
|
|
2778
|
+
registry.register(command);
|
|
2779
|
+
registeredNamesRef.current.add(command.name);
|
|
2780
|
+
added = true;
|
|
2711
2781
|
}
|
|
2712
|
-
if (
|
|
2782
|
+
if (removed || added) setStamp((n) => n + 1);
|
|
2713
2783
|
}).catch(() => {
|
|
2784
|
+
if (aborted) return;
|
|
2785
|
+
if (clearRegistered()) setStamp((n) => n + 1);
|
|
2714
2786
|
});
|
|
2715
2787
|
return () => {
|
|
2716
2788
|
aborted = true;
|
|
2717
2789
|
};
|
|
2718
2790
|
}, [apiBaseUrl, enabled, fetchImpl, refreshKey, requestHeaders, registry, storageScope]);
|
|
2719
|
-
return
|
|
2720
|
-
}
|
|
2721
|
-
function agentResourceUrl2(apiBaseUrl, path) {
|
|
2722
|
-
const base = apiBaseUrl?.replace(/\/$/, "") ?? "";
|
|
2723
|
-
return `${base}${path}`;
|
|
2791
|
+
return stamp;
|
|
2724
2792
|
}
|
|
2725
2793
|
function scopedHeaders3(headers, storageScope) {
|
|
2726
2794
|
if (!headers && !storageScope) return void 0;
|
|
2727
2795
|
const result = { ...headers ?? {} };
|
|
2728
|
-
const
|
|
2729
|
-
if (storageScope && !
|
|
2796
|
+
const hasScope = Object.keys(result).some((k) => k.toLowerCase() === "x-boring-storage-scope");
|
|
2797
|
+
if (storageScope && !hasScope) result["x-boring-storage-scope"] = storageScope;
|
|
2730
2798
|
return result;
|
|
2731
2799
|
}
|
|
2732
2800
|
|
|
@@ -3320,7 +3388,7 @@ function resolveStorage2(storage) {
|
|
|
3320
3388
|
}
|
|
3321
3389
|
|
|
3322
3390
|
// src/front/chat/session/usePiSessions.ts
|
|
3323
|
-
import { useCallback as useCallback7, useEffect as useEffect8, useMemo as useMemo3, useRef as
|
|
3391
|
+
import { useCallback as useCallback7, useEffect as useEffect8, useMemo as useMemo3, useRef as useRef8, useState as useState10 } from "react";
|
|
3324
3392
|
|
|
3325
3393
|
// src/front/chat/pi/piChatAssistantCommit.ts
|
|
3326
3394
|
function commitFinalMessage(state, messageId, final) {
|
|
@@ -4895,20 +4963,20 @@ function usePiSessions(options = {}) {
|
|
|
4895
4963
|
const [loadingMore, setLoadingMore] = useState10(false);
|
|
4896
4964
|
const [hasMore, setHasMore] = useState10(false);
|
|
4897
4965
|
const [error, setError] = useState10(void 0);
|
|
4898
|
-
const mountedRef =
|
|
4899
|
-
const refreshVersionRef =
|
|
4900
|
-
const retryTimerRef =
|
|
4901
|
-
const sessionsRef =
|
|
4902
|
-
const activeSessionIdRef =
|
|
4903
|
-
const hasMoreRef =
|
|
4904
|
-
const canonicalLoadedCountRef =
|
|
4905
|
-
const loadMoreRequestSeqRef =
|
|
4906
|
-
const loadMoreInFlightRef =
|
|
4907
|
-
const pendingCreatedRef =
|
|
4908
|
-
const pendingCreatedScopeRef =
|
|
4909
|
-
const dataStorageScopeRef =
|
|
4910
|
-
const loadedDataSourceRef =
|
|
4911
|
-
const requestScopeRef =
|
|
4966
|
+
const mountedRef = useRef8(false);
|
|
4967
|
+
const refreshVersionRef = useRef8(0);
|
|
4968
|
+
const retryTimerRef = useRef8(void 0);
|
|
4969
|
+
const sessionsRef = useRef8([]);
|
|
4970
|
+
const activeSessionIdRef = useRef8(activeSessionId);
|
|
4971
|
+
const hasMoreRef = useRef8(hasMore);
|
|
4972
|
+
const canonicalLoadedCountRef = useRef8(0);
|
|
4973
|
+
const loadMoreRequestSeqRef = useRef8(0);
|
|
4974
|
+
const loadMoreInFlightRef = useRef8(false);
|
|
4975
|
+
const pendingCreatedRef = useRef8(/* @__PURE__ */ new Map());
|
|
4976
|
+
const pendingCreatedScopeRef = useRef8(requestScopeKey);
|
|
4977
|
+
const dataStorageScopeRef = useRef8(storageScope);
|
|
4978
|
+
const loadedDataSourceRef = useRef8(dataSourceKey);
|
|
4979
|
+
const requestScopeRef = useRef8(requestScopeKey);
|
|
4912
4980
|
requestScopeRef.current = requestScopeKey;
|
|
4913
4981
|
useEffect8(() => {
|
|
4914
4982
|
sessionsRef.current = sessions;
|
|
@@ -5429,7 +5497,7 @@ function sortByUpdatedDesc(a, b) {
|
|
|
5429
5497
|
|
|
5430
5498
|
// src/front/chat/components/PiConversationSurface.tsx
|
|
5431
5499
|
import { Loader2 as Loader22 } from "lucide-react";
|
|
5432
|
-
import { useCallback as useCallback14, useEffect as useEffect14, useLayoutEffect, useRef as
|
|
5500
|
+
import { useCallback as useCallback14, useEffect as useEffect14, useLayoutEffect, useRef as useRef10, useState as useState15 } from "react";
|
|
5433
5501
|
import { useStickToBottomContext as useStickToBottomContext2 } from "use-stick-to-bottom";
|
|
5434
5502
|
|
|
5435
5503
|
// src/front/primitives/conversation.tsx
|
|
@@ -6125,7 +6193,7 @@ import {
|
|
|
6125
6193
|
useContext as useContext5,
|
|
6126
6194
|
useEffect as useEffect11,
|
|
6127
6195
|
useMemo as useMemo8,
|
|
6128
|
-
useRef as
|
|
6196
|
+
useRef as useRef9,
|
|
6129
6197
|
useState as useState12
|
|
6130
6198
|
} from "react";
|
|
6131
6199
|
import { Streamdown as Streamdown2 } from "streamdown";
|
|
@@ -6217,9 +6285,9 @@ var Reasoning = memo5(
|
|
|
6217
6285
|
defaultProp: void 0,
|
|
6218
6286
|
prop: durationProp
|
|
6219
6287
|
});
|
|
6220
|
-
const hasEverStreamedRef =
|
|
6288
|
+
const hasEverStreamedRef = useRef9(isStreaming);
|
|
6221
6289
|
const [hasAutoClosed, setHasAutoClosed] = useState12(false);
|
|
6222
|
-
const startTimeRef =
|
|
6290
|
+
const startTimeRef = useRef9(null);
|
|
6223
6291
|
useEffect11(() => {
|
|
6224
6292
|
if (isStreaming) {
|
|
6225
6293
|
hasEverStreamedRef.current = true;
|
|
@@ -6947,8 +7015,8 @@ function PiConversationSurface({
|
|
|
6947
7015
|
}
|
|
6948
7016
|
function TranscriptHistoryLoader({ olderCount, onLoadOlder }) {
|
|
6949
7017
|
const { scrollRef } = useStickToBottomContext2();
|
|
6950
|
-
const pendingAnchor =
|
|
6951
|
-
const armed =
|
|
7018
|
+
const pendingAnchor = useRef10(null);
|
|
7019
|
+
const armed = useRef10(true);
|
|
6952
7020
|
useEffect14(() => {
|
|
6953
7021
|
const el = scrollRef.current;
|
|
6954
7022
|
if (!el) return;
|
|
@@ -7009,38 +7077,34 @@ function buildMessageRenderItems(messages) {
|
|
|
7009
7077
|
}
|
|
7010
7078
|
|
|
7011
7079
|
// src/front/chat/components/PiChatComposerSurface.tsx
|
|
7012
|
-
import { useCallback as
|
|
7080
|
+
import { useCallback as useCallback16, useLayoutEffect as useLayoutEffect2 } from "react";
|
|
7013
7081
|
import { motion as motion2 } from "motion/react";
|
|
7014
7082
|
|
|
7015
7083
|
// src/front/composer/PluginUpdateStatus.tsx
|
|
7016
|
-
import { useEffect as useEffect15, useRef as
|
|
7017
|
-
|
|
7084
|
+
import { useEffect as useEffect15, useRef as useRef11 } from "react";
|
|
7085
|
+
|
|
7086
|
+
// src/front/composer/ComposerStatusBanner.tsx
|
|
7018
7087
|
import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
7019
|
-
function
|
|
7020
|
-
|
|
7088
|
+
function ComposerStatusBanner({
|
|
7089
|
+
tone,
|
|
7090
|
+
dataAttribute,
|
|
7091
|
+
runningContent,
|
|
7092
|
+
title,
|
|
7093
|
+
detail,
|
|
7094
|
+
message,
|
|
7095
|
+
children,
|
|
7021
7096
|
onDismiss,
|
|
7022
7097
|
onRetry,
|
|
7023
|
-
|
|
7098
|
+
retryLabel = "Try again",
|
|
7099
|
+
dismissAriaLabel = "Dismiss status",
|
|
7024
7100
|
maxWidthClassName = "max-w-3xl"
|
|
7025
7101
|
}) {
|
|
7026
|
-
const
|
|
7027
|
-
|
|
7028
|
-
onDismissRef.current = onDismiss;
|
|
7029
|
-
}, [onDismiss]);
|
|
7030
|
-
const successDismissKey = state?.kind === "success" ? `${state.reloaded}:${(state.restartWarnings?.length ?? 0) > 0 || (state.diagnostics?.length ?? 0) > 0}` : null;
|
|
7031
|
-
useEffect15(() => {
|
|
7032
|
-
if (!state || state.kind !== "success" || successAutoDismissMs <= 0) return;
|
|
7033
|
-
const hasWarningsOrDiagnostics = (state.restartWarnings?.length ?? 0) > 0 || (state.diagnostics?.length ?? 0) > 0;
|
|
7034
|
-
if (hasWarningsOrDiagnostics) return;
|
|
7035
|
-
const timeout = window.setTimeout(() => onDismissRef.current(), successAutoDismissMs);
|
|
7036
|
-
return () => window.clearTimeout(timeout);
|
|
7037
|
-
}, [state?.kind, successDismissKey, successAutoDismissMs]);
|
|
7038
|
-
if (!state) return null;
|
|
7039
|
-
if (state.kind === "running") {
|
|
7102
|
+
const toneAttr = { [dataAttribute]: tone };
|
|
7103
|
+
if (tone === "running") {
|
|
7040
7104
|
return /* @__PURE__ */ jsxs22(
|
|
7041
7105
|
"div",
|
|
7042
7106
|
{
|
|
7043
|
-
|
|
7107
|
+
...toneAttr,
|
|
7044
7108
|
role: "status",
|
|
7045
7109
|
"aria-live": "polite",
|
|
7046
7110
|
className: cn(
|
|
@@ -7050,22 +7114,16 @@ function PluginUpdateStatus({
|
|
|
7050
7114
|
),
|
|
7051
7115
|
children: [
|
|
7052
7116
|
/* @__PURE__ */ jsx24("span", { className: "inline-block h-2 w-2 animate-pulse rounded-full bg-accent", "aria-hidden": "true" }),
|
|
7053
|
-
/* @__PURE__ */ jsx24("span", { children:
|
|
7117
|
+
/* @__PURE__ */ jsx24("span", { children: runningContent })
|
|
7054
7118
|
]
|
|
7055
7119
|
}
|
|
7056
7120
|
);
|
|
7057
7121
|
}
|
|
7058
|
-
if (
|
|
7059
|
-
const warnings = state.restartWarnings ?? [];
|
|
7060
|
-
const diagnostics = state.diagnostics ?? [];
|
|
7061
|
-
const frontEvents = state.frontEvents ?? [];
|
|
7062
|
-
const hasWarningsOrDiagnostics = warnings.length > 0 || diagnostics.length > 0;
|
|
7063
|
-
const title = state.reloaded ? hasWarningsOrDiagnostics ? "Reload finished with warnings" : "Reload complete" : "Reload queued";
|
|
7064
|
-
const detail = state.reloaded ? hasWarningsOrDiagnostics ? "Some plugin changes need attention." : frontEvents.length > 0 ? `${frontEvents.length} plugin module${frontEvents.length === 1 ? "" : "s"} refreshed. Changes are live.` : "Changes are live." : void 0;
|
|
7122
|
+
if (tone === "success") {
|
|
7065
7123
|
return /* @__PURE__ */ jsxs22(
|
|
7066
7124
|
"div",
|
|
7067
7125
|
{
|
|
7068
|
-
|
|
7126
|
+
...toneAttr,
|
|
7069
7127
|
role: "status",
|
|
7070
7128
|
"aria-live": "polite",
|
|
7071
7129
|
className: cn(
|
|
@@ -7080,18 +7138,115 @@ function PluginUpdateStatus({
|
|
|
7080
7138
|
/* @__PURE__ */ jsx24("span", { className: "block font-medium leading-5", children: title }),
|
|
7081
7139
|
detail ? /* @__PURE__ */ jsx24("span", { className: "block leading-4 text-muted-foreground", children: detail }) : null
|
|
7082
7140
|
] }),
|
|
7083
|
-
/* @__PURE__ */ jsx24(
|
|
7141
|
+
onDismiss ? /* @__PURE__ */ jsx24(
|
|
7084
7142
|
"button",
|
|
7085
7143
|
{
|
|
7086
7144
|
type: "button",
|
|
7087
7145
|
onClick: onDismiss,
|
|
7088
7146
|
className: "-mr-1 rounded border border-transparent px-1.5 py-0.5 text-[13px] leading-none text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
7089
|
-
"aria-label":
|
|
7147
|
+
"aria-label": dismissAriaLabel,
|
|
7090
7148
|
children: "\xD7"
|
|
7091
7149
|
}
|
|
7092
|
-
)
|
|
7150
|
+
) : null
|
|
7093
7151
|
] }),
|
|
7094
|
-
|
|
7152
|
+
children
|
|
7153
|
+
]
|
|
7154
|
+
}
|
|
7155
|
+
);
|
|
7156
|
+
}
|
|
7157
|
+
return /* @__PURE__ */ jsxs22(
|
|
7158
|
+
"div",
|
|
7159
|
+
{
|
|
7160
|
+
...toneAttr,
|
|
7161
|
+
role: "status",
|
|
7162
|
+
"aria-live": "polite",
|
|
7163
|
+
className: cn(
|
|
7164
|
+
"mx-auto mb-2 w-full rounded-[var(--radius-md)] border border-destructive/40 bg-destructive/10",
|
|
7165
|
+
"px-3 py-2 text-xs text-foreground",
|
|
7166
|
+
maxWidthClassName
|
|
7167
|
+
),
|
|
7168
|
+
children: [
|
|
7169
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-2", children: [
|
|
7170
|
+
/* @__PURE__ */ jsx24("span", { className: "text-destructive", "aria-hidden": "true", children: "\u26A0" }),
|
|
7171
|
+
/* @__PURE__ */ jsx24("span", { className: "flex-1 font-medium", children: title }),
|
|
7172
|
+
onRetry ? /* @__PURE__ */ jsx24(
|
|
7173
|
+
"button",
|
|
7174
|
+
{
|
|
7175
|
+
type: "button",
|
|
7176
|
+
onClick: onRetry,
|
|
7177
|
+
className: "rounded border border-destructive/40 px-2 py-0.5 text-[11px] font-medium hover:bg-destructive/10",
|
|
7178
|
+
children: retryLabel
|
|
7179
|
+
}
|
|
7180
|
+
) : null,
|
|
7181
|
+
onDismiss ? /* @__PURE__ */ jsx24(
|
|
7182
|
+
"button",
|
|
7183
|
+
{
|
|
7184
|
+
type: "button",
|
|
7185
|
+
onClick: onDismiss,
|
|
7186
|
+
className: "rounded border border-transparent px-2 py-0.5 text-[11px] font-medium text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
7187
|
+
"aria-label": dismissAriaLabel,
|
|
7188
|
+
children: "Dismiss"
|
|
7189
|
+
}
|
|
7190
|
+
) : null
|
|
7191
|
+
] }),
|
|
7192
|
+
message ? /* @__PURE__ */ jsx24("pre", { className: "mt-2 whitespace-pre-wrap break-words text-[11px] text-destructive/90", children: message }) : null
|
|
7193
|
+
]
|
|
7194
|
+
}
|
|
7195
|
+
);
|
|
7196
|
+
}
|
|
7197
|
+
|
|
7198
|
+
// src/front/composer/PluginUpdateStatus.tsx
|
|
7199
|
+
import { jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
7200
|
+
function PluginUpdateStatus({
|
|
7201
|
+
state,
|
|
7202
|
+
onDismiss,
|
|
7203
|
+
onRetry,
|
|
7204
|
+
successAutoDismissMs = 1400,
|
|
7205
|
+
maxWidthClassName = "max-w-3xl"
|
|
7206
|
+
}) {
|
|
7207
|
+
const onDismissRef = useRef11(onDismiss);
|
|
7208
|
+
useEffect15(() => {
|
|
7209
|
+
onDismissRef.current = onDismiss;
|
|
7210
|
+
}, [onDismiss]);
|
|
7211
|
+
const successDismissKey = state?.kind === "success" ? `${state.reloaded}:${(state.restartWarnings?.length ?? 0) > 0 || (state.diagnostics?.length ?? 0) > 0}` : null;
|
|
7212
|
+
useEffect15(() => {
|
|
7213
|
+
if (!state || state.kind !== "success" || successAutoDismissMs <= 0) return;
|
|
7214
|
+
const hasWarningsOrDiagnostics = (state.restartWarnings?.length ?? 0) > 0 || (state.diagnostics?.length ?? 0) > 0;
|
|
7215
|
+
if (hasWarningsOrDiagnostics) return;
|
|
7216
|
+
const timeout = window.setTimeout(() => onDismissRef.current(), successAutoDismissMs);
|
|
7217
|
+
return () => window.clearTimeout(timeout);
|
|
7218
|
+
}, [state?.kind, successDismissKey, successAutoDismissMs]);
|
|
7219
|
+
if (!state) return null;
|
|
7220
|
+
if (state.kind === "running") {
|
|
7221
|
+
return /* @__PURE__ */ jsx25(
|
|
7222
|
+
ComposerStatusBanner,
|
|
7223
|
+
{
|
|
7224
|
+
tone: "running",
|
|
7225
|
+
dataAttribute: "data-boring-plugin-update",
|
|
7226
|
+
maxWidthClassName,
|
|
7227
|
+
runningContent: "Updating plugins\u2026"
|
|
7228
|
+
}
|
|
7229
|
+
);
|
|
7230
|
+
}
|
|
7231
|
+
if (state.kind === "success") {
|
|
7232
|
+
const warnings = state.restartWarnings ?? [];
|
|
7233
|
+
const diagnostics = state.diagnostics ?? [];
|
|
7234
|
+
const frontEvents = state.frontEvents ?? [];
|
|
7235
|
+
const hasWarningsOrDiagnostics = warnings.length > 0 || diagnostics.length > 0;
|
|
7236
|
+
const title = state.reloaded ? hasWarningsOrDiagnostics ? "Reload finished with warnings" : "Reload complete" : "Reload queued";
|
|
7237
|
+
const detail = state.reloaded ? hasWarningsOrDiagnostics ? "Some plugin changes need attention." : frontEvents.length > 0 ? `${frontEvents.length} plugin module${frontEvents.length === 1 ? "" : "s"} refreshed. Changes are live.` : "Changes are live." : void 0;
|
|
7238
|
+
return /* @__PURE__ */ jsxs23(
|
|
7239
|
+
ComposerStatusBanner,
|
|
7240
|
+
{
|
|
7241
|
+
tone: "success",
|
|
7242
|
+
dataAttribute: "data-boring-plugin-update",
|
|
7243
|
+
maxWidthClassName,
|
|
7244
|
+
title,
|
|
7245
|
+
detail,
|
|
7246
|
+
onDismiss,
|
|
7247
|
+
dismissAriaLabel: "Dismiss plugin update status",
|
|
7248
|
+
children: [
|
|
7249
|
+
diagnostics.length > 0 ? /* @__PURE__ */ jsxs23(
|
|
7095
7250
|
"div",
|
|
7096
7251
|
{
|
|
7097
7252
|
"data-boring-plugin-update-diagnostics": "",
|
|
@@ -7100,24 +7255,24 @@ function PluginUpdateStatus({
|
|
|
7100
7255
|
"px-2 py-1.5 text-[11px] text-foreground"
|
|
7101
7256
|
),
|
|
7102
7257
|
children: [
|
|
7103
|
-
/* @__PURE__ */
|
|
7104
|
-
/* @__PURE__ */
|
|
7105
|
-
/* @__PURE__ */
|
|
7258
|
+
/* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-1.5 font-medium text-[oklch(0.48_0.15_60)]", children: [
|
|
7259
|
+
/* @__PURE__ */ jsx25("span", { "aria-hidden": "true", children: "\u26A0" }),
|
|
7260
|
+
/* @__PURE__ */ jsxs23("span", { children: [
|
|
7106
7261
|
"Reload diagnostics for ",
|
|
7107
7262
|
diagnostics.length,
|
|
7108
7263
|
" plugin",
|
|
7109
7264
|
diagnostics.length === 1 ? "" : "s"
|
|
7110
7265
|
] })
|
|
7111
7266
|
] }),
|
|
7112
|
-
/* @__PURE__ */
|
|
7113
|
-
/* @__PURE__ */
|
|
7267
|
+
/* @__PURE__ */ jsx25("ul", { className: "mt-1 ml-4 list-disc text-foreground/85", children: diagnostics.map((diagnostic, index) => /* @__PURE__ */ jsxs23("li", { children: [
|
|
7268
|
+
/* @__PURE__ */ jsx25("code", { className: "font-mono text-[10.5px]", children: diagnostic.pluginId ?? diagnostic.source ?? "plugin" }),
|
|
7114
7269
|
" \u2014 ",
|
|
7115
7270
|
diagnostic.message ?? "reload diagnostic"
|
|
7116
7271
|
] }, `${diagnostic.pluginId ?? diagnostic.source ?? "plugin"}-${index}`)) })
|
|
7117
7272
|
]
|
|
7118
7273
|
}
|
|
7119
7274
|
) : null,
|
|
7120
|
-
warnings.length > 0 ? /* @__PURE__ */
|
|
7275
|
+
warnings.length > 0 ? /* @__PURE__ */ jsxs23(
|
|
7121
7276
|
"div",
|
|
7122
7277
|
{
|
|
7123
7278
|
"data-boring-plugin-update-restart-warning": "",
|
|
@@ -7126,21 +7281,21 @@ function PluginUpdateStatus({
|
|
|
7126
7281
|
"px-2 py-1.5 text-[11px] text-foreground"
|
|
7127
7282
|
),
|
|
7128
7283
|
children: [
|
|
7129
|
-
/* @__PURE__ */
|
|
7130
|
-
/* @__PURE__ */
|
|
7131
|
-
/* @__PURE__ */
|
|
7284
|
+
/* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-1.5 font-medium text-[oklch(0.48_0.15_60)]", children: [
|
|
7285
|
+
/* @__PURE__ */ jsx25("span", { "aria-hidden": "true", children: "\u26A0" }),
|
|
7286
|
+
/* @__PURE__ */ jsxs23("span", { children: [
|
|
7132
7287
|
"Restart needed for ",
|
|
7133
7288
|
warnings.length,
|
|
7134
7289
|
" plugin",
|
|
7135
7290
|
warnings.length === 1 ? "" : "s"
|
|
7136
7291
|
] })
|
|
7137
7292
|
] }),
|
|
7138
|
-
/* @__PURE__ */
|
|
7139
|
-
/* @__PURE__ */
|
|
7293
|
+
/* @__PURE__ */ jsx25("ul", { className: "mt-1 ml-4 list-disc text-foreground/85", children: warnings.map((w) => /* @__PURE__ */ jsxs23("li", { children: [
|
|
7294
|
+
/* @__PURE__ */ jsx25("code", { className: "font-mono text-[10.5px]", children: w.id }),
|
|
7140
7295
|
" \u2014 ",
|
|
7141
7296
|
w.surfaces.join(" + ")
|
|
7142
7297
|
] }, w.id)) }),
|
|
7143
|
-
/* @__PURE__ */
|
|
7298
|
+
/* @__PURE__ */ jsx25("p", { className: "mt-1 text-foreground/70", children: "The front bundle reloaded successfully, but routes and agent tools were wired at boot. Stop and restart the workspace process (Ctrl-C, then re-run your dev command) to pick up the new code." })
|
|
7144
7299
|
]
|
|
7145
7300
|
}
|
|
7146
7301
|
) : null
|
|
@@ -7148,45 +7303,104 @@ function PluginUpdateStatus({
|
|
|
7148
7303
|
}
|
|
7149
7304
|
);
|
|
7150
7305
|
}
|
|
7151
|
-
return /* @__PURE__ */
|
|
7152
|
-
|
|
7306
|
+
return /* @__PURE__ */ jsx25(
|
|
7307
|
+
ComposerStatusBanner,
|
|
7153
7308
|
{
|
|
7154
|
-
|
|
7155
|
-
|
|
7156
|
-
|
|
7157
|
-
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
|
|
7162
|
-
|
|
7163
|
-
|
|
7164
|
-
|
|
7165
|
-
|
|
7166
|
-
|
|
7167
|
-
|
|
7168
|
-
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7175
|
-
|
|
7176
|
-
|
|
7177
|
-
|
|
7178
|
-
|
|
7179
|
-
|
|
7180
|
-
|
|
7309
|
+
tone: "error",
|
|
7310
|
+
dataAttribute: "data-boring-plugin-update",
|
|
7311
|
+
maxWidthClassName,
|
|
7312
|
+
title: "Plugin update failed.",
|
|
7313
|
+
message: state.message,
|
|
7314
|
+
onRetry,
|
|
7315
|
+
onDismiss,
|
|
7316
|
+
retryLabel: "Try again",
|
|
7317
|
+
dismissAriaLabel: "Dismiss plugin update status"
|
|
7318
|
+
}
|
|
7319
|
+
);
|
|
7320
|
+
}
|
|
7321
|
+
|
|
7322
|
+
// src/front/composer/CommandRunStatus.tsx
|
|
7323
|
+
import { useEffect as useEffect16, useRef as useRef12 } from "react";
|
|
7324
|
+
import { Fragment as Fragment7, jsx as jsx26, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
7325
|
+
function CommandRunStatus({
|
|
7326
|
+
state,
|
|
7327
|
+
onDismiss,
|
|
7328
|
+
successAutoDismissMs = 1400,
|
|
7329
|
+
maxWidthClassName = "max-w-3xl"
|
|
7330
|
+
}) {
|
|
7331
|
+
const onDismissRef = useRef12(onDismiss);
|
|
7332
|
+
useEffect16(() => {
|
|
7333
|
+
onDismissRef.current = onDismiss;
|
|
7334
|
+
}, [onDismiss]);
|
|
7335
|
+
const successKey = state?.kind === "success" ? `${state.runId}:${state.command}:${state.detail ?? ""}` : null;
|
|
7336
|
+
useEffect16(() => {
|
|
7337
|
+
if (!state || state.kind !== "success" || successAutoDismissMs <= 0) return;
|
|
7338
|
+
const timeout = window.setTimeout(() => onDismissRef.current(), successAutoDismissMs);
|
|
7339
|
+
return () => window.clearTimeout(timeout);
|
|
7340
|
+
}, [state?.kind, successKey, successAutoDismissMs]);
|
|
7341
|
+
if (!state) return null;
|
|
7342
|
+
if (state.kind === "running") {
|
|
7343
|
+
return /* @__PURE__ */ jsx26(
|
|
7344
|
+
ComposerStatusBanner,
|
|
7345
|
+
{
|
|
7346
|
+
tone: "running",
|
|
7347
|
+
dataAttribute: "data-boring-command-run",
|
|
7348
|
+
maxWidthClassName,
|
|
7349
|
+
runningContent: state.command ? /* @__PURE__ */ jsxs24(Fragment7, { children: [
|
|
7350
|
+
" Running ",
|
|
7351
|
+
/* @__PURE__ */ jsxs24("code", { className: "font-mono", children: [
|
|
7352
|
+
"/",
|
|
7353
|
+
state.command
|
|
7354
|
+
] }),
|
|
7355
|
+
"\u2026 "
|
|
7356
|
+
] }) : "Running command\u2026"
|
|
7357
|
+
}
|
|
7358
|
+
);
|
|
7359
|
+
}
|
|
7360
|
+
if (state.kind === "success") {
|
|
7361
|
+
return /* @__PURE__ */ jsx26(
|
|
7362
|
+
ComposerStatusBanner,
|
|
7363
|
+
{
|
|
7364
|
+
tone: "success",
|
|
7365
|
+
dataAttribute: "data-boring-command-run",
|
|
7366
|
+
maxWidthClassName,
|
|
7367
|
+
title: state.command ? /* @__PURE__ */ jsxs24(Fragment7, { children: [
|
|
7368
|
+
" Ran ",
|
|
7369
|
+
/* @__PURE__ */ jsxs24("code", { className: "font-mono", children: [
|
|
7370
|
+
"/",
|
|
7371
|
+
state.command
|
|
7372
|
+
] }),
|
|
7373
|
+
" "
|
|
7374
|
+
] }) : "Command ran",
|
|
7375
|
+
detail: state.detail,
|
|
7376
|
+
onDismiss,
|
|
7377
|
+
dismissAriaLabel: "Dismiss command status"
|
|
7378
|
+
}
|
|
7379
|
+
);
|
|
7380
|
+
}
|
|
7381
|
+
return /* @__PURE__ */ jsx26(
|
|
7382
|
+
ComposerStatusBanner,
|
|
7383
|
+
{
|
|
7384
|
+
tone: "error",
|
|
7385
|
+
dataAttribute: "data-boring-command-run",
|
|
7386
|
+
maxWidthClassName,
|
|
7387
|
+
title: state.command ? /* @__PURE__ */ jsxs24(Fragment7, { children: [
|
|
7388
|
+
" ",
|
|
7389
|
+
/* @__PURE__ */ jsxs24("code", { className: "font-mono", children: [
|
|
7390
|
+
"/",
|
|
7391
|
+
state.command
|
|
7181
7392
|
] }),
|
|
7182
|
-
|
|
7183
|
-
]
|
|
7393
|
+
" failed. "
|
|
7394
|
+
] }) : "Command failed.",
|
|
7395
|
+
message: state.message,
|
|
7396
|
+
onDismiss,
|
|
7397
|
+
dismissAriaLabel: "Dismiss command status"
|
|
7184
7398
|
}
|
|
7185
7399
|
);
|
|
7186
7400
|
}
|
|
7187
7401
|
|
|
7188
7402
|
// src/front/chatPanelComposerControls.tsx
|
|
7189
|
-
import { forwardRef, useEffect as
|
|
7403
|
+
import { forwardRef, useEffect as useEffect17, useRef as useRef13, useState as useState16 } from "react";
|
|
7190
7404
|
import { CheckIcon as CheckIcon3, ChevronDownIcon as ChevronDownIcon5 } from "lucide-react";
|
|
7191
7405
|
import {
|
|
7192
7406
|
Command,
|
|
@@ -7220,7 +7434,7 @@ function displayProviderLabel(provider) {
|
|
|
7220
7434
|
}
|
|
7221
7435
|
|
|
7222
7436
|
// src/front/chatPanelComposerControls.tsx
|
|
7223
|
-
import { Fragment as
|
|
7437
|
+
import { Fragment as Fragment8, jsx as jsx27, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
7224
7438
|
var composerActionClass = cn(
|
|
7225
7439
|
"inline-flex h-8 items-center justify-center gap-1.5 rounded-[var(--radius-md)] border-0 bg-transparent",
|
|
7226
7440
|
"text-muted-foreground shadow-none transition",
|
|
@@ -7270,7 +7484,7 @@ function isTextInputTarget(target) {
|
|
|
7270
7484
|
return target instanceof HTMLInputElement;
|
|
7271
7485
|
}
|
|
7272
7486
|
function useDismissOnOutsidePointer(ref, onClose) {
|
|
7273
|
-
|
|
7487
|
+
useEffect17(() => {
|
|
7274
7488
|
if (!onClose) return;
|
|
7275
7489
|
const handler = (event) => {
|
|
7276
7490
|
const target = event.target;
|
|
@@ -7288,7 +7502,7 @@ function useDismissOnOutsidePointer(ref, onClose) {
|
|
|
7288
7502
|
}
|
|
7289
7503
|
function ThinkingLevelGlyph({ level }) {
|
|
7290
7504
|
const lit = level === "off" ? 0 : level === "low" ? 1 : level === "medium" ? 2 : 3;
|
|
7291
|
-
return /* @__PURE__ */
|
|
7505
|
+
return /* @__PURE__ */ jsx27(
|
|
7292
7506
|
"svg",
|
|
7293
7507
|
{
|
|
7294
7508
|
"aria-hidden": "true",
|
|
@@ -7297,7 +7511,7 @@ function ThinkingLevelGlyph({ level }) {
|
|
|
7297
7511
|
viewBox: "0 0 14 14",
|
|
7298
7512
|
fill: "none",
|
|
7299
7513
|
className: "shrink-0",
|
|
7300
|
-
children: [0, 1, 2].map((i) => /* @__PURE__ */
|
|
7514
|
+
children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx27(
|
|
7301
7515
|
"rect",
|
|
7302
7516
|
{
|
|
7303
7517
|
x: 2 + i * 4,
|
|
@@ -7354,7 +7568,7 @@ var ModelSelectTrigger = forwardRef(function ModelSelectTrigger2({
|
|
|
7354
7568
|
}, ref) {
|
|
7355
7569
|
const triggerLabel = modelTriggerLabel(value, options);
|
|
7356
7570
|
const triggerDisplay = value ? `${triggerLabel} (${displayProviderLabel(value.provider)})` : triggerLabel;
|
|
7357
|
-
return /* @__PURE__ */
|
|
7571
|
+
return /* @__PURE__ */ jsx27(
|
|
7358
7572
|
"button",
|
|
7359
7573
|
{
|
|
7360
7574
|
ref,
|
|
@@ -7372,12 +7586,12 @@ var ModelSelectTrigger = forwardRef(function ModelSelectTrigger2({
|
|
|
7372
7586
|
className
|
|
7373
7587
|
),
|
|
7374
7588
|
...props,
|
|
7375
|
-
children: trigger === "slash" ? /* @__PURE__ */
|
|
7376
|
-
/* @__PURE__ */
|
|
7377
|
-
/* @__PURE__ */
|
|
7378
|
-
] }) : /* @__PURE__ */
|
|
7379
|
-
/* @__PURE__ */
|
|
7380
|
-
/* @__PURE__ */
|
|
7589
|
+
children: trigger === "slash" ? /* @__PURE__ */ jsxs25(Fragment8, { children: [
|
|
7590
|
+
/* @__PURE__ */ jsx27("span", { className: "text-muted-foreground", children: "/model: " }),
|
|
7591
|
+
/* @__PURE__ */ jsx27("span", { className: "text-foreground", children: triggerDisplay })
|
|
7592
|
+
] }) : /* @__PURE__ */ jsxs25(Fragment8, { children: [
|
|
7593
|
+
/* @__PURE__ */ jsx27("span", { className: "min-w-0 truncate", children: triggerDisplay }),
|
|
7594
|
+
/* @__PURE__ */ jsx27(ChevronDownIcon5, { className: "h-3 w-3 shrink-0 text-muted-foreground/50", "aria-hidden": "true" })
|
|
7381
7595
|
] })
|
|
7382
7596
|
}
|
|
7383
7597
|
);
|
|
@@ -7397,18 +7611,18 @@ function ModelPickerMenu({
|
|
|
7397
7611
|
const keyboardOptions = [null, ...groupedOptions];
|
|
7398
7612
|
const selectedIndex = currentKey ? Math.max(0, keyboardOptions.findIndex((option) => option && encodeModelKey(option) === currentKey)) : 0;
|
|
7399
7613
|
const [activeIndex, setActiveIndex] = useState16(selectedIndex);
|
|
7400
|
-
const activeIndexRef =
|
|
7401
|
-
const menuRef =
|
|
7614
|
+
const activeIndexRef = useRef13(selectedIndex);
|
|
7615
|
+
const menuRef = useRef13(null);
|
|
7402
7616
|
useDismissOnOutsidePointer(menuRef, onClose);
|
|
7403
7617
|
const setKeyboardActiveIndex = (next) => {
|
|
7404
7618
|
const resolved = typeof next === "function" ? next(activeIndexRef.current) : next;
|
|
7405
7619
|
activeIndexRef.current = resolved;
|
|
7406
7620
|
setActiveIndex(resolved);
|
|
7407
7621
|
};
|
|
7408
|
-
|
|
7622
|
+
useEffect17(() => {
|
|
7409
7623
|
setKeyboardActiveIndex(selectedIndex);
|
|
7410
7624
|
}, [selectedIndex]);
|
|
7411
|
-
|
|
7625
|
+
useEffect17(() => {
|
|
7412
7626
|
const handler = (event) => {
|
|
7413
7627
|
if (event.key === "Escape") {
|
|
7414
7628
|
event.preventDefault();
|
|
@@ -7432,8 +7646,8 @@ function ModelPickerMenu({
|
|
|
7432
7646
|
return () => window.removeEventListener("keydown", handler, { capture: true });
|
|
7433
7647
|
}, [activeIndex, disabled, keyboardOptions, onChange, onClose]);
|
|
7434
7648
|
const optionIndexes = new Map(groupedOptions.map((option, index) => [encodeModelKey(option), index + 1]));
|
|
7435
|
-
return /* @__PURE__ */
|
|
7436
|
-
menuOptions.length > 8 && /* @__PURE__ */
|
|
7649
|
+
return /* @__PURE__ */ jsx27("div", { ref: menuRef, "data-boring-agent": "", "data-boring-agent-part": "model-picker-menu", className: cn(composerPickerMenuClass, className), children: /* @__PURE__ */ jsxs25(Command, { className: "bg-transparent text-[color:var(--popover-foreground)]", children: [
|
|
7650
|
+
menuOptions.length > 8 && /* @__PURE__ */ jsx27("div", { className: "border-b border-border/60 px-2", children: /* @__PURE__ */ jsx27(
|
|
7437
7651
|
CommandInput,
|
|
7438
7652
|
{
|
|
7439
7653
|
placeholder: "Search models\u2026",
|
|
@@ -7441,9 +7655,9 @@ function ModelPickerMenu({
|
|
|
7441
7655
|
className: "h-8 w-full border-0 bg-transparent text-[13px] outline-none focus:ring-0"
|
|
7442
7656
|
}
|
|
7443
7657
|
) }),
|
|
7444
|
-
/* @__PURE__ */
|
|
7445
|
-
/* @__PURE__ */
|
|
7446
|
-
/* @__PURE__ */
|
|
7658
|
+
/* @__PURE__ */ jsxs25(CommandList, { className: "max-h-[300px] p-0.5", children: [
|
|
7659
|
+
/* @__PURE__ */ jsx27(CommandEmpty, { className: "py-4 text-center text-[13px] text-muted-foreground", children: "No models found" }),
|
|
7660
|
+
/* @__PURE__ */ jsx27(CommandGroup, { children: /* @__PURE__ */ jsxs25(
|
|
7447
7661
|
CommandItem,
|
|
7448
7662
|
{
|
|
7449
7663
|
value: "Pi default automatic auto",
|
|
@@ -7454,7 +7668,7 @@ function ModelPickerMenu({
|
|
|
7454
7668
|
},
|
|
7455
7669
|
className: selectorItemClass(!value || activeIndex === 0),
|
|
7456
7670
|
children: [
|
|
7457
|
-
/* @__PURE__ */
|
|
7671
|
+
/* @__PURE__ */ jsx27(
|
|
7458
7672
|
CheckIcon3,
|
|
7459
7673
|
{
|
|
7460
7674
|
className: cn(
|
|
@@ -7463,12 +7677,12 @@ function ModelPickerMenu({
|
|
|
7463
7677
|
)
|
|
7464
7678
|
}
|
|
7465
7679
|
),
|
|
7466
|
-
/* @__PURE__ */
|
|
7467
|
-
/* @__PURE__ */
|
|
7680
|
+
/* @__PURE__ */ jsx27("span", { className: "truncate", children: "Pi default" }),
|
|
7681
|
+
/* @__PURE__ */ jsx27("span", { className: "ml-auto shrink-0 text-[10px] text-muted-foreground/60", children: "auto" })
|
|
7468
7682
|
]
|
|
7469
7683
|
}
|
|
7470
7684
|
) }),
|
|
7471
|
-
[...groups.entries()].map(([provider, list]) => /* @__PURE__ */
|
|
7685
|
+
[...groups.entries()].map(([provider, list]) => /* @__PURE__ */ jsx27(
|
|
7472
7686
|
CommandGroup,
|
|
7473
7687
|
{
|
|
7474
7688
|
heading: displayProviderLabel(provider),
|
|
@@ -7477,7 +7691,7 @@ function ModelPickerMenu({
|
|
|
7477
7691
|
const key = encodeModelKey(m);
|
|
7478
7692
|
const label = m.label || displayModelLabel(m.id);
|
|
7479
7693
|
const itemIndex = optionIndexes.get(key) ?? 0;
|
|
7480
|
-
return /* @__PURE__ */
|
|
7694
|
+
return /* @__PURE__ */ jsxs25(
|
|
7481
7695
|
CommandItem,
|
|
7482
7696
|
{
|
|
7483
7697
|
value: `${label} ${m.id} ${displayProviderLabel(m.provider)}`,
|
|
@@ -7488,7 +7702,7 @@ function ModelPickerMenu({
|
|
|
7488
7702
|
},
|
|
7489
7703
|
className: cn(selectorItemClass(key === currentKey || activeIndex === itemIndex)),
|
|
7490
7704
|
children: [
|
|
7491
|
-
/* @__PURE__ */
|
|
7705
|
+
/* @__PURE__ */ jsx27(
|
|
7492
7706
|
CheckIcon3,
|
|
7493
7707
|
{
|
|
7494
7708
|
className: cn(
|
|
@@ -7497,8 +7711,8 @@ function ModelPickerMenu({
|
|
|
7497
7711
|
)
|
|
7498
7712
|
}
|
|
7499
7713
|
),
|
|
7500
|
-
/* @__PURE__ */
|
|
7501
|
-
/* @__PURE__ */
|
|
7714
|
+
/* @__PURE__ */ jsx27("span", { className: "min-w-0 flex-1 truncate whitespace-nowrap", children: label }),
|
|
7715
|
+
/* @__PURE__ */ jsx27("span", { className: "ml-auto max-w-[45%] shrink-0 truncate whitespace-nowrap text-right text-[10px] text-muted-foreground/60", children: m.id })
|
|
7502
7716
|
]
|
|
7503
7717
|
},
|
|
7504
7718
|
key
|
|
@@ -7519,7 +7733,7 @@ var ThinkingSelectTrigger = forwardRef(function ThinkingSelectTrigger2({
|
|
|
7519
7733
|
className,
|
|
7520
7734
|
...props
|
|
7521
7735
|
}, ref) {
|
|
7522
|
-
return /* @__PURE__ */
|
|
7736
|
+
return /* @__PURE__ */ jsxs25(
|
|
7523
7737
|
"button",
|
|
7524
7738
|
{
|
|
7525
7739
|
ref,
|
|
@@ -7540,13 +7754,13 @@ var ThinkingSelectTrigger = forwardRef(function ThinkingSelectTrigger2({
|
|
|
7540
7754
|
onClick,
|
|
7541
7755
|
...props,
|
|
7542
7756
|
children: [
|
|
7543
|
-
trigger === "button" ? /* @__PURE__ */
|
|
7544
|
-
trigger === "slash" ? /* @__PURE__ */
|
|
7545
|
-
/* @__PURE__ */
|
|
7546
|
-
/* @__PURE__ */
|
|
7547
|
-
] }) : /* @__PURE__ */
|
|
7548
|
-
/* @__PURE__ */
|
|
7549
|
-
/* @__PURE__ */
|
|
7757
|
+
trigger === "button" ? /* @__PURE__ */ jsx27(ThinkingLevelGlyph, { level: value }) : null,
|
|
7758
|
+
trigger === "slash" ? /* @__PURE__ */ jsxs25(Fragment8, { children: [
|
|
7759
|
+
/* @__PURE__ */ jsx27("span", { className: "text-muted-foreground", children: "/thinking: " }),
|
|
7760
|
+
/* @__PURE__ */ jsx27("span", { className: "text-foreground", children: THINKING_LEVEL_STATUS_LABELS[value] })
|
|
7761
|
+
] }) : /* @__PURE__ */ jsxs25(Fragment8, { children: [
|
|
7762
|
+
/* @__PURE__ */ jsx27("span", { children: THINKING_LEVEL_LABELS[value] }),
|
|
7763
|
+
/* @__PURE__ */ jsx27(ChevronDownIcon5, { className: "h-3 w-3 shrink-0 text-muted-foreground/50", "aria-hidden": "true" })
|
|
7550
7764
|
] })
|
|
7551
7765
|
]
|
|
7552
7766
|
}
|
|
@@ -7561,18 +7775,18 @@ function ThinkingPickerMenu({
|
|
|
7561
7775
|
}) {
|
|
7562
7776
|
const selectedIndex = Math.max(0, THINKING_LEVELS.indexOf(value));
|
|
7563
7777
|
const [activeIndex, setActiveIndex] = useState16(selectedIndex);
|
|
7564
|
-
const activeIndexRef =
|
|
7565
|
-
const menuRef =
|
|
7778
|
+
const activeIndexRef = useRef13(selectedIndex);
|
|
7779
|
+
const menuRef = useRef13(null);
|
|
7566
7780
|
useDismissOnOutsidePointer(menuRef, onClose);
|
|
7567
7781
|
const setKeyboardActiveIndex = (next) => {
|
|
7568
7782
|
const resolved = typeof next === "function" ? next(activeIndexRef.current) : next;
|
|
7569
7783
|
activeIndexRef.current = resolved;
|
|
7570
7784
|
setActiveIndex(resolved);
|
|
7571
7785
|
};
|
|
7572
|
-
|
|
7786
|
+
useEffect17(() => {
|
|
7573
7787
|
setKeyboardActiveIndex(selectedIndex);
|
|
7574
7788
|
}, [selectedIndex]);
|
|
7575
|
-
|
|
7789
|
+
useEffect17(() => {
|
|
7576
7790
|
const handler = (event) => {
|
|
7577
7791
|
if (event.key === "Escape") {
|
|
7578
7792
|
event.preventDefault();
|
|
@@ -7595,7 +7809,7 @@ function ThinkingPickerMenu({
|
|
|
7595
7809
|
window.addEventListener("keydown", handler, { capture: true });
|
|
7596
7810
|
return () => window.removeEventListener("keydown", handler, { capture: true });
|
|
7597
7811
|
}, [activeIndex, disabled, onChange, onClose]);
|
|
7598
|
-
return /* @__PURE__ */
|
|
7812
|
+
return /* @__PURE__ */ jsx27("div", { ref: menuRef, "data-boring-agent": "", "data-boring-agent-part": "thinking-picker-menu", className: cn(composerPickerMenuClass, className), children: /* @__PURE__ */ jsx27(Command, { className: "bg-transparent text-[color:var(--popover-foreground)]", children: /* @__PURE__ */ jsx27(CommandList, { className: "max-h-[300px] p-0.5", children: THINKING_LEVELS.map((level, index) => /* @__PURE__ */ jsxs25(
|
|
7599
7813
|
CommandItem,
|
|
7600
7814
|
{
|
|
7601
7815
|
value: `Thinking ${THINKING_LEVEL_LABELS[level]} ${THINKING_LEVEL_DETAILS[level]}`,
|
|
@@ -7606,7 +7820,7 @@ function ThinkingPickerMenu({
|
|
|
7606
7820
|
},
|
|
7607
7821
|
className: selectorItemClass(level === value || index === activeIndex),
|
|
7608
7822
|
children: [
|
|
7609
|
-
/* @__PURE__ */
|
|
7823
|
+
/* @__PURE__ */ jsx27(
|
|
7610
7824
|
CheckIcon3,
|
|
7611
7825
|
{
|
|
7612
7826
|
className: cn(
|
|
@@ -7615,9 +7829,9 @@ function ThinkingPickerMenu({
|
|
|
7615
7829
|
)
|
|
7616
7830
|
}
|
|
7617
7831
|
),
|
|
7618
|
-
/* @__PURE__ */
|
|
7619
|
-
/* @__PURE__ */
|
|
7620
|
-
/* @__PURE__ */
|
|
7832
|
+
/* @__PURE__ */ jsx27(ThinkingLevelGlyph, { level }),
|
|
7833
|
+
/* @__PURE__ */ jsx27("span", { className: "font-medium", children: THINKING_LEVEL_LABELS[level] }),
|
|
7834
|
+
/* @__PURE__ */ jsx27("span", { className: "ml-auto text-[11px] text-muted-foreground/65", children: THINKING_LEVEL_DETAILS[level] })
|
|
7621
7835
|
]
|
|
7622
7836
|
},
|
|
7623
7837
|
level
|
|
@@ -7655,10 +7869,10 @@ import {
|
|
|
7655
7869
|
Monitor,
|
|
7656
7870
|
PlusIcon as PlusIcon2,
|
|
7657
7871
|
SquareIcon,
|
|
7658
|
-
XIcon as
|
|
7872
|
+
XIcon as XIcon4
|
|
7659
7873
|
} from "lucide-react";
|
|
7660
7874
|
import { nanoid } from "nanoid";
|
|
7661
|
-
import { useCallback as useCallback15, useEffect as
|
|
7875
|
+
import { useCallback as useCallback15, useEffect as useEffect18, useMemo as useMemo10, useRef as useRef14, useState as useState17 } from "react";
|
|
7662
7876
|
|
|
7663
7877
|
// src/front/primitives/prompt-input-context.ts
|
|
7664
7878
|
import { createContext as createContext6, useContext as useContext6 } from "react";
|
|
@@ -7693,12 +7907,12 @@ import {
|
|
|
7693
7907
|
TooltipTrigger as TooltipTrigger3
|
|
7694
7908
|
} from "@hachej/boring-ui-kit";
|
|
7695
7909
|
import { Children } from "react";
|
|
7696
|
-
import { jsx as
|
|
7910
|
+
import { jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
7697
7911
|
var PromptInputFooter = ({
|
|
7698
7912
|
align = "block-end",
|
|
7699
7913
|
className,
|
|
7700
7914
|
...props
|
|
7701
|
-
}) => /* @__PURE__ */
|
|
7915
|
+
}) => /* @__PURE__ */ jsx28(
|
|
7702
7916
|
InputGroupAddon,
|
|
7703
7917
|
{
|
|
7704
7918
|
align,
|
|
@@ -7708,7 +7922,7 @@ var PromptInputFooter = ({
|
|
|
7708
7922
|
);
|
|
7709
7923
|
|
|
7710
7924
|
// src/front/primitives/prompt-input.tsx
|
|
7711
|
-
import { Fragment as
|
|
7925
|
+
import { Fragment as Fragment9, jsx as jsx29, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
7712
7926
|
var PromptInput = ({
|
|
7713
7927
|
className,
|
|
7714
7928
|
accept,
|
|
@@ -7725,12 +7939,12 @@ var PromptInput = ({
|
|
|
7725
7939
|
}) => {
|
|
7726
7940
|
const controller = useOptionalPromptInputController();
|
|
7727
7941
|
const usingProvider = !!controller;
|
|
7728
|
-
const providerTextValueRef =
|
|
7942
|
+
const providerTextValueRef = useRef14("");
|
|
7729
7943
|
if (usingProvider) {
|
|
7730
7944
|
providerTextValueRef.current = controller.textInput.value;
|
|
7731
7945
|
}
|
|
7732
|
-
const inputRef =
|
|
7733
|
-
const formRef =
|
|
7946
|
+
const inputRef = useRef14(null);
|
|
7947
|
+
const formRef = useRef14(null);
|
|
7734
7948
|
const [items, setItems] = useState17([]);
|
|
7735
7949
|
const setFileUrlLocal = useCallback15((id, url, status) => {
|
|
7736
7950
|
setItems((prev) => prev.map((f) => {
|
|
@@ -7741,8 +7955,8 @@ var PromptInput = ({
|
|
|
7741
7955
|
}, []);
|
|
7742
7956
|
const files = usingProvider ? controller.attachments.files : items;
|
|
7743
7957
|
const [referencedSources, setReferencedSources] = useState17([]);
|
|
7744
|
-
const filesRef =
|
|
7745
|
-
|
|
7958
|
+
const filesRef = useRef14(files);
|
|
7959
|
+
useEffect18(() => {
|
|
7746
7960
|
filesRef.current = files;
|
|
7747
7961
|
}, [files]);
|
|
7748
7962
|
const openFileDialogLocal = useCallback15(() => {
|
|
@@ -7878,18 +8092,18 @@ var PromptInput = ({
|
|
|
7878
8092
|
clearAttachments();
|
|
7879
8093
|
clearReferencedSources();
|
|
7880
8094
|
}, [clearAttachments, clearReferencedSources]);
|
|
7881
|
-
|
|
8095
|
+
useEffect18(() => {
|
|
7882
8096
|
if (!usingProvider) {
|
|
7883
8097
|
return;
|
|
7884
8098
|
}
|
|
7885
8099
|
controller.__registerFileInput(inputRef, () => inputRef.current?.click());
|
|
7886
8100
|
}, [usingProvider, controller]);
|
|
7887
|
-
|
|
8101
|
+
useEffect18(() => {
|
|
7888
8102
|
if (syncHiddenInput && inputRef.current && files.length === 0) {
|
|
7889
8103
|
inputRef.current.value = "";
|
|
7890
8104
|
}
|
|
7891
8105
|
}, [files, syncHiddenInput]);
|
|
7892
|
-
|
|
8106
|
+
useEffect18(() => {
|
|
7893
8107
|
const form = formRef.current;
|
|
7894
8108
|
if (!form) {
|
|
7895
8109
|
return;
|
|
@@ -7917,7 +8131,7 @@ var PromptInput = ({
|
|
|
7917
8131
|
form.removeEventListener("drop", onDrop);
|
|
7918
8132
|
};
|
|
7919
8133
|
}, [add, globalDrop]);
|
|
7920
|
-
|
|
8134
|
+
useEffect18(() => {
|
|
7921
8135
|
if (!globalDrop) {
|
|
7922
8136
|
return;
|
|
7923
8137
|
}
|
|
@@ -7941,7 +8155,7 @@ var PromptInput = ({
|
|
|
7941
8155
|
document.removeEventListener("drop", onDrop);
|
|
7942
8156
|
};
|
|
7943
8157
|
}, [add, globalDrop]);
|
|
7944
|
-
|
|
8158
|
+
useEffect18(
|
|
7945
8159
|
() => () => {
|
|
7946
8160
|
if (!usingProvider) {
|
|
7947
8161
|
for (const f of filesRef.current) {
|
|
@@ -8051,8 +8265,8 @@ var PromptInput = ({
|
|
|
8051
8265
|
},
|
|
8052
8266
|
[usingProvider, controller, files, onSubmit, clear]
|
|
8053
8267
|
);
|
|
8054
|
-
const inner = /* @__PURE__ */
|
|
8055
|
-
/* @__PURE__ */
|
|
8268
|
+
const inner = /* @__PURE__ */ jsxs27(Fragment9, { children: [
|
|
8269
|
+
/* @__PURE__ */ jsx29(
|
|
8056
8270
|
Input,
|
|
8057
8271
|
{
|
|
8058
8272
|
accept,
|
|
@@ -8065,7 +8279,7 @@ var PromptInput = ({
|
|
|
8065
8279
|
type: "file"
|
|
8066
8280
|
}
|
|
8067
8281
|
),
|
|
8068
|
-
/* @__PURE__ */
|
|
8282
|
+
/* @__PURE__ */ jsx29(
|
|
8069
8283
|
"form",
|
|
8070
8284
|
{
|
|
8071
8285
|
"data-boring-agent-part": "composer",
|
|
@@ -8073,12 +8287,12 @@ var PromptInput = ({
|
|
|
8073
8287
|
onSubmit: handleSubmit,
|
|
8074
8288
|
ref: formRef,
|
|
8075
8289
|
...props,
|
|
8076
|
-
children: /* @__PURE__ */
|
|
8290
|
+
children: /* @__PURE__ */ jsx29(InputGroup, { className: "overflow-hidden", children })
|
|
8077
8291
|
}
|
|
8078
8292
|
)
|
|
8079
8293
|
] });
|
|
8080
|
-
const withReferencedSources = /* @__PURE__ */
|
|
8081
|
-
return /* @__PURE__ */
|
|
8294
|
+
const withReferencedSources = /* @__PURE__ */ jsx29(LocalReferencedSourcesContext.Provider, { value: refsCtx, children: inner });
|
|
8295
|
+
return /* @__PURE__ */ jsx29(LocalAttachmentsContext.Provider, { value: attachmentsCtx, children: withReferencedSources });
|
|
8082
8296
|
};
|
|
8083
8297
|
var PromptInputTextarea = ({
|
|
8084
8298
|
onChange,
|
|
@@ -8156,7 +8370,7 @@ var PromptInputTextarea = ({
|
|
|
8156
8370
|
} : {
|
|
8157
8371
|
onChange
|
|
8158
8372
|
};
|
|
8159
|
-
return /* @__PURE__ */
|
|
8373
|
+
return /* @__PURE__ */ jsx29(
|
|
8160
8374
|
InputGroupTextarea,
|
|
8161
8375
|
{
|
|
8162
8376
|
"data-boring-agent-part": "composer-input",
|
|
@@ -8183,13 +8397,13 @@ var PromptInputSubmit = ({
|
|
|
8183
8397
|
...props
|
|
8184
8398
|
}) => {
|
|
8185
8399
|
const isGenerating = status === "submitted" || status === "streaming";
|
|
8186
|
-
let Icon = /* @__PURE__ */
|
|
8400
|
+
let Icon = /* @__PURE__ */ jsx29(CornerDownLeftIcon, { className: "size-4" });
|
|
8187
8401
|
if (status === "submitted") {
|
|
8188
|
-
Icon = /* @__PURE__ */
|
|
8402
|
+
Icon = /* @__PURE__ */ jsx29(Spinner, {});
|
|
8189
8403
|
} else if (status === "streaming") {
|
|
8190
|
-
Icon = /* @__PURE__ */
|
|
8404
|
+
Icon = /* @__PURE__ */ jsx29(SquareIcon, { className: "size-4" });
|
|
8191
8405
|
} else if (status === "error") {
|
|
8192
|
-
Icon = /* @__PURE__ */
|
|
8406
|
+
Icon = /* @__PURE__ */ jsx29(XIcon4, { className: "size-4" });
|
|
8193
8407
|
}
|
|
8194
8408
|
const handleClick = useCallback15(
|
|
8195
8409
|
(e) => {
|
|
@@ -8202,7 +8416,7 @@ var PromptInputSubmit = ({
|
|
|
8202
8416
|
},
|
|
8203
8417
|
[isGenerating, onStop, onClick]
|
|
8204
8418
|
);
|
|
8205
|
-
return /* @__PURE__ */
|
|
8419
|
+
return /* @__PURE__ */ jsx29(
|
|
8206
8420
|
InputGroupButton2,
|
|
8207
8421
|
{
|
|
8208
8422
|
"aria-label": isGenerating ? "Stop" : "Submit",
|
|
@@ -8219,54 +8433,142 @@ var PromptInputSubmit = ({
|
|
|
8219
8433
|
};
|
|
8220
8434
|
|
|
8221
8435
|
// src/front/primitives/slash-command-picker.tsx
|
|
8222
|
-
import {
|
|
8223
|
-
import { jsx as
|
|
8436
|
+
import { useEffect as useEffect19, useMemo as useMemo11, useRef as useRef15, useState as useState18 } from "react";
|
|
8437
|
+
import { Fragment as Fragment10, jsx as jsx30, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
8438
|
+
var ALL_PLUGINS = "__all__";
|
|
8439
|
+
function commandGroup(cmd) {
|
|
8440
|
+
if (cmd.source === "skill") return "skills";
|
|
8441
|
+
if (cmd.sourcePlugin) return cmd.sourcePlugin;
|
|
8442
|
+
return "built-in";
|
|
8443
|
+
}
|
|
8224
8444
|
function SlashCommandPicker({ query, commands, onSelect, onDismiss }) {
|
|
8225
|
-
const
|
|
8226
|
-
|
|
8227
|
-
[commands, query]
|
|
8228
|
-
);
|
|
8445
|
+
const [plugin, setPlugin] = useState18(ALL_PLUGINS);
|
|
8446
|
+
const [searchQuery, setSearchQuery] = useState18(query);
|
|
8229
8447
|
const [activeIdx, setActiveIdx] = useState18(0);
|
|
8230
|
-
const
|
|
8231
|
-
|
|
8232
|
-
const
|
|
8233
|
-
|
|
8234
|
-
|
|
8235
|
-
|
|
8236
|
-
|
|
8237
|
-
|
|
8238
|
-
|
|
8239
|
-
|
|
8240
|
-
|
|
8241
|
-
|
|
8242
|
-
|
|
8243
|
-
|
|
8244
|
-
|
|
8245
|
-
)
|
|
8246
|
-
|
|
8247
|
-
|
|
8248
|
-
|
|
8249
|
-
|
|
8250
|
-
|
|
8251
|
-
|
|
8252
|
-
|
|
8253
|
-
|
|
8254
|
-
|
|
8255
|
-
|
|
8256
|
-
|
|
8257
|
-
|
|
8448
|
+
const containerRef = useRef15(null);
|
|
8449
|
+
const listRef = useRef15(null);
|
|
8450
|
+
const inputRef = useRef15(null);
|
|
8451
|
+
useEffect19(() => {
|
|
8452
|
+
setSearchQuery(query);
|
|
8453
|
+
}, [query]);
|
|
8454
|
+
const groups = useMemo11(() => {
|
|
8455
|
+
const set = new Set(commands.map(commandGroup));
|
|
8456
|
+
return Array.from(set).sort((a, b) => a.localeCompare(b));
|
|
8457
|
+
}, [commands]);
|
|
8458
|
+
const filtered = useMemo11(() => {
|
|
8459
|
+
const q = searchQuery.trim().toLowerCase();
|
|
8460
|
+
return commands.filter((c) => {
|
|
8461
|
+
if (plugin !== ALL_PLUGINS && commandGroup(c) !== plugin) return false;
|
|
8462
|
+
if (!q) return true;
|
|
8463
|
+
return c.name.toLowerCase().includes(q) || c.description.toLowerCase().includes(q);
|
|
8464
|
+
});
|
|
8465
|
+
}, [commands, searchQuery, plugin]);
|
|
8466
|
+
useEffect19(() => {
|
|
8467
|
+
setActiveIdx((i) => filtered.length === 0 ? 0 : Math.min(i, filtered.length - 1));
|
|
8468
|
+
}, [filtered.length]);
|
|
8469
|
+
useEffect19(() => {
|
|
8470
|
+
const handler = (e) => {
|
|
8471
|
+
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
8472
|
+
onDismiss();
|
|
8473
|
+
}
|
|
8474
|
+
};
|
|
8475
|
+
document.addEventListener("mousedown", handler);
|
|
8476
|
+
return () => document.removeEventListener("mousedown", handler);
|
|
8477
|
+
}, [onDismiss]);
|
|
8478
|
+
usePickerKeyboard({
|
|
8479
|
+
count: filtered.length,
|
|
8480
|
+
activeIdx,
|
|
8481
|
+
setActiveIdx,
|
|
8482
|
+
listRef,
|
|
8483
|
+
onSelect: (idx) => {
|
|
8484
|
+
if (filtered[idx]) onSelect(filtered[idx].name);
|
|
8258
8485
|
},
|
|
8259
|
-
|
|
8260
|
-
|
|
8486
|
+
onDismiss
|
|
8487
|
+
});
|
|
8488
|
+
return /* @__PURE__ */ jsxs28("div", { ref: containerRef, className: "mb-1 w-full overflow-hidden rounded-lg border border-border/60 bg-popover shadow-lg", children: [
|
|
8489
|
+
/* @__PURE__ */ jsx30(
|
|
8490
|
+
"input",
|
|
8491
|
+
{
|
|
8492
|
+
ref: inputRef,
|
|
8493
|
+
"aria-label": "Search commands",
|
|
8494
|
+
type: "text",
|
|
8495
|
+
value: searchQuery,
|
|
8496
|
+
onChange: (e) => {
|
|
8497
|
+
setSearchQuery(e.target.value);
|
|
8498
|
+
setActiveIdx(0);
|
|
8499
|
+
},
|
|
8500
|
+
className: "w-full border-b border-border/50 bg-transparent px-3 py-1.5 text-[12px] outline-none",
|
|
8501
|
+
autoComplete: "off"
|
|
8502
|
+
}
|
|
8503
|
+
),
|
|
8504
|
+
groups.length > 1 && /* @__PURE__ */ jsx30("div", { className: "flex flex-wrap gap-1 border-b border-border/50 px-2 py-1.5", role: "tablist", "aria-label": "Filter by plugin", children: [ALL_PLUGINS, ...groups].map((g) => {
|
|
8505
|
+
const selected = plugin === g;
|
|
8506
|
+
return /* @__PURE__ */ jsx30(
|
|
8507
|
+
"button",
|
|
8508
|
+
{
|
|
8509
|
+
type: "button",
|
|
8510
|
+
role: "tab",
|
|
8511
|
+
"aria-selected": selected,
|
|
8512
|
+
onMouseDown: (e) => {
|
|
8513
|
+
e.preventDefault();
|
|
8514
|
+
setPlugin(g);
|
|
8515
|
+
setActiveIdx(0);
|
|
8516
|
+
},
|
|
8517
|
+
className: cn(
|
|
8518
|
+
"rounded-full px-2 py-px text-[10px] font-medium transition-colors",
|
|
8519
|
+
selected ? "bg-accent/15 text-accent-foreground" : "bg-muted/60 text-muted-foreground hover:bg-muted"
|
|
8520
|
+
),
|
|
8521
|
+
children: g === ALL_PLUGINS ? "All" : g
|
|
8522
|
+
},
|
|
8523
|
+
g
|
|
8524
|
+
);
|
|
8525
|
+
}) }),
|
|
8526
|
+
filtered.length === 0 ? /* @__PURE__ */ jsx30("div", { className: "px-3 py-2 text-[11px] text-muted-foreground", children: "No matching commands." }) : /* @__PURE__ */ jsx30("ul", { ref: listRef, className: "max-h-80 overflow-y-auto py-1", role: "listbox", "aria-label": "Commands", children: filtered.map((cmd, i) => /* @__PURE__ */ jsxs28(
|
|
8527
|
+
"li",
|
|
8528
|
+
{
|
|
8529
|
+
role: "option",
|
|
8530
|
+
"aria-selected": i === activeIdx,
|
|
8531
|
+
title: cmd.description || void 0,
|
|
8532
|
+
className: cn(
|
|
8533
|
+
"flex cursor-pointer flex-col gap-0.5 px-3 py-1.5 text-[12px]",
|
|
8534
|
+
// Single highlight: hovering moves the active row (onMouseEnter),
|
|
8535
|
+
// so the active style is the only highlight — no separate hover bg.
|
|
8536
|
+
i === activeIdx ? "bg-accent/10 text-foreground" : "text-muted-foreground"
|
|
8537
|
+
),
|
|
8538
|
+
onMouseEnter: () => setActiveIdx(i),
|
|
8539
|
+
onMouseDown: (e) => {
|
|
8540
|
+
e.preventDefault();
|
|
8541
|
+
onSelect(cmd.name);
|
|
8542
|
+
},
|
|
8543
|
+
children: [
|
|
8544
|
+
/* @__PURE__ */ jsxs28("span", { className: "flex items-center gap-1.5", children: [
|
|
8545
|
+
/* @__PURE__ */ jsxs28("span", { className: "font-medium text-foreground/80", children: [
|
|
8546
|
+
"/",
|
|
8547
|
+
cmd.name
|
|
8548
|
+
] }),
|
|
8549
|
+
cmd.source === "skill" ? /* @__PURE__ */ jsxs28(Fragment10, { children: [
|
|
8550
|
+
/* @__PURE__ */ jsx30("span", { className: "rounded-sm bg-accent/15 px-1 py-px text-[9px] font-medium uppercase tracking-wide text-accent-foreground", children: "skill" }),
|
|
8551
|
+
cmd.sourcePlugin ? /* @__PURE__ */ jsx30("span", { className: "rounded-sm bg-muted px-1 py-px text-[9px] font-medium text-muted-foreground", children: cmd.sourcePlugin }) : null
|
|
8552
|
+
] }) : cmd.sourcePlugin ? (
|
|
8553
|
+
// Originating plugin/package for non-skill commands.
|
|
8554
|
+
/* @__PURE__ */ jsx30("span", { className: "rounded-sm bg-muted px-1 py-px text-[9px] font-medium text-muted-foreground", children: cmd.sourcePlugin })
|
|
8555
|
+
) : null
|
|
8556
|
+
] }),
|
|
8557
|
+
/* @__PURE__ */ jsx30("span", { className: "truncate text-[11px] opacity-50", children: cmd.description })
|
|
8558
|
+
]
|
|
8559
|
+
},
|
|
8560
|
+
cmd.name
|
|
8561
|
+
)) })
|
|
8562
|
+
] });
|
|
8261
8563
|
}
|
|
8262
8564
|
|
|
8263
8565
|
// src/front/chat/components/ComposerAttachments.tsx
|
|
8264
|
-
import { AlertCircleIcon as
|
|
8566
|
+
import { AlertCircleIcon as AlertCircleIcon2, Loader2 as Loader23, PaperclipIcon as PaperclipIcon2 } from "lucide-react";
|
|
8265
8567
|
import { IconButton as IconButton3 } from "@hachej/boring-ui-kit";
|
|
8266
|
-
import { jsx as
|
|
8568
|
+
import { jsx as jsx31, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
8267
8569
|
function AttachmentButton({ disabled, className }) {
|
|
8268
8570
|
const attachments = usePromptInputAttachments();
|
|
8269
|
-
return /* @__PURE__ */
|
|
8571
|
+
return /* @__PURE__ */ jsx31(
|
|
8270
8572
|
IconButton3,
|
|
8271
8573
|
{
|
|
8272
8574
|
type: "button",
|
|
@@ -8279,21 +8581,21 @@ function AttachmentButton({ disabled, className }) {
|
|
|
8279
8581
|
className: cn(composerActionClass, "w-8", className),
|
|
8280
8582
|
"aria-label": "Attach files",
|
|
8281
8583
|
title: disabled ? "Attachments are available when the composer is ready." : "Attach files",
|
|
8282
|
-
children: /* @__PURE__ */
|
|
8584
|
+
children: /* @__PURE__ */ jsx31(PaperclipIcon2, { className: "h-3.5 w-3.5", strokeWidth: 1.75 })
|
|
8283
8585
|
}
|
|
8284
8586
|
);
|
|
8285
8587
|
}
|
|
8286
8588
|
function AttachmentsList() {
|
|
8287
8589
|
const attachments = usePromptInputAttachments();
|
|
8288
8590
|
if (attachments.files.length === 0) return null;
|
|
8289
|
-
return /* @__PURE__ */
|
|
8591
|
+
return /* @__PURE__ */ jsx31(
|
|
8290
8592
|
Attachments,
|
|
8291
8593
|
{
|
|
8292
8594
|
"data-boring-agent-part": "composer-attachment-row",
|
|
8293
8595
|
"data-align": "block-start",
|
|
8294
8596
|
variant: "inline",
|
|
8295
8597
|
className: "w-full flex-wrap items-center justify-start gap-2 px-5 pb-0 pt-3",
|
|
8296
|
-
children: attachments.files.map((file) => /* @__PURE__ */
|
|
8598
|
+
children: attachments.files.map((file) => /* @__PURE__ */ jsxs29(
|
|
8297
8599
|
Attachment,
|
|
8298
8600
|
{
|
|
8299
8601
|
data: file,
|
|
@@ -8304,13 +8606,13 @@ function AttachmentsList() {
|
|
|
8304
8606
|
file.status === "error" && "!border-destructive/50 !bg-destructive/10"
|
|
8305
8607
|
),
|
|
8306
8608
|
children: [
|
|
8307
|
-
/* @__PURE__ */
|
|
8308
|
-
/* @__PURE__ */
|
|
8309
|
-
file.status === "uploading" ? /* @__PURE__ */
|
|
8310
|
-
file.status === "error" ? /* @__PURE__ */
|
|
8609
|
+
/* @__PURE__ */ jsxs29("div", { className: "relative shrink-0", children: [
|
|
8610
|
+
/* @__PURE__ */ jsx31(AttachmentPreview, { className: "!size-7 overflow-hidden !rounded-full bg-background/60" }),
|
|
8611
|
+
file.status === "uploading" ? /* @__PURE__ */ jsx31("div", { className: "absolute inset-0 flex items-center justify-center rounded-full bg-background/70", children: /* @__PURE__ */ jsx31(Loader23, { className: "size-3.5 animate-spin text-muted-foreground" }) }) : null,
|
|
8612
|
+
file.status === "error" ? /* @__PURE__ */ jsx31("div", { className: "absolute inset-0 flex items-center justify-center rounded-full bg-destructive/20", children: /* @__PURE__ */ jsx31(AlertCircleIcon2, { className: "size-3.5 text-destructive" }) }) : null
|
|
8311
8613
|
] }),
|
|
8312
|
-
/* @__PURE__ */
|
|
8313
|
-
/* @__PURE__ */
|
|
8614
|
+
/* @__PURE__ */ jsx31(AttachmentInfo, { className: "min-w-0 !max-w-[180px] truncate text-[13px] font-medium" }),
|
|
8615
|
+
/* @__PURE__ */ jsx31(AttachmentRemove, { className: "!size-5 !rounded-full !opacity-100 text-muted-foreground/80 hover:text-foreground" })
|
|
8314
8616
|
]
|
|
8315
8617
|
},
|
|
8316
8618
|
file.id
|
|
@@ -8320,7 +8622,7 @@ function AttachmentsList() {
|
|
|
8320
8622
|
}
|
|
8321
8623
|
|
|
8322
8624
|
// src/front/chat/components/PiChatComposerSurface.tsx
|
|
8323
|
-
import { jsx as
|
|
8625
|
+
import { jsx as jsx32, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
8324
8626
|
var MAX_PROMPT_ATTACHMENTS = 2;
|
|
8325
8627
|
var MAX_PROMPT_ATTACHMENT_BYTES = 4 * 1024 * 1024;
|
|
8326
8628
|
var COMPOSER_INPUT_GROUP_MIN_HEIGHT = 56;
|
|
@@ -8362,6 +8664,8 @@ function PiChatComposerSurface({
|
|
|
8362
8664
|
pluginUpdateState,
|
|
8363
8665
|
onDismissPluginUpdate,
|
|
8364
8666
|
onRunPluginUpdate,
|
|
8667
|
+
commandNotifyState,
|
|
8668
|
+
onDismissCommandNotify,
|
|
8365
8669
|
attachmentNotice,
|
|
8366
8670
|
onAttachmentNotice,
|
|
8367
8671
|
mentionState,
|
|
@@ -8396,7 +8700,7 @@ function PiChatComposerSurface({
|
|
|
8396
8700
|
onSubmitMessage,
|
|
8397
8701
|
onStop
|
|
8398
8702
|
}) {
|
|
8399
|
-
const resizeTextarea =
|
|
8703
|
+
const resizeTextarea = useCallback16((node) => {
|
|
8400
8704
|
if (!node) return;
|
|
8401
8705
|
node.style.height = "auto";
|
|
8402
8706
|
const style = window.getComputedStyle(node);
|
|
@@ -8420,8 +8724,8 @@ function PiChatComposerSurface({
|
|
|
8420
8724
|
useLayoutEffect2(() => {
|
|
8421
8725
|
resizeTextarea(textareaRef.current);
|
|
8422
8726
|
}, [draft, resizeTextarea, textareaRef]);
|
|
8423
|
-
return /* @__PURE__ */
|
|
8424
|
-
/* @__PURE__ */
|
|
8727
|
+
return /* @__PURE__ */ jsxs30("div", { className: cn(chrome ? "px-4 pb-4 pt-2 sm:px-6 sm:pb-5" : "px-3 pb-2 pt-1"), children: [
|
|
8728
|
+
/* @__PURE__ */ jsx32(
|
|
8425
8729
|
"div",
|
|
8426
8730
|
{
|
|
8427
8731
|
"data-boring-agent-part": "chat-working-slot",
|
|
@@ -8431,7 +8735,7 @@ function PiChatComposerSurface({
|
|
|
8431
8735
|
isStreaming ? "mb-2 max-h-8 opacity-100" : "mb-0 max-h-0 opacity-0"
|
|
8432
8736
|
),
|
|
8433
8737
|
"aria-hidden": !isStreaming,
|
|
8434
|
-
children: /* @__PURE__ */
|
|
8738
|
+
children: /* @__PURE__ */ jsxs30(
|
|
8435
8739
|
"div",
|
|
8436
8740
|
{
|
|
8437
8741
|
"data-testid": isStreaming ? "chat-working" : void 0,
|
|
@@ -8439,7 +8743,7 @@ function PiChatComposerSurface({
|
|
|
8439
8743
|
"aria-live": isStreaming ? "polite" : void 0,
|
|
8440
8744
|
className: "inline-flex items-center gap-2 rounded-full border border-border/50 bg-background/85 px-2.5 py-1 text-[12px] text-muted-foreground/75 shadow-sm backdrop-blur",
|
|
8441
8745
|
children: [
|
|
8442
|
-
/* @__PURE__ */
|
|
8746
|
+
/* @__PURE__ */ jsx32(
|
|
8443
8747
|
motion2.span,
|
|
8444
8748
|
{
|
|
8445
8749
|
"aria-hidden": "true",
|
|
@@ -8448,14 +8752,14 @@ function PiChatComposerSurface({
|
|
|
8448
8752
|
transition: { duration: 1.2, repeat: Infinity, ease: "easeInOut" }
|
|
8449
8753
|
}
|
|
8450
8754
|
),
|
|
8451
|
-
/* @__PURE__ */
|
|
8755
|
+
/* @__PURE__ */ jsx32("span", { children: "Working\u2026" })
|
|
8452
8756
|
]
|
|
8453
8757
|
}
|
|
8454
8758
|
)
|
|
8455
8759
|
}
|
|
8456
8760
|
),
|
|
8457
|
-
composerStatusNotice ? /* @__PURE__ */
|
|
8458
|
-
composerBlocked && !workspaceWarmupBlocked ? /* @__PURE__ */
|
|
8761
|
+
composerStatusNotice ? /* @__PURE__ */ jsx32(ComposerRuntimeNotice, { notice: composerStatusNotice }) : null,
|
|
8762
|
+
composerBlocked && !workspaceWarmupBlocked ? /* @__PURE__ */ jsx32(
|
|
8459
8763
|
ComposerBlockerNotice,
|
|
8460
8764
|
{
|
|
8461
8765
|
blocker: primaryComposerBlocker,
|
|
@@ -8463,8 +8767,8 @@ function PiChatComposerSurface({
|
|
|
8463
8767
|
onAction: onComposerBlockerAction
|
|
8464
8768
|
}
|
|
8465
8769
|
) : null,
|
|
8466
|
-
queuePreview.length > 0 ? /* @__PURE__ */
|
|
8467
|
-
hotReloadEnabled ? /* @__PURE__ */
|
|
8770
|
+
queuePreview.length > 0 ? /* @__PURE__ */ jsx32(QueuedComposerNotice, { followUps: queuePreview, onEdit: onEditQueued }) : null,
|
|
8771
|
+
hotReloadEnabled ? /* @__PURE__ */ jsx32(
|
|
8468
8772
|
PluginUpdateStatus,
|
|
8469
8773
|
{
|
|
8470
8774
|
state: pluginUpdateState,
|
|
@@ -8472,7 +8776,14 @@ function PiChatComposerSurface({
|
|
|
8472
8776
|
onRetry: onRunPluginUpdate
|
|
8473
8777
|
}
|
|
8474
8778
|
) : null,
|
|
8475
|
-
|
|
8779
|
+
/* @__PURE__ */ jsx32(
|
|
8780
|
+
CommandRunStatus,
|
|
8781
|
+
{
|
|
8782
|
+
state: commandNotifyState,
|
|
8783
|
+
onDismiss: onDismissCommandNotify
|
|
8784
|
+
}
|
|
8785
|
+
),
|
|
8786
|
+
attachmentNotice ? /* @__PURE__ */ jsx32(
|
|
8476
8787
|
"div",
|
|
8477
8788
|
{
|
|
8478
8789
|
role: "status",
|
|
@@ -8481,8 +8792,8 @@ function PiChatComposerSurface({
|
|
|
8481
8792
|
children: attachmentNotice
|
|
8482
8793
|
}
|
|
8483
8794
|
) : null,
|
|
8484
|
-
/* @__PURE__ */
|
|
8485
|
-
mentionState ? /* @__PURE__ */
|
|
8795
|
+
/* @__PURE__ */ jsxs30("div", { className: cn("mx-auto w-full", chrome ? "max-w-3xl" : "max-w-[680px]"), children: [
|
|
8796
|
+
mentionState ? /* @__PURE__ */ jsx32(
|
|
8486
8797
|
MentionPicker,
|
|
8487
8798
|
{
|
|
8488
8799
|
mention: mentionState,
|
|
@@ -8494,7 +8805,7 @@ function PiChatComposerSurface({
|
|
|
8494
8805
|
onDismiss: onDismissMention
|
|
8495
8806
|
}
|
|
8496
8807
|
) : null,
|
|
8497
|
-
slashQuery !== null ? /* @__PURE__ */
|
|
8808
|
+
slashQuery !== null ? /* @__PURE__ */ jsx32(
|
|
8498
8809
|
SlashCommandPicker,
|
|
8499
8810
|
{
|
|
8500
8811
|
query: slashQuery,
|
|
@@ -8503,7 +8814,7 @@ function PiChatComposerSurface({
|
|
|
8503
8814
|
onDismiss: onDismissSlash
|
|
8504
8815
|
}
|
|
8505
8816
|
) : null,
|
|
8506
|
-
mentionState === null && slashQuery === null && modelPickerOpen ? /* @__PURE__ */
|
|
8817
|
+
mentionState === null && slashQuery === null && modelPickerOpen ? /* @__PURE__ */ jsx32(
|
|
8507
8818
|
ModelPickerMenu,
|
|
8508
8819
|
{
|
|
8509
8820
|
value: selectedModel,
|
|
@@ -8513,7 +8824,7 @@ function PiChatComposerSurface({
|
|
|
8513
8824
|
onClose: () => onSetModelPickerOpen(false)
|
|
8514
8825
|
}
|
|
8515
8826
|
) : null,
|
|
8516
|
-
mentionState === null && slashQuery === null && thinkingPickerOpen ? /* @__PURE__ */
|
|
8827
|
+
mentionState === null && slashQuery === null && thinkingPickerOpen ? /* @__PURE__ */ jsx32(
|
|
8517
8828
|
ThinkingPickerMenu,
|
|
8518
8829
|
{
|
|
8519
8830
|
value: selectedThinking,
|
|
@@ -8523,7 +8834,7 @@ function PiChatComposerSurface({
|
|
|
8523
8834
|
}
|
|
8524
8835
|
) : null
|
|
8525
8836
|
] }),
|
|
8526
|
-
/* @__PURE__ */
|
|
8837
|
+
/* @__PURE__ */ jsx32(
|
|
8527
8838
|
"div",
|
|
8528
8839
|
{
|
|
8529
8840
|
"data-boring-agent-part": "composer-rail",
|
|
@@ -8542,7 +8853,7 @@ function PiChatComposerSurface({
|
|
|
8542
8853
|
"[&[data-composer-multiline=true]_[data-boring-agent-part=composer-submit-addon]]:self-end",
|
|
8543
8854
|
"[&[data-composer-multiline=true]_[data-boring-agent-part=composer-submit-addon]]:mb-2"
|
|
8544
8855
|
),
|
|
8545
|
-
children: /* @__PURE__ */
|
|
8856
|
+
children: /* @__PURE__ */ jsxs30(
|
|
8546
8857
|
PromptInput,
|
|
8547
8858
|
{
|
|
8548
8859
|
"data-boring-state": status,
|
|
@@ -8557,15 +8868,15 @@ function PiChatComposerSurface({
|
|
|
8557
8868
|
else onAttachmentNotice(err.message || "Attachment rejected.");
|
|
8558
8869
|
},
|
|
8559
8870
|
children: [
|
|
8560
|
-
/* @__PURE__ */
|
|
8561
|
-
/* @__PURE__ */
|
|
8871
|
+
/* @__PURE__ */ jsx32(AttachmentsList, {}),
|
|
8872
|
+
/* @__PURE__ */ jsxs30(
|
|
8562
8873
|
"div",
|
|
8563
8874
|
{
|
|
8564
8875
|
"data-boring-agent-part": "composer-input-row",
|
|
8565
8876
|
className: "flex min-h-[var(--composer-input-group-height)] w-full items-center",
|
|
8566
8877
|
children: [
|
|
8567
|
-
/* @__PURE__ */
|
|
8568
|
-
/* @__PURE__ */
|
|
8878
|
+
/* @__PURE__ */ jsx32("div", { className: "flex h-14 shrink-0 items-center pl-2", children: /* @__PURE__ */ jsx32(AttachmentButton, { disabled: disabled || isStreaming }) }),
|
|
8879
|
+
/* @__PURE__ */ jsx32(
|
|
8569
8880
|
PromptInputTextarea,
|
|
8570
8881
|
{
|
|
8571
8882
|
value: draft,
|
|
@@ -8589,13 +8900,13 @@ function PiChatComposerSurface({
|
|
|
8589
8900
|
)
|
|
8590
8901
|
}
|
|
8591
8902
|
),
|
|
8592
|
-
/* @__PURE__ */
|
|
8903
|
+
/* @__PURE__ */ jsx32(
|
|
8593
8904
|
PromptInputFooter,
|
|
8594
8905
|
{
|
|
8595
8906
|
align: "inline-end",
|
|
8596
8907
|
"data-boring-agent-part": "composer-submit-addon",
|
|
8597
8908
|
className: "!order-none !w-auto shrink-0 self-center justify-between border-0 bg-transparent !px-2 !py-0",
|
|
8598
|
-
children: /* @__PURE__ */
|
|
8909
|
+
children: /* @__PURE__ */ jsx32("div", { className: "ml-auto flex items-center gap-1.5", children: /* @__PURE__ */ jsx32(
|
|
8599
8910
|
PromptInputSubmit,
|
|
8600
8911
|
{
|
|
8601
8912
|
"data-boring-agent-part": "composer-submit",
|
|
@@ -8625,7 +8936,7 @@ function PiChatComposerSurface({
|
|
|
8625
8936
|
)
|
|
8626
8937
|
}
|
|
8627
8938
|
),
|
|
8628
|
-
/* @__PURE__ */
|
|
8939
|
+
/* @__PURE__ */ jsxs30(
|
|
8629
8940
|
"div",
|
|
8630
8941
|
{
|
|
8631
8942
|
"data-boring-agent-part": "composer-settings-row",
|
|
@@ -8634,7 +8945,7 @@ function PiChatComposerSurface({
|
|
|
8634
8945
|
chrome ? "max-w-3xl" : "max-w-[680px]"
|
|
8635
8946
|
),
|
|
8636
8947
|
children: [
|
|
8637
|
-
/* @__PURE__ */
|
|
8948
|
+
/* @__PURE__ */ jsx32(
|
|
8638
8949
|
ModelSelectTrigger,
|
|
8639
8950
|
{
|
|
8640
8951
|
value: selectedModel,
|
|
@@ -8651,7 +8962,7 @@ function PiChatComposerSurface({
|
|
|
8651
8962
|
}
|
|
8652
8963
|
}
|
|
8653
8964
|
),
|
|
8654
|
-
thinkingControl ? /* @__PURE__ */
|
|
8965
|
+
thinkingControl ? /* @__PURE__ */ jsx32(
|
|
8655
8966
|
ThinkingSelectTrigger,
|
|
8656
8967
|
{
|
|
8657
8968
|
value: selectedThinking,
|
|
@@ -8674,7 +8985,7 @@ function PiChatComposerSurface({
|
|
|
8674
8985
|
}
|
|
8675
8986
|
|
|
8676
8987
|
// src/front/chat/piChatPanelHooks.ts
|
|
8677
|
-
import { useCallback as
|
|
8988
|
+
import { useCallback as useCallback17, useEffect as useEffect20, useState as useState19, useSyncExternalStore } from "react";
|
|
8678
8989
|
function useExternalRemotePiSession({
|
|
8679
8990
|
sessionId,
|
|
8680
8991
|
workspaceId,
|
|
@@ -8686,7 +8997,7 @@ function useExternalRemotePiSession({
|
|
|
8686
8997
|
remoteSessionOptions
|
|
8687
8998
|
}) {
|
|
8688
8999
|
const [session, setSession] = useState19();
|
|
8689
|
-
|
|
9000
|
+
useEffect20(() => {
|
|
8690
9001
|
if (!sessionId) {
|
|
8691
9002
|
setSession(void 0);
|
|
8692
9003
|
return;
|
|
@@ -8707,10 +9018,10 @@ function useExternalRemotePiSession({
|
|
|
8707
9018
|
}
|
|
8708
9019
|
function useRemotePiSessionState(session) {
|
|
8709
9020
|
return useSyncExternalStore(
|
|
8710
|
-
|
|
9021
|
+
useCallback17((listener) => session?.subscribe(listener) ?? (() => {
|
|
8711
9022
|
}), [session]),
|
|
8712
|
-
|
|
8713
|
-
|
|
9023
|
+
useCallback17(() => session?.getState(), [session]),
|
|
9024
|
+
useCallback17(() => session?.getState(), [session])
|
|
8714
9025
|
);
|
|
8715
9026
|
}
|
|
8716
9027
|
|
|
@@ -8826,7 +9137,7 @@ function errorMessage2(error, fallback) {
|
|
|
8826
9137
|
}
|
|
8827
9138
|
|
|
8828
9139
|
// src/front/chat/PiChatPanel.tsx
|
|
8829
|
-
import { jsx as
|
|
9140
|
+
import { jsx as jsx33, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
8830
9141
|
var DebugDrawer2 = lazy(() => import("../DebugDrawer-2PUDZ2RL.js").then((m) => ({ default: m.DebugDrawer })));
|
|
8831
9142
|
var EMPTY_COMMANDS = [];
|
|
8832
9143
|
var EMPTY_BLOCKERS = [];
|
|
@@ -8880,9 +9191,9 @@ function PiChatPanel({
|
|
|
8880
9191
|
}) {
|
|
8881
9192
|
const externalSessionId = sessionId?.trim() || void 0;
|
|
8882
9193
|
const showSessionSidebar = showSessions ?? externalSessionId === void 0;
|
|
8883
|
-
const onDataRef =
|
|
9194
|
+
const onDataRef = useRef16(onData);
|
|
8884
9195
|
onDataRef.current = onData;
|
|
8885
|
-
const sessionListRefreshRef =
|
|
9196
|
+
const sessionListRefreshRef = useRef16(void 0);
|
|
8886
9197
|
const requestHeadersKey = useMemo12(() => headersContentKey(requestHeaders), [requestHeaders]);
|
|
8887
9198
|
const normalizedRequestHeaders = useMemo12(() => normalizedHeadersFromContentKey(requestHeadersKey), [requestHeadersKey]);
|
|
8888
9199
|
const remoteSessionOptionsWithEvents = useMemo12(() => ({
|
|
@@ -8905,7 +9216,7 @@ function PiChatPanel({
|
|
|
8905
9216
|
remoteSessionOptions: remoteSessionOptionsWithEvents,
|
|
8906
9217
|
enabled: externalSessionId === void 0
|
|
8907
9218
|
});
|
|
8908
|
-
|
|
9219
|
+
useEffect21(() => {
|
|
8909
9220
|
if (externalSessionId) {
|
|
8910
9221
|
sessionListRefreshRef.current = void 0;
|
|
8911
9222
|
return;
|
|
@@ -8959,19 +9270,19 @@ function PiChatPanel({
|
|
|
8959
9270
|
() => readPiComposerSettings({ storageScope, storage }).showThoughts
|
|
8960
9271
|
);
|
|
8961
9272
|
const [composerSettingsOwner, setComposerSettingsOwner] = useState20(() => ({ storageScope, storage }));
|
|
8962
|
-
|
|
9273
|
+
useEffect21(() => {
|
|
8963
9274
|
const settings = readPiComposerSettings({ storageScope, storage });
|
|
8964
9275
|
setStoredThinkingLevel(thinkingControl ? settings.thinkingLevel : DEFAULT_THINKING);
|
|
8965
9276
|
setShowThoughts(settings.showThoughts);
|
|
8966
9277
|
setComposerSettingsOwner({ storageScope, storage });
|
|
8967
9278
|
}, [storage, storageScope, thinkingControl]);
|
|
8968
9279
|
const composerSettingsLoaded = composerSettingsOwner.storageScope === storageScope && composerSettingsOwner.storage === storage;
|
|
8969
|
-
|
|
9280
|
+
useEffect21(() => {
|
|
8970
9281
|
if (!thinkingControl) return;
|
|
8971
9282
|
if (!composerSettingsLoaded) return;
|
|
8972
9283
|
writePiComposerThinking(storedThinkingLevel, { storageScope, storage });
|
|
8973
9284
|
}, [composerSettingsLoaded, storage, storageScope, storedThinkingLevel, thinkingControl]);
|
|
8974
|
-
|
|
9285
|
+
useEffect21(() => {
|
|
8975
9286
|
if (!composerSettingsLoaded) return;
|
|
8976
9287
|
writePiComposerShowThoughts(showThoughts, { storageScope, storage });
|
|
8977
9288
|
}, [composerSettingsLoaded, showThoughts, storage, storageScope]);
|
|
@@ -8980,14 +9291,14 @@ function PiChatPanel({
|
|
|
8980
9291
|
const [modelPickerOpen, setModelPickerOpen] = useState20(false);
|
|
8981
9292
|
const [thinkingPickerOpen, setThinkingPickerOpen] = useState20(false);
|
|
8982
9293
|
const [draft, setDraft] = useState20(() => initialDraft ?? "");
|
|
8983
|
-
const draftRef =
|
|
9294
|
+
const draftRef = useRef16(draft);
|
|
8984
9295
|
draftRef.current = draft;
|
|
8985
|
-
const initialDraftGuard =
|
|
8986
|
-
const pendingAutoSubmitSettleRef =
|
|
8987
|
-
const acceptedAutoSubmitSettleRef =
|
|
8988
|
-
const resetInProgressRef =
|
|
8989
|
-
const autoCreateInFlightRef =
|
|
8990
|
-
const settlePendingAutoSubmit =
|
|
9296
|
+
const initialDraftGuard = useRef16(new InitialDraftAutoSubmitGuard());
|
|
9297
|
+
const pendingAutoSubmitSettleRef = useRef16(void 0);
|
|
9298
|
+
const acceptedAutoSubmitSettleRef = useRef16(void 0);
|
|
9299
|
+
const resetInProgressRef = useRef16(false);
|
|
9300
|
+
const autoCreateInFlightRef = useRef16(false);
|
|
9301
|
+
const settlePendingAutoSubmit = useCallback18((sessionId2) => {
|
|
8991
9302
|
const pendingSessionId = pendingAutoSubmitSettleRef.current;
|
|
8992
9303
|
if (!pendingSessionId || sessionId2 && pendingSessionId !== sessionId2) return false;
|
|
8993
9304
|
pendingAutoSubmitSettleRef.current = void 0;
|
|
@@ -8995,23 +9306,25 @@ function PiChatPanel({
|
|
|
8995
9306
|
onAutoSubmitInitialDraftSettled?.();
|
|
8996
9307
|
return true;
|
|
8997
9308
|
}, [onAutoSubmitInitialDraftSettled]);
|
|
8998
|
-
const prevStatusRef =
|
|
8999
|
-
const statusRef =
|
|
9000
|
-
const scrollToBottomRef =
|
|
9309
|
+
const prevStatusRef = useRef16("idle");
|
|
9310
|
+
const statusRef = useRef16("idle");
|
|
9311
|
+
const scrollToBottomRef = useRef16(() => {
|
|
9001
9312
|
});
|
|
9002
|
-
const textareaRef =
|
|
9313
|
+
const textareaRef = useRef16(null);
|
|
9003
9314
|
const [localNotices, setLocalNotices] = useState20([]);
|
|
9004
9315
|
const [dismissedNoticeIds, setDismissedNoticeIds] = useState20(() => /* @__PURE__ */ new Set());
|
|
9005
9316
|
const [pluginUpdateState, setPluginUpdateState] = useState20(null);
|
|
9317
|
+
const [commandNotifyState, setCommandNotifyState] = useState20(null);
|
|
9318
|
+
const commandRunIdRef = useRef16(0);
|
|
9006
9319
|
const [serverSkillsRefreshKey, setServerSkillsRefreshKey] = useState20(0);
|
|
9007
9320
|
const [localSubmittedSessionId, setLocalSubmittedSessionId] = useState20();
|
|
9008
|
-
const localSubmittedSessionRef =
|
|
9321
|
+
const localSubmittedSessionRef = useRef16(void 0);
|
|
9009
9322
|
const { attachmentNotice, setAttachmentNotice } = useAttachmentNotice();
|
|
9010
|
-
const markLocalSubmitted =
|
|
9323
|
+
const markLocalSubmitted = useCallback18((sessionId2) => {
|
|
9011
9324
|
localSubmittedSessionRef.current = sessionId2;
|
|
9012
9325
|
setLocalSubmittedSessionId(sessionId2);
|
|
9013
9326
|
}, []);
|
|
9014
|
-
const clearLocalSubmitted =
|
|
9327
|
+
const clearLocalSubmitted = useCallback18((sessionId2) => {
|
|
9015
9328
|
if (sessionId2 && localSubmittedSessionRef.current !== sessionId2) return;
|
|
9016
9329
|
localSubmittedSessionRef.current = void 0;
|
|
9017
9330
|
setLocalSubmittedSessionId(void 0);
|
|
@@ -9023,16 +9336,17 @@ function PiChatPanel({
|
|
|
9023
9336
|
for (const command of commands) next.register(command);
|
|
9024
9337
|
return next;
|
|
9025
9338
|
}, [apiBaseUrl, commands, extraCommands, hotReloadEnabled, normalizedRequestHeaders, serverResourcesEnabled, serverSkillsRefreshKey, storageScope]);
|
|
9026
|
-
const
|
|
9027
|
-
apiBaseUrl,
|
|
9028
|
-
fetch: fetch2,
|
|
9339
|
+
const commandsStamp = useServerCommands({
|
|
9029
9340
|
registry,
|
|
9030
|
-
refreshKey: serverSkillsRefreshKey,
|
|
9031
9341
|
requestHeaders: normalizedRequestHeaders,
|
|
9342
|
+
sessionId: activeSessionId ?? "default",
|
|
9343
|
+
apiBaseUrl,
|
|
9344
|
+
fetch: fetch2,
|
|
9032
9345
|
storageScope,
|
|
9346
|
+
refreshKey: serverSkillsRefreshKey,
|
|
9033
9347
|
enabled: serverResourcesEnabled
|
|
9034
9348
|
});
|
|
9035
|
-
const allCommands = useMemo12(() => registry.list(), [registry,
|
|
9349
|
+
const allCommands = useMemo12(() => registry.list(), [registry, commandsStamp]);
|
|
9036
9350
|
const activeChatSessionId = selectedChatState?.sessionId;
|
|
9037
9351
|
const warmupNotice = composerNoticeForWarmup(workspaceWarmupStatus);
|
|
9038
9352
|
const runtimeDependenciesNotice = composerNoticeForRuntimeDependencies(workspaceWarmupStatus);
|
|
@@ -9063,23 +9377,23 @@ function PiChatPanel({
|
|
|
9063
9377
|
}] : [];
|
|
9064
9378
|
return [...fromState, ...sessionNotice, ...largeStateNotice, ...localNotices].filter((notice) => !dismissedNoticeIds.has(notice.id));
|
|
9065
9379
|
}, [debug, debugState?.largeStateWarning, dismissedNoticeIds, localNotices, selectedChatState, sessionsError]);
|
|
9066
|
-
const addLocalNotice =
|
|
9380
|
+
const addLocalNotice = useCallback18((notice) => {
|
|
9067
9381
|
setLocalNotices((previous) => {
|
|
9068
9382
|
const next = previous.filter((candidate) => candidate.id !== notice.id);
|
|
9069
9383
|
return [...next, notice];
|
|
9070
9384
|
});
|
|
9071
9385
|
}, []);
|
|
9072
|
-
const clearLocalNotice =
|
|
9386
|
+
const clearLocalNotice = useCallback18((id) => {
|
|
9073
9387
|
setDismissedNoticeIds((previous) => new Set(previous).add(id));
|
|
9074
9388
|
setLocalNotices((previous) => previous.filter((notice) => notice.id !== id));
|
|
9075
9389
|
}, []);
|
|
9076
|
-
const createSession =
|
|
9390
|
+
const createSession = useCallback18(() => {
|
|
9077
9391
|
if (externalSessionId) return;
|
|
9078
9392
|
void sessions.create().catch((error) => {
|
|
9079
9393
|
addLocalNotice({ id: "session-create-error", level: "error", text: errorMessage2(error, "Could not create a Pi session."), dismissible: true });
|
|
9080
9394
|
});
|
|
9081
9395
|
}, [addLocalNotice, externalSessionId, sessions.create]);
|
|
9082
|
-
|
|
9396
|
+
useEffect21(() => {
|
|
9083
9397
|
if (externalSessionId || sessionsLoading || sessionsError || activeSessionId || sessionList.length > 0) return;
|
|
9084
9398
|
if (resetInProgressRef.current) return;
|
|
9085
9399
|
if (autoCreateInFlightRef.current) return;
|
|
@@ -9089,18 +9403,18 @@ function PiChatPanel({
|
|
|
9089
9403
|
addLocalNotice({ id: "session-auto-create-error", level: "error", text: errorMessage2(error, "Could not create a Pi session."), dismissible: true });
|
|
9090
9404
|
});
|
|
9091
9405
|
}, [activeSessionId, addLocalNotice, externalSessionId, sessionList.length, sessions.create, sessionsError, sessionsLoading]);
|
|
9092
|
-
|
|
9406
|
+
useEffect21(() => {
|
|
9093
9407
|
if (externalSessionId || sessionsError || activeSessionId || sessionList.length > 0) {
|
|
9094
9408
|
autoCreateInFlightRef.current = false;
|
|
9095
9409
|
}
|
|
9096
9410
|
}, [activeSessionId, externalSessionId, sessionList.length, sessionsError]);
|
|
9097
|
-
const deleteSession =
|
|
9411
|
+
const deleteSession = useCallback18((sessionId2) => {
|
|
9098
9412
|
if (externalSessionId) return;
|
|
9099
9413
|
void sessions.delete(sessionId2).catch((error) => {
|
|
9100
9414
|
addLocalNotice({ id: `session-delete-error:${sessionId2}`, level: "error", text: errorMessage2(error, "Could not delete the Pi session."), dismissible: true });
|
|
9101
9415
|
});
|
|
9102
9416
|
}, [addLocalNotice, externalSessionId, sessions.delete]);
|
|
9103
|
-
const resetSession =
|
|
9417
|
+
const resetSession = useCallback18(() => {
|
|
9104
9418
|
const currentSessionId = activeSessionId;
|
|
9105
9419
|
if (externalSessionId) {
|
|
9106
9420
|
void onSessionReset?.();
|
|
@@ -9118,11 +9432,11 @@ function PiChatPanel({
|
|
|
9118
9432
|
resetInProgressRef.current = false;
|
|
9119
9433
|
});
|
|
9120
9434
|
}, [activeSessionId, addLocalNotice, externalSessionId, onSessionReset, sessions.create, sessions.delete]);
|
|
9121
|
-
const reloadAgentPlugins =
|
|
9435
|
+
const reloadAgentPlugins = useCallback18(async () => {
|
|
9122
9436
|
if (!onReloadAgentPlugins) throw new Error("Agent plugin reload is not configured.");
|
|
9123
9437
|
return await onReloadAgentPlugins();
|
|
9124
9438
|
}, [onReloadAgentPlugins]);
|
|
9125
|
-
const runPluginUpdate =
|
|
9439
|
+
const runPluginUpdate = useCallback18(async () => {
|
|
9126
9440
|
setPluginUpdateState({ kind: "running" });
|
|
9127
9441
|
try {
|
|
9128
9442
|
const message = await reloadAgentPlugins();
|
|
@@ -9140,8 +9454,26 @@ function PiChatPanel({
|
|
|
9140
9454
|
return `Plugin update failed: ${message}`;
|
|
9141
9455
|
}
|
|
9142
9456
|
}, [reloadAgentPlugins]);
|
|
9143
|
-
const dismissPluginUpdate =
|
|
9144
|
-
|
|
9457
|
+
const dismissPluginUpdate = useCallback18(() => setPluginUpdateState(null), []);
|
|
9458
|
+
const dismissCommandNotify = useCallback18(() => setCommandNotifyState(null), []);
|
|
9459
|
+
useEffect21(() => {
|
|
9460
|
+
if (typeof window === "undefined") return;
|
|
9461
|
+
const onCommandNotify = (event) => {
|
|
9462
|
+
const payload = event.detail;
|
|
9463
|
+
if (!payload || typeof payload.message !== "string") return;
|
|
9464
|
+
const tone = payload.tone;
|
|
9465
|
+
const command = payload.command ?? "";
|
|
9466
|
+
if (tone === "error") {
|
|
9467
|
+
setCommandNotifyState({ kind: "error", command, message: payload.message });
|
|
9468
|
+
} else {
|
|
9469
|
+
const runId = ++commandRunIdRef.current;
|
|
9470
|
+
setCommandNotifyState({ kind: "success", command, detail: payload.message, runId });
|
|
9471
|
+
}
|
|
9472
|
+
};
|
|
9473
|
+
window.addEventListener(WORKSPACE_COMMAND_NOTIFY_EVENT, onCommandNotify);
|
|
9474
|
+
return () => window.removeEventListener(WORKSPACE_COMMAND_NOTIFY_EVENT, onCommandNotify);
|
|
9475
|
+
}, []);
|
|
9476
|
+
useEffect21(() => {
|
|
9145
9477
|
if (!hotReloadEnabled || typeof window === "undefined") return;
|
|
9146
9478
|
const onBrowserPluginReload = (event) => {
|
|
9147
9479
|
const parsed = parseBrowserPluginReloadDetail(event.detail);
|
|
@@ -9179,7 +9511,7 @@ function PiChatPanel({
|
|
|
9179
9511
|
textareaRef,
|
|
9180
9512
|
disabled: mentionState !== null || slashQuery !== null || modelPickerOpen || thinkingPickerOpen
|
|
9181
9513
|
});
|
|
9182
|
-
const setComposerDraft =
|
|
9514
|
+
const setComposerDraft = useCallback18((next, focus = true) => {
|
|
9183
9515
|
draftRef.current = next;
|
|
9184
9516
|
setDraft(next);
|
|
9185
9517
|
if (textareaRef.current) {
|
|
@@ -9187,11 +9519,11 @@ function PiChatPanel({
|
|
|
9187
9519
|
if (focus) textareaRef.current.focus();
|
|
9188
9520
|
}
|
|
9189
9521
|
}, []);
|
|
9190
|
-
const warnComposer =
|
|
9522
|
+
const warnComposer = useCallback18((message) => {
|
|
9191
9523
|
onComposerWarning?.(message);
|
|
9192
9524
|
addLocalNotice({ id: `composer-warning:${Date.now()}`, level: "warning", text: message, dismissible: true });
|
|
9193
9525
|
}, [addLocalNotice, onComposerWarning]);
|
|
9194
|
-
const openModelPicker =
|
|
9526
|
+
const openModelPicker = useCallback18(() => {
|
|
9195
9527
|
if (isPiBusyStatus(statusRef.current)) {
|
|
9196
9528
|
warnComposer("Model picker is unavailable while the agent is running.");
|
|
9197
9529
|
return false;
|
|
@@ -9204,7 +9536,7 @@ function PiChatPanel({
|
|
|
9204
9536
|
setModelPickerOpen(true);
|
|
9205
9537
|
return true;
|
|
9206
9538
|
}, [model, warnComposer]);
|
|
9207
|
-
const openThinkingPicker =
|
|
9539
|
+
const openThinkingPicker = useCallback18(() => {
|
|
9208
9540
|
if (isPiBusyStatus(statusRef.current)) {
|
|
9209
9541
|
warnComposer("Thinking picker is unavailable while the agent is running.");
|
|
9210
9542
|
return false;
|
|
@@ -9217,21 +9549,21 @@ function PiChatPanel({
|
|
|
9217
9549
|
setThinkingPickerOpen(true);
|
|
9218
9550
|
return true;
|
|
9219
9551
|
}, [thinkingControl, thinkingLevel, warnComposer]);
|
|
9220
|
-
const selectComposerModel =
|
|
9552
|
+
const selectComposerModel = useCallback18((query) => {
|
|
9221
9553
|
if (model !== void 0) return "Model selection is controlled by the host.";
|
|
9222
9554
|
const match = resolveModelSlashSelection(query, modelOptions);
|
|
9223
9555
|
if (!match) return `No model matched "${query}".`;
|
|
9224
9556
|
modelDiscovery.setModel(match);
|
|
9225
9557
|
return `Model set to ${match.label ?? match.id}.`;
|
|
9226
9558
|
}, [model, modelDiscovery, modelOptions]);
|
|
9227
|
-
const selectComposerThinking =
|
|
9559
|
+
const selectComposerThinking = useCallback18((query) => {
|
|
9228
9560
|
if (!thinkingControl || thinkingLevel !== void 0) return "Thinking level is controlled by the host.";
|
|
9229
9561
|
const match = resolveThinkingSlashSelection(query);
|
|
9230
9562
|
if (!match) return `No thinking level matched "${query}".`;
|
|
9231
9563
|
setStoredThinkingLevel(match);
|
|
9232
9564
|
return `Thinking set to ${thinkingLabel(match)}.`;
|
|
9233
9565
|
}, [thinkingControl, thinkingLevel]);
|
|
9234
|
-
const selectSlashCommand =
|
|
9566
|
+
const selectSlashCommand = useCallback18((name) => {
|
|
9235
9567
|
if (name === "model") {
|
|
9236
9568
|
dismissSlash();
|
|
9237
9569
|
if (openModelPicker()) setComposerDraft("");
|
|
@@ -9309,7 +9641,7 @@ function PiChatPanel({
|
|
|
9309
9641
|
}
|
|
9310
9642
|
});
|
|
9311
9643
|
}, [activeChatSessionId, addLocalNotice, clearMentionedFiles, composerBlocked, composerBlockerLabel, effectiveMentionedFiles, markLocalSubmitted, onBeforeSubmit, onCommandResult, onComposerWarning, onMentionedFilesConsumed, openModelPicker, openThinkingPicker, registry, reloadAgentPlugins, resetSession, runPluginUpdate, selectComposerModel, selectComposerThinking, selectedModel, selectedPiSession, selectedThinking, setComposerDraft, submitThinkingControl]);
|
|
9312
|
-
const sendComposerMessage =
|
|
9644
|
+
const sendComposerMessage = useCallback18(async ({ text, files, source = "composer" }) => {
|
|
9313
9645
|
if (!policy) {
|
|
9314
9646
|
addLocalNotice({ id: "composer-no-session", level: "warning", text: "Create or select a Pi session before sending.", dismissible: true });
|
|
9315
9647
|
return false;
|
|
@@ -9337,7 +9669,7 @@ function PiChatPanel({
|
|
|
9337
9669
|
throw error;
|
|
9338
9670
|
}
|
|
9339
9671
|
}, [activeChatSessionId, addLocalNotice, clearLocalSubmitted, markLocalSubmitted, policy, selectedPiSession, setComposerDraft]);
|
|
9340
|
-
const editQueued =
|
|
9672
|
+
const editQueued = useCallback18(() => {
|
|
9341
9673
|
if (!policy) return;
|
|
9342
9674
|
void policy.editQueued().then((result) => {
|
|
9343
9675
|
if (result.type === "clear-failed") {
|
|
@@ -9345,23 +9677,24 @@ function PiChatPanel({
|
|
|
9345
9677
|
}
|
|
9346
9678
|
});
|
|
9347
9679
|
}, [addLocalNotice, policy]);
|
|
9348
|
-
const stop =
|
|
9680
|
+
const stop = useCallback18(() => {
|
|
9349
9681
|
onComposerStop?.();
|
|
9350
9682
|
void policy?.stop().catch((error) => {
|
|
9351
9683
|
addLocalNotice({ id: "stop-error", level: "error", text: errorMessage2(error, "Could not stop the Pi session."), dismissible: true });
|
|
9352
9684
|
});
|
|
9353
9685
|
}, [addLocalNotice, onComposerStop, policy]);
|
|
9354
|
-
const interrupt =
|
|
9686
|
+
const interrupt = useCallback18(() => {
|
|
9355
9687
|
void policy?.interrupt().catch((error) => {
|
|
9356
9688
|
addLocalNotice({ id: "interrupt-error", level: "error", text: errorMessage2(error, "Could not interrupt the Pi session."), dismissible: true });
|
|
9357
9689
|
});
|
|
9358
9690
|
}, [addLocalNotice, policy]);
|
|
9359
|
-
|
|
9691
|
+
useEffect21(() => {
|
|
9360
9692
|
setPluginUpdateState(null);
|
|
9693
|
+
setCommandNotifyState(null);
|
|
9361
9694
|
setLocalNotices([]);
|
|
9362
9695
|
setDismissedNoticeIds(/* @__PURE__ */ new Set());
|
|
9363
9696
|
}, [activeSessionId]);
|
|
9364
|
-
|
|
9697
|
+
useEffect21(() => {
|
|
9365
9698
|
const currentSessionId = activeSessionId ?? "__none__";
|
|
9366
9699
|
if (initialDraftGuard.current.shouldRestore(currentSessionId, initialDraft) && initialDraft !== void 0) {
|
|
9367
9700
|
setComposerDraft(initialDraft, initialDraft.length > 0);
|
|
@@ -9370,7 +9703,7 @@ function PiChatPanel({
|
|
|
9370
9703
|
}, [activeSessionId, initialDraft, onDraftRestored, setComposerDraft]);
|
|
9371
9704
|
const remoteStatus = selectedChatState?.status ?? (sessionsLoading || chatStatePending || selectedSessionPending ? "hydrating" : "idle");
|
|
9372
9705
|
const status = localSubmittedSessionId === activeSessionId && remoteStatus === "idle" ? "submitted" : remoteStatus;
|
|
9373
|
-
|
|
9706
|
+
useEffect21(() => {
|
|
9374
9707
|
if (!localSubmittedSessionId) return;
|
|
9375
9708
|
if (localSubmittedSessionId !== activeSessionId) {
|
|
9376
9709
|
clearLocalSubmitted();
|
|
@@ -9378,7 +9711,7 @@ function PiChatPanel({
|
|
|
9378
9711
|
}
|
|
9379
9712
|
if (remoteStatus !== "idle") clearLocalSubmitted(localSubmittedSessionId);
|
|
9380
9713
|
}, [activeSessionId, clearLocalSubmitted, localSubmittedSessionId, remoteStatus]);
|
|
9381
|
-
|
|
9714
|
+
useEffect21(() => {
|
|
9382
9715
|
const previous = prevStatusRef.current;
|
|
9383
9716
|
statusRef.current = status;
|
|
9384
9717
|
prevStatusRef.current = status;
|
|
@@ -9388,7 +9721,7 @@ function PiChatPanel({
|
|
|
9388
9721
|
if (!isPiBusyStatus(previous) && previous !== "submitted") return;
|
|
9389
9722
|
settlePendingAutoSubmit();
|
|
9390
9723
|
}, [settlePendingAutoSubmit, status]);
|
|
9391
|
-
|
|
9724
|
+
useEffect21(() => {
|
|
9392
9725
|
if (!autoSubmitInitialDraft || !policy || !activeSessionId || composerBlocked) return;
|
|
9393
9726
|
if (!initialDraftGuard.current.claimAutoSubmit(activeSessionId, initialDraft)) return;
|
|
9394
9727
|
pendingAutoSubmitSettleRef.current = activeSessionId;
|
|
@@ -9423,7 +9756,7 @@ function PiChatPanel({
|
|
|
9423
9756
|
addLocalNotice({ id: "auto-submit-error", level: "error", text: errorMessage2(error, "Could not auto-submit the initial draft."), dismissible: true });
|
|
9424
9757
|
});
|
|
9425
9758
|
}, [activeSessionId, addLocalNotice, autoSubmitInitialDraft, clearLocalSubmitted, composerBlocked, initialDraft, markLocalSubmitted, onAutoSubmitInitialDraftAccepted, policy, selectedPiSession, setComposerDraft, settlePendingAutoSubmit]);
|
|
9426
|
-
|
|
9759
|
+
useEffect21(() => {
|
|
9427
9760
|
if (workspaceWarmupStatus?.status === "ready") {
|
|
9428
9761
|
clearLocalNotice("workspace-warmup");
|
|
9429
9762
|
}
|
|
@@ -9434,18 +9767,18 @@ function PiChatPanel({
|
|
|
9434
9767
|
const submitDisabled = !policy || sessionsLoading || composerBlocked && !isStreaming;
|
|
9435
9768
|
const mergedToolRenderers = useMemo12(() => mergeShadcnToolRenderers(toolRenderers), [toolRenderers]);
|
|
9436
9769
|
const debugMessages = useMemo12(() => messages.map(toDebugUiMessage), [messages]);
|
|
9437
|
-
const onTextareaChange =
|
|
9770
|
+
const onTextareaChange = useCallback18((event) => {
|
|
9438
9771
|
setModelPickerOpen(false);
|
|
9439
9772
|
setThinkingPickerOpen(false);
|
|
9440
9773
|
setDraft(event.currentTarget.value);
|
|
9441
9774
|
handleComposerChange(event);
|
|
9442
9775
|
}, [handleComposerChange]);
|
|
9443
|
-
|
|
9776
|
+
useEffect21(() => {
|
|
9444
9777
|
if (!isStreaming) return;
|
|
9445
9778
|
setModelPickerOpen(false);
|
|
9446
9779
|
setThinkingPickerOpen(false);
|
|
9447
9780
|
}, [isStreaming]);
|
|
9448
|
-
|
|
9781
|
+
useEffect21(() => {
|
|
9449
9782
|
if (typeof window === "undefined" || !activeChatSessionId) return;
|
|
9450
9783
|
window.dispatchEvent(new CustomEvent("boring:chat-session-status", {
|
|
9451
9784
|
detail: { sessionId: activeChatSessionId, working: isStreaming }
|
|
@@ -9458,7 +9791,7 @@ function PiChatPanel({
|
|
|
9458
9791
|
}));
|
|
9459
9792
|
};
|
|
9460
9793
|
}, [activeChatSessionId, isStreaming]);
|
|
9461
|
-
const onTextareaKeyDown =
|
|
9794
|
+
const onTextareaKeyDown = useCallback18((event) => {
|
|
9462
9795
|
if (event.key === "Escape" && isStreaming) {
|
|
9463
9796
|
if (event.defaultPrevented || mentionState !== null || slashQuery !== null) {
|
|
9464
9797
|
handleComposerKeyDown(event);
|
|
@@ -9470,7 +9803,7 @@ function PiChatPanel({
|
|
|
9470
9803
|
}
|
|
9471
9804
|
handleComposerKeyDown(event);
|
|
9472
9805
|
}, [handleComposerKeyDown, interrupt, isStreaming, mentionState, slashQuery]);
|
|
9473
|
-
return /* @__PURE__ */
|
|
9806
|
+
return /* @__PURE__ */ jsx33(ArtifactOpenProvider, { onOpenArtifact, children: /* @__PURE__ */ jsxs31(
|
|
9474
9807
|
"div",
|
|
9475
9808
|
{
|
|
9476
9809
|
"data-boring-agent": "",
|
|
@@ -9487,7 +9820,7 @@ function PiChatPanel({
|
|
|
9487
9820
|
role: "region",
|
|
9488
9821
|
"aria-label": "Agent assistant",
|
|
9489
9822
|
children: [
|
|
9490
|
-
showSessionSidebar ? /* @__PURE__ */
|
|
9823
|
+
showSessionSidebar ? /* @__PURE__ */ jsx33("aside", { "data-boring-agent-part": "pi-chat-session-sidebar", className: "min-h-0 w-64 shrink-0 border-r border-border/60", children: /* @__PURE__ */ jsx33(
|
|
9491
9824
|
SessionList,
|
|
9492
9825
|
{
|
|
9493
9826
|
sessions: sessionList,
|
|
@@ -9501,7 +9834,7 @@ function PiChatPanel({
|
|
|
9501
9834
|
loadingMore: sessions.loadingMore
|
|
9502
9835
|
}
|
|
9503
9836
|
) }) : null,
|
|
9504
|
-
/* @__PURE__ */
|
|
9837
|
+
/* @__PURE__ */ jsx33("div", { className: "flex min-h-0 min-w-0 flex-1 flex-col", children: /* @__PURE__ */ jsxs31(
|
|
9505
9838
|
"div",
|
|
9506
9839
|
{
|
|
9507
9840
|
className: cn(
|
|
@@ -9510,7 +9843,7 @@ function PiChatPanel({
|
|
|
9510
9843
|
chrome && "mx-3 my-3 rounded-xl bg-[color:var(--surface-chat)] shadow-[0_1px_0_oklch(0_0_0/0.02),0_1px_2px_-1px_oklch(0_0_0/0.04),inset_0_0_0_1px_oklch(from_var(--border)_l_c_h/0.6)]"
|
|
9511
9844
|
),
|
|
9512
9845
|
children: [
|
|
9513
|
-
/* @__PURE__ */
|
|
9846
|
+
/* @__PURE__ */ jsx33(
|
|
9514
9847
|
PiConversationSurface,
|
|
9515
9848
|
{
|
|
9516
9849
|
chrome,
|
|
@@ -9532,7 +9865,7 @@ function PiChatPanel({
|
|
|
9532
9865
|
windowResetKey: activeSessionId
|
|
9533
9866
|
}
|
|
9534
9867
|
),
|
|
9535
|
-
/* @__PURE__ */
|
|
9868
|
+
/* @__PURE__ */ jsx33(
|
|
9536
9869
|
PiChatComposerSurface,
|
|
9537
9870
|
{
|
|
9538
9871
|
chrome,
|
|
@@ -9554,6 +9887,8 @@ function PiChatPanel({
|
|
|
9554
9887
|
pluginUpdateState,
|
|
9555
9888
|
onDismissPluginUpdate: dismissPluginUpdate,
|
|
9556
9889
|
onRunPluginUpdate: runPluginUpdate,
|
|
9890
|
+
commandNotifyState,
|
|
9891
|
+
onDismissCommandNotify: dismissCommandNotify,
|
|
9557
9892
|
attachmentNotice,
|
|
9558
9893
|
onAttachmentNotice: setAttachmentNotice,
|
|
9559
9894
|
mentionState,
|
|
@@ -9592,7 +9927,7 @@ function PiChatPanel({
|
|
|
9592
9927
|
]
|
|
9593
9928
|
}
|
|
9594
9929
|
) }),
|
|
9595
|
-
debug ? /* @__PURE__ */
|
|
9930
|
+
debug ? /* @__PURE__ */ jsx33(Suspense, { fallback: null, children: /* @__PURE__ */ jsx33("div", { "aria-label": "Pi chat debug metadata", className: "contents", role: "region", children: /* @__PURE__ */ jsx33(
|
|
9596
9931
|
DebugDrawer2,
|
|
9597
9932
|
{
|
|
9598
9933
|
apiBaseUrl,
|