code-ollama 0.6.0 → 0.7.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.
@@ -4,17 +4,24 @@ import { join, relative } from "node:path";
4
4
  import { homedir } from "node:os";
5
5
  import { exec } from "node:child_process";
6
6
  import { Box, Text, render, useApp, useInput } from "ink";
7
- import { memo, useCallback, useEffect, useMemo, useState } from "react";
7
+ import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
8
8
  import { Select, Spinner, TextInput } from "@inkjs/ui";
9
9
  import { jsx, jsxs } from "react/jsx-runtime";
10
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
- }];
11
+ var LIST = [
12
+ {
13
+ name: "/clear",
14
+ description: "clear the current session"
15
+ },
16
+ {
17
+ name: "/model",
18
+ description: "switch the model"
19
+ },
20
+ {
21
+ name: "/exit",
22
+ description: "exit the application"
23
+ }
24
+ ];
18
25
  //#endregion
19
26
  //#region src/constants/decision.ts
20
27
  var APPROVE = "approve";
@@ -298,7 +305,7 @@ async function listProjectFiles(rootDir) {
298
305
  return listProjectFilesFallback(rootDir);
299
306
  }
300
307
  }
301
- function FileSuggestions({ input, isDisabled = false, onSelect }) {
308
+ function FileSuggestions({ input, isDisabled = false, onChange, onSelect }) {
302
309
  const [filePaths, setFilePaths] = useState([]);
303
310
  const [focusedIndex, setFocusedIndex] = useState(0);
304
311
  useEffect(() => {
@@ -323,6 +330,20 @@ function FileSuggestions({ input, isDisabled = false, onSelect }) {
323
330
  }
324
331
  setFocusedIndex((currentIndex) => Math.min(currentIndex, options.length - 1));
325
332
  }, [options]);
333
+ useEffect(() => {
334
+ if (!onChange) return;
335
+ if (!mentionMatch || !options.length) {
336
+ onChange(null);
337
+ return;
338
+ }
339
+ onChange(buildNextInput(input, options[focusedIndex]));
340
+ }, [
341
+ focusedIndex,
342
+ input,
343
+ mentionMatch,
344
+ onChange,
345
+ options
346
+ ]);
326
347
  useInput((_, key) => {
327
348
  if (isDisabled || !options.length) return;
328
349
  if (key.downArrow) {
@@ -333,7 +354,7 @@ function FileSuggestions({ input, isDisabled = false, onSelect }) {
333
354
  setFocusedIndex((currentIndex) => Math.max(currentIndex - 1, 0));
334
355
  return;
335
356
  }
336
- if (key.tab) onSelect(buildNextInput(input, options[focusedIndex]));
357
+ if (key.tab || key.return) onSelect(buildNextInput(input, options[focusedIndex]));
337
358
  });
338
359
  if (!mentionMatch || !options.length) return null;
339
360
  const visibleStart = Math.min(Math.max(0, focusedIndex - MAX_VISIBLE_OPTIONS + 1), Math.max(0, options.length - MAX_VISIBLE_OPTIONS));
@@ -352,43 +373,52 @@ function FileSuggestions({ input, isDisabled = false, onSelect }) {
352
373
  }
353
374
  //#endregion
354
375
  //#region src/components/Chat/Input.tsx
355
- function hasActiveMentionQuery(input) {
376
+ function hasFileSuggestionQuery(input) {
356
377
  return /(^|\s)@\S+$/.test(input);
357
378
  }
358
379
  function Input({ isDisabled = false, onSubmit }) {
359
380
  const { exit } = useApp();
360
381
  const [input, setInput] = useState("");
361
382
  const [inputKey, setInputKey] = useState(0);
383
+ const fileSuggestionRef = useRef(null);
362
384
  const remountTextInput = useCallback(() => {
363
385
  setInputKey((key) => key + 1);
364
386
  }, [setInputKey]);
365
- const handleSubmitText = useCallback(async (input) => {
366
- await tick();
367
- if (input.startsWith("/")) return;
387
+ const handleSelectFileSuggestion = useCallback((nextInput) => {
388
+ setInput(nextInput);
389
+ remountTextInput();
390
+ }, [remountTextInput]);
391
+ const handleFileSuggestionChange = useCallback((nextInput) => {
392
+ fileSuggestionRef.current = nextInput;
393
+ }, []);
394
+ const submitAndReset = useCallback((input) => {
368
395
  const trimmedInput = input.trim();
369
396
  if (!trimmedInput) return;
370
397
  onSubmit(trimmedInput);
371
398
  setInput("");
399
+ fileSuggestionRef.current = null;
372
400
  remountTextInput();
373
401
  }, [onSubmit, remountTextInput]);
402
+ const showCommandMenu = input.startsWith("/");
403
+ const showFileSuggestions = !showCommandMenu && hasFileSuggestionQuery(input);
404
+ const handleSubmitText = useCallback(async (input) => {
405
+ await tick();
406
+ if (input.startsWith("/")) return;
407
+ if (hasFileSuggestionQuery(input)) {
408
+ if (fileSuggestionRef.current) handleSelectFileSuggestion(fileSuggestionRef.current);
409
+ return;
410
+ }
411
+ submitAndReset(input);
412
+ }, [handleSelectFileSuggestion, submitAndReset]);
374
413
  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]);
414
+ if (LIST.find(({ name }) => name === input)) submitAndReset(input);
415
+ }, [submitAndReset]);
384
416
  useInput((_input, key) => {
385
417
  if (key.ctrl && _input === "c") if (input) {
386
418
  setInput("");
387
419
  remountTextInput();
388
420
  } else exit();
389
421
  });
390
- const showCommandMenu = input.startsWith("/");
391
- const showFileSuggestions = !showCommandMenu && hasActiveMentionQuery(input);
392
422
  return /* @__PURE__ */ jsxs(Box, {
393
423
  flexDirection: "column",
394
424
  children: [
@@ -406,6 +436,7 @@ function Input({ isDisabled = false, onSubmit }) {
406
436
  showFileSuggestions && /* @__PURE__ */ jsx(FileSuggestions, {
407
437
  input,
408
438
  isDisabled,
439
+ onChange: handleFileSuggestionChange,
409
440
  onSelect: handleSelectFileSuggestion
410
441
  })
411
442
  ]
@@ -843,6 +874,7 @@ function ModelPicker({ currentModel, onSelect, onClose }) {
843
874
  //#endregion
844
875
  //#region src/components/App.tsx
845
876
  function App() {
877
+ const { exit } = useApp();
846
878
  const [model, setModel] = useState(() => loadConfig().model);
847
879
  const [picking, setPicking] = useState(false);
848
880
  const [mode, setMode] = useState(NAME.SAFE);
@@ -857,8 +889,11 @@ function App() {
857
889
  setPicking(false);
858
890
  setSessionId((sessionId) => sessionId + 1);
859
891
  break;
892
+ case "/exit":
893
+ exit();
894
+ break;
860
895
  }
861
- }, []);
896
+ }, [exit]);
862
897
  const handleSelect = useCallback((selected) => {
863
898
  setModel(selected);
864
899
  saveConfig({ model: selected });
package/dist/cli.js CHANGED
@@ -8,7 +8,7 @@ import { exec } from "node:child_process";
8
8
  import { promisify } from "node:util";
9
9
  //#endregion
10
10
  //#region src/constants/package.ts
11
- var VERSION = "0.6.0";
11
+ var VERSION = "0.7.0";
12
12
  //#endregion
13
13
  //#region src/constants/prompt.ts
14
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
@@ -502,7 +502,7 @@ async function processRunStream(messages, model) {
502
502
  }
503
503
  async function main(args = process.argv.slice(2)) {
504
504
  if (!args.length) {
505
- const { renderApp } = await import("./assets/tui-UfyDivSA.js");
505
+ const { renderApp } = await import("./assets/tui-CDaKDOEJ.js");
506
506
  process.stdout.write("\x1Bc");
507
507
  renderApp();
508
508
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-ollama",
3
- "version": "0.6.0",
3
+ "version": "0.7.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",
@@ -46,9 +46,9 @@
46
46
  "react": "19.2.6"
47
47
  },
48
48
  "devDependencies": {
49
- "@commitlint/cli": "20.5.3",
50
- "@commitlint/config-conventional": "20.5.3",
51
- "@eslint/compat": "2.0.5",
49
+ "@commitlint/cli": "21.0.0",
50
+ "@commitlint/config-conventional": "21.0.0",
51
+ "@eslint/config-helpers": "0.6.0",
52
52
  "@eslint/js": "10.0.1",
53
53
  "@types/node": "25.6.2",
54
54
  "@types/react": "19.2.14",
@@ -59,9 +59,9 @@
59
59
  "globals": "17.6.0",
60
60
  "husky": "9.1.7",
61
61
  "ink-testing-library": "4.0.0",
62
- "lint-staged": "17.0.2",
62
+ "lint-staged": "17.0.3",
63
63
  "prettier": "3.8.3",
64
- "publint": "0.3.19",
64
+ "publint": "0.3.20",
65
65
  "tsx": "4.21.0",
66
66
  "typescript": "6.0.3",
67
67
  "typescript-eslint": "8.59.2",