code-ollama 0.18.1 → 0.18.2

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.
@@ -1,4 +1,4 @@
1
- import { A as SYSTEM, B as REJECT, C as resetSystemMessage, D as LIST$1, E as WARNING, F as AUTO, H as LIST, I as LABEL, L as PLAN, M as PLAN_GENERATION_INSTRUCTION, N as BACK, O as getTheme, P as CATALOG, R as SAFE, S as saveConfig, T as HEADER_PREFIX, V as VERSION, _ as deleteModel, a as color, b as streamChat, c as createSession, d as listSessions, f as loadSession, g as setClearHandler, h as reset, i as WRITE_TOOLS, j as USER, k as ASSISTANT, l as deleteSession, m as clear, n as READ_TOOLS, o as write, p as updateSessionModel, r as TOOLS, s as appendMessage, t as executeTool, u as deleteSessionIfEmpty, v as listModels, w as withSystemMessage, x as loadConfig, y as pullModel, z as APPROVE } from "../cli.js";
1
+ import { A as ASSISTANT, B as APPROVE, C as saveConfig, D as WARNING, E as HEADER_PREFIX, F as CATALOG, H as VERSION, I as AUTO, L as LABEL, M as USER, N as PLAN_GENERATION_INSTRUCTION, O as LIST$1, P as BACK, R as PLAN, S as loadConfig, T as withSystemMessage, U as LIST, V as REJECT, _ as checkHealth, a as color, b as pullModel, c as createSession, d as listSessions, f as loadSession, g as setClearHandler, h as reset, i as WRITE_TOOLS, j as SYSTEM, k as getTheme, l as deleteSession, m as clear, n as READ_TOOLS, o as write, p as updateSessionModel, r as TOOLS, s as appendMessage, t as executeTool, u as deleteSessionIfEmpty, v as deleteModel, w as resetSystemMessage, x as streamChat, y as listModels, z as SAFE } from "../cli.js";
2
2
  import { readdirSync } from "node:fs";
3
3
  import { homedir } from "node:os";
4
4
  import { join, relative } from "node:path";
@@ -520,9 +520,13 @@ function SelectPrompt({ borderStyle, children, onCancel, ...selectProps }) {
520
520
  }
521
521
  //#endregion
522
522
  //#region src/components/SelectPrompt/SelectPromptHint.tsx
523
+ /**
524
+ * Select prompt hint component that displays:
525
+ * Select option (↑↓ + Enter to confirm, Esc/Ctrl+C to cancel)
526
+ */
523
527
  function SelectPromptHint({ message = "Select option", escapeLabel = "cancel" }) {
524
- return /* @__PURE__ */ jsxs(Box, {
525
- flexDirection: "row",
528
+ return /* @__PURE__ */ jsxs(Text, {
529
+ color: getTheme().colors.secondary,
526
530
  children: [
527
531
  /* @__PURE__ */ jsxs(Text, {
528
532
  dimColor: true,
@@ -548,6 +552,14 @@ function SelectPromptHint({ message = "Select option", escapeLabel = "cancel" })
548
552
  bold: true,
549
553
  children: "Esc"
550
554
  }),
555
+ /* @__PURE__ */ jsx(Text, {
556
+ dimColor: true,
557
+ children: "/"
558
+ }),
559
+ /* @__PURE__ */ jsx(Text, {
560
+ bold: true,
561
+ children: "Ctrl+C"
562
+ }),
551
563
  /* @__PURE__ */ jsxs(Text, {
552
564
  dimColor: true,
553
565
  children: [
@@ -560,7 +572,7 @@ function SelectPromptHint({ message = "Select option", escapeLabel = "cancel" })
560
572
  });
561
573
  }
562
574
  //#endregion
563
- //#region src/components/PlanApproval.tsx
575
+ //#region src/components/PlanApproval/PlanApproval.tsx
564
576
  var options$1 = [
565
577
  {
566
578
  label: "Auto - Execute tools automatically",
@@ -606,7 +618,7 @@ function PlanApproval({ planContent, onModeChange, theme = getTheme() }) {
606
618
  });
607
619
  }
608
620
  //#endregion
609
- //#region src/components/ToolApproval.tsx
621
+ //#region src/components/ToolApproval/ToolApproval.tsx
610
622
  var options = [{
611
623
  label: "Approve tool call",
612
624
  value: APPROVE
@@ -821,7 +833,7 @@ function CommandMenu({ input, onSubmit }) {
821
833
  });
822
834
  }
823
835
  //#endregion
824
- //#region src/components/Suggestions.tsx
836
+ //#region src/components/Suggestions/Suggestions.tsx
825
837
  var DEFAULT_MAX_VISIBLE_OPTIONS = 5;
826
838
  function Suggestions({ options, isDisabled = false, maxVisibleOptions = DEFAULT_MAX_VISIBLE_OPTIONS, resetKey, onHighlight, onSelect }) {
827
839
  const [focusedIndex, setFocusedIndex] = useState(0);
@@ -1532,7 +1544,7 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
1532
1544
  });
1533
1545
  }
1534
1546
  //#endregion
1535
- //#region src/components/Footer.tsx
1547
+ //#region src/components/Footer/Footer.tsx
1536
1548
  function getModeColor(mode, theme) {
1537
1549
  switch (mode) {
1538
1550
  case PLAN: return theme.colors.modePlan;
@@ -1574,7 +1586,7 @@ function Footer({ mode, model, onToggleMode, theme = getTheme() }) {
1574
1586
  });
1575
1587
  }
1576
1588
  //#endregion
1577
- //#region src/components/Header.tsx
1589
+ //#region src/components/Header/Header.tsx
1578
1590
  function abbreviatePath(dir) {
1579
1591
  const home = homedir();
1580
1592
  return dir.startsWith(home) ? `~${dir.slice(home.length)}` : dir;
@@ -1813,11 +1825,15 @@ function ModelCustomDownloadView({ downloadDraft, notice, theme, onDraftChange,
1813
1825
  onSelect: onSelectSuggestion
1814
1826
  }),
1815
1827
  renderNotice(),
1816
- /* @__PURE__ */ jsx(Text, {
1817
- color: theme.colors.secondary,
1818
- dimColor: true,
1819
- children: "Press Enter to download, Esc or Ctrl+C to go back."
1820
- })
1828
+ /* @__PURE__ */ jsxs(Text, { children: [
1829
+ /* @__PURE__ */ jsx(Text, {
1830
+ color: theme.colors.secondary,
1831
+ dimColor: true,
1832
+ children: "Press Enter to download."
1833
+ }),
1834
+ " ",
1835
+ /* @__PURE__ */ jsx(ExitHint, {})
1836
+ ] })
1821
1837
  ]
1822
1838
  });
1823
1839
  }
@@ -2017,6 +2033,10 @@ function ModelManager({ currentModel, onSelect, onClose, theme = getTheme() }) {
2017
2033
  useInput((input, key) => {
2018
2034
  const isEscape = key.escape || input === "\x1B\x1B";
2019
2035
  const isCtrlC = key.ctrl && input === "c" || input === "";
2036
+ if (loadError && view !== View.Menu && (isEscape || isCtrlC)) {
2037
+ handleBackToMenu();
2038
+ return;
2039
+ }
2020
2040
  if (view === View.CustomDownload && (isEscape || isCtrlC)) {
2021
2041
  setNotice(null);
2022
2042
  setHighlightedSuggestion(null);
@@ -2167,17 +2187,10 @@ function ModelManager({ currentModel, onSelect, onClose, theme = getTheme() }) {
2167
2187
  color: notice.tone === "error" ? theme.colors.error : notice.tone === "success" ? theme.colors.status : theme.colors.secondary,
2168
2188
  children: notice.text
2169
2189
  }) : null;
2170
- if (loadError && view !== View.Menu) return /* @__PURE__ */ jsxs(Box, {
2171
- flexDirection: "column",
2172
- children: [/* @__PURE__ */ jsxs(Text, {
2173
- color: theme.colors.error,
2174
- children: ["Error loading models: ", loadError]
2175
- }), /* @__PURE__ */ jsx(Text, {
2176
- color: theme.colors.secondary,
2177
- dimColor: true,
2178
- children: "Press Esc to go back."
2179
- })]
2180
- });
2190
+ if (loadError && view !== View.Menu) return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(Text, {
2191
+ color: theme.colors.error,
2192
+ children: ["Error loading models: ", loadError]
2193
+ }), /* @__PURE__ */ jsx(ExitHint, {})] });
2181
2194
  if (view === View.Downloading && downloadProgress) return /* @__PURE__ */ jsx(ModelDownloadingView, {
2182
2195
  progress: downloadProgress,
2183
2196
  theme,
@@ -2243,7 +2256,7 @@ function ModelManager({ currentModel, onSelect, onClose, theme = getTheme() }) {
2243
2256
  });
2244
2257
  }
2245
2258
  //#endregion
2246
- //#region src/components/SearchSettings.tsx
2259
+ //#region src/components/SearchSettings/SearchSettings.tsx
2247
2260
  function SearchSettings({ currentUrl, onClose, onSave, theme = getTheme() }) {
2248
2261
  const [view, setView] = useState("menu");
2249
2262
  const [draftUrl, setDraftUrl] = useState(currentUrl ?? "");
@@ -2319,11 +2332,15 @@ function SearchSettings({ currentUrl, onClose, onSave, theme = getTheme() }) {
2319
2332
  color: theme.colors.error,
2320
2333
  children: error
2321
2334
  }),
2322
- /* @__PURE__ */ jsx(Text, {
2323
- color: theme.colors.secondary,
2324
- dimColor: true,
2325
- children: "Press Enter to save, Esc to go back."
2326
- })
2335
+ /* @__PURE__ */ jsxs(Text, { children: [
2336
+ /* @__PURE__ */ jsx(Text, {
2337
+ color: theme.colors.secondary,
2338
+ dimColor: true,
2339
+ children: "Press Enter to save."
2340
+ }),
2341
+ " ",
2342
+ /* @__PURE__ */ jsx(ExitHint, {})
2343
+ ] })
2327
2344
  ]
2328
2345
  });
2329
2346
  return /* @__PURE__ */ jsxs(SelectPrompt, {
@@ -2345,7 +2362,7 @@ function SearchSettings({ currentUrl, onClose, onSave, theme = getTheme() }) {
2345
2362
  });
2346
2363
  }
2347
2364
  //#endregion
2348
- //#region src/components/SessionManager.tsx
2365
+ //#region src/components/SessionManager/SessionManager.tsx
2349
2366
  var ACTION = {
2350
2367
  CLOSE: "close",
2351
2368
  DELETE_MENU: "delete-menu",
@@ -2457,7 +2474,7 @@ function SessionManager({ currentSessionId, onClose, onDelete, onNew, onOpen, th
2457
2474
  });
2458
2475
  }
2459
2476
  //#endregion
2460
- //#region src/components/ThemeSettings.tsx
2477
+ //#region src/components/ThemeSettings/ThemeSettings.tsx
2461
2478
  function ThemeSettings({ currentTheme, onClose, onPreview, onSave }) {
2462
2479
  const [selectedIndex, setSelectedIndex] = useState(() => {
2463
2480
  const initialIndex = LIST$1.findIndex(({ id }) => id === currentTheme);
@@ -2701,11 +2718,13 @@ var ReadinessState = /* @__PURE__ */ function(ReadinessState) {
2701
2718
  ReadinessState["Ready"] = "ready";
2702
2719
  ReadinessState["MissingModelConfig"] = "missing-model-config";
2703
2720
  ReadinessState["NoInstalledModels"] = "no-installed-models";
2721
+ ReadinessState["ServerUnavailable"] = "server-unavailable";
2704
2722
  ReadinessState["ModelLoadError"] = "model-load-error";
2705
2723
  return ReadinessState;
2706
2724
  }({});
2707
2725
  function getTitle(setupState) {
2708
2726
  switch (setupState) {
2727
+ case "server-unavailable": return "Ollama Server Unavailable";
2709
2728
  case "model-load-error": return "Connection Error";
2710
2729
  case "missing-model-config": return "No Model Configured";
2711
2730
  case "no-installed-models": return "No Model Installed";
@@ -2714,7 +2733,7 @@ function getTitle(setupState) {
2714
2733
  function getMessage(setupState, errorMessage) {
2715
2734
  const theme = getTheme();
2716
2735
  switch (setupState) {
2717
- case "checking": return /* @__PURE__ */ jsx(Text, { children: "Checking model setup..." });
2736
+ case "checking": return /* @__PURE__ */ jsx(Text, { children: "Checking Ollama server and model setup..." });
2718
2737
  case "missing-model-config": return /* @__PURE__ */ jsxs(Text, { children: [
2719
2738
  "Select or download a model with",
2720
2739
  " ",
@@ -2727,6 +2746,15 @@ function getMessage(setupState, errorMessage) {
2727
2746
  color: theme.colors.command,
2728
2747
  children: "/model"
2729
2748
  })] });
2749
+ case "server-unavailable": return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Text, { children: "Ollama server is not running or unreachable." }), /* @__PURE__ */ jsxs(Text, { children: [
2750
+ "Start it with ",
2751
+ /* @__PURE__ */ jsx(Text, {
2752
+ color: theme.colors.command,
2753
+ children: "ollama serve"
2754
+ }),
2755
+ " ",
2756
+ "and restart the app"
2757
+ ] })] });
2730
2758
  case "model-load-error": return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(Text, { children: [
2731
2759
  "Error loading models",
2732
2760
  errorMessage ? `: ${errorMessage}` : "",
@@ -2792,9 +2820,13 @@ function App({ sessionId }) {
2792
2820
  setSetupState(ReadinessState.Checking);
2793
2821
  }
2794
2822
  try {
2795
- const installedModels = await listModels();
2823
+ const isHealthy = await checkHealth();
2796
2824
  if (!isMounted) return;
2797
- setSetupState(installedModels.length > 0 ? ReadinessState.Ready : ReadinessState.NoInstalledModels);
2825
+ if (!isHealthy) {
2826
+ setSetupState(ReadinessState.ServerUnavailable);
2827
+ return;
2828
+ }
2829
+ setSetupState((await listModels()).length > 0 ? ReadinessState.Ready : ReadinessState.NoInstalledModels);
2798
2830
  } catch (error) {
2799
2831
  // v8 ignore start
2800
2832
  if (!isMounted) return;
@@ -2937,6 +2969,43 @@ function App({ sessionId }) {
2937
2969
  });
2938
2970
  }
2939
2971
  //#endregion
2972
+ //#region src/components/ExitHint/ExitHint.tsx
2973
+ /**
2974
+ * Exit hint component that displays:
2975
+ * Press Esc/Ctrl+C to go back.
2976
+ */
2977
+ function ExitHint({ action = "go back" }) {
2978
+ return /* @__PURE__ */ jsxs(Text, {
2979
+ color: getTheme().colors.secondary,
2980
+ children: [
2981
+ /* @__PURE__ */ jsx(Text, {
2982
+ dimColor: true,
2983
+ children: "Press "
2984
+ }),
2985
+ /* @__PURE__ */ jsx(Text, {
2986
+ bold: true,
2987
+ children: "Esc"
2988
+ }),
2989
+ /* @__PURE__ */ jsx(Text, {
2990
+ dimColor: true,
2991
+ children: "/"
2992
+ }),
2993
+ /* @__PURE__ */ jsx(Text, {
2994
+ bold: true,
2995
+ children: "Ctrl+C"
2996
+ }),
2997
+ /* @__PURE__ */ jsxs(Text, {
2998
+ dimColor: true,
2999
+ children: [
3000
+ " to ",
3001
+ action,
3002
+ "."
3003
+ ]
3004
+ })
3005
+ ]
3006
+ });
3007
+ }
3008
+ //#endregion
2940
3009
  //#region src/tui.tsx
2941
3010
  function renderApp(sessionId) {
2942
3011
  let resetKey = 0;
package/dist/cli.js CHANGED
@@ -37,7 +37,7 @@ var LIST$1 = [
37
37
  //#endregion
38
38
  //#region package.json
39
39
  var name = "code-ollama";
40
- var version = "0.18.1";
40
+ var version = "0.18.2";
41
41
  //#endregion
42
42
  //#region src/constants/package.ts
43
43
  var NAME = name;
@@ -358,6 +358,13 @@ function saveConfig(patch) {
358
358
  //#region src/utils/ollama.ts
359
359
  var { host } = loadConfig();
360
360
  var client = new Ollama({ host });
361
+ async function checkHealth() {
362
+ try {
363
+ return (await fetch(host)).ok;
364
+ } catch {
365
+ return false;
366
+ }
367
+ }
361
368
  async function* streamChat(messages, model, tools, signal) {
362
369
  const response = await client.chat({
363
370
  model,
@@ -1123,7 +1130,7 @@ async function main(args = process.argv.slice(2)) {
1123
1130
  else await launchTui();
1124
1131
  }
1125
1132
  async function launchTui(sessionId) {
1126
- const { renderApp } = await import("./assets/tui-GfzUJAWj.js");
1133
+ const { renderApp } = await import("./assets/tui-XD0Ekj5m.js");
1127
1134
  reset();
1128
1135
  renderApp(sessionId);
1129
1136
  }
@@ -1139,4 +1146,4 @@ function isEntrypoint(argv1 = process.argv[1]) {
1139
1146
  if (isEntrypoint()) main();
1140
1147
  // v8 ignore stop
1141
1148
  //#endregion
1142
- export { SYSTEM as A, REJECT as B, resetSystemMessage as C, LIST as D, WARNING as E, AUTO as F, LIST$1 as H, LABEL as I, PLAN as L, PLAN_GENERATION_INSTRUCTION as M, BACK as N, getTheme as O, CATALOG as P, SAFE as R, saveConfig as S, HEADER_PREFIX as T, VERSION as V, deleteModel as _, color as a, streamChat as b, createSession as c, listSessions as d, loadSession as f, setClearHandler as g, reset as h, WRITE_TOOLS as i, USER as j, ASSISTANT as k, deleteSession as l, clear as m, main, READ_TOOLS as n, write as o, updateSessionModel as p, TOOLS as r, appendMessage as s, executeTool as t, deleteSessionIfEmpty as u, listModels as v, withSystemMessage as w, loadConfig as x, pullModel as y, APPROVE as z };
1149
+ export { ASSISTANT as A, APPROVE as B, saveConfig as C, WARNING as D, HEADER_PREFIX as E, CATALOG as F, VERSION as H, AUTO as I, LABEL as L, USER as M, PLAN_GENERATION_INSTRUCTION as N, LIST as O, BACK as P, PLAN as R, loadConfig as S, withSystemMessage as T, LIST$1 as U, REJECT as V, checkHealth as _, color as a, pullModel as b, createSession as c, listSessions as d, loadSession as f, setClearHandler as g, reset as h, WRITE_TOOLS as i, SYSTEM as j, getTheme as k, deleteSession as l, clear as m, main, READ_TOOLS as n, write as o, updateSessionModel as p, TOOLS as r, appendMessage as s, executeTool as t, deleteSessionIfEmpty as u, deleteModel as v, resetSystemMessage as w, streamChat as x, listModels as y, SAFE as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-ollama",
3
- "version": "0.18.1",
3
+ "version": "0.18.2",
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",
@@ -53,7 +53,7 @@
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.8.0",
56
+ "@types/node": "25.9.0",
57
57
  "@types/react": "19.2.14",
58
58
  "@vitest/coverage-v8": "4.1.6",
59
59
  "eslint": "10.4.0",
@@ -65,9 +65,9 @@
65
65
  "lint-staged": "17.0.5",
66
66
  "prettier": "3.8.3",
67
67
  "publint": "0.3.21",
68
- "tsx": "4.22.1",
68
+ "tsx": "4.22.2",
69
69
  "typescript": "6.0.3",
70
- "typescript-eslint": "8.59.3",
70
+ "typescript-eslint": "8.59.4",
71
71
  "vite": "8.0.13",
72
72
  "vitest": "4.1.6"
73
73
  },