@unikode/cli 1.0.16 → 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 +416 -118
- 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)
|
|
@@ -3680,36 +3884,46 @@ async function executeLocalTool(toolName, input, mode) {
|
|
|
3680
3884
|
}
|
|
3681
3885
|
case "webSearchTool": {
|
|
3682
3886
|
const { query, searchDepth, maxResults, includeAnswer } = toolInputSchemas.webSearchTool.parse(input);
|
|
3683
|
-
const
|
|
3684
|
-
const
|
|
3685
|
-
if (!
|
|
3887
|
+
const apiUrl = process.env.API_URL ?? "http://localhost:3000";
|
|
3888
|
+
const searchEndpointUrl = apiUrl + "/tools/webSearchTool";
|
|
3889
|
+
if (!searchEndpointUrl) {
|
|
3686
3890
|
return {
|
|
3687
3891
|
error: true,
|
|
3688
|
-
message: "
|
|
3892
|
+
message: "WEB_SEARCH_ENDPOINT_URL is not configured in the CLI environment."
|
|
3689
3893
|
};
|
|
3690
3894
|
}
|
|
3691
3895
|
try {
|
|
3692
|
-
const
|
|
3896
|
+
const auth = getAuth();
|
|
3897
|
+
const headers = {
|
|
3898
|
+
"Content-Type": "application/json"
|
|
3899
|
+
};
|
|
3900
|
+
if (auth) {
|
|
3901
|
+
headers["Authorization"] = `Bearer ${auth.token}`;
|
|
3902
|
+
}
|
|
3903
|
+
const response = await fetch(searchEndpointUrl, {
|
|
3693
3904
|
method: "POST",
|
|
3694
|
-
headers
|
|
3695
|
-
"Content-Type": "application/json"
|
|
3696
|
-
},
|
|
3905
|
+
headers,
|
|
3697
3906
|
body: JSON.stringify({
|
|
3698
|
-
api_key: apiKey,
|
|
3699
3907
|
query,
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3908
|
+
searchDepth,
|
|
3909
|
+
maxResults,
|
|
3910
|
+
includeAnswer
|
|
3703
3911
|
})
|
|
3704
3912
|
});
|
|
3705
3913
|
if (!response.ok) {
|
|
3706
3914
|
const errorText = await response.text();
|
|
3707
3915
|
return {
|
|
3708
3916
|
error: true,
|
|
3709
|
-
message: `
|
|
3917
|
+
message: `Web search service failed (${response.status}): ${errorText}`
|
|
3710
3918
|
};
|
|
3711
3919
|
}
|
|
3712
3920
|
const data = await response.json();
|
|
3921
|
+
if (data.error) {
|
|
3922
|
+
return {
|
|
3923
|
+
error: true,
|
|
3924
|
+
message: data.error
|
|
3925
|
+
};
|
|
3926
|
+
}
|
|
3713
3927
|
return {
|
|
3714
3928
|
error: false,
|
|
3715
3929
|
query,
|
|
@@ -3952,6 +4166,7 @@ ${outline.join(`
|
|
|
3952
4166
|
// src/hooks/use-chat.ts
|
|
3953
4167
|
function useChat(sessionId, initialMessages) {
|
|
3954
4168
|
const [questionPrompts, setQuestionPrompts] = useState11([]);
|
|
4169
|
+
const [pendingConfirmations, setPendingConfirmations] = useState11([]);
|
|
3955
4170
|
const transport = useMemo5(() => {
|
|
3956
4171
|
return new DefaultChatTransport({
|
|
3957
4172
|
api: apiClient.chat.$url().toString(),
|
|
@@ -3994,6 +4209,20 @@ function useChat(sessionId, initialMessages) {
|
|
|
3994
4209
|
}
|
|
3995
4210
|
});
|
|
3996
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
|
+
};
|
|
3997
4226
|
const chat = useAiChat({
|
|
3998
4227
|
id: sessionId,
|
|
3999
4228
|
messages: initialMessages,
|
|
@@ -4017,6 +4246,17 @@ function useChat(sessionId, initialMessages) {
|
|
|
4017
4246
|
return;
|
|
4018
4247
|
}
|
|
4019
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
|
+
}
|
|
4020
4260
|
executeLocalTool(toolCall.toolName, toolCall.input, mode).then((output) => chat.addToolOutput({
|
|
4021
4261
|
tool: toolCall.toolName,
|
|
4022
4262
|
toolCallId: toolCall.toolCallId,
|
|
@@ -4030,6 +4270,27 @@ function useChat(sessionId, initialMessages) {
|
|
|
4030
4270
|
},
|
|
4031
4271
|
sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls
|
|
4032
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]);
|
|
4033
4294
|
return {
|
|
4034
4295
|
messages: chat.messages,
|
|
4035
4296
|
status: chat.status,
|
|
@@ -4047,13 +4308,16 @@ function useChat(sessionId, initialMessages) {
|
|
|
4047
4308
|
});
|
|
4048
4309
|
},
|
|
4049
4310
|
abort: chat.stop,
|
|
4050
|
-
interrupt: chat.stop
|
|
4311
|
+
interrupt: chat.stop,
|
|
4312
|
+
pendingConfirmations,
|
|
4313
|
+
allowConfirmation,
|
|
4314
|
+
disallowConfirmation
|
|
4051
4315
|
};
|
|
4052
4316
|
}
|
|
4053
4317
|
|
|
4054
4318
|
// src/screens/session.tsx
|
|
4055
|
-
import { useKeyboard as useKeyboard6 } from "@opentui/react";
|
|
4056
|
-
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";
|
|
4057
4321
|
var sessionLocationSchema = z3.object({
|
|
4058
4322
|
session: z3.custom((val) => val != null && typeof val === "object" && ("id" in val)),
|
|
4059
4323
|
initialPrompt: z3.object({
|
|
@@ -4066,23 +4330,29 @@ function ChatMessage({
|
|
|
4066
4330
|
msg,
|
|
4067
4331
|
questionPrompts,
|
|
4068
4332
|
onSubmitQuestionAnswer,
|
|
4333
|
+
pendingConfirmations,
|
|
4334
|
+
onAllowConfirmation,
|
|
4335
|
+
onDisallowConfirmation,
|
|
4069
4336
|
isStreaming = false
|
|
4070
4337
|
}) {
|
|
4071
4338
|
if (msg.role === "user") {
|
|
4072
4339
|
const text = msg.parts.filter((p) => p.type === "text").map((p) => p.text).join("");
|
|
4073
|
-
return /* @__PURE__ */
|
|
4340
|
+
return /* @__PURE__ */ jsxDEV28(UserMessage, {
|
|
4074
4341
|
message: text,
|
|
4075
4342
|
mode: msg.metadata?.mode ?? "BUILD"
|
|
4076
4343
|
}, undefined, false, undefined, this);
|
|
4077
4344
|
}
|
|
4078
|
-
return /* @__PURE__ */
|
|
4345
|
+
return /* @__PURE__ */ jsxDEV28(BotMessage, {
|
|
4079
4346
|
parts: msg.parts,
|
|
4080
4347
|
model: msg.metadata?.model ?? "unknown",
|
|
4081
4348
|
mode: msg.metadata?.mode ?? "BUILD",
|
|
4082
4349
|
durationMs: msg.metadata?.durationMs,
|
|
4083
4350
|
streaming: isStreaming,
|
|
4084
4351
|
questionPrompts,
|
|
4085
|
-
onSubmitQuestionAnswer
|
|
4352
|
+
onSubmitQuestionAnswer,
|
|
4353
|
+
pendingConfirmations,
|
|
4354
|
+
onAllowConfirmation,
|
|
4355
|
+
onDisallowConfirmation
|
|
4086
4356
|
}, undefined, false, undefined, this);
|
|
4087
4357
|
}
|
|
4088
4358
|
function SessionChat({ session, initialPrompt }) {
|
|
@@ -4096,11 +4366,16 @@ function SessionChat({ session, initialPrompt }) {
|
|
|
4096
4366
|
error,
|
|
4097
4367
|
questionPrompts,
|
|
4098
4368
|
submitQuestionAnswer,
|
|
4099
|
-
deactivateQuestionPrompts
|
|
4369
|
+
deactivateQuestionPrompts,
|
|
4370
|
+
pendingConfirmations,
|
|
4371
|
+
allowConfirmation,
|
|
4372
|
+
disallowConfirmation
|
|
4100
4373
|
} = useChat(session.id, initialMessages);
|
|
4101
4374
|
const hasSubmittedInitialPromptRef = useRef9(false);
|
|
4102
4375
|
const { mode, model } = usePromptConfig();
|
|
4103
4376
|
const { isTopLayer } = useKeyboardLayer();
|
|
4377
|
+
const renderer = useRenderer3();
|
|
4378
|
+
const toast = useToast();
|
|
4104
4379
|
useEffect5(() => {
|
|
4105
4380
|
return () => {
|
|
4106
4381
|
abort();
|
|
@@ -4112,6 +4387,25 @@ function SessionChat({ session, initialPrompt }) {
|
|
|
4112
4387
|
interrupt();
|
|
4113
4388
|
}
|
|
4114
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
|
+
});
|
|
4115
4409
|
useEffect5(() => {
|
|
4116
4410
|
if (!initialPrompt || hasSubmittedInitialPromptRef.current)
|
|
4117
4411
|
return;
|
|
@@ -4122,24 +4416,28 @@ function SessionChat({ session, initialPrompt }) {
|
|
|
4122
4416
|
model: initialPrompt.model
|
|
4123
4417
|
});
|
|
4124
4418
|
}, [initialPrompt, submit]);
|
|
4125
|
-
return /* @__PURE__ */
|
|
4419
|
+
return /* @__PURE__ */ jsxDEV28(SessionShell, {
|
|
4126
4420
|
onSubmit: (text) => {
|
|
4127
4421
|
deactivateQuestionPrompts();
|
|
4128
4422
|
submit({ userText: text, mode, model });
|
|
4129
4423
|
},
|
|
4130
4424
|
loading: status === "submitted" || status === "streaming",
|
|
4131
4425
|
interruptible: status === "submitted" || status === "streaming",
|
|
4426
|
+
inputDisabled: status === "submitted" || status === "streaming" || questionPrompts.some((p) => p.isActive) || pendingConfirmations.length > 0,
|
|
4132
4427
|
children: [
|
|
4133
4428
|
messages.map((msg, i) => {
|
|
4134
4429
|
const isLastAssistant = msg.role === "assistant" && i === messages.length - 1;
|
|
4135
|
-
return /* @__PURE__ */
|
|
4430
|
+
return /* @__PURE__ */ jsxDEV28(ChatMessage, {
|
|
4136
4431
|
msg,
|
|
4137
4432
|
questionPrompts,
|
|
4138
4433
|
onSubmitQuestionAnswer: submitQuestionAnswer,
|
|
4434
|
+
pendingConfirmations,
|
|
4435
|
+
onAllowConfirmation: allowConfirmation,
|
|
4436
|
+
onDisallowConfirmation: disallowConfirmation,
|
|
4139
4437
|
isStreaming: isLastAssistant && status === "streaming"
|
|
4140
4438
|
}, msg.id, false, undefined, this);
|
|
4141
4439
|
}),
|
|
4142
|
-
error && /* @__PURE__ */
|
|
4440
|
+
error && /* @__PURE__ */ jsxDEV28(ErrorMessage, {
|
|
4143
4441
|
message: error.message
|
|
4144
4442
|
}, undefined, false, undefined, this)
|
|
4145
4443
|
]
|
|
@@ -4189,34 +4487,34 @@ function Session() {
|
|
|
4189
4487
|
};
|
|
4190
4488
|
}, [id, prefetched, toast, navigate]);
|
|
4191
4489
|
if (!session) {
|
|
4192
|
-
return /* @__PURE__ */
|
|
4490
|
+
return /* @__PURE__ */ jsxDEV28(SessionShell, {
|
|
4193
4491
|
onSubmit: () => {},
|
|
4194
4492
|
inputDisabled: true,
|
|
4195
4493
|
loading: true
|
|
4196
4494
|
}, undefined, false, undefined, this);
|
|
4197
4495
|
}
|
|
4198
|
-
return /* @__PURE__ */
|
|
4496
|
+
return /* @__PURE__ */ jsxDEV28(SessionChat, {
|
|
4199
4497
|
session,
|
|
4200
4498
|
initialPrompt: prefetched?.initialPrompt
|
|
4201
4499
|
}, session.id, false, undefined, this);
|
|
4202
4500
|
}
|
|
4203
4501
|
|
|
4204
4502
|
// src/index.tsx
|
|
4205
|
-
import { jsxDEV as
|
|
4503
|
+
import { jsxDEV as jsxDEV29 } from "@opentui/react/jsx-dev-runtime";
|
|
4206
4504
|
var router = createMemoryRouter([
|
|
4207
4505
|
{
|
|
4208
4506
|
path: "/",
|
|
4209
|
-
element: /* @__PURE__ */
|
|
4507
|
+
element: /* @__PURE__ */ jsxDEV29(RootLayout, {}, undefined, false, undefined, this),
|
|
4210
4508
|
children: [
|
|
4211
|
-
{ index: true, element: /* @__PURE__ */
|
|
4212
|
-
{ path: "sessions/new", element: /* @__PURE__ */
|
|
4213
|
-
{ path: "sessions/:id", element: /* @__PURE__ */
|
|
4214
|
-
{ 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) }
|
|
4215
4513
|
]
|
|
4216
4514
|
}
|
|
4217
4515
|
]);
|
|
4218
4516
|
function App() {
|
|
4219
|
-
return /* @__PURE__ */
|
|
4517
|
+
return /* @__PURE__ */ jsxDEV29(RouterProvider, {
|
|
4220
4518
|
router
|
|
4221
4519
|
}, undefined, false, undefined, this);
|
|
4222
4520
|
}
|
|
@@ -4224,4 +4522,4 @@ var renderer = await createCliRenderer({
|
|
|
4224
4522
|
targetFps: 60,
|
|
4225
4523
|
exitOnCtrlC: false
|
|
4226
4524
|
});
|
|
4227
|
-
createRoot(renderer).render(/* @__PURE__ */
|
|
4525
|
+
createRoot(renderer).render(/* @__PURE__ */ jsxDEV29(App, {}, undefined, false, undefined, this));
|