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 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
  [![NPM](https://nodei.co/npm/code-ollama.svg)](https://www.npmjs.com/package/code-ollama)
@@ -1,9 +1,40 @@
1
- import { _ as NAME, a as setClearHandler, b as NAMES, c as loadConfig, d as withSystemMessage, f as HEADER_PREFIX, g as LABEL, h as VERSION, i as executeTool, l as saveConfig, m as PLAN_GENERATION_INSTRUCTION, n as READ_ONLY_TOOLS, o as listModels, p as ROLE, r as TOOLS, s as streamChat, t as DANGEROUS_TOOLS, u as resetSystemMessage, v as APPROVE, y as REJECT } from "../cli.js";
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 { Box, Text, render, useInput } from "ink";
4
- import { memo, useCallback, useEffect, useState } from "react";
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(Text, {
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(Text, {
144
- dimColor: true,
145
- children: "Select approval action (↑↓ + Enter to confirm, Esc to reject)"
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 [resetKey, setResetKey] = useState(0);
159
- const handleSubmit = useCallback((input) => {
160
- const trimmed = input.trim();
161
- if (!trimmed) return;
162
- onSubmit(trimmed);
163
- setResetKey((key) => key + 1);
164
- }, [onSubmit]);
165
- return /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Text, { children: "> " }), /* @__PURE__ */ jsx(TextInput, {
166
- isDisabled,
167
- suggestions: NAMES,
168
- onSubmit: handleSubmit
169
- }, resetKey)] });
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 = DANGEROUS_TOOLS.has(toolCall.function.name);
494
+ const requiresApproval = WRITE_TOOLS.has(toolCall.function.name);
252
495
  // v8 ignore start
253
- const allowedTools = executionMode === NAME.PLAN ? READ_ONLY_TOOLS : void 0;
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) => READ_ONLY_TOOLS.has(tool.function.name));
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 (!READ_ONLY_TOOLS.has(toolCall.function.name)) {
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: READ_ONLY_TOOLS });
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(Text, {
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.4.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 READ_ONLY_TOOLS = new Set([
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 DANGEROUS_TOOLS = new Set([
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 === 0) return { content: "No matches found" };
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-BLJeczya.js");
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 { NAME$1 as _, setClearHandler as a, NAMES as b, loadConfig as c, withSystemMessage as d, HEADER_PREFIX as f, LABEL as g, VERSION as h, executeTool as i, saveConfig as l, PLAN_GENERATION_INSTRUCTION as m, main, READ_ONLY_TOOLS as n, listModels as o, ROLE as p, TOOLS as r, streamChat as s, DANGEROUS_TOOLS as t, resetSystemMessage as u, APPROVE as v, REJECT as y };
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.4.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.0",
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.10",
68
+ "vite": "8.0.11",
69
69
  "vitest": "4.1.5"
70
70
  },
71
71
  "files": [