@unikode/cli 1.0.17 → 1.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +393 -105
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -29,6 +29,40 @@ import { createContext, useContext, useState, useCallback } from "react";
|
|
|
29
29
|
|
|
30
30
|
// src/theme.ts
|
|
31
31
|
var THEMES = [
|
|
32
|
+
{
|
|
33
|
+
name: "Mist",
|
|
34
|
+
colors: {
|
|
35
|
+
primary: "#3B82F6",
|
|
36
|
+
planMode: "#F59E0B",
|
|
37
|
+
selection: "#008ca5ff",
|
|
38
|
+
thinking: "#f59f0be5",
|
|
39
|
+
success: "#22C55E",
|
|
40
|
+
error: "#EF4444",
|
|
41
|
+
info: "#8B5CF6",
|
|
42
|
+
background: "#9db2c4b4",
|
|
43
|
+
surface: "#868c90ff",
|
|
44
|
+
dialogSurface: "#75818a29",
|
|
45
|
+
thinkingBorder: "#D97706",
|
|
46
|
+
dimSeparator: "#94A3B8"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: "Neon Horizon",
|
|
51
|
+
colors: {
|
|
52
|
+
primary: "#00F0FF",
|
|
53
|
+
planMode: "#FF007F",
|
|
54
|
+
selection: "#393153",
|
|
55
|
+
thinking: "#FFB800",
|
|
56
|
+
success: "#00FF66",
|
|
57
|
+
error: "#FF3333",
|
|
58
|
+
info: "#9D4EDD",
|
|
59
|
+
background: "#0D0E15",
|
|
60
|
+
surface: "#1A1C28",
|
|
61
|
+
dialogSurface: "#131520",
|
|
62
|
+
thinkingBorder: "#5A3E85",
|
|
63
|
+
dimSeparator: "#2A2D44"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
32
66
|
{
|
|
33
67
|
name: "Nightfox",
|
|
34
68
|
colors: {
|
|
@@ -746,6 +780,8 @@ function KeyboardLayerProvider({ children }) {
|
|
|
746
780
|
}
|
|
747
781
|
}, []);
|
|
748
782
|
useKeyboard((key) => {
|
|
783
|
+
if (key.name === "f5")
|
|
784
|
+
return;
|
|
749
785
|
if (!key.ctrl || key.name !== "c")
|
|
750
786
|
return;
|
|
751
787
|
const currentStack = stackRef.current;
|
|
@@ -896,7 +932,8 @@ var SUPPORTED_CHAT_MODELS = [
|
|
|
896
932
|
pricing: {
|
|
897
933
|
inputUsdPerMillionTokens: 3,
|
|
898
934
|
outputUsdPerMillionTokens: 15
|
|
899
|
-
}
|
|
935
|
+
},
|
|
936
|
+
tools: true
|
|
900
937
|
},
|
|
901
938
|
{
|
|
902
939
|
id: "claude-haiku-4-5",
|
|
@@ -904,7 +941,8 @@ var SUPPORTED_CHAT_MODELS = [
|
|
|
904
941
|
pricing: {
|
|
905
942
|
inputUsdPerMillionTokens: 1,
|
|
906
943
|
outputUsdPerMillionTokens: 5
|
|
907
|
-
}
|
|
944
|
+
},
|
|
945
|
+
tools: true
|
|
908
946
|
},
|
|
909
947
|
{
|
|
910
948
|
id: "claude-opus-4-6",
|
|
@@ -912,7 +950,8 @@ var SUPPORTED_CHAT_MODELS = [
|
|
|
912
950
|
pricing: {
|
|
913
951
|
inputUsdPerMillionTokens: 5,
|
|
914
952
|
outputUsdPerMillionTokens: 25
|
|
915
|
-
}
|
|
953
|
+
},
|
|
954
|
+
tools: true
|
|
916
955
|
},
|
|
917
956
|
{
|
|
918
957
|
id: "gpt-5.4",
|
|
@@ -920,7 +959,8 @@ var SUPPORTED_CHAT_MODELS = [
|
|
|
920
959
|
pricing: {
|
|
921
960
|
inputUsdPerMillionTokens: 2.5,
|
|
922
961
|
outputUsdPerMillionTokens: 15
|
|
923
|
-
}
|
|
962
|
+
},
|
|
963
|
+
tools: true
|
|
924
964
|
},
|
|
925
965
|
{
|
|
926
966
|
id: "gpt-5.4-mini",
|
|
@@ -928,7 +968,8 @@ var SUPPORTED_CHAT_MODELS = [
|
|
|
928
968
|
pricing: {
|
|
929
969
|
inputUsdPerMillionTokens: 0.75,
|
|
930
970
|
outputUsdPerMillionTokens: 4.5
|
|
931
|
-
}
|
|
971
|
+
},
|
|
972
|
+
tools: true
|
|
932
973
|
},
|
|
933
974
|
{
|
|
934
975
|
id: "gpt-5.4-nano",
|
|
@@ -936,7 +977,8 @@ var SUPPORTED_CHAT_MODELS = [
|
|
|
936
977
|
pricing: {
|
|
937
978
|
inputUsdPerMillionTokens: 0.2,
|
|
938
979
|
outputUsdPerMillionTokens: 1.25
|
|
939
|
-
}
|
|
980
|
+
},
|
|
981
|
+
tools: true
|
|
940
982
|
},
|
|
941
983
|
{
|
|
942
984
|
id: "gemini-2.5-flash",
|
|
@@ -944,7 +986,8 @@ var SUPPORTED_CHAT_MODELS = [
|
|
|
944
986
|
pricing: {
|
|
945
987
|
inputUsdPerMillionTokens: 0.3,
|
|
946
988
|
outputUsdPerMillionTokens: 1
|
|
947
|
-
}
|
|
989
|
+
},
|
|
990
|
+
tools: true
|
|
948
991
|
},
|
|
949
992
|
{
|
|
950
993
|
id: "gemini-3.1-flash-lite",
|
|
@@ -952,7 +995,8 @@ var SUPPORTED_CHAT_MODELS = [
|
|
|
952
995
|
pricing: {
|
|
953
996
|
inputUsdPerMillionTokens: 100.25,
|
|
954
997
|
outputUsdPerMillionTokens: 110.5
|
|
955
|
-
}
|
|
998
|
+
},
|
|
999
|
+
tools: true
|
|
956
1000
|
},
|
|
957
1001
|
{
|
|
958
1002
|
id: "ai/smollm2",
|
|
@@ -960,7 +1004,26 @@ var SUPPORTED_CHAT_MODELS = [
|
|
|
960
1004
|
pricing: {
|
|
961
1005
|
inputUsdPerMillionTokens: 2,
|
|
962
1006
|
outputUsdPerMillionTokens: 2
|
|
963
|
-
}
|
|
1007
|
+
},
|
|
1008
|
+
tools: true
|
|
1009
|
+
},
|
|
1010
|
+
{
|
|
1011
|
+
id: "gpt-oss:20b",
|
|
1012
|
+
provider: "local-ollama",
|
|
1013
|
+
pricing: {
|
|
1014
|
+
inputUsdPerMillionTokens: 30,
|
|
1015
|
+
outputUsdPerMillionTokens: 30
|
|
1016
|
+
},
|
|
1017
|
+
tools: true
|
|
1018
|
+
},
|
|
1019
|
+
{
|
|
1020
|
+
id: "llama3.1:8b-instruct-fp16",
|
|
1021
|
+
provider: "local-ollama",
|
|
1022
|
+
pricing: {
|
|
1023
|
+
inputUsdPerMillionTokens: 3,
|
|
1024
|
+
outputUsdPerMillionTokens: 3
|
|
1025
|
+
},
|
|
1026
|
+
tools: true
|
|
964
1027
|
},
|
|
965
1028
|
{
|
|
966
1029
|
id: "gpt-oss:20b-cloud",
|
|
@@ -968,7 +1031,8 @@ var SUPPORTED_CHAT_MODELS = [
|
|
|
968
1031
|
pricing: {
|
|
969
1032
|
inputUsdPerMillionTokens: 30,
|
|
970
1033
|
outputUsdPerMillionTokens: 30
|
|
971
|
-
}
|
|
1034
|
+
},
|
|
1035
|
+
tools: true
|
|
972
1036
|
},
|
|
973
1037
|
{
|
|
974
1038
|
id: "qwen3:4b",
|
|
@@ -976,7 +1040,8 @@ var SUPPORTED_CHAT_MODELS = [
|
|
|
976
1040
|
pricing: {
|
|
977
1041
|
inputUsdPerMillionTokens: 30,
|
|
978
1042
|
outputUsdPerMillionTokens: 30
|
|
979
|
-
}
|
|
1043
|
+
},
|
|
1044
|
+
tools: true
|
|
980
1045
|
},
|
|
981
1046
|
{
|
|
982
1047
|
id: "gpt-oss:120b-cloud",
|
|
@@ -984,12 +1049,17 @@ var SUPPORTED_CHAT_MODELS = [
|
|
|
984
1049
|
pricing: {
|
|
985
1050
|
inputUsdPerMillionTokens: 30,
|
|
986
1051
|
outputUsdPerMillionTokens: 30
|
|
987
|
-
}
|
|
1052
|
+
},
|
|
1053
|
+
tools: true
|
|
988
1054
|
}
|
|
989
1055
|
];
|
|
990
1056
|
function findSupportedChatModel(modelId) {
|
|
991
1057
|
return SUPPORTED_CHAT_MODELS.find((model) => model.id === modelId);
|
|
992
1058
|
}
|
|
1059
|
+
function modelSupportsTools(modelId) {
|
|
1060
|
+
const model = findSupportedChatModel(modelId);
|
|
1061
|
+
return model?.tools !== false;
|
|
1062
|
+
}
|
|
993
1063
|
var DEFAULT_CHAT_MODEL_ID = "gemini-2.5-flash";
|
|
994
1064
|
// ../shared/src/schemas.ts
|
|
995
1065
|
import { z } from "zod";
|
|
@@ -997,7 +1067,8 @@ import { tool } from "ai";
|
|
|
997
1067
|
var Mode = {
|
|
998
1068
|
BUILD: "BUILD",
|
|
999
1069
|
PLAN: "PLAN",
|
|
1000
|
-
DOCUMENTATION: "DOCUMENTATION"
|
|
1070
|
+
DOCUMENTATION: "DOCUMENTATION",
|
|
1071
|
+
ASK: "ASK"
|
|
1001
1072
|
};
|
|
1002
1073
|
var allModes = Object.values(Mode);
|
|
1003
1074
|
var modeSchema = z.enum(Object.values(Mode));
|
|
@@ -1158,6 +1229,13 @@ var buildToolContracts = {
|
|
|
1158
1229
|
inputSchema: toolInputSchemas.undoLastEditSchema
|
|
1159
1230
|
})
|
|
1160
1231
|
};
|
|
1232
|
+
var confirmationRequiredTools = new Set([
|
|
1233
|
+
"writeFile",
|
|
1234
|
+
"editFile",
|
|
1235
|
+
"terminalTool",
|
|
1236
|
+
"undoLastEditSchema",
|
|
1237
|
+
"writeMarkdownFile"
|
|
1238
|
+
]);
|
|
1161
1239
|
// src/providers/prompt-config/index.tsx
|
|
1162
1240
|
import { jsxDEV as jsxDEV6 } from "@opentui/react/jsx-dev-runtime";
|
|
1163
1241
|
var PromptConfigContext = createContext5(null);
|
|
@@ -1169,11 +1247,35 @@ function usePromptConfig() {
|
|
|
1169
1247
|
return value;
|
|
1170
1248
|
}
|
|
1171
1249
|
function PromptConfigProvider({ children }) {
|
|
1172
|
-
const
|
|
1173
|
-
const [model,
|
|
1250
|
+
const toast = useToast();
|
|
1251
|
+
const [model, setModelProp] = useState5(DEFAULT_CHAT_MODEL_ID);
|
|
1252
|
+
const [mode, setModeState] = useState5(() => modelSupportsTools(DEFAULT_CHAT_MODEL_ID) ? Mode.BUILD : Mode.ASK);
|
|
1253
|
+
const setMode = useCallback5((newMode) => {
|
|
1254
|
+
setModeState((prevMode) => {
|
|
1255
|
+
const resolvedMode = typeof newMode === "function" ? newMode(prevMode) : newMode;
|
|
1256
|
+
if (!modelSupportsTools(model)) {
|
|
1257
|
+
toast.show({
|
|
1258
|
+
variant: "error",
|
|
1259
|
+
message: 'this model doesnt support tools, and can only be used in the "ASK" mode !!'
|
|
1260
|
+
});
|
|
1261
|
+
return Mode.ASK;
|
|
1262
|
+
}
|
|
1263
|
+
return resolvedMode;
|
|
1264
|
+
});
|
|
1265
|
+
}, [model, toast]);
|
|
1266
|
+
const setModel = useCallback5((newModel) => {
|
|
1267
|
+
setModelProp(newModel);
|
|
1268
|
+
if (!modelSupportsTools(newModel)) {
|
|
1269
|
+
toast.show({
|
|
1270
|
+
variant: "error",
|
|
1271
|
+
message: 'this model doesnt support tools, and can only be used in the "ASK" mode !!'
|
|
1272
|
+
});
|
|
1273
|
+
setModeState(Mode.ASK);
|
|
1274
|
+
}
|
|
1275
|
+
}, [toast]);
|
|
1174
1276
|
const toggleMode = useCallback5(() => {
|
|
1175
1277
|
setMode((m) => m === Mode.BUILD ? Mode.PLAN : Mode.BUILD);
|
|
1176
|
-
}, []);
|
|
1278
|
+
}, [setMode]);
|
|
1177
1279
|
return /* @__PURE__ */ jsxDEV6(PromptConfigContext.Provider, {
|
|
1178
1280
|
value: {
|
|
1179
1281
|
mode,
|
|
@@ -2092,6 +2194,17 @@ function useCommandMenu() {
|
|
|
2092
2194
|
|
|
2093
2195
|
// src/components/input-bar.tsx
|
|
2094
2196
|
import { useNavigate as useNavigate2 } from "react-router";
|
|
2197
|
+
|
|
2198
|
+
// src/lib/textarea-ref.ts
|
|
2199
|
+
var textarea = null;
|
|
2200
|
+
function getInputTextarea() {
|
|
2201
|
+
return textarea;
|
|
2202
|
+
}
|
|
2203
|
+
function setInputTextarea(t) {
|
|
2204
|
+
textarea = t;
|
|
2205
|
+
}
|
|
2206
|
+
|
|
2207
|
+
// src/components/input-bar.tsx
|
|
2095
2208
|
import { jsxDEV as jsxDEV17 } from "@opentui/react/jsx-dev-runtime";
|
|
2096
2209
|
var MAX_VISIBLE_MENTIONS = 8;
|
|
2097
2210
|
var CURRENT_DIRECTORY = process.cwd();
|
|
@@ -2324,48 +2437,48 @@ function InputBar({ onSubmit, disabled = false }) {
|
|
|
2324
2437
|
}
|
|
2325
2438
|
}, [closeMentionMenu, push]);
|
|
2326
2439
|
const handleTextareaContentChange = useCallback11(() => {
|
|
2327
|
-
const
|
|
2328
|
-
if (!
|
|
2440
|
+
const textarea2 = textareaRef.current;
|
|
2441
|
+
if (!textarea2)
|
|
2329
2442
|
return;
|
|
2330
|
-
const text =
|
|
2331
|
-
handleContentChange(
|
|
2332
|
-
syncMentionMenu(text,
|
|
2443
|
+
const text = textarea2.plainText;
|
|
2444
|
+
handleContentChange(textarea2.plainText);
|
|
2445
|
+
syncMentionMenu(text, textarea2.cursorOffset);
|
|
2333
2446
|
}, [handleContentChange, syncMentionMenu]);
|
|
2334
2447
|
const handleSubmit = useCallback11(() => {
|
|
2335
2448
|
if (disabled)
|
|
2336
2449
|
return;
|
|
2337
|
-
const
|
|
2338
|
-
if (!
|
|
2450
|
+
const textarea2 = textareaRef.current;
|
|
2451
|
+
if (!textarea2)
|
|
2339
2452
|
return;
|
|
2340
|
-
const text =
|
|
2453
|
+
const text = textarea2.plainText.trim();
|
|
2341
2454
|
if (text.length === 0)
|
|
2342
2455
|
return;
|
|
2343
2456
|
onSubmit(text);
|
|
2344
|
-
|
|
2457
|
+
textarea2.setText("");
|
|
2345
2458
|
}, [disabled, onSubmit]);
|
|
2346
2459
|
const handleMentionExecute = useCallback11((index) => {
|
|
2347
|
-
const
|
|
2460
|
+
const textarea2 = textareaRef.current;
|
|
2348
2461
|
const mention = activeMentionRef.current;
|
|
2349
2462
|
const candidate = mentionCandidates[index];
|
|
2350
|
-
if (!
|
|
2463
|
+
if (!textarea2 || !mention || !candidate)
|
|
2351
2464
|
return;
|
|
2352
2465
|
const insertion = candidate.kind === "directory" ? candidate.path : `${candidate.path} `;
|
|
2353
|
-
const nextText = `${
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
syncMentionMenu(nextText,
|
|
2466
|
+
const nextText = `${textarea2.plainText.slice(0, mention.start)}@${insertion}${textarea2.plainText.slice(mention.end)}`;
|
|
2467
|
+
textarea2.replaceText(nextText);
|
|
2468
|
+
textarea2.cursorOffset = mention.start + insertion.length + 1;
|
|
2469
|
+
syncMentionMenu(nextText, textarea2.cursorOffset);
|
|
2357
2470
|
}, [mentionCandidates, syncMentionMenu]);
|
|
2358
2471
|
const handleTextareaCursorChange = useCallback11(() => {
|
|
2359
|
-
const
|
|
2360
|
-
if (!
|
|
2472
|
+
const textarea2 = textareaRef.current;
|
|
2473
|
+
if (!textarea2)
|
|
2361
2474
|
return;
|
|
2362
|
-
syncMentionMenu(
|
|
2475
|
+
syncMentionMenu(textarea2.plainText, textarea2.cursorOffset);
|
|
2363
2476
|
}, [syncMentionMenu]);
|
|
2364
2477
|
const handleCommand = useCallback11((command) => {
|
|
2365
|
-
const
|
|
2366
|
-
if (!
|
|
2478
|
+
const textarea2 = textareaRef.current;
|
|
2479
|
+
if (!textarea2 || !command)
|
|
2367
2480
|
return;
|
|
2368
|
-
|
|
2481
|
+
textarea2.setText("");
|
|
2369
2482
|
if (command.action) {
|
|
2370
2483
|
command.action({
|
|
2371
2484
|
exit: () => renderer.destroy(),
|
|
@@ -2377,7 +2490,7 @@ function InputBar({ onSubmit, disabled = false }) {
|
|
|
2377
2490
|
setModel
|
|
2378
2491
|
});
|
|
2379
2492
|
} else {
|
|
2380
|
-
|
|
2493
|
+
textarea2.insertText(command.value + " ");
|
|
2381
2494
|
}
|
|
2382
2495
|
}, [renderer, toast, dialog, navigate, Mode, setMode, setModel]);
|
|
2383
2496
|
const handleCommandExecute = useCallback11((index) => {
|
|
@@ -2408,10 +2521,10 @@ function InputBar({ onSubmit, disabled = false }) {
|
|
|
2408
2521
|
};
|
|
2409
2522
|
}, [activeMention]);
|
|
2410
2523
|
useEffect3(() => {
|
|
2411
|
-
const
|
|
2412
|
-
if (!
|
|
2524
|
+
const textarea2 = textareaRef.current;
|
|
2525
|
+
if (!textarea2)
|
|
2413
2526
|
return;
|
|
2414
|
-
|
|
2527
|
+
textarea2.onSubmit = () => {
|
|
2415
2528
|
onSubmitRef.current();
|
|
2416
2529
|
};
|
|
2417
2530
|
}, []);
|
|
@@ -2444,13 +2557,24 @@ function InputBar({ onSubmit, disabled = false }) {
|
|
|
2444
2557
|
toggleMode();
|
|
2445
2558
|
}
|
|
2446
2559
|
});
|
|
2560
|
+
useKeyboard5((key) => {
|
|
2561
|
+
if (key.name === "f5") {
|
|
2562
|
+
key.preventDefault();
|
|
2563
|
+
const textarea2 = textareaRef.current;
|
|
2564
|
+
if (textarea2 && textarea2.hasSelection()) {
|
|
2565
|
+
const selectedText = textarea2.getSelectedText();
|
|
2566
|
+
renderer.copyToClipboardOSC52(selectedText);
|
|
2567
|
+
toast.show({ variant: "success", message: "Copied to clipboard" });
|
|
2568
|
+
}
|
|
2569
|
+
}
|
|
2570
|
+
});
|
|
2447
2571
|
useEffect3(() => {
|
|
2448
2572
|
setResponder("base", () => {
|
|
2449
2573
|
if (disabled)
|
|
2450
2574
|
return false;
|
|
2451
|
-
const
|
|
2452
|
-
if (
|
|
2453
|
-
|
|
2575
|
+
const textarea2 = textareaRef.current;
|
|
2576
|
+
if (textarea2 && textarea2.plainText.length > 0) {
|
|
2577
|
+
textarea2.setText("");
|
|
2454
2578
|
return true;
|
|
2455
2579
|
}
|
|
2456
2580
|
return false;
|
|
@@ -2494,6 +2618,9 @@ function InputBar({ onSubmit, disabled = false }) {
|
|
|
2494
2618
|
});
|
|
2495
2619
|
}
|
|
2496
2620
|
});
|
|
2621
|
+
useEffect3(() => {
|
|
2622
|
+
setInputTextarea(textareaRef.current);
|
|
2623
|
+
});
|
|
2497
2624
|
return /* @__PURE__ */ jsxDEV17("box", {
|
|
2498
2625
|
width: "100%",
|
|
2499
2626
|
alignItems: "stretch",
|
|
@@ -3061,7 +3188,7 @@ function UserMessage({ message, mode }) {
|
|
|
3061
3188
|
// src/components/messages/bot-message.tsx
|
|
3062
3189
|
import { useMemo as useMemo3 } from "react";
|
|
3063
3190
|
import prettyMs from "pretty-ms";
|
|
3064
|
-
import { SyntaxStyle, TextAttributes as
|
|
3191
|
+
import { SyntaxStyle, TextAttributes as TextAttributes11, getTreeSitterClient, BoxRenderable } from "@opentui/core";
|
|
3065
3192
|
|
|
3066
3193
|
// src/components/messages/question-message.tsx
|
|
3067
3194
|
import { useCallback as useCallback13, useRef as useRef7, useState as useState10 } from "react";
|
|
@@ -3150,8 +3277,71 @@ function QuestionMessage({ prompt, onSubmit }) {
|
|
|
3150
3277
|
}, undefined, false, undefined, this);
|
|
3151
3278
|
}
|
|
3152
3279
|
|
|
3280
|
+
// src/components/messages/confirmation-message.tsx
|
|
3281
|
+
import { TextAttributes as TextAttributes10 } from "@opentui/core";
|
|
3282
|
+
import { jsxDEV as jsxDEV24 } from "@opentui/react/jsx-dev-runtime";
|
|
3283
|
+
function ConfirmationMessage({ confirmation, onAllow, onDisallow }) {
|
|
3284
|
+
const { colors } = useTheme();
|
|
3285
|
+
return /* @__PURE__ */ jsxDEV24("box", {
|
|
3286
|
+
width: "100%",
|
|
3287
|
+
alignItems: "center",
|
|
3288
|
+
children: /* @__PURE__ */ jsxDEV24("box", {
|
|
3289
|
+
border: ["left"],
|
|
3290
|
+
borderColor: colors.error,
|
|
3291
|
+
width: "100%",
|
|
3292
|
+
children: /* @__PURE__ */ jsxDEV24("box", {
|
|
3293
|
+
flexDirection: "column",
|
|
3294
|
+
gap: 1,
|
|
3295
|
+
paddingX: 2,
|
|
3296
|
+
paddingY: 1,
|
|
3297
|
+
backgroundColor: colors.surface,
|
|
3298
|
+
width: "100%",
|
|
3299
|
+
children: [
|
|
3300
|
+
/* @__PURE__ */ jsxDEV24("text", {
|
|
3301
|
+
attributes: TextAttributes10.BOLD,
|
|
3302
|
+
fg: colors.error,
|
|
3303
|
+
children: "Confirmation required"
|
|
3304
|
+
}, undefined, false, undefined, this),
|
|
3305
|
+
/* @__PURE__ */ jsxDEV24("text", {
|
|
3306
|
+
children: confirmation.summary
|
|
3307
|
+
}, undefined, false, undefined, this),
|
|
3308
|
+
/* @__PURE__ */ jsxDEV24("box", {
|
|
3309
|
+
flexDirection: "row",
|
|
3310
|
+
gap: 2,
|
|
3311
|
+
paddingTop: 1,
|
|
3312
|
+
children: [
|
|
3313
|
+
/* @__PURE__ */ jsxDEV24("box", {
|
|
3314
|
+
border: true,
|
|
3315
|
+
paddingX: 2,
|
|
3316
|
+
paddingY: 0,
|
|
3317
|
+
onMouseDown: () => onAllow(confirmation.id),
|
|
3318
|
+
children: /* @__PURE__ */ jsxDEV24("text", {
|
|
3319
|
+
fg: colors.success,
|
|
3320
|
+
attributes: TextAttributes10.BOLD,
|
|
3321
|
+
children: "Allow"
|
|
3322
|
+
}, undefined, false, undefined, this)
|
|
3323
|
+
}, undefined, false, undefined, this),
|
|
3324
|
+
/* @__PURE__ */ jsxDEV24("box", {
|
|
3325
|
+
border: true,
|
|
3326
|
+
paddingX: 2,
|
|
3327
|
+
paddingY: 0,
|
|
3328
|
+
onMouseDown: () => onDisallow(confirmation.id),
|
|
3329
|
+
children: /* @__PURE__ */ jsxDEV24("text", {
|
|
3330
|
+
fg: colors.error,
|
|
3331
|
+
attributes: TextAttributes10.BOLD,
|
|
3332
|
+
children: "Disallow"
|
|
3333
|
+
}, undefined, false, undefined, this)
|
|
3334
|
+
}, undefined, false, undefined, this)
|
|
3335
|
+
]
|
|
3336
|
+
}, undefined, true, undefined, this)
|
|
3337
|
+
]
|
|
3338
|
+
}, undefined, true, undefined, this)
|
|
3339
|
+
}, undefined, false, undefined, this)
|
|
3340
|
+
}, undefined, false, undefined, this);
|
|
3341
|
+
}
|
|
3342
|
+
|
|
3153
3343
|
// src/components/messages/bot-message.tsx
|
|
3154
|
-
import { jsxDEV as
|
|
3344
|
+
import { jsxDEV as jsxDEV25, Fragment as Fragment3 } from "@opentui/react/jsx-dev-runtime";
|
|
3155
3345
|
function formatToolName(name) {
|
|
3156
3346
|
return name.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/^./, (c) => c.toUpperCase());
|
|
3157
3347
|
}
|
|
@@ -3186,7 +3376,10 @@ function BotMessage({
|
|
|
3186
3376
|
durationMs,
|
|
3187
3377
|
streaming = false,
|
|
3188
3378
|
questionPrompts = [],
|
|
3189
|
-
onSubmitQuestionAnswer
|
|
3379
|
+
onSubmitQuestionAnswer,
|
|
3380
|
+
pendingConfirmations = [],
|
|
3381
|
+
onAllowConfirmation,
|
|
3382
|
+
onDisallowConfirmation
|
|
3190
3383
|
}) {
|
|
3191
3384
|
const { colors } = useTheme();
|
|
3192
3385
|
const syntaxStyle = useMemo3(() => SyntaxStyle.fromStyles({
|
|
@@ -3241,24 +3434,24 @@ function BotMessage({
|
|
|
3241
3434
|
return;
|
|
3242
3435
|
};
|
|
3243
3436
|
}, [colors]);
|
|
3244
|
-
return /* @__PURE__ */
|
|
3437
|
+
return /* @__PURE__ */ jsxDEV25("box", {
|
|
3245
3438
|
width: "100%",
|
|
3246
3439
|
alignItems: "center",
|
|
3247
3440
|
children: [
|
|
3248
|
-
groupConsecutiveParts(parts).map((group, i) => /* @__PURE__ */
|
|
3441
|
+
groupConsecutiveParts(parts).map((group, i) => /* @__PURE__ */ jsxDEV25("box", {
|
|
3249
3442
|
width: "100%",
|
|
3250
3443
|
paddingTop: i === 0 ? 0 : 1,
|
|
3251
3444
|
children: group.parts.map((part, j) => {
|
|
3252
3445
|
if (part.type === "reasoning") {
|
|
3253
|
-
return /* @__PURE__ */
|
|
3446
|
+
return /* @__PURE__ */ jsxDEV25("box", {
|
|
3254
3447
|
border: ["left"],
|
|
3255
3448
|
borderColor: colors.thinkingBorder,
|
|
3256
3449
|
width: "100%",
|
|
3257
3450
|
paddingX: 2,
|
|
3258
|
-
children: /* @__PURE__ */
|
|
3259
|
-
attributes:
|
|
3451
|
+
children: /* @__PURE__ */ jsxDEV25("text", {
|
|
3452
|
+
attributes: TextAttributes11.DIM,
|
|
3260
3453
|
children: [
|
|
3261
|
-
/* @__PURE__ */
|
|
3454
|
+
/* @__PURE__ */ jsxDEV25("em", {
|
|
3262
3455
|
fg: colors.thinking,
|
|
3263
3456
|
children: "Thinking:"
|
|
3264
3457
|
}, undefined, false, undefined, this),
|
|
@@ -3272,23 +3465,34 @@ function BotMessage({
|
|
|
3272
3465
|
const toolName = part.type === "dynamic-tool" ? part.toolName : part.type.slice("tool-".length);
|
|
3273
3466
|
const questionPrompt = toolName === "askQuestionTool" ? questionPrompts.find((prompt) => prompt.toolCallId === part.toolCallId) : undefined;
|
|
3274
3467
|
if (questionPrompt) {
|
|
3275
|
-
return /* @__PURE__ */
|
|
3468
|
+
return /* @__PURE__ */ jsxDEV25("box", {
|
|
3276
3469
|
width: "100%",
|
|
3277
|
-
children: /* @__PURE__ */
|
|
3470
|
+
children: /* @__PURE__ */ jsxDEV25(QuestionMessage, {
|
|
3278
3471
|
prompt: questionPrompt,
|
|
3279
3472
|
onSubmit: onSubmitQuestionAnswer ?? (() => {})
|
|
3280
3473
|
}, undefined, false, undefined, this)
|
|
3281
3474
|
}, part.toolCallId, false, undefined, this);
|
|
3282
3475
|
}
|
|
3283
|
-
|
|
3476
|
+
const confirmationPrompt = pendingConfirmations?.find((c) => c.toolCallId === part.toolCallId);
|
|
3477
|
+
if (confirmationPrompt) {
|
|
3478
|
+
return /* @__PURE__ */ jsxDEV25("box", {
|
|
3479
|
+
width: "100%",
|
|
3480
|
+
children: /* @__PURE__ */ jsxDEV25(ConfirmationMessage, {
|
|
3481
|
+
confirmation: confirmationPrompt,
|
|
3482
|
+
onAllow: onAllowConfirmation ?? (() => {}),
|
|
3483
|
+
onDisallow: onDisallowConfirmation ?? (() => {})
|
|
3484
|
+
}, undefined, false, undefined, this)
|
|
3485
|
+
}, `confirm-${part.toolCallId}`, false, undefined, this);
|
|
3486
|
+
}
|
|
3487
|
+
return /* @__PURE__ */ jsxDEV25("box", {
|
|
3284
3488
|
border: ["left"],
|
|
3285
3489
|
borderColor: colors.thinkingBorder,
|
|
3286
3490
|
width: "100%",
|
|
3287
3491
|
paddingX: 2,
|
|
3288
|
-
children: /* @__PURE__ */
|
|
3289
|
-
attributes:
|
|
3492
|
+
children: /* @__PURE__ */ jsxDEV25("text", {
|
|
3493
|
+
attributes: TextAttributes11.DIM,
|
|
3290
3494
|
children: [
|
|
3291
|
-
/* @__PURE__ */
|
|
3495
|
+
/* @__PURE__ */ jsxDEV25("em", {
|
|
3292
3496
|
fg: colors.info,
|
|
3293
3497
|
children: [
|
|
3294
3498
|
formatToolName(toolName),
|
|
@@ -3307,10 +3511,10 @@ function BotMessage({
|
|
|
3307
3511
|
if (j > 0)
|
|
3308
3512
|
return null;
|
|
3309
3513
|
const fullText = group.parts.filter((p) => p.type === "text").map((p) => p.text).join("");
|
|
3310
|
-
return /* @__PURE__ */
|
|
3514
|
+
return /* @__PURE__ */ jsxDEV25("box", {
|
|
3311
3515
|
paddingX: 3,
|
|
3312
3516
|
width: "100%",
|
|
3313
|
-
children: /* @__PURE__ */
|
|
3517
|
+
children: /* @__PURE__ */ jsxDEV25("markdown", {
|
|
3314
3518
|
content: fullText,
|
|
3315
3519
|
syntaxStyle,
|
|
3316
3520
|
streaming,
|
|
@@ -3322,44 +3526,44 @@ function BotMessage({
|
|
|
3322
3526
|
return null;
|
|
3323
3527
|
})
|
|
3324
3528
|
}, group.key, false, undefined, this)),
|
|
3325
|
-
/* @__PURE__ */
|
|
3529
|
+
/* @__PURE__ */ jsxDEV25("box", {
|
|
3326
3530
|
paddingX: 3,
|
|
3327
3531
|
paddingY: 1,
|
|
3328
3532
|
gap: 1,
|
|
3329
3533
|
width: "100%",
|
|
3330
|
-
children: /* @__PURE__ */
|
|
3534
|
+
children: /* @__PURE__ */ jsxDEV25("box", {
|
|
3331
3535
|
flexDirection: "row",
|
|
3332
3536
|
gap: 2,
|
|
3333
3537
|
children: [
|
|
3334
|
-
/* @__PURE__ */
|
|
3538
|
+
/* @__PURE__ */ jsxDEV25("text", {
|
|
3335
3539
|
fg: mode === Mode.PLAN ? colors.planMode : colors.primary,
|
|
3336
3540
|
children: "\u25C9"
|
|
3337
3541
|
}, undefined, false, undefined, this),
|
|
3338
|
-
/* @__PURE__ */
|
|
3542
|
+
/* @__PURE__ */ jsxDEV25("box", {
|
|
3339
3543
|
flexDirection: "row",
|
|
3340
3544
|
gap: 1,
|
|
3341
3545
|
children: [
|
|
3342
|
-
/* @__PURE__ */
|
|
3546
|
+
/* @__PURE__ */ jsxDEV25("text", {
|
|
3343
3547
|
children: mode
|
|
3344
3548
|
}, undefined, false, undefined, this),
|
|
3345
|
-
/* @__PURE__ */
|
|
3346
|
-
attributes:
|
|
3549
|
+
/* @__PURE__ */ jsxDEV25("text", {
|
|
3550
|
+
attributes: TextAttributes11.DIM,
|
|
3347
3551
|
fg: colors.dimSeparator,
|
|
3348
3552
|
children: "\u203A"
|
|
3349
3553
|
}, undefined, false, undefined, this),
|
|
3350
|
-
/* @__PURE__ */
|
|
3351
|
-
attributes:
|
|
3554
|
+
/* @__PURE__ */ jsxDEV25("text", {
|
|
3555
|
+
attributes: TextAttributes11.DIM,
|
|
3352
3556
|
children: model
|
|
3353
3557
|
}, undefined, false, undefined, this),
|
|
3354
|
-
durationMs != null ? /* @__PURE__ */
|
|
3558
|
+
durationMs != null ? /* @__PURE__ */ jsxDEV25(Fragment3, {
|
|
3355
3559
|
children: [
|
|
3356
|
-
/* @__PURE__ */
|
|
3357
|
-
attributes:
|
|
3560
|
+
/* @__PURE__ */ jsxDEV25("text", {
|
|
3561
|
+
attributes: TextAttributes11.DIM,
|
|
3358
3562
|
fg: colors.dimSeparator,
|
|
3359
3563
|
children: "\u203A"
|
|
3360
3564
|
}, undefined, false, undefined, this),
|
|
3361
|
-
/* @__PURE__ */
|
|
3362
|
-
attributes:
|
|
3565
|
+
/* @__PURE__ */ jsxDEV25("text", {
|
|
3566
|
+
attributes: TextAttributes11.DIM,
|
|
3363
3567
|
children: prettyMs(durationMs)
|
|
3364
3568
|
}, undefined, false, undefined, this)
|
|
3365
3569
|
]
|
|
@@ -3373,25 +3577,25 @@ function BotMessage({
|
|
|
3373
3577
|
}, undefined, true, undefined, this);
|
|
3374
3578
|
}
|
|
3375
3579
|
// src/components/messages/error-message.tsx
|
|
3376
|
-
import { TextAttributes as
|
|
3377
|
-
import { jsxDEV as
|
|
3580
|
+
import { TextAttributes as TextAttributes12 } from "@opentui/core";
|
|
3581
|
+
import { jsxDEV as jsxDEV26 } from "@opentui/react/jsx-dev-runtime";
|
|
3378
3582
|
function ErrorMessage({ message }) {
|
|
3379
3583
|
const { colors } = useTheme();
|
|
3380
|
-
return /* @__PURE__ */
|
|
3584
|
+
return /* @__PURE__ */ jsxDEV26("box", {
|
|
3381
3585
|
width: "100%",
|
|
3382
3586
|
alignItems: "center",
|
|
3383
|
-
children: /* @__PURE__ */
|
|
3587
|
+
children: /* @__PURE__ */ jsxDEV26("box", {
|
|
3384
3588
|
border: ["left"],
|
|
3385
3589
|
borderColor: colors.error,
|
|
3386
3590
|
width: "100%",
|
|
3387
|
-
children: /* @__PURE__ */
|
|
3591
|
+
children: /* @__PURE__ */ jsxDEV26("box", {
|
|
3388
3592
|
justifyContent: "center",
|
|
3389
3593
|
paddingX: 2,
|
|
3390
3594
|
paddingY: 1,
|
|
3391
3595
|
backgroundColor: colors.surface,
|
|
3392
3596
|
width: "100%",
|
|
3393
|
-
children: /* @__PURE__ */
|
|
3394
|
-
attributes:
|
|
3597
|
+
children: /* @__PURE__ */ jsxDEV26("text", {
|
|
3598
|
+
attributes: TextAttributes12.DIM,
|
|
3395
3599
|
children: message
|
|
3396
3600
|
}, undefined, false, undefined, this)
|
|
3397
3601
|
}, undefined, false, undefined, this)
|
|
@@ -3399,7 +3603,7 @@ function ErrorMessage({ message }) {
|
|
|
3399
3603
|
}, undefined, false, undefined, this);
|
|
3400
3604
|
}
|
|
3401
3605
|
// src/screens/new-session.tsx
|
|
3402
|
-
import { jsxDEV as
|
|
3606
|
+
import { jsxDEV as jsxDEV27 } from "@opentui/react/jsx-dev-runtime";
|
|
3403
3607
|
var newSessionStateSchema = z2.object({
|
|
3404
3608
|
message: z2.string(),
|
|
3405
3609
|
mode: modeSchema,
|
|
@@ -3455,11 +3659,11 @@ function NewSession() {
|
|
|
3455
3659
|
}, [state, navigate, toast]);
|
|
3456
3660
|
if (!state)
|
|
3457
3661
|
return null;
|
|
3458
|
-
return /* @__PURE__ */
|
|
3662
|
+
return /* @__PURE__ */ jsxDEV27(SessionShell, {
|
|
3459
3663
|
onSubmit: () => {},
|
|
3460
3664
|
inputDisabled: true,
|
|
3461
3665
|
loading: true,
|
|
3462
|
-
children: /* @__PURE__ */
|
|
3666
|
+
children: /* @__PURE__ */ jsxDEV27(UserMessage, {
|
|
3463
3667
|
message: state.message,
|
|
3464
3668
|
mode: state.mode
|
|
3465
3669
|
}, undefined, false, undefined, this)
|
|
@@ -3962,6 +4166,7 @@ ${outline.join(`
|
|
|
3962
4166
|
// src/hooks/use-chat.ts
|
|
3963
4167
|
function useChat(sessionId, initialMessages) {
|
|
3964
4168
|
const [questionPrompts, setQuestionPrompts] = useState11([]);
|
|
4169
|
+
const [pendingConfirmations, setPendingConfirmations] = useState11([]);
|
|
3965
4170
|
const transport = useMemo5(() => {
|
|
3966
4171
|
return new DefaultChatTransport({
|
|
3967
4172
|
api: apiClient.chat.$url().toString(),
|
|
@@ -4004,6 +4209,20 @@ function useChat(sessionId, initialMessages) {
|
|
|
4004
4209
|
}
|
|
4005
4210
|
});
|
|
4006
4211
|
}, [questionPrompts]);
|
|
4212
|
+
const formatToolSummary = (toolName, input) => {
|
|
4213
|
+
switch (toolName) {
|
|
4214
|
+
case "writeFile":
|
|
4215
|
+
return `Create/write file: ${input.path}`;
|
|
4216
|
+
case "editFile":
|
|
4217
|
+
return `Edit file: ${input.path}`;
|
|
4218
|
+
case "terminalTool":
|
|
4219
|
+
return `Run command: ${input.explanation || input.command}`;
|
|
4220
|
+
case "undoLastEditSchema":
|
|
4221
|
+
return `Undo edit: ${input.path}`;
|
|
4222
|
+
default:
|
|
4223
|
+
return `Execute ${toolName}`;
|
|
4224
|
+
}
|
|
4225
|
+
};
|
|
4007
4226
|
const chat = useAiChat({
|
|
4008
4227
|
id: sessionId,
|
|
4009
4228
|
messages: initialMessages,
|
|
@@ -4027,6 +4246,17 @@ function useChat(sessionId, initialMessages) {
|
|
|
4027
4246
|
return;
|
|
4028
4247
|
}
|
|
4029
4248
|
const mode = chat.messages.at(-1)?.metadata?.mode ?? "BUILD";
|
|
4249
|
+
if (confirmationRequiredTools.has(toolCall.toolName)) {
|
|
4250
|
+
const promptId = crypto.randomUUID();
|
|
4251
|
+
setPendingConfirmations((prev) => [...prev, {
|
|
4252
|
+
id: promptId,
|
|
4253
|
+
toolCallId: toolCall.toolCallId,
|
|
4254
|
+
toolName: toolCall.toolName,
|
|
4255
|
+
input: toolCall.input,
|
|
4256
|
+
summary: formatToolSummary(toolCall.toolName, toolCall.input)
|
|
4257
|
+
}]);
|
|
4258
|
+
return;
|
|
4259
|
+
}
|
|
4030
4260
|
executeLocalTool(toolCall.toolName, toolCall.input, mode).then((output) => chat.addToolOutput({
|
|
4031
4261
|
tool: toolCall.toolName,
|
|
4032
4262
|
toolCallId: toolCall.toolCallId,
|
|
@@ -4040,6 +4270,27 @@ function useChat(sessionId, initialMessages) {
|
|
|
4040
4270
|
},
|
|
4041
4271
|
sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls
|
|
4042
4272
|
});
|
|
4273
|
+
const allowConfirmation = useCallback14((confirmationId) => {
|
|
4274
|
+
const confirmation = pendingConfirmations.find((c) => c.id === confirmationId);
|
|
4275
|
+
if (!confirmation)
|
|
4276
|
+
return;
|
|
4277
|
+
setPendingConfirmations((prev) => prev.filter((c) => c.id !== confirmationId));
|
|
4278
|
+
const currentMode = chat.messages.at(-1)?.metadata?.mode ?? "BUILD";
|
|
4279
|
+
executeLocalTool(confirmation.toolName, confirmation.input, currentMode).then((output) => chat.addToolOutput({ tool: confirmation.toolName, toolCallId: confirmation.toolCallId, output })).catch((error) => chat.addToolOutput({ tool: confirmation.toolName, toolCallId: confirmation.toolCallId, state: "output-error", errorText: error instanceof Error ? error.message : String(error) }));
|
|
4280
|
+
}, [pendingConfirmations, chat]);
|
|
4281
|
+
const disallowConfirmation = useCallback14((confirmationId) => {
|
|
4282
|
+
const confirmation = pendingConfirmations.find((c) => c.id === confirmationId);
|
|
4283
|
+
if (!confirmation)
|
|
4284
|
+
return;
|
|
4285
|
+
setPendingConfirmations((prev) => prev.filter((c) => c.id !== confirmationId));
|
|
4286
|
+
chat.addToolOutput({
|
|
4287
|
+
tool: confirmation.toolName,
|
|
4288
|
+
toolCallId: confirmation.toolCallId,
|
|
4289
|
+
output: {
|
|
4290
|
+
SYSTEM_CONSTRAINT: "Action Aborted by User. Permission permanently denied for this specific command string. Do NOT retry this command or repeatedly ask user to allow the action. Search for an alternative tool, modify your approach, or explain the limitation to the user."
|
|
4291
|
+
}
|
|
4292
|
+
});
|
|
4293
|
+
}, [pendingConfirmations, chat]);
|
|
4043
4294
|
return {
|
|
4044
4295
|
messages: chat.messages,
|
|
4045
4296
|
status: chat.status,
|
|
@@ -4057,13 +4308,16 @@ function useChat(sessionId, initialMessages) {
|
|
|
4057
4308
|
});
|
|
4058
4309
|
},
|
|
4059
4310
|
abort: chat.stop,
|
|
4060
|
-
interrupt: chat.stop
|
|
4311
|
+
interrupt: chat.stop,
|
|
4312
|
+
pendingConfirmations,
|
|
4313
|
+
allowConfirmation,
|
|
4314
|
+
disallowConfirmation
|
|
4061
4315
|
};
|
|
4062
4316
|
}
|
|
4063
4317
|
|
|
4064
4318
|
// src/screens/session.tsx
|
|
4065
|
-
import { useKeyboard as useKeyboard6 } from "@opentui/react";
|
|
4066
|
-
import { jsxDEV as
|
|
4319
|
+
import { useKeyboard as useKeyboard6, useRenderer as useRenderer3 } from "@opentui/react";
|
|
4320
|
+
import { jsxDEV as jsxDEV28 } from "@opentui/react/jsx-dev-runtime";
|
|
4067
4321
|
var sessionLocationSchema = z3.object({
|
|
4068
4322
|
session: z3.custom((val) => val != null && typeof val === "object" && ("id" in val)),
|
|
4069
4323
|
initialPrompt: z3.object({
|
|
@@ -4076,23 +4330,29 @@ function ChatMessage({
|
|
|
4076
4330
|
msg,
|
|
4077
4331
|
questionPrompts,
|
|
4078
4332
|
onSubmitQuestionAnswer,
|
|
4333
|
+
pendingConfirmations,
|
|
4334
|
+
onAllowConfirmation,
|
|
4335
|
+
onDisallowConfirmation,
|
|
4079
4336
|
isStreaming = false
|
|
4080
4337
|
}) {
|
|
4081
4338
|
if (msg.role === "user") {
|
|
4082
4339
|
const text = msg.parts.filter((p) => p.type === "text").map((p) => p.text).join("");
|
|
4083
|
-
return /* @__PURE__ */
|
|
4340
|
+
return /* @__PURE__ */ jsxDEV28(UserMessage, {
|
|
4084
4341
|
message: text,
|
|
4085
4342
|
mode: msg.metadata?.mode ?? "BUILD"
|
|
4086
4343
|
}, undefined, false, undefined, this);
|
|
4087
4344
|
}
|
|
4088
|
-
return /* @__PURE__ */
|
|
4345
|
+
return /* @__PURE__ */ jsxDEV28(BotMessage, {
|
|
4089
4346
|
parts: msg.parts,
|
|
4090
4347
|
model: msg.metadata?.model ?? "unknown",
|
|
4091
4348
|
mode: msg.metadata?.mode ?? "BUILD",
|
|
4092
4349
|
durationMs: msg.metadata?.durationMs,
|
|
4093
4350
|
streaming: isStreaming,
|
|
4094
4351
|
questionPrompts,
|
|
4095
|
-
onSubmitQuestionAnswer
|
|
4352
|
+
onSubmitQuestionAnswer,
|
|
4353
|
+
pendingConfirmations,
|
|
4354
|
+
onAllowConfirmation,
|
|
4355
|
+
onDisallowConfirmation
|
|
4096
4356
|
}, undefined, false, undefined, this);
|
|
4097
4357
|
}
|
|
4098
4358
|
function SessionChat({ session, initialPrompt }) {
|
|
@@ -4106,11 +4366,16 @@ function SessionChat({ session, initialPrompt }) {
|
|
|
4106
4366
|
error,
|
|
4107
4367
|
questionPrompts,
|
|
4108
4368
|
submitQuestionAnswer,
|
|
4109
|
-
deactivateQuestionPrompts
|
|
4369
|
+
deactivateQuestionPrompts,
|
|
4370
|
+
pendingConfirmations,
|
|
4371
|
+
allowConfirmation,
|
|
4372
|
+
disallowConfirmation
|
|
4110
4373
|
} = useChat(session.id, initialMessages);
|
|
4111
4374
|
const hasSubmittedInitialPromptRef = useRef9(false);
|
|
4112
4375
|
const { mode, model } = usePromptConfig();
|
|
4113
4376
|
const { isTopLayer } = useKeyboardLayer();
|
|
4377
|
+
const renderer = useRenderer3();
|
|
4378
|
+
const toast = useToast();
|
|
4114
4379
|
useEffect5(() => {
|
|
4115
4380
|
return () => {
|
|
4116
4381
|
abort();
|
|
@@ -4122,6 +4387,25 @@ function SessionChat({ session, initialPrompt }) {
|
|
|
4122
4387
|
interrupt();
|
|
4123
4388
|
}
|
|
4124
4389
|
});
|
|
4390
|
+
useKeyboard6((key) => {
|
|
4391
|
+
if (key.name === "f5") {
|
|
4392
|
+
key.preventDefault();
|
|
4393
|
+
const inputTextarea = getInputTextarea();
|
|
4394
|
+
if (inputTextarea && inputTextarea.hasSelection()) {
|
|
4395
|
+
renderer.copyToClipboardOSC52(inputTextarea.getSelectedText());
|
|
4396
|
+
toast.show({ variant: "success", message: "Copied to clipboard" });
|
|
4397
|
+
return;
|
|
4398
|
+
}
|
|
4399
|
+
const lastAssistantMessage = messages.findLast((m) => m.role === "assistant");
|
|
4400
|
+
if (lastAssistantMessage) {
|
|
4401
|
+
const text = lastAssistantMessage.parts.filter((p) => p.type === "text").map((p) => p.text).join("");
|
|
4402
|
+
if (text) {
|
|
4403
|
+
renderer.copyToClipboardOSC52(text);
|
|
4404
|
+
toast.show({ variant: "success", message: "Copied last response to clipboard" });
|
|
4405
|
+
}
|
|
4406
|
+
}
|
|
4407
|
+
}
|
|
4408
|
+
});
|
|
4125
4409
|
useEffect5(() => {
|
|
4126
4410
|
if (!initialPrompt || hasSubmittedInitialPromptRef.current)
|
|
4127
4411
|
return;
|
|
@@ -4132,24 +4416,28 @@ function SessionChat({ session, initialPrompt }) {
|
|
|
4132
4416
|
model: initialPrompt.model
|
|
4133
4417
|
});
|
|
4134
4418
|
}, [initialPrompt, submit]);
|
|
4135
|
-
return /* @__PURE__ */
|
|
4419
|
+
return /* @__PURE__ */ jsxDEV28(SessionShell, {
|
|
4136
4420
|
onSubmit: (text) => {
|
|
4137
4421
|
deactivateQuestionPrompts();
|
|
4138
4422
|
submit({ userText: text, mode, model });
|
|
4139
4423
|
},
|
|
4140
4424
|
loading: status === "submitted" || status === "streaming",
|
|
4141
4425
|
interruptible: status === "submitted" || status === "streaming",
|
|
4426
|
+
inputDisabled: status === "submitted" || status === "streaming" || questionPrompts.some((p) => p.isActive) || pendingConfirmations.length > 0,
|
|
4142
4427
|
children: [
|
|
4143
4428
|
messages.map((msg, i) => {
|
|
4144
4429
|
const isLastAssistant = msg.role === "assistant" && i === messages.length - 1;
|
|
4145
|
-
return /* @__PURE__ */
|
|
4430
|
+
return /* @__PURE__ */ jsxDEV28(ChatMessage, {
|
|
4146
4431
|
msg,
|
|
4147
4432
|
questionPrompts,
|
|
4148
4433
|
onSubmitQuestionAnswer: submitQuestionAnswer,
|
|
4434
|
+
pendingConfirmations,
|
|
4435
|
+
onAllowConfirmation: allowConfirmation,
|
|
4436
|
+
onDisallowConfirmation: disallowConfirmation,
|
|
4149
4437
|
isStreaming: isLastAssistant && status === "streaming"
|
|
4150
4438
|
}, msg.id, false, undefined, this);
|
|
4151
4439
|
}),
|
|
4152
|
-
error && /* @__PURE__ */
|
|
4440
|
+
error && /* @__PURE__ */ jsxDEV28(ErrorMessage, {
|
|
4153
4441
|
message: error.message
|
|
4154
4442
|
}, undefined, false, undefined, this)
|
|
4155
4443
|
]
|
|
@@ -4199,34 +4487,34 @@ function Session() {
|
|
|
4199
4487
|
};
|
|
4200
4488
|
}, [id, prefetched, toast, navigate]);
|
|
4201
4489
|
if (!session) {
|
|
4202
|
-
return /* @__PURE__ */
|
|
4490
|
+
return /* @__PURE__ */ jsxDEV28(SessionShell, {
|
|
4203
4491
|
onSubmit: () => {},
|
|
4204
4492
|
inputDisabled: true,
|
|
4205
4493
|
loading: true
|
|
4206
4494
|
}, undefined, false, undefined, this);
|
|
4207
4495
|
}
|
|
4208
|
-
return /* @__PURE__ */
|
|
4496
|
+
return /* @__PURE__ */ jsxDEV28(SessionChat, {
|
|
4209
4497
|
session,
|
|
4210
4498
|
initialPrompt: prefetched?.initialPrompt
|
|
4211
4499
|
}, session.id, false, undefined, this);
|
|
4212
4500
|
}
|
|
4213
4501
|
|
|
4214
4502
|
// src/index.tsx
|
|
4215
|
-
import { jsxDEV as
|
|
4503
|
+
import { jsxDEV as jsxDEV29 } from "@opentui/react/jsx-dev-runtime";
|
|
4216
4504
|
var router = createMemoryRouter([
|
|
4217
4505
|
{
|
|
4218
4506
|
path: "/",
|
|
4219
|
-
element: /* @__PURE__ */
|
|
4507
|
+
element: /* @__PURE__ */ jsxDEV29(RootLayout, {}, undefined, false, undefined, this),
|
|
4220
4508
|
children: [
|
|
4221
|
-
{ index: true, element: /* @__PURE__ */
|
|
4222
|
-
{ path: "sessions/new", element: /* @__PURE__ */
|
|
4223
|
-
{ path: "sessions/:id", element: /* @__PURE__ */
|
|
4224
|
-
{ path: "docs", element: /* @__PURE__ */
|
|
4509
|
+
{ index: true, element: /* @__PURE__ */ jsxDEV29(Home, {}, undefined, false, undefined, this) },
|
|
4510
|
+
{ path: "sessions/new", element: /* @__PURE__ */ jsxDEV29(NewSession, {}, undefined, false, undefined, this) },
|
|
4511
|
+
{ path: "sessions/:id", element: /* @__PURE__ */ jsxDEV29(Session, {}, undefined, false, undefined, this) },
|
|
4512
|
+
{ path: "docs", element: /* @__PURE__ */ jsxDEV29(Docs, {}, undefined, false, undefined, this) }
|
|
4225
4513
|
]
|
|
4226
4514
|
}
|
|
4227
4515
|
]);
|
|
4228
4516
|
function App() {
|
|
4229
|
-
return /* @__PURE__ */
|
|
4517
|
+
return /* @__PURE__ */ jsxDEV29(RouterProvider, {
|
|
4230
4518
|
router
|
|
4231
4519
|
}, undefined, false, undefined, this);
|
|
4232
4520
|
}
|
|
@@ -4234,4 +4522,4 @@ var renderer = await createCliRenderer({
|
|
|
4234
4522
|
targetFps: 60,
|
|
4235
4523
|
exitOnCtrlC: false
|
|
4236
4524
|
});
|
|
4237
|
-
createRoot(renderer).render(/* @__PURE__ */
|
|
4525
|
+
createRoot(renderer).render(/* @__PURE__ */ jsxDEV29(App, {}, undefined, false, undefined, this));
|