code-ollama 0.18.2 → 0.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{tui-XD0Ekj5m.js → tui-DDbMjcMS.js} +286 -77
- package/dist/cli.js +152 -14
- package/package.json +9 -9
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
import { readdirSync } from "node:fs";
|
|
1
|
+
import { A as WARNING, B as LABEL, C as loadConfig, D as resetSystemMessage, E as saveClipboardImage, F as USER, G as VERSION, H as SAFE, I as PLAN_GENERATION_INSTRUCTION, K as LIST, L as BACK, M as getTheme, N as ASSISTANT, O as withSystemMessage, P as SYSTEM, R as CATALOG, S as streamChat, T as removeClipboardImage, U as APPROVE, V as PLAN, W as REJECT, _ as setClearHandler, a as tick, b as listModels, c as appendMessage, d as deleteSessionIfEmpty, f as listSessions, g as reset, h as clear, i as WRITE_TOOLS, j as LIST$1, k as HEADER_PREFIX, l as createSession, m as updateSessionModel, n as READ_TOOLS, o as color, p as loadSession, r as TOOLS, s as write, t as executeTool, u as deleteSession, v as checkHealth, w as saveConfig, x as pullModel, y as deleteModel, z as AUTO } from "../cli.js";
|
|
2
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
|
-
import { join, relative } from "node:path";
|
|
4
|
+
import { basename, extname, isAbsolute, join, relative, resolve } from "node:path";
|
|
5
5
|
import { exec } from "node:child_process";
|
|
6
6
|
import { Box, Static, Text, render, useApp, useInput, useStdout } from "ink";
|
|
7
7
|
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
@@ -227,8 +227,6 @@ var Markdown = memo(function Markdown({ content, color, dimColor, theme = getThe
|
|
|
227
227
|
//#endregion
|
|
228
228
|
//#region src/components/Messages/layout.ts
|
|
229
229
|
var ANSI_REGEX = new RegExp(String.raw`\u001B\[[0-9;]*m`, "g");
|
|
230
|
-
var CODE_BLOCK_MARGIN_Y = 2;
|
|
231
|
-
var CODE_BLOCK_BORDER_Y = 2;
|
|
232
230
|
var CODE_BLOCK_CHROME_X = 4;
|
|
233
231
|
function stripAnsi(value) {
|
|
234
232
|
return value.replaceAll(ANSI_REGEX, "");
|
|
@@ -264,8 +262,7 @@ function countWrappedLines(content, width) {
|
|
|
264
262
|
* @returns The total height in lines.
|
|
265
263
|
*/
|
|
266
264
|
function getCodeBlockHeight(content, width) {
|
|
267
|
-
|
|
268
|
-
return CODE_BLOCK_MARGIN_Y + CODE_BLOCK_BORDER_Y + countWrappedLines(content, contentWidth);
|
|
265
|
+
return 4 + countWrappedLines(content, Math.max(1, width - CODE_BLOCK_CHROME_X));
|
|
269
266
|
}
|
|
270
267
|
/**
|
|
271
268
|
* Calculates the total height of streaming text content based on wrapped lines.
|
|
@@ -416,6 +413,26 @@ function Message({ message, isStreaming = false, theme }) {
|
|
|
416
413
|
children: message.content
|
|
417
414
|
})
|
|
418
415
|
});
|
|
416
|
+
if (isUser) {
|
|
417
|
+
// v8 ignore start
|
|
418
|
+
const attachmentPrefix = (message.images ?? []).map((path) => `[${path.split(/[\\/]/).at(-1) ?? path}]`).join(" ");
|
|
419
|
+
// v8 ignore stop
|
|
420
|
+
return /* @__PURE__ */ jsx(Box, {
|
|
421
|
+
flexDirection: "column",
|
|
422
|
+
marginBottom: 1,
|
|
423
|
+
children: /* @__PURE__ */ jsxs(Text, {
|
|
424
|
+
color: messageColor,
|
|
425
|
+
children: [
|
|
426
|
+
"> ",
|
|
427
|
+
attachmentPrefix ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Text, {
|
|
428
|
+
color: theme.colors.accent,
|
|
429
|
+
children: attachmentPrefix
|
|
430
|
+
}), message.content ? " " : ""] }) : null,
|
|
431
|
+
message.content
|
|
432
|
+
]
|
|
433
|
+
})
|
|
434
|
+
});
|
|
435
|
+
}
|
|
419
436
|
const segments = parseContent(message.content);
|
|
420
437
|
const availableWidth = getAssistantContentWidth(stdout.columns);
|
|
421
438
|
if (stickyHeightRef.current.columns !== stdout.columns) stickyHeightRef.current = {
|
|
@@ -436,11 +453,7 @@ function Message({ message, isStreaming = false, theme }) {
|
|
|
436
453
|
flexDirection: "column",
|
|
437
454
|
marginBottom: 1,
|
|
438
455
|
children: [segments.map((segment, index) => {
|
|
439
|
-
|
|
440
|
-
if (segment.type === "code") return isUser ? /* @__PURE__ */ jsx(Text, {
|
|
441
|
-
color: messageColor,
|
|
442
|
-
children: segment.content
|
|
443
|
-
}, index) : /* @__PURE__ */ jsx(Box, {
|
|
456
|
+
if (segment.type === "code") return /* @__PURE__ */ jsx(Box, {
|
|
444
457
|
marginX: 2,
|
|
445
458
|
children: /* @__PURE__ */ jsx(CodeBlock, {
|
|
446
459
|
code: segment.content,
|
|
@@ -461,17 +474,13 @@ function Message({ message, isStreaming = false, theme }) {
|
|
|
461
474
|
})
|
|
462
475
|
}, index);
|
|
463
476
|
}
|
|
464
|
-
|
|
465
|
-
type: "markdown",
|
|
466
|
-
content: segment.content
|
|
467
|
-
}];
|
|
468
|
-
return isUser ? /* @__PURE__ */ jsx(Text, {
|
|
469
|
-
color: messageColor,
|
|
470
|
-
children: prefix + segment.content
|
|
471
|
-
}, index) : /* @__PURE__ */ jsx(Box, {
|
|
477
|
+
return /* @__PURE__ */ jsx(Box, {
|
|
472
478
|
flexDirection: "column",
|
|
473
479
|
marginX: 2,
|
|
474
|
-
children:
|
|
480
|
+
children: [{
|
|
481
|
+
type: "markdown",
|
|
482
|
+
content: segment.content
|
|
483
|
+
}].map((part, partIndex) => /* @__PURE__ */ jsx(Markdown, {
|
|
475
484
|
content: part.content,
|
|
476
485
|
theme
|
|
477
486
|
}, partIndex))
|
|
@@ -509,13 +518,27 @@ function Messages({ messages, isLoading, sessionId, streamingMessage, theme = ge
|
|
|
509
518
|
//#endregion
|
|
510
519
|
//#region src/components/SelectPrompt/SelectPrompt.tsx
|
|
511
520
|
function SelectPrompt({ borderStyle, children, onCancel, ...selectProps }) {
|
|
521
|
+
const [isInteractive, setIsInteractive] = useState(false);
|
|
522
|
+
useEffect(() => {
|
|
523
|
+
let isMounted = true;
|
|
524
|
+
tick().then(() => {
|
|
525
|
+
// v8 ignore next
|
|
526
|
+
if (isMounted) setIsInteractive(true);
|
|
527
|
+
});
|
|
528
|
+
return () => {
|
|
529
|
+
isMounted = false;
|
|
530
|
+
};
|
|
531
|
+
}, []);
|
|
512
532
|
useInput((input, key) => {
|
|
513
533
|
if (key.escape || key.ctrl && input === "c") onCancel?.();
|
|
514
534
|
});
|
|
515
535
|
return /* @__PURE__ */ jsxs(Box, {
|
|
516
536
|
borderStyle,
|
|
517
537
|
flexDirection: "column",
|
|
518
|
-
children: [children, /* @__PURE__ */ jsx(Select, {
|
|
538
|
+
children: [children, /* @__PURE__ */ jsx(Select, {
|
|
539
|
+
...selectProps,
|
|
540
|
+
isDisabled: selectProps.isDisabled ?? !isInteractive
|
|
541
|
+
})]
|
|
519
542
|
});
|
|
520
543
|
}
|
|
521
544
|
//#endregion
|
|
@@ -778,6 +801,7 @@ function TextInput({ value, isDisabled = false, placeholder, cursorPosition: ext
|
|
|
778
801
|
setCursorPosition(value.length);
|
|
779
802
|
return;
|
|
780
803
|
}
|
|
804
|
+
if (key.ctrl) return;
|
|
781
805
|
// v8 ignore start
|
|
782
806
|
if (input) {
|
|
783
807
|
onChange(value.slice(0, cursorPosition) + input + value.slice(cursorPosition));
|
|
@@ -814,6 +838,74 @@ function TextInput({ value, isDisabled = false, placeholder, cursorPosition: ext
|
|
|
814
838
|
});
|
|
815
839
|
}
|
|
816
840
|
//#endregion
|
|
841
|
+
//#region src/components/Chat/attachments.ts
|
|
842
|
+
var IMAGE_EXTENSIONS = new Set([
|
|
843
|
+
".avif",
|
|
844
|
+
".bmp",
|
|
845
|
+
".gif",
|
|
846
|
+
".heic",
|
|
847
|
+
".heif",
|
|
848
|
+
".jpeg",
|
|
849
|
+
".jpg",
|
|
850
|
+
".png",
|
|
851
|
+
".tif",
|
|
852
|
+
".tiff",
|
|
853
|
+
".webp"
|
|
854
|
+
]);
|
|
855
|
+
var PATH_CANDIDATE_PATTERN = /"([^"\n\r]+\.(?:avif|bmp|gif|heic|heif|jpeg|jpg|png|tif|tiff|webp))"|'([^'\n\r]+\.(?:avif|bmp|gif|heic|heif|jpeg|jpg|png|tif|tiff|webp))'|([^\s"'`]+\.(?:avif|bmp|gif|heic|heif|jpeg|jpg|png|tif|tiff|webp))/gi;
|
|
856
|
+
function normalizeCandidatePath(value) {
|
|
857
|
+
return value.replaceAll(String.raw`\ `, " ");
|
|
858
|
+
}
|
|
859
|
+
function isPathLikeCandidate(candidate, matchedValue) {
|
|
860
|
+
return matchedValue.startsWith("\"") || matchedValue.startsWith("'") || candidate.includes("/") || candidate.includes("\\") || candidate.startsWith(".");
|
|
861
|
+
}
|
|
862
|
+
function getAttachmentLabel(path) {
|
|
863
|
+
return basename(path);
|
|
864
|
+
}
|
|
865
|
+
function isReadableImagePath(path) {
|
|
866
|
+
const normalizedPath = normalizeCandidatePath(path);
|
|
867
|
+
const extension = extname(normalizedPath).toLowerCase();
|
|
868
|
+
if (!IMAGE_EXTENSIONS.has(extension)) return false;
|
|
869
|
+
const resolvedPath = isAbsolute(normalizedPath) ? normalizedPath : resolve(normalizedPath);
|
|
870
|
+
if (!existsSync(resolvedPath)) return false;
|
|
871
|
+
try {
|
|
872
|
+
return statSync(resolvedPath).isFile();
|
|
873
|
+
} catch {
|
|
874
|
+
// v8 ignore next
|
|
875
|
+
return false;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
function resolveAttachmentPath(path) {
|
|
879
|
+
const normalizedPath = normalizeCandidatePath(path);
|
|
880
|
+
return isAbsolute(normalizedPath) ? normalizedPath : resolve(normalizedPath);
|
|
881
|
+
}
|
|
882
|
+
function extractImageAttachments(input) {
|
|
883
|
+
const attachments = [];
|
|
884
|
+
const segments = [];
|
|
885
|
+
let lastIndex = 0;
|
|
886
|
+
for (const match of input.matchAll(PATH_CANDIDATE_PATTERN)) {
|
|
887
|
+
const matchedValue = match[0];
|
|
888
|
+
const candidate = match.slice(1).find((value) => Boolean(value));
|
|
889
|
+
// v8 ignore start
|
|
890
|
+
if (candidate === void 0) continue;
|
|
891
|
+
// v8 ignore stop
|
|
892
|
+
if (!isPathLikeCandidate(candidate, matchedValue)) continue;
|
|
893
|
+
if (!isReadableImagePath(candidate)) continue;
|
|
894
|
+
attachments.push(resolveAttachmentPath(candidate));
|
|
895
|
+
segments.push(input.slice(lastIndex, match.index));
|
|
896
|
+
lastIndex = match.index + matchedValue.length;
|
|
897
|
+
}
|
|
898
|
+
if (!attachments.length) return {
|
|
899
|
+
attachments,
|
|
900
|
+
remainingInput: input
|
|
901
|
+
};
|
|
902
|
+
segments.push(input.slice(lastIndex));
|
|
903
|
+
return {
|
|
904
|
+
attachments,
|
|
905
|
+
remainingInput: segments.join("").replaceAll(/\s{2,}/g, " ").trim()
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
//#endregion
|
|
817
909
|
//#region src/components/Chat/CommandMenu.tsx
|
|
818
910
|
function getMatchingCommands(input) {
|
|
819
911
|
const normalizedInput = input.trim().toLowerCase();
|
|
@@ -1004,28 +1096,81 @@ function FileSuggestions({ input, isDisabled = false, onChange, onSelect }) {
|
|
|
1004
1096
|
function hasFileSuggestionQuery(input) {
|
|
1005
1097
|
return /(^|.)@\S+/.test(input);
|
|
1006
1098
|
}
|
|
1007
|
-
function
|
|
1099
|
+
function toAttachment(path, index, isTemp = false) {
|
|
1100
|
+
return {
|
|
1101
|
+
id: `${path}-${String(index)}`,
|
|
1102
|
+
isTemp,
|
|
1103
|
+
label: getAttachmentLabel(path),
|
|
1104
|
+
path
|
|
1105
|
+
};
|
|
1106
|
+
}
|
|
1107
|
+
function cleanupAttachments(attachments) {
|
|
1108
|
+
for (const attachment of attachments) if (attachment.isTemp) removeClipboardImage(attachment.path);
|
|
1109
|
+
}
|
|
1110
|
+
function ChatInput({ history: sessionHistory, isDisabled = false, onInterrupt, onSubmit, theme = getTheme() }) {
|
|
1008
1111
|
const { exit } = useApp();
|
|
1009
1112
|
const [history, setHistory] = useState(sessionHistory);
|
|
1010
1113
|
const [historyIndex, setHistoryIndex] = useState(null);
|
|
1011
1114
|
const [input, setInput] = useState("");
|
|
1012
1115
|
const [cursorPosition, setCursorPosition] = useState(void 0);
|
|
1116
|
+
const [attachments, setAttachments] = useState([]);
|
|
1117
|
+
const [error, setError] = useState(null);
|
|
1013
1118
|
const fileSuggestionRef = useRef(null);
|
|
1119
|
+
const nextClipboardImageRef = useRef(1);
|
|
1120
|
+
const hasAttachments = attachments.length > 0;
|
|
1014
1121
|
useEffect(() => {
|
|
1015
1122
|
setHistory(sessionHistory);
|
|
1016
1123
|
setHistoryIndex(null);
|
|
1017
1124
|
setInput("");
|
|
1018
1125
|
setCursorPosition(void 0);
|
|
1126
|
+
setError(null);
|
|
1019
1127
|
fileSuggestionRef.current = null;
|
|
1128
|
+
nextClipboardImageRef.current = 1;
|
|
1129
|
+
setAttachments((previousAttachments) => {
|
|
1130
|
+
cleanupAttachments(previousAttachments);
|
|
1131
|
+
return [];
|
|
1132
|
+
});
|
|
1020
1133
|
}, [sessionHistory]);
|
|
1021
|
-
const resetInput = useCallback(() => {
|
|
1134
|
+
const resetInput = useCallback((deleteTempAttachments = false) => {
|
|
1022
1135
|
setInput("");
|
|
1023
1136
|
setCursorPosition(void 0);
|
|
1024
1137
|
setHistoryIndex(null);
|
|
1138
|
+
setError(null);
|
|
1139
|
+
if (deleteTempAttachments) {
|
|
1140
|
+
setAttachments((previousAttachments) => {
|
|
1141
|
+
cleanupAttachments(previousAttachments);
|
|
1142
|
+
return [];
|
|
1143
|
+
});
|
|
1144
|
+
nextClipboardImageRef.current = 1;
|
|
1145
|
+
return;
|
|
1146
|
+
}
|
|
1147
|
+
setAttachments([]);
|
|
1148
|
+
}, []);
|
|
1149
|
+
const removeLastAttachment = useCallback(() => {
|
|
1150
|
+
setAttachments((previousAttachments) => {
|
|
1151
|
+
const removedAttachment = previousAttachments.at(-1);
|
|
1152
|
+
if (removedAttachment?.isTemp) removeClipboardImage(removedAttachment.path);
|
|
1153
|
+
return previousAttachments.slice(0, -1);
|
|
1154
|
+
});
|
|
1155
|
+
setError(null);
|
|
1156
|
+
}, []);
|
|
1157
|
+
const stageAttachments = useCallback((paths, isTemp = false) => {
|
|
1158
|
+
setAttachments((previousAttachments) => [...previousAttachments, ...paths.map((path, index) => toAttachment(path, previousAttachments.length + index, isTemp))]);
|
|
1159
|
+
setError(null);
|
|
1025
1160
|
}, []);
|
|
1161
|
+
const attachClipboardImage = useCallback(() => {
|
|
1162
|
+
try {
|
|
1163
|
+
const path = saveClipboardImage(`image-${String(nextClipboardImageRef.current)}`);
|
|
1164
|
+
nextClipboardImageRef.current += 1;
|
|
1165
|
+
stageAttachments([path], true);
|
|
1166
|
+
} catch (error) {
|
|
1167
|
+
setError(error instanceof Error ? error.message : String(error));
|
|
1168
|
+
}
|
|
1169
|
+
}, [stageAttachments]);
|
|
1026
1170
|
const handleSelectFileSuggestion = useCallback((nextInput) => {
|
|
1027
1171
|
setInput(nextInput.value);
|
|
1028
1172
|
setCursorPosition(nextInput.cursorPosition);
|
|
1173
|
+
setError(null);
|
|
1029
1174
|
}, []);
|
|
1030
1175
|
const handleFileSuggestionChange = useCallback((nextInput) => {
|
|
1031
1176
|
if (nextInput) {
|
|
@@ -1046,21 +1191,40 @@ function ChatInput({ history: sessionHistory, isDisabled = false, onInterrupt, o
|
|
|
1046
1191
|
} else fileSuggestionRef.current = null;
|
|
1047
1192
|
}, [input]);
|
|
1048
1193
|
const handleInputChange = useCallback((nextInput) => {
|
|
1194
|
+
if (nextInput.length - input.length > 1) {
|
|
1195
|
+
const { attachments: nextAttachments, remainingInput } = extractImageAttachments(nextInput);
|
|
1196
|
+
if (nextAttachments.length) {
|
|
1197
|
+
stageAttachments(nextAttachments);
|
|
1198
|
+
setInput(remainingInput);
|
|
1199
|
+
setCursorPosition(remainingInput.length);
|
|
1200
|
+
setHistoryIndex(null);
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1049
1204
|
setInput(nextInput);
|
|
1050
1205
|
setHistoryIndex(null);
|
|
1051
|
-
|
|
1206
|
+
setError(null);
|
|
1207
|
+
}, [input, stageAttachments]);
|
|
1052
1208
|
const submitAndReset = useCallback((input) => {
|
|
1053
1209
|
const trimmedInput = input.trim();
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1210
|
+
const imagePaths = attachments.map(({ path }) => path);
|
|
1211
|
+
if (!trimmedInput && !imagePaths.length) return;
|
|
1212
|
+
onSubmit({
|
|
1213
|
+
content: trimmedInput,
|
|
1214
|
+
...imagePaths.length ? { images: imagePaths } : {}
|
|
1215
|
+
});
|
|
1216
|
+
if (trimmedInput && !trimmedInput.startsWith("/")) setHistory((previousHistory) => [...previousHistory, trimmedInput]);
|
|
1217
|
+
resetInput(trimmedInput.startsWith("/"));
|
|
1058
1218
|
fileSuggestionRef.current = null;
|
|
1059
|
-
}, [
|
|
1219
|
+
}, [
|
|
1220
|
+
attachments,
|
|
1221
|
+
onSubmit,
|
|
1222
|
+
resetInput
|
|
1223
|
+
]);
|
|
1060
1224
|
const showCommandMenu = input.startsWith("/");
|
|
1061
1225
|
const showFileSuggestions = !showCommandMenu && hasFileSuggestionQuery(input);
|
|
1062
1226
|
const handleHistoryNavigation = useCallback((direction) => {
|
|
1063
|
-
if (!history.length || showFileSuggestions) return;
|
|
1227
|
+
if (!history.length || showFileSuggestions || hasAttachments) return;
|
|
1064
1228
|
if (direction === "up") {
|
|
1065
1229
|
if (historyIndex === null) {
|
|
1066
1230
|
if (input) return;
|
|
@@ -1092,21 +1256,22 @@ function ChatInput({ history: sessionHistory, isDisabled = false, onInterrupt, o
|
|
|
1092
1256
|
setInput(nextInput);
|
|
1093
1257
|
setCursorPosition(nextInput.length);
|
|
1094
1258
|
}, [
|
|
1259
|
+
hasAttachments,
|
|
1095
1260
|
history,
|
|
1096
1261
|
historyIndex,
|
|
1097
1262
|
input,
|
|
1098
1263
|
showFileSuggestions
|
|
1099
1264
|
]);
|
|
1100
|
-
const handleSubmitText = useCallback((
|
|
1101
|
-
if (
|
|
1102
|
-
if (hasFileSuggestionQuery(
|
|
1265
|
+
const handleSubmitText = useCallback((value) => {
|
|
1266
|
+
if (value.startsWith("/")) return;
|
|
1267
|
+
if (hasFileSuggestionQuery(value)) {
|
|
1103
1268
|
if (fileSuggestionRef.current) handleSelectFileSuggestion(fileSuggestionRef.current);
|
|
1104
1269
|
return;
|
|
1105
1270
|
}
|
|
1106
|
-
submitAndReset(
|
|
1271
|
+
submitAndReset(value);
|
|
1107
1272
|
}, [handleSelectFileSuggestion, submitAndReset]);
|
|
1108
|
-
const handleSubmitCommand = useCallback((
|
|
1109
|
-
if (LIST.find(({ name }) => name ===
|
|
1273
|
+
const handleSubmitCommand = useCallback((value) => {
|
|
1274
|
+
if (LIST.find(({ name }) => name === value)) submitAndReset(value);
|
|
1110
1275
|
}, [submitAndReset]);
|
|
1111
1276
|
useInput((inputKey, key) => {
|
|
1112
1277
|
const isCtrlC = key.ctrl && inputKey === "c";
|
|
@@ -1114,6 +1279,14 @@ function ChatInput({ history: sessionHistory, isDisabled = false, onInterrupt, o
|
|
|
1114
1279
|
if (key.escape || isCtrlC) onInterrupt?.();
|
|
1115
1280
|
return;
|
|
1116
1281
|
}
|
|
1282
|
+
if (key.ctrl && inputKey === "v") {
|
|
1283
|
+
attachClipboardImage();
|
|
1284
|
+
return;
|
|
1285
|
+
}
|
|
1286
|
+
if ((key.backspace || key.delete || inputKey === "") && !input) {
|
|
1287
|
+
if (hasAttachments) removeLastAttachment();
|
|
1288
|
+
return;
|
|
1289
|
+
}
|
|
1117
1290
|
if (isCtrlC) {
|
|
1118
1291
|
if (input) {
|
|
1119
1292
|
resetInput();
|
|
@@ -1127,18 +1300,35 @@ function ChatInput({ history: sessionHistory, isDisabled = false, onInterrupt, o
|
|
|
1127
1300
|
}
|
|
1128
1301
|
if (key.downArrow) handleHistoryNavigation("down");
|
|
1129
1302
|
});
|
|
1303
|
+
const attachmentPrefix = attachments.map(({ label }) => `[${label}]`).join(" ");
|
|
1304
|
+
const wrapIndent = 2 + (attachmentPrefix ? attachmentPrefix.length + 1 : 0);
|
|
1130
1305
|
return /* @__PURE__ */ jsxs(Box, {
|
|
1131
1306
|
flexDirection: "column",
|
|
1132
1307
|
children: [
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1308
|
+
error && /* @__PURE__ */ jsx(Box, {
|
|
1309
|
+
marginBottom: 1,
|
|
1310
|
+
marginX: 2,
|
|
1311
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
1312
|
+
color: theme.colors.error,
|
|
1313
|
+
children: error
|
|
1314
|
+
})
|
|
1315
|
+
}),
|
|
1316
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
1317
|
+
/* @__PURE__ */ jsx(Text, { children: "> " }),
|
|
1318
|
+
hasAttachments && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Text, {
|
|
1319
|
+
color: theme.colors.accent,
|
|
1320
|
+
children: attachmentPrefix
|
|
1321
|
+
}), /* @__PURE__ */ jsx(Text, { children: " " })] }),
|
|
1322
|
+
/* @__PURE__ */ jsx(TextInput, {
|
|
1323
|
+
value: input,
|
|
1324
|
+
isDisabled,
|
|
1325
|
+
cursorPosition,
|
|
1326
|
+
wrapIndent,
|
|
1327
|
+
onChange: handleInputChange,
|
|
1328
|
+
onSubmit: handleSubmitText,
|
|
1329
|
+
placeholder: hasAttachments ? void 0 : "Ask anything... (/ commands, @ files, Ctrl+V images)"
|
|
1330
|
+
})
|
|
1331
|
+
] }),
|
|
1142
1332
|
showCommandMenu && /* @__PURE__ */ jsx(CommandMenu, {
|
|
1143
1333
|
input,
|
|
1144
1334
|
onSubmit: handleSubmitCommand
|
|
@@ -1480,10 +1670,10 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
|
|
|
1480
1670
|
messages,
|
|
1481
1671
|
processStream
|
|
1482
1672
|
]);
|
|
1483
|
-
const handleSubmit = useCallback(async (
|
|
1673
|
+
const handleSubmit = useCallback(async ({ content, images }) => {
|
|
1484
1674
|
setInterruptReason(null);
|
|
1485
|
-
const userContent =
|
|
1486
|
-
if (!userContent) return;
|
|
1675
|
+
const userContent = content.trim();
|
|
1676
|
+
if (!userContent && !images?.length) return;
|
|
1487
1677
|
if (userContent.startsWith("/")) {
|
|
1488
1678
|
onCommand(userContent);
|
|
1489
1679
|
return;
|
|
@@ -1491,7 +1681,8 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
|
|
|
1491
1681
|
setIsLoading(true);
|
|
1492
1682
|
const userMessage = {
|
|
1493
1683
|
role: USER,
|
|
1494
|
-
content: userContent
|
|
1684
|
+
content: userContent,
|
|
1685
|
+
...images?.length ? { images } : {}
|
|
1495
1686
|
};
|
|
1496
1687
|
const updatedMessages = [...messages, userMessage];
|
|
1497
1688
|
setMessages(updatedMessages);
|
|
@@ -1537,7 +1728,8 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
|
|
|
1537
1728
|
history,
|
|
1538
1729
|
isDisabled: isLoading,
|
|
1539
1730
|
onInterrupt: handleInterrupt,
|
|
1540
|
-
onSubmit: handleSubmit
|
|
1731
|
+
onSubmit: handleSubmit,
|
|
1732
|
+
theme
|
|
1541
1733
|
})
|
|
1542
1734
|
})
|
|
1543
1735
|
]
|
|
@@ -1874,6 +2066,7 @@ function ModelDeleteConfirmView({ deleteCandidate, isDeleting, notice, theme, on
|
|
|
1874
2066
|
//#endregion
|
|
1875
2067
|
//#region src/components/ModelManager/ModelDeleteView.tsx
|
|
1876
2068
|
function ModelDeleteView({ currentModel, installedModels, isLoading, notice, theme, onCancel, onSelect }) {
|
|
2069
|
+
// v8 ignore next
|
|
1877
2070
|
if (isLoading) return /* @__PURE__ */ jsx(Spinner, { label: "Loading models..." });
|
|
1878
2071
|
return /* @__PURE__ */ jsxs(SelectPrompt, {
|
|
1879
2072
|
options: [...buildInstalledModelOptions(installedModels.filter((model) => model !== currentModel), currentModel), BACK],
|
|
@@ -2372,6 +2565,24 @@ var ACTION = {
|
|
|
2372
2565
|
OPEN_PREFIX: "open:"
|
|
2373
2566
|
};
|
|
2374
2567
|
var SESSION_LABEL_PADDING = 4;
|
|
2568
|
+
var MAIN_OPTIONS = [
|
|
2569
|
+
{
|
|
2570
|
+
label: "New session",
|
|
2571
|
+
value: ACTION.NEW
|
|
2572
|
+
},
|
|
2573
|
+
{
|
|
2574
|
+
label: "Open session",
|
|
2575
|
+
value: ACTION.OPEN_MENU
|
|
2576
|
+
},
|
|
2577
|
+
{
|
|
2578
|
+
label: "Delete session",
|
|
2579
|
+
value: ACTION.DELETE_MENU
|
|
2580
|
+
},
|
|
2581
|
+
{
|
|
2582
|
+
label: "Close",
|
|
2583
|
+
value: ACTION.CLOSE
|
|
2584
|
+
}
|
|
2585
|
+
];
|
|
2375
2586
|
function truncate(value, maxLength) {
|
|
2376
2587
|
return value.length > maxLength ? `${value.slice(0, maxLength - 1).trimEnd()}…` : value;
|
|
2377
2588
|
}
|
|
@@ -2384,34 +2595,29 @@ function formatSessionLabel(session, maxWidth, prefix = "") {
|
|
|
2384
2595
|
function SessionManager({ currentSessionId, onClose, onDelete, onNew, onOpen, theme = getTheme() }) {
|
|
2385
2596
|
const [view, setView] = useState("main");
|
|
2386
2597
|
const [error, setError] = useState();
|
|
2387
|
-
const [, refreshSessionList] = useState(0);
|
|
2598
|
+
const [sessionListVersion, refreshSessionList] = useState(0);
|
|
2388
2599
|
const { stdout } = useStdout();
|
|
2389
2600
|
const sessions = listSessions();
|
|
2390
2601
|
const maxLabelWidth = Math.max(1, stdout.columns - SESSION_LABEL_PADDING);
|
|
2391
|
-
const options =
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
{
|
|
2403
|
-
label: "Open session",
|
|
2404
|
-
value: ACTION.OPEN_MENU
|
|
2405
|
-
},
|
|
2406
|
-
{
|
|
2407
|
-
label: "Delete session",
|
|
2408
|
-
value: ACTION.DELETE_MENU
|
|
2409
|
-
},
|
|
2410
|
-
{
|
|
2411
|
-
label: "Close",
|
|
2412
|
-
value: ACTION.CLOSE
|
|
2602
|
+
const options = useMemo(() => {
|
|
2603
|
+
switch (view) {
|
|
2604
|
+
case "open": return [...sessions.filter(({ id }) => id !== currentSessionId).map((session) => ({
|
|
2605
|
+
label: formatSessionLabel(session, maxLabelWidth),
|
|
2606
|
+
value: `${ACTION.OPEN_PREFIX}${session.id}`
|
|
2607
|
+
})), BACK];
|
|
2608
|
+
case "delete": return [...sessions.filter(({ id }) => id !== currentSessionId).map((session) => ({
|
|
2609
|
+
label: formatSessionLabel(session, maxLabelWidth, "Delete "),
|
|
2610
|
+
value: `${ACTION.DELETE_PREFIX}${session.id}`
|
|
2611
|
+
})), BACK];
|
|
2612
|
+
default: return MAIN_OPTIONS;
|
|
2413
2613
|
}
|
|
2414
|
-
|
|
2614
|
+
}, [
|
|
2615
|
+
currentSessionId,
|
|
2616
|
+
maxLabelWidth,
|
|
2617
|
+
sessionListVersion,
|
|
2618
|
+
sessions,
|
|
2619
|
+
view
|
|
2620
|
+
]);
|
|
2415
2621
|
const handleChange = useCallback((value) => {
|
|
2416
2622
|
switch (true) {
|
|
2417
2623
|
case value === ACTION.CLOSE:
|
|
@@ -2469,7 +2675,7 @@ function SessionManager({ currentSessionId, onClose, onDelete, onNew, onOpen, th
|
|
|
2469
2675
|
options,
|
|
2470
2676
|
onCancel: onClose,
|
|
2471
2677
|
onChange: handleChange
|
|
2472
|
-
}
|
|
2678
|
+
})
|
|
2473
2679
|
]
|
|
2474
2680
|
});
|
|
2475
2681
|
}
|
|
@@ -2784,7 +2990,10 @@ function ReadinessCheck({ errorMessage, onCommand, setupState, theme = getTheme(
|
|
|
2784
2990
|
}), getMessage(setupState, errorMessage)]
|
|
2785
2991
|
}), /* @__PURE__ */ jsx(ChatInput, {
|
|
2786
2992
|
history: [],
|
|
2787
|
-
onSubmit:
|
|
2993
|
+
onSubmit: ({ content }) => {
|
|
2994
|
+
onCommand(content);
|
|
2995
|
+
},
|
|
2996
|
+
theme
|
|
2788
2997
|
})]
|
|
2789
2998
|
});
|
|
2790
2999
|
}
|
package/dist/cli.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import cac from "cac";
|
|
4
|
-
import { homedir } from "node:os";
|
|
4
|
+
import { homedir, tmpdir } from "node:os";
|
|
5
5
|
import { join } from "node:path";
|
|
6
|
+
import { exec, execFileSync, spawnSync } from "node:child_process";
|
|
7
|
+
import { randomUUID } from "node:crypto";
|
|
6
8
|
import { Ollama } from "ollama";
|
|
7
9
|
import { v7 } from "uuid";
|
|
8
|
-
import { exec } from "node:child_process";
|
|
9
10
|
import { promisify } from "node:util";
|
|
10
11
|
//#region src/constants/command.ts
|
|
11
12
|
var LIST$1 = [
|
|
@@ -37,7 +38,7 @@ var LIST$1 = [
|
|
|
37
38
|
//#endregion
|
|
38
39
|
//#region package.json
|
|
39
40
|
var name = "code-ollama";
|
|
40
|
-
var version = "0.
|
|
41
|
+
var version = "0.19.1";
|
|
41
42
|
//#endregion
|
|
42
43
|
//#region src/constants/package.ts
|
|
43
44
|
var NAME = name;
|
|
@@ -326,6 +327,114 @@ function withSystemMessage(messages) {
|
|
|
326
327
|
return [systemMessage, ...messages];
|
|
327
328
|
}
|
|
328
329
|
//#endregion
|
|
330
|
+
//#region src/utils/clipboard.ts
|
|
331
|
+
var TEMP_IMAGES_DIRECTORY = join(tmpdir(), "code-ollama", "images");
|
|
332
|
+
var WINDOWS_CLIPBOARD_EXIT_CODE = 11;
|
|
333
|
+
function ensureTempDirectory(directory) {
|
|
334
|
+
mkdirSync(directory, { recursive: true });
|
|
335
|
+
return directory;
|
|
336
|
+
}
|
|
337
|
+
function buildTargetPath(directory, extension) {
|
|
338
|
+
const uniqueName = `${randomUUID()}.${extension}`;
|
|
339
|
+
return join(ensureTempDirectory(directory), uniqueName);
|
|
340
|
+
}
|
|
341
|
+
function readMacClipboardImage(path) {
|
|
342
|
+
execFileSync("osascript", ["-e", `
|
|
343
|
+
set outputPath to POSIX file ${JSON.stringify(path)}
|
|
344
|
+
try
|
|
345
|
+
set clipboardData to the clipboard as «class PNGf»
|
|
346
|
+
on error
|
|
347
|
+
error "Clipboard does not contain an image"
|
|
348
|
+
end try
|
|
349
|
+
set fileHandle to open for access outputPath with write permission
|
|
350
|
+
try
|
|
351
|
+
set eof fileHandle to 0
|
|
352
|
+
write clipboardData to fileHandle
|
|
353
|
+
on error errorMessage
|
|
354
|
+
close access fileHandle
|
|
355
|
+
error errorMessage
|
|
356
|
+
end try
|
|
357
|
+
close access fileHandle
|
|
358
|
+
`], { stdio: "ignore" });
|
|
359
|
+
}
|
|
360
|
+
function getClipboardErrorMessage(error) {
|
|
361
|
+
if (error.message.includes("Clipboard does not contain an image")) return "Clipboard does not contain an image.";
|
|
362
|
+
return "Clipboard image paste failed. Paste an image path instead.";
|
|
363
|
+
}
|
|
364
|
+
function readWindowsClipboardImage(path) {
|
|
365
|
+
execFileSync("powershell", [
|
|
366
|
+
"-NoProfile",
|
|
367
|
+
"-Command",
|
|
368
|
+
`
|
|
369
|
+
Add-Type -AssemblyName System.Windows.Forms
|
|
370
|
+
Add-Type -AssemblyName System.Drawing
|
|
371
|
+
$image = [Windows.Forms.Clipboard]::GetImage()
|
|
372
|
+
if ($null -eq $image) { exit ${String(WINDOWS_CLIPBOARD_EXIT_CODE)} }
|
|
373
|
+
$image.Save($args[0], [System.Drawing.Imaging.ImageFormat]::Png)
|
|
374
|
+
`,
|
|
375
|
+
path
|
|
376
|
+
], { stdio: "ignore" });
|
|
377
|
+
}
|
|
378
|
+
function readLinuxClipboardImage(directory) {
|
|
379
|
+
const wlPng = spawnSync("wl-paste", [
|
|
380
|
+
"--no-newline",
|
|
381
|
+
"--type",
|
|
382
|
+
"image/png"
|
|
383
|
+
], { encoding: "buffer" });
|
|
384
|
+
if (wlPng.status === 0 && wlPng.stdout.length > 0) {
|
|
385
|
+
const path = buildTargetPath(directory, "png");
|
|
386
|
+
writeClipboardImageFile(path, wlPng.stdout);
|
|
387
|
+
return path;
|
|
388
|
+
}
|
|
389
|
+
const xclipPng = spawnSync("xclip", [
|
|
390
|
+
"-selection",
|
|
391
|
+
"clipboard",
|
|
392
|
+
"-t",
|
|
393
|
+
"image/png",
|
|
394
|
+
"-o"
|
|
395
|
+
], { encoding: "buffer" });
|
|
396
|
+
if (xclipPng.status === 0 && xclipPng.stdout.length > 0) {
|
|
397
|
+
const path = buildTargetPath(directory, "png");
|
|
398
|
+
writeClipboardImageFile(path, xclipPng.stdout);
|
|
399
|
+
return path;
|
|
400
|
+
}
|
|
401
|
+
throw new Error("Clipboard image paste is unavailable. Paste an image path instead.");
|
|
402
|
+
}
|
|
403
|
+
function writeClipboardImageFile(path, data) {
|
|
404
|
+
writeFileSync(path, data, {
|
|
405
|
+
flag: "wx",
|
|
406
|
+
mode: 384
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
function saveClipboardImage(baseName, directory = TEMP_IMAGES_DIRECTORY) {
|
|
410
|
+
try {
|
|
411
|
+
switch (process.platform) {
|
|
412
|
+
case "darwin": {
|
|
413
|
+
const path = buildTargetPath(directory, "png");
|
|
414
|
+
readMacClipboardImage(path);
|
|
415
|
+
return path;
|
|
416
|
+
}
|
|
417
|
+
case "win32": {
|
|
418
|
+
const path = buildTargetPath(directory, "png");
|
|
419
|
+
readWindowsClipboardImage(path);
|
|
420
|
+
return path;
|
|
421
|
+
}
|
|
422
|
+
case "linux": return readLinuxClipboardImage(directory);
|
|
423
|
+
default: throw new Error("Clipboard image paste is not supported on this platform. Paste an image path instead.");
|
|
424
|
+
}
|
|
425
|
+
} catch (error) {
|
|
426
|
+
if (error instanceof Error && "status" in error && error.status === WINDOWS_CLIPBOARD_EXIT_CODE) throw new Error("Clipboard does not contain an image.", { cause: error });
|
|
427
|
+
const path = join(directory, `${baseName}.png`);
|
|
428
|
+
if (existsSync(path)) rmSync(path, { force: true });
|
|
429
|
+
if (error instanceof Error) throw new Error(getClipboardErrorMessage(error), { cause: error });
|
|
430
|
+
// v8 ignore next
|
|
431
|
+
throw error;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
function removeClipboardImage(path) {
|
|
435
|
+
if (existsSync(path)) rmSync(path, { force: true });
|
|
436
|
+
}
|
|
437
|
+
//#endregion
|
|
329
438
|
//#region src/utils/config.ts
|
|
330
439
|
var CONFIG_PATH = join(DIRECTORY, "config.json");
|
|
331
440
|
var DEFAULT_HOST = "http://localhost:11434";
|
|
@@ -584,6 +693,9 @@ function writeError(text) {
|
|
|
584
693
|
process.stderr.write(text);
|
|
585
694
|
}
|
|
586
695
|
//#endregion
|
|
696
|
+
//#region src/utils/time.ts
|
|
697
|
+
var tick = (ms = 0) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
698
|
+
//#endregion
|
|
587
699
|
//#region src/utils/tools/definitions.ts
|
|
588
700
|
/**
|
|
589
701
|
* Helper to define tool parameters
|
|
@@ -1042,6 +1154,29 @@ function formatSearchResults(source, results, note) {
|
|
|
1042
1154
|
}
|
|
1043
1155
|
//#endregion
|
|
1044
1156
|
//#region src/utils/tools/dispatcher.ts
|
|
1157
|
+
var REQUIRED_STRING_ARGS = {
|
|
1158
|
+
[READ_FILE]: ["path"],
|
|
1159
|
+
[WRITE_FILE]: ["path", "content"],
|
|
1160
|
+
[EDIT_FILE]: [
|
|
1161
|
+
"path",
|
|
1162
|
+
"oldText",
|
|
1163
|
+
"newText"
|
|
1164
|
+
],
|
|
1165
|
+
[RUN_SHELL]: ["command"],
|
|
1166
|
+
[LIST_DIR]: ["path"],
|
|
1167
|
+
[GREP_SEARCH]: ["pattern", "path"],
|
|
1168
|
+
[VIEW_RANGE]: ["path"],
|
|
1169
|
+
[WEB_SEARCH]: ["query"],
|
|
1170
|
+
[WEB_FETCH]: ["url"]
|
|
1171
|
+
};
|
|
1172
|
+
function validateArgs(name, args) {
|
|
1173
|
+
const required = REQUIRED_STRING_ARGS[name] ?? [];
|
|
1174
|
+
const received = Object.keys(args).join(", ") || "none";
|
|
1175
|
+
for (const key of required) if (typeof args[key] !== "string") return {
|
|
1176
|
+
content: "",
|
|
1177
|
+
error: `Missing required argument: ${key} (received keys: ${received})`
|
|
1178
|
+
};
|
|
1179
|
+
}
|
|
1045
1180
|
/**
|
|
1046
1181
|
* Execute a tool by name with arguments
|
|
1047
1182
|
*/
|
|
@@ -1050,16 +1185,19 @@ async function executeTool(name, args, options) {
|
|
|
1050
1185
|
content: "",
|
|
1051
1186
|
error: `Tool not allowed: ${name}`
|
|
1052
1187
|
};
|
|
1188
|
+
const invalid = validateArgs(name, args);
|
|
1189
|
+
if (invalid) return invalid;
|
|
1190
|
+
const stringArgs = args;
|
|
1053
1191
|
switch (name) {
|
|
1054
|
-
case READ_FILE: return readFile(
|
|
1055
|
-
case WRITE_FILE: return writeFile(
|
|
1056
|
-
case EDIT_FILE: return editFile(
|
|
1057
|
-
case RUN_SHELL: return runShell(
|
|
1058
|
-
case LIST_DIR: return listDir(
|
|
1059
|
-
case GREP_SEARCH: return await grepSearch(
|
|
1060
|
-
case VIEW_RANGE: return viewRange(
|
|
1061
|
-
case WEB_SEARCH: return await webSearch(
|
|
1062
|
-
case WEB_FETCH: return await webFetch(
|
|
1192
|
+
case READ_FILE: return readFile(stringArgs.path);
|
|
1193
|
+
case WRITE_FILE: return writeFile(stringArgs.path, stringArgs.content);
|
|
1194
|
+
case EDIT_FILE: return editFile(stringArgs.path, stringArgs.oldText, stringArgs.newText);
|
|
1195
|
+
case RUN_SHELL: return runShell(stringArgs.command);
|
|
1196
|
+
case LIST_DIR: return listDir(stringArgs.path);
|
|
1197
|
+
case GREP_SEARCH: return await grepSearch(stringArgs.pattern, stringArgs.path);
|
|
1198
|
+
case VIEW_RANGE: return viewRange(stringArgs.path, args.start, args.end);
|
|
1199
|
+
case WEB_SEARCH: return await webSearch(stringArgs.query);
|
|
1200
|
+
case WEB_FETCH: return await webFetch(stringArgs.url);
|
|
1063
1201
|
default: return {
|
|
1064
1202
|
content: "",
|
|
1065
1203
|
error: `Unknown tool: ${name}`
|
|
@@ -1130,7 +1268,7 @@ async function main(args = process.argv.slice(2)) {
|
|
|
1130
1268
|
else await launchTui();
|
|
1131
1269
|
}
|
|
1132
1270
|
async function launchTui(sessionId) {
|
|
1133
|
-
const { renderApp } = await import("./assets/tui-
|
|
1271
|
+
const { renderApp } = await import("./assets/tui-DDbMjcMS.js");
|
|
1134
1272
|
reset();
|
|
1135
1273
|
renderApp(sessionId);
|
|
1136
1274
|
}
|
|
@@ -1146,4 +1284,4 @@ function isEntrypoint(argv1 = process.argv[1]) {
|
|
|
1146
1284
|
if (isEntrypoint()) main();
|
|
1147
1285
|
// v8 ignore stop
|
|
1148
1286
|
//#endregion
|
|
1149
|
-
export {
|
|
1287
|
+
export { WARNING as A, LABEL as B, loadConfig as C, resetSystemMessage as D, saveClipboardImage as E, USER as F, VERSION as G, SAFE as H, PLAN_GENERATION_INSTRUCTION as I, LIST$1 as K, BACK as L, getTheme as M, ASSISTANT as N, withSystemMessage as O, SYSTEM as P, CATALOG as R, streamChat as S, removeClipboardImage as T, APPROVE as U, PLAN as V, REJECT as W, setClearHandler as _, tick as a, listModels as b, appendMessage as c, deleteSessionIfEmpty as d, listSessions as f, reset as g, clear as h, WRITE_TOOLS as i, LIST as j, HEADER_PREFIX as k, createSession as l, updateSessionModel as m, main, READ_TOOLS as n, color as o, loadSession as p, TOOLS as r, write as s, executeTool as t, deleteSession as u, checkHealth as v, saveConfig as w, pullModel as x, deleteModel as y, AUTO as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "code-ollama",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.1",
|
|
4
4
|
"description": "Ollama coding agent that runs in your terminal",
|
|
5
5
|
"author": "Mark <mark@remarkablemark.org> (https://remarkablemark.org)",
|
|
6
6
|
"type": "module",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
12
|
"build": "vite build",
|
|
13
|
-
"start": "tsx
|
|
13
|
+
"start": "tsx src/cli.ts",
|
|
14
14
|
"clean": "rm -rf coverage dist docs",
|
|
15
15
|
"lint": "eslint .",
|
|
16
16
|
"lint:fix": "npm run lint -- --fix",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@inkjs/ui": "2.0.0",
|
|
43
|
-
"@shikijs/cli": "4.0
|
|
43
|
+
"@shikijs/cli": "4.1.0",
|
|
44
44
|
"cac": "7.0.0",
|
|
45
45
|
"ink": "7.0.3",
|
|
46
46
|
"marked": "15.0.12",
|
|
@@ -53,9 +53,9 @@
|
|
|
53
53
|
"@commitlint/cli": "21.0.1",
|
|
54
54
|
"@commitlint/config-conventional": "21.0.1",
|
|
55
55
|
"@eslint/js": "10.0.1",
|
|
56
|
-
"@types/node": "25.9.
|
|
57
|
-
"@types/react": "19.2.
|
|
58
|
-
"@vitest/coverage-v8": "4.1.
|
|
56
|
+
"@types/node": "25.9.1",
|
|
57
|
+
"@types/react": "19.2.15",
|
|
58
|
+
"@vitest/coverage-v8": "4.1.7",
|
|
59
59
|
"eslint": "10.4.0",
|
|
60
60
|
"eslint-plugin-prettier": "5.5.5",
|
|
61
61
|
"eslint-plugin-simple-import-sort": "13.0.0",
|
|
@@ -65,11 +65,11 @@
|
|
|
65
65
|
"lint-staged": "17.0.5",
|
|
66
66
|
"prettier": "3.8.3",
|
|
67
67
|
"publint": "0.3.21",
|
|
68
|
-
"tsx": "4.22.
|
|
68
|
+
"tsx": "4.22.3",
|
|
69
69
|
"typescript": "6.0.3",
|
|
70
70
|
"typescript-eslint": "8.59.4",
|
|
71
|
-
"vite": "8.0.
|
|
72
|
-
"vitest": "4.1.
|
|
71
|
+
"vite": "8.0.14",
|
|
72
|
+
"vitest": "4.1.7"
|
|
73
73
|
},
|
|
74
74
|
"files": [
|
|
75
75
|
"dist/"
|