code-ollama 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/assets/{tui-BLJeczya.js → tui-UfyDivSA.js} +275 -31
- package/dist/cli.js +9 -32
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
> [!NOTE]
|
|
2
2
|
> TUI is under active development. APIs may change.
|
|
3
3
|
|
|
4
|
+
<p align="center">
|
|
5
|
+
<img alt="Ollama" height="200" src="https://github.com/ai-action/assets/blob/master/logos/ollama.svg?raw=true">
|
|
6
|
+
</p>
|
|
7
|
+
|
|
4
8
|
# Code Ollama
|
|
5
9
|
|
|
6
10
|
[](https://www.npmjs.com/package/code-ollama)
|
|
@@ -1,9 +1,40 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as tick, c as streamChat, d as resetSystemMessage, f as withSystemMessage, h as VERSION, i as executeTool, l as loadConfig, m as PLAN_GENERATION_INSTRUCTION, n as TOOLS, o as setClearHandler, p as ROLE, r as WRITE_TOOLS, s as listModels, t as READ_TOOLS, u as saveConfig } from "../cli.js";
|
|
2
|
+
import { readdirSync } from "node:fs";
|
|
3
|
+
import { join, relative } from "node:path";
|
|
2
4
|
import { homedir } from "node:os";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
+
import { exec } from "node:child_process";
|
|
6
|
+
import { Box, Text, render, useApp, useInput } from "ink";
|
|
7
|
+
import { memo, useCallback, useEffect, useMemo, useState } from "react";
|
|
5
8
|
import { Select, Spinner, TextInput } from "@inkjs/ui";
|
|
6
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
//#region src/constants/command.ts
|
|
11
|
+
var LIST = [{
|
|
12
|
+
name: "/clear",
|
|
13
|
+
description: "clear the current session"
|
|
14
|
+
}, {
|
|
15
|
+
name: "/model",
|
|
16
|
+
description: "switch the model"
|
|
17
|
+
}];
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/constants/decision.ts
|
|
20
|
+
var APPROVE = "approve";
|
|
21
|
+
var REJECT = "reject";
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/constants/mode.ts
|
|
24
|
+
var NAME = {
|
|
25
|
+
SAFE: "safe",
|
|
26
|
+
AUTO: "auto",
|
|
27
|
+
PLAN: "plan"
|
|
28
|
+
};
|
|
29
|
+
var LABEL = {
|
|
30
|
+
safe: "Safe",
|
|
31
|
+
auto: "Auto",
|
|
32
|
+
plan: "Plan"
|
|
33
|
+
};
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/constants/ui.ts
|
|
36
|
+
var HEADER_PREFIX = "🦙";
|
|
37
|
+
//#endregion
|
|
7
38
|
//#region src/components/Messages.tsx
|
|
8
39
|
function getMessageColor(role) {
|
|
9
40
|
switch (role) {
|
|
@@ -48,6 +79,45 @@ function SelectPrompt({ children, onEscape, ...selectProps }) {
|
|
|
48
79
|
children: [children, /* @__PURE__ */ jsx(Select, { ...selectProps })]
|
|
49
80
|
});
|
|
50
81
|
}
|
|
82
|
+
function SelectPromptHint({ message = "Select option", escapeLabel = "cancel" }) {
|
|
83
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
84
|
+
flexDirection: "row",
|
|
85
|
+
children: [
|
|
86
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
87
|
+
dimColor: true,
|
|
88
|
+
children: [message, " ("]
|
|
89
|
+
}),
|
|
90
|
+
/* @__PURE__ */ jsx(Text, {
|
|
91
|
+
bold: true,
|
|
92
|
+
children: "↑↓"
|
|
93
|
+
}),
|
|
94
|
+
/* @__PURE__ */ jsx(Text, {
|
|
95
|
+
dimColor: true,
|
|
96
|
+
children: " + "
|
|
97
|
+
}),
|
|
98
|
+
/* @__PURE__ */ jsx(Text, {
|
|
99
|
+
bold: true,
|
|
100
|
+
children: "Enter"
|
|
101
|
+
}),
|
|
102
|
+
/* @__PURE__ */ jsx(Text, {
|
|
103
|
+
dimColor: true,
|
|
104
|
+
children: " to confirm, "
|
|
105
|
+
}),
|
|
106
|
+
/* @__PURE__ */ jsx(Text, {
|
|
107
|
+
bold: true,
|
|
108
|
+
children: "Esc"
|
|
109
|
+
}),
|
|
110
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
111
|
+
dimColor: true,
|
|
112
|
+
children: [
|
|
113
|
+
" to ",
|
|
114
|
+
escapeLabel,
|
|
115
|
+
")"
|
|
116
|
+
]
|
|
117
|
+
})
|
|
118
|
+
]
|
|
119
|
+
});
|
|
120
|
+
}
|
|
51
121
|
//#endregion
|
|
52
122
|
//#region src/components/PlanApproval.tsx
|
|
53
123
|
var options$1 = [
|
|
@@ -86,10 +156,7 @@ function PlanApproval({ planContent, onModeChange }) {
|
|
|
86
156
|
marginY: 1,
|
|
87
157
|
children: /* @__PURE__ */ jsx(Text, { children: planContent })
|
|
88
158
|
}),
|
|
89
|
-
/* @__PURE__ */ jsx(
|
|
90
|
-
dimColor: true,
|
|
91
|
-
children: "Select execution mode (↑↓ + Enter to confirm, Esc to cancel)"
|
|
92
|
-
})
|
|
159
|
+
/* @__PURE__ */ jsx(SelectPromptHint, { message: "Select execution mode" })
|
|
93
160
|
]
|
|
94
161
|
})
|
|
95
162
|
});
|
|
@@ -140,9 +207,9 @@ function ToolApproval({ toolCall, onDecision }) {
|
|
|
140
207
|
args
|
|
141
208
|
] })]
|
|
142
209
|
}),
|
|
143
|
-
/* @__PURE__ */ jsx(
|
|
144
|
-
|
|
145
|
-
|
|
210
|
+
/* @__PURE__ */ jsx(SelectPromptHint, {
|
|
211
|
+
message: "Select approval action",
|
|
212
|
+
escapeLabel: "reject"
|
|
146
213
|
})
|
|
147
214
|
]
|
|
148
215
|
});
|
|
@@ -153,20 +220,196 @@ var ACTION_NOT_PERFORMED = "The requested action was NOT performed";
|
|
|
153
220
|
var PLAN_CHECKLIST_REMINDER = "Then display the execution plan as an unchecked Markdown checklist only";
|
|
154
221
|
var PLAN_EXECUTION_REMINDER = "Do not claim success and do not call write_file or run_shell until the user approves execution";
|
|
155
222
|
//#endregion
|
|
223
|
+
//#region src/components/Chat/CommandMenu.tsx
|
|
224
|
+
function getMatchingCommands(input) {
|
|
225
|
+
const normalizedInput = input.trim().toLowerCase();
|
|
226
|
+
if (!normalizedInput.startsWith("/")) return [];
|
|
227
|
+
return LIST.filter(({ name }) => name.toLowerCase().startsWith(normalizedInput)).map(({ name, description }) => ({
|
|
228
|
+
label: `${name} - ${description}`,
|
|
229
|
+
value: name
|
|
230
|
+
}));
|
|
231
|
+
}
|
|
232
|
+
function CommandMenu({ input, onSubmit }) {
|
|
233
|
+
const commandOptions = useMemo(() => getMatchingCommands(input), [input]);
|
|
234
|
+
if (!commandOptions.length) return null;
|
|
235
|
+
return /* @__PURE__ */ jsx(SelectPrompt, {
|
|
236
|
+
highlightText: input,
|
|
237
|
+
onChange: onSubmit,
|
|
238
|
+
options: commandOptions
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
//#endregion
|
|
242
|
+
//#region src/components/Chat/FileSuggestions.tsx
|
|
243
|
+
var MAX_VISIBLE_OPTIONS = 5;
|
|
244
|
+
var MENTION_PATTERN = /(^|\s)@(\S+)$/;
|
|
245
|
+
var RIPGREP_MAX_BUFFER = 10 * 1024 * 1024;
|
|
246
|
+
function normalizePath(filePath) {
|
|
247
|
+
return filePath.replaceAll("\\", "/");
|
|
248
|
+
}
|
|
249
|
+
function getMentionMatch(input) {
|
|
250
|
+
const match = MENTION_PATTERN.exec(input);
|
|
251
|
+
if (!match) return null;
|
|
252
|
+
return {
|
|
253
|
+
prefix: input.slice(0, match.index + match[1].length),
|
|
254
|
+
query: match[2]
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
function buildNextInput(input, filePath) {
|
|
258
|
+
const mentionMatch = getMentionMatch(input);
|
|
259
|
+
// v8 ignore next 3
|
|
260
|
+
if (!mentionMatch) return input;
|
|
261
|
+
return `${mentionMatch.prefix}${filePath} `;
|
|
262
|
+
}
|
|
263
|
+
function listProjectFilesFallback(rootDir) {
|
|
264
|
+
const filePaths = [];
|
|
265
|
+
function walk(currentPath) {
|
|
266
|
+
const entries = readdirSync(currentPath, { withFileTypes: true });
|
|
267
|
+
for (const entry of entries) {
|
|
268
|
+
if (entry.name === ".git") continue;
|
|
269
|
+
const fullPath = join(currentPath, entry.name);
|
|
270
|
+
if (entry.isDirectory()) {
|
|
271
|
+
walk(fullPath);
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
if (entry.isFile()) filePaths.push(normalizePath(relative(rootDir, fullPath)));
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
walk(rootDir);
|
|
278
|
+
return filePaths.sort((left, right) => left.localeCompare(right));
|
|
279
|
+
}
|
|
280
|
+
function listProjectFilesWithRipgrep(rootDir) {
|
|
281
|
+
return new Promise((resolve, reject) => {
|
|
282
|
+
exec("rg --files --hidden -g \"!**/.git/**\"", {
|
|
283
|
+
cwd: rootDir,
|
|
284
|
+
maxBuffer: RIPGREP_MAX_BUFFER
|
|
285
|
+
}, (error, stdout) => {
|
|
286
|
+
if (error) {
|
|
287
|
+
reject(error);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
resolve(stdout.split("\n").map((line) => line.trim()).filter(Boolean).map(normalizePath).sort((left, right) => left.localeCompare(right)));
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
async function listProjectFiles(rootDir) {
|
|
295
|
+
try {
|
|
296
|
+
return await listProjectFilesWithRipgrep(rootDir);
|
|
297
|
+
} catch {
|
|
298
|
+
return listProjectFilesFallback(rootDir);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
function FileSuggestions({ input, isDisabled = false, onSelect }) {
|
|
302
|
+
const [filePaths, setFilePaths] = useState([]);
|
|
303
|
+
const [focusedIndex, setFocusedIndex] = useState(0);
|
|
304
|
+
useEffect(() => {
|
|
305
|
+
async function loadProjectFiles() {
|
|
306
|
+
setFilePaths(await listProjectFiles(process.cwd()));
|
|
307
|
+
}
|
|
308
|
+
loadProjectFiles();
|
|
309
|
+
}, []);
|
|
310
|
+
const mentionMatch = getMentionMatch(input);
|
|
311
|
+
const options = useMemo(() => {
|
|
312
|
+
if (!mentionMatch) return [];
|
|
313
|
+
const normalizedQuery = mentionMatch.query.toLowerCase();
|
|
314
|
+
return filePaths.filter((filePath) => filePath.toLowerCase().includes(normalizedQuery));
|
|
315
|
+
}, [filePaths, mentionMatch]);
|
|
316
|
+
useEffect(() => {
|
|
317
|
+
setFocusedIndex(0);
|
|
318
|
+
}, [input]);
|
|
319
|
+
useEffect(() => {
|
|
320
|
+
if (!options.length) {
|
|
321
|
+
setFocusedIndex(0);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
setFocusedIndex((currentIndex) => Math.min(currentIndex, options.length - 1));
|
|
325
|
+
}, [options]);
|
|
326
|
+
useInput((_, key) => {
|
|
327
|
+
if (isDisabled || !options.length) return;
|
|
328
|
+
if (key.downArrow) {
|
|
329
|
+
setFocusedIndex((currentIndex) => Math.min(currentIndex + 1, options.length - 1));
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
if (key.upArrow) {
|
|
333
|
+
setFocusedIndex((currentIndex) => Math.max(currentIndex - 1, 0));
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
if (key.tab) onSelect(buildNextInput(input, options[focusedIndex]));
|
|
337
|
+
});
|
|
338
|
+
if (!mentionMatch || !options.length) return null;
|
|
339
|
+
const visibleStart = Math.min(Math.max(0, focusedIndex - MAX_VISIBLE_OPTIONS + 1), Math.max(0, options.length - MAX_VISIBLE_OPTIONS));
|
|
340
|
+
return /* @__PURE__ */ jsx(Box, {
|
|
341
|
+
flexDirection: "column",
|
|
342
|
+
children: options.slice(visibleStart, visibleStart + MAX_VISIBLE_OPTIONS).map((option, index) => {
|
|
343
|
+
return /* @__PURE__ */ jsx(Box, {
|
|
344
|
+
marginLeft: 2,
|
|
345
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
346
|
+
color: visibleStart + index === focusedIndex ? "cyan" : void 0,
|
|
347
|
+
children: option
|
|
348
|
+
})
|
|
349
|
+
}, option);
|
|
350
|
+
})
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
//#endregion
|
|
156
354
|
//#region src/components/Chat/Input.tsx
|
|
355
|
+
function hasActiveMentionQuery(input) {
|
|
356
|
+
return /(^|\s)@\S+$/.test(input);
|
|
357
|
+
}
|
|
157
358
|
function Input({ isDisabled = false, onSubmit }) {
|
|
158
|
-
const
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
359
|
+
const { exit } = useApp();
|
|
360
|
+
const [input, setInput] = useState("");
|
|
361
|
+
const [inputKey, setInputKey] = useState(0);
|
|
362
|
+
const remountTextInput = useCallback(() => {
|
|
363
|
+
setInputKey((key) => key + 1);
|
|
364
|
+
}, [setInputKey]);
|
|
365
|
+
const handleSubmitText = useCallback(async (input) => {
|
|
366
|
+
await tick();
|
|
367
|
+
if (input.startsWith("/")) return;
|
|
368
|
+
const trimmedInput = input.trim();
|
|
369
|
+
if (!trimmedInput) return;
|
|
370
|
+
onSubmit(trimmedInput);
|
|
371
|
+
setInput("");
|
|
372
|
+
remountTextInput();
|
|
373
|
+
}, [onSubmit, remountTextInput]);
|
|
374
|
+
const handleSubmitCommand = useCallback((input) => {
|
|
375
|
+
if (!LIST.find(({ name }) => name === input)) return;
|
|
376
|
+
onSubmit(input);
|
|
377
|
+
setInput("");
|
|
378
|
+
remountTextInput();
|
|
379
|
+
}, [onSubmit, remountTextInput]);
|
|
380
|
+
const handleSelectFileSuggestion = useCallback((nextInput) => {
|
|
381
|
+
setInput(nextInput);
|
|
382
|
+
remountTextInput();
|
|
383
|
+
}, [remountTextInput]);
|
|
384
|
+
useInput((_input, key) => {
|
|
385
|
+
if (key.ctrl && _input === "c") if (input) {
|
|
386
|
+
setInput("");
|
|
387
|
+
remountTextInput();
|
|
388
|
+
} else exit();
|
|
389
|
+
});
|
|
390
|
+
const showCommandMenu = input.startsWith("/");
|
|
391
|
+
const showFileSuggestions = !showCommandMenu && hasActiveMentionQuery(input);
|
|
392
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
393
|
+
flexDirection: "column",
|
|
394
|
+
children: [
|
|
395
|
+
/* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Text, { children: "> " }), /* @__PURE__ */ jsx(TextInput, {
|
|
396
|
+
defaultValue: input,
|
|
397
|
+
isDisabled,
|
|
398
|
+
onChange: setInput,
|
|
399
|
+
onSubmit: handleSubmitText,
|
|
400
|
+
placeholder: "Ask anything... (/ commands, @ files)"
|
|
401
|
+
}, inputKey)] }),
|
|
402
|
+
showCommandMenu && /* @__PURE__ */ jsx(CommandMenu, {
|
|
403
|
+
input,
|
|
404
|
+
onSubmit: handleSubmitCommand
|
|
405
|
+
}),
|
|
406
|
+
showFileSuggestions && /* @__PURE__ */ jsx(FileSuggestions, {
|
|
407
|
+
input,
|
|
408
|
+
isDisabled,
|
|
409
|
+
onSelect: handleSelectFileSuggestion
|
|
410
|
+
})
|
|
411
|
+
]
|
|
412
|
+
});
|
|
170
413
|
}
|
|
171
414
|
//#endregion
|
|
172
415
|
//#region src/components/Chat/plan.ts
|
|
@@ -248,9 +491,9 @@ function Chat({ model, onCommand, mode, onModeChange, sessionId }) {
|
|
|
248
491
|
assistantMessage.content += chunk.content;
|
|
249
492
|
setStreamingMessage({ ...assistantMessage });
|
|
250
493
|
} else if (chunk.type === "tool_calls") for (const toolCall of chunk.tool_calls) {
|
|
251
|
-
const requiresApproval =
|
|
494
|
+
const requiresApproval = WRITE_TOOLS.has(toolCall.function.name);
|
|
252
495
|
// v8 ignore start
|
|
253
|
-
const allowedTools = executionMode === NAME.PLAN ?
|
|
496
|
+
const allowedTools = executionMode === NAME.PLAN ? READ_TOOLS : void 0;
|
|
254
497
|
// v8 ignore stop
|
|
255
498
|
const updatedMessages = commitAssistantMessage();
|
|
256
499
|
if (executionMode === NAME.SAFE && requiresApproval) {
|
|
@@ -267,6 +510,7 @@ function Chat({ model, onCommand, mode, onModeChange, sessionId }) {
|
|
|
267
510
|
}
|
|
268
511
|
commitAssistantMessage();
|
|
269
512
|
} catch (error) {
|
|
513
|
+
// v8 ignore next
|
|
270
514
|
assistantMessage.content = `Error: ${error instanceof Error ? error.message : String(error)}`;
|
|
271
515
|
commitAssistantMessage();
|
|
272
516
|
} finally {
|
|
@@ -305,20 +549,20 @@ function Chat({ model, onCommand, mode, onModeChange, sessionId }) {
|
|
|
305
549
|
};
|
|
306
550
|
setStreamingMessage(assistantMessage);
|
|
307
551
|
try {
|
|
308
|
-
const readOnlyTools = TOOLS.filter((tool) =>
|
|
552
|
+
const readOnlyTools = TOOLS.filter((tool) => READ_TOOLS.has(tool.function.name));
|
|
309
553
|
for await (const chunk of streamChat(withSystemMessage(currentMessages), model, readOnlyTools)) if (chunk.type === "content") {
|
|
310
554
|
assistantMessage.content += chunk.content;
|
|
311
555
|
setStreamingMessage({ ...assistantMessage });
|
|
312
556
|
} else if (chunk.type === "tool_calls") for (const toolCall of chunk.tool_calls) {
|
|
313
557
|
const updatedMessages = commitAssistantMessage();
|
|
314
|
-
if (!
|
|
558
|
+
if (!READ_TOOLS.has(toolCall.function.name)) {
|
|
315
559
|
const correctionMessage = buildPlanModeCorrectionMessage(toolCall.function.name);
|
|
316
560
|
const newMessages = [...updatedMessages, correctionMessage];
|
|
317
561
|
setMessages(newMessages);
|
|
318
562
|
await processStreamReadOnly(newMessages);
|
|
319
563
|
return;
|
|
320
564
|
}
|
|
321
|
-
const result = await executeTool(toolCall.function.name, toolCall.function.arguments, { allowedTools:
|
|
565
|
+
const result = await executeTool(toolCall.function.name, toolCall.function.arguments, { allowedTools: READ_TOOLS });
|
|
322
566
|
const toolResultMessage = buildToolResultMessage(toolCall.function.name, result);
|
|
323
567
|
const newMessages = [...updatedMessages, toolResultMessage];
|
|
324
568
|
setMessages(newMessages);
|
|
@@ -342,6 +586,7 @@ function Chat({ model, onCommand, mode, onModeChange, sessionId }) {
|
|
|
342
586
|
setStreamingMessage({ ...planAssistantMessage });
|
|
343
587
|
}
|
|
344
588
|
} catch (error) {
|
|
589
|
+
// v8 ignore next
|
|
345
590
|
planAssistantMessage.content = `Error: ${error instanceof Error ? error.message : String(error)}`;
|
|
346
591
|
setMessages([...planMessages, { ...planAssistantMessage }]);
|
|
347
592
|
setStreamingMessage(null);
|
|
@@ -357,6 +602,7 @@ function Chat({ model, onCommand, mode, onModeChange, sessionId }) {
|
|
|
357
602
|
});
|
|
358
603
|
setIsLoading(false);
|
|
359
604
|
} catch (error) {
|
|
605
|
+
// v8 ignore next
|
|
360
606
|
assistantMessage.content = `Error: ${error instanceof Error ? error.message : String(error)}`;
|
|
361
607
|
commitAssistantMessage();
|
|
362
608
|
} finally {
|
|
@@ -591,10 +837,7 @@ function ModelPicker({ currentModel, onSelect, onClose }) {
|
|
|
591
837
|
defaultValue: currentModel,
|
|
592
838
|
onChange: onSelect,
|
|
593
839
|
onEscape: onClose,
|
|
594
|
-
children: /* @__PURE__ */ jsx(
|
|
595
|
-
dimColor: true,
|
|
596
|
-
children: "Select a model (↑↓ + Enter to confirm, Esc to cancel)"
|
|
597
|
-
})
|
|
840
|
+
children: /* @__PURE__ */ jsx(SelectPromptHint, { message: "Select a model" })
|
|
598
841
|
});
|
|
599
842
|
}
|
|
600
843
|
//#endregion
|
|
@@ -670,6 +913,7 @@ function App() {
|
|
|
670
913
|
function renderApp() {
|
|
671
914
|
const tree = /* @__PURE__ */ jsx(App, {});
|
|
672
915
|
const app = render(tree, {
|
|
916
|
+
exitOnCtrlC: false,
|
|
673
917
|
incrementalRendering: true,
|
|
674
918
|
maxFps: 60
|
|
675
919
|
});
|
package/dist/cli.js
CHANGED
|
@@ -6,32 +6,9 @@ import { homedir } from "node:os";
|
|
|
6
6
|
import { Ollama } from "ollama";
|
|
7
7
|
import { exec } from "node:child_process";
|
|
8
8
|
import { promisify } from "node:util";
|
|
9
|
-
var NAMES = [{
|
|
10
|
-
name: "/clear",
|
|
11
|
-
description: "clear the current session"
|
|
12
|
-
}, {
|
|
13
|
-
name: "/model",
|
|
14
|
-
description: "switch the model"
|
|
15
|
-
}].map(({ name }) => name);
|
|
16
|
-
//#endregion
|
|
17
|
-
//#region src/constants/decision.ts
|
|
18
|
-
var APPROVE = "approve";
|
|
19
|
-
var REJECT = "reject";
|
|
20
|
-
//#endregion
|
|
21
|
-
//#region src/constants/mode.ts
|
|
22
|
-
var NAME$1 = {
|
|
23
|
-
SAFE: "safe",
|
|
24
|
-
AUTO: "auto",
|
|
25
|
-
PLAN: "plan"
|
|
26
|
-
};
|
|
27
|
-
var LABEL = {
|
|
28
|
-
safe: "Safe",
|
|
29
|
-
auto: "Auto",
|
|
30
|
-
plan: "Plan"
|
|
31
|
-
};
|
|
32
9
|
//#endregion
|
|
33
10
|
//#region src/constants/package.ts
|
|
34
|
-
var VERSION = "0.
|
|
11
|
+
var VERSION = "0.6.0";
|
|
35
12
|
//#endregion
|
|
36
13
|
//#region src/constants/prompt.ts
|
|
37
14
|
var BASE_SYSTEM_PROMPT = `You are a coding assistant that helps users write, edit, and understand code. You have access to tools for reading files, writing files, running shell commands, and searching code
|
|
@@ -90,9 +67,6 @@ var NAME = {
|
|
|
90
67
|
VIEW_RANGE: "view_range"
|
|
91
68
|
};
|
|
92
69
|
//#endregion
|
|
93
|
-
//#region src/constants/ui.ts
|
|
94
|
-
var HEADER_PREFIX = "🦙";
|
|
95
|
-
//#endregion
|
|
96
70
|
//#region src/utils/agents.ts
|
|
97
71
|
var AGENTS_FILE = "AGENTS.md";
|
|
98
72
|
function loadAgentsContent() {
|
|
@@ -184,6 +158,9 @@ async function listModels() {
|
|
|
184
158
|
}
|
|
185
159
|
function setClearHandler(handler) {}
|
|
186
160
|
//#endregion
|
|
161
|
+
//#region src/utils/time.ts
|
|
162
|
+
var tick = (ms = 0) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
163
|
+
//#endregion
|
|
187
164
|
//#region src/utils/tools.ts
|
|
188
165
|
var execAsync = promisify(exec);
|
|
189
166
|
/**
|
|
@@ -276,13 +253,13 @@ var TOOLS = [
|
|
|
276
253
|
"end"
|
|
277
254
|
])
|
|
278
255
|
];
|
|
279
|
-
var
|
|
256
|
+
var READ_TOOLS = new Set([
|
|
280
257
|
NAME.READ_FILE,
|
|
281
258
|
NAME.LIST_DIR,
|
|
282
259
|
NAME.GREP_SEARCH,
|
|
283
260
|
NAME.VIEW_RANGE
|
|
284
261
|
]);
|
|
285
|
-
var
|
|
262
|
+
var WRITE_TOOLS = new Set([
|
|
286
263
|
NAME.WRITE_FILE,
|
|
287
264
|
NAME.EDIT_FILE,
|
|
288
265
|
NAME.RUN_SHELL
|
|
@@ -442,7 +419,7 @@ async function grepSearch(pattern, dirPath) {
|
|
|
442
419
|
}
|
|
443
420
|
}
|
|
444
421
|
searchDirectory(dirPath);
|
|
445
|
-
if (results.length
|
|
422
|
+
if (!results.length) return { content: "No matches found" };
|
|
446
423
|
return { content: results.join("\n") };
|
|
447
424
|
} catch (error) {
|
|
448
425
|
return {
|
|
@@ -525,7 +502,7 @@ async function processRunStream(messages, model) {
|
|
|
525
502
|
}
|
|
526
503
|
async function main(args = process.argv.slice(2)) {
|
|
527
504
|
if (!args.length) {
|
|
528
|
-
const { renderApp } = await import("./assets/tui-
|
|
505
|
+
const { renderApp } = await import("./assets/tui-UfyDivSA.js");
|
|
529
506
|
process.stdout.write("\x1Bc");
|
|
530
507
|
renderApp();
|
|
531
508
|
return;
|
|
@@ -548,4 +525,4 @@ function isEntrypoint(argv1 = process.argv[1]) {
|
|
|
548
525
|
if (isEntrypoint()) main();
|
|
549
526
|
// v8 ignore stop
|
|
550
527
|
//#endregion
|
|
551
|
-
export {
|
|
528
|
+
export { tick as a, streamChat as c, resetSystemMessage as d, withSystemMessage as f, VERSION as h, executeTool as i, loadConfig as l, PLAN_GENERATION_INSTRUCTION as m, main, TOOLS as n, setClearHandler as o, ROLE as p, WRITE_TOOLS as r, listModels as s, READ_TOOLS as t, saveConfig as u };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "code-ollama",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
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",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@commitlint/config-conventional": "20.5.3",
|
|
51
51
|
"@eslint/compat": "2.0.5",
|
|
52
52
|
"@eslint/js": "10.0.1",
|
|
53
|
-
"@types/node": "25.6.
|
|
53
|
+
"@types/node": "25.6.2",
|
|
54
54
|
"@types/react": "19.2.14",
|
|
55
55
|
"@vitest/coverage-v8": "4.1.5",
|
|
56
56
|
"eslint": "10.3.0",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"tsx": "4.21.0",
|
|
66
66
|
"typescript": "6.0.3",
|
|
67
67
|
"typescript-eslint": "8.59.2",
|
|
68
|
-
"vite": "8.0.
|
|
68
|
+
"vite": "8.0.11",
|
|
69
69
|
"vitest": "4.1.5"
|
|
70
70
|
},
|
|
71
71
|
"files": [
|