code-ollama 0.14.2 → 0.15.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.
@@ -218,6 +218,99 @@ var TURN_ABORTED_MESSAGE = [
218
218
  ].join("\n");
219
219
  //#endregion
220
220
  //#region src/components/Messages/utils.ts
221
+ var FENCE_LINE_REGEX = /^(?<indent>[ \t]*)(?<fence>`{3,})(?<language>\w+)?[ \t]*$/;
222
+ function flushTextSegment(segments, textLines) {
223
+ const textContent = textLines.join("\n").trim();
224
+ if (textContent) segments.push({
225
+ type: "text",
226
+ content: textContent
227
+ });
228
+ }
229
+ function flushCodeSegment(segments, codeLines, fenceState) {
230
+ if (fenceState.ambiguous) {
231
+ segments.push({
232
+ type: "raw",
233
+ content: fenceState.rawLines.join("\n")
234
+ });
235
+ return;
236
+ }
237
+ const codeContent = normalizeCodeBlockContent(codeLines.join("\n"), fenceState.indent);
238
+ if (codeContent) segments.push({
239
+ type: "code",
240
+ content: codeContent,
241
+ language: fenceState.language
242
+ });
243
+ }
244
+ function unwrapRawMarkdownFence(content) {
245
+ if (!content.startsWith("```markdown\n") || !content.endsWith("\n```")) return null;
246
+ return content.slice(12, -4);
247
+ }
248
+ function parseContent(content) {
249
+ const segments = [];
250
+ const lines = content.split("\n");
251
+ const textLines = [];
252
+ const codeLines = [];
253
+ let fenceState = null;
254
+ for (const line of lines) {
255
+ const fenceMatch = FENCE_LINE_REGEX.exec(line);
256
+ if (fenceMatch?.groups) {
257
+ const { indent, fence, language } = fenceMatch.groups;
258
+ if (!fenceState) {
259
+ flushTextSegment(segments, textLines);
260
+ textLines.length = 0;
261
+ fenceState = {
262
+ indent,
263
+ fence,
264
+ language,
265
+ rawLines: [line],
266
+ ambiguous: false,
267
+ rawFenceDepth: 1
268
+ };
269
+ continue;
270
+ }
271
+ if (indent === fenceState.indent && fence === fenceState.fence) {
272
+ fenceState.rawLines.push(line);
273
+ if (fenceState.ambiguous) {
274
+ if (language) {
275
+ fenceState.rawFenceDepth += 1;
276
+ continue;
277
+ }
278
+ fenceState.rawFenceDepth -= 1;
279
+ if (fenceState.rawFenceDepth === 0) {
280
+ flushCodeSegment(segments, codeLines, fenceState);
281
+ codeLines.length = 0;
282
+ fenceState = null;
283
+ }
284
+ continue;
285
+ }
286
+ if (!language) {
287
+ flushCodeSegment(segments, codeLines, fenceState);
288
+ codeLines.length = 0;
289
+ fenceState = null;
290
+ continue;
291
+ }
292
+ fenceState.ambiguous = true;
293
+ fenceState.rawFenceDepth += 1;
294
+ continue;
295
+ }
296
+ }
297
+ if (fenceState) {
298
+ fenceState.rawLines.push(line);
299
+ codeLines.push(line);
300
+ } else textLines.push(line);
301
+ }
302
+ if (fenceState) textLines.push(...fenceState.rawLines);
303
+ flushTextSegment(segments, textLines);
304
+ return segments;
305
+ }
306
+ function getMessageColor(role) {
307
+ switch (role) {
308
+ case USER: return "black";
309
+ case ASSISTANT: return "cyan";
310
+ case SYSTEM: return "gray";
311
+ default: return;
312
+ }
313
+ }
221
314
  function isWordCharacter(char) {
222
315
  return char !== void 0 && /[A-Za-z0-9]/.test(char);
223
316
  }
@@ -313,100 +406,7 @@ function splitStreamingInlineContent(content) {
313
406
  }
314
407
  //#endregion
315
408
  //#region src/components/Messages/Messages.tsx
316
- function getMessageColor(role) {
317
- switch (role) {
318
- case USER: return "black";
319
- case ASSISTANT: return "cyan";
320
- case SYSTEM: return "gray";
321
- default: return;
322
- }
323
- }
324
- var FENCE_LINE_REGEX = /^(?<indent>[ \t]*)(?<fence>`{3,})(?<language>\w+)?[ \t]*$/;
325
- function flushTextSegment(segments, textLines) {
326
- const textContent = textLines.join("\n").trim();
327
- if (textContent) segments.push({
328
- type: "text",
329
- content: textContent
330
- });
331
- }
332
- function flushCodeSegment(segments, codeLines, fenceState) {
333
- if (fenceState.ambiguous) {
334
- segments.push({
335
- type: "raw",
336
- content: fenceState.rawLines.join("\n")
337
- });
338
- return;
339
- }
340
- const codeContent = normalizeCodeBlockContent(codeLines.join("\n"), fenceState.indent);
341
- if (codeContent) segments.push({
342
- type: "code",
343
- content: codeContent,
344
- language: fenceState.language
345
- });
346
- }
347
- function unwrapRawMarkdownFence(content) {
348
- if (!content.startsWith("```markdown\n") || !content.endsWith("\n```")) return null;
349
- return content.slice(12, -4);
350
- }
351
- function parseContent(content) {
352
- const segments = [];
353
- const lines = content.split("\n");
354
- const textLines = [];
355
- const codeLines = [];
356
- let fenceState = null;
357
- for (const line of lines) {
358
- const fenceMatch = FENCE_LINE_REGEX.exec(line);
359
- if (fenceMatch?.groups) {
360
- const { indent, fence, language } = fenceMatch.groups;
361
- if (!fenceState) {
362
- flushTextSegment(segments, textLines);
363
- textLines.length = 0;
364
- fenceState = {
365
- indent,
366
- fence,
367
- language,
368
- rawLines: [line],
369
- ambiguous: false,
370
- rawFenceDepth: 1
371
- };
372
- continue;
373
- }
374
- if (indent === fenceState.indent && fence === fenceState.fence) {
375
- fenceState.rawLines.push(line);
376
- if (fenceState.ambiguous) {
377
- if (language) {
378
- fenceState.rawFenceDepth += 1;
379
- continue;
380
- }
381
- fenceState.rawFenceDepth -= 1;
382
- if (fenceState.rawFenceDepth === 0) {
383
- flushCodeSegment(segments, codeLines, fenceState);
384
- codeLines.length = 0;
385
- fenceState = null;
386
- }
387
- continue;
388
- }
389
- if (!language) {
390
- flushCodeSegment(segments, codeLines, fenceState);
391
- codeLines.length = 0;
392
- fenceState = null;
393
- continue;
394
- }
395
- fenceState.ambiguous = true;
396
- fenceState.rawFenceDepth += 1;
397
- continue;
398
- }
399
- }
400
- if (fenceState) {
401
- fenceState.rawLines.push(line);
402
- codeLines.push(line);
403
- } else textLines.push(line);
404
- }
405
- if (fenceState) textLines.push(...fenceState.rawLines);
406
- flushTextSegment(segments, textLines);
407
- return segments;
408
- }
409
- var Message = memo(function Message({ message, isStreaming = false }) {
409
+ function Message({ message, isStreaming = false }) {
410
410
  const messageColor = getMessageColor(message.role);
411
411
  const isSystem = message.role === SYSTEM;
412
412
  const isUser = message.role === USER;
@@ -467,8 +467,8 @@ var Message = memo(function Message({ message, isStreaming = false }) {
467
467
  }, index);
468
468
  })
469
469
  });
470
- });
471
- function Messages({ messages, isLoading, sessionId = 0, streamingMessage }) {
470
+ }
471
+ function Messages({ messages, isLoading, sessionId, streamingMessage }) {
472
472
  return /* @__PURE__ */ jsxs(Box, {
473
473
  flexDirection: "column",
474
474
  children: [
@@ -1659,34 +1659,49 @@ var ACTION = {
1659
1659
  DELETE_MENU: "delete-menu",
1660
1660
  DELETE_PREFIX: "delete:",
1661
1661
  NEW: "new",
1662
+ OPEN_MENU: "open-menu",
1662
1663
  OPEN_PREFIX: "open:"
1663
1664
  };
1664
- function formatSessionLabel(session) {
1665
- const timestamp = new Date(session.updatedAt).toLocaleString();
1666
- return `${session.title} (${timestamp})`;
1665
+ var SESSION_LABEL_PADDING = 4;
1666
+ function truncate(value, maxLength) {
1667
+ return value.length > maxLength ? `${value.slice(0, maxLength - 1).trimEnd()}…` : value;
1668
+ }
1669
+ function formatSessionLabel(session, maxWidth, prefix = "") {
1670
+ const suffix = ` (${new Date(session.updatedAt).toLocaleString()})`;
1671
+ const availableTitleWidth = maxWidth - prefix.length - suffix.length;
1672
+ if (availableTitleWidth < 1) return truncate(`${prefix}${session.title}${suffix}`, maxWidth);
1673
+ return `${prefix}${truncate(session.title, availableTitleWidth)}${suffix}`;
1667
1674
  }
1668
1675
  function SessionManager({ currentSessionId, onClose, onDelete, onNew, onOpen }) {
1669
1676
  const [view, setView] = useState("main");
1670
1677
  const [error, setError] = useState();
1671
1678
  const [, refreshSessionList] = useState(0);
1679
+ const { stdout } = useStdout();
1672
1680
  const sessions = listSessions();
1673
- const options = view === "delete" ? [...sessions.filter(({ id }) => id !== currentSessionId).map((session) => ({
1674
- label: `Delete ${formatSessionLabel(session)}`,
1681
+ const maxLabelWidth = Math.max(1, stdout.columns - SESSION_LABEL_PADDING);
1682
+ const options = view === "open" ? [...sessions.filter(({ id }) => id !== currentSessionId).map((session) => ({
1683
+ label: formatSessionLabel(session, maxLabelWidth),
1684
+ value: `${ACTION.OPEN_PREFIX}${session.id}`
1685
+ })), {
1686
+ label: "Back",
1687
+ value: ACTION.BACK
1688
+ }] : view === "delete" ? [...sessions.filter(({ id }) => id !== currentSessionId).map((session) => ({
1689
+ label: formatSessionLabel(session, maxLabelWidth, "Delete "),
1675
1690
  value: `${ACTION.DELETE_PREFIX}${session.id}`
1676
1691
  })), {
1677
1692
  label: "Back",
1678
1693
  value: ACTION.BACK
1679
1694
  }] : [
1680
1695
  {
1681
- label: "Start new session",
1696
+ label: "New session",
1682
1697
  value: ACTION.NEW
1683
1698
  },
1684
- ...sessions.map((session) => ({
1685
- label: `${session.id === currentSessionId ? "Current: " : ""}${formatSessionLabel(session)}`,
1686
- value: `${ACTION.OPEN_PREFIX}${session.id}`
1687
- })),
1688
1699
  {
1689
- label: "Delete a session",
1700
+ label: "Open session",
1701
+ value: ACTION.OPEN_MENU
1702
+ },
1703
+ {
1704
+ label: "Delete session",
1690
1705
  value: ACTION.DELETE_MENU
1691
1706
  },
1692
1707
  {
@@ -1705,6 +1720,9 @@ function SessionManager({ currentSessionId, onClose, onDelete, onNew, onOpen })
1705
1720
  case value === ACTION.DELETE_MENU:
1706
1721
  setView("delete");
1707
1722
  break;
1723
+ case value === ACTION.OPEN_MENU:
1724
+ setView("open");
1725
+ break;
1708
1726
  case value === ACTION.BACK:
1709
1727
  setView("main");
1710
1728
  break;
@@ -1736,7 +1754,7 @@ function SessionManager({ currentSessionId, onClose, onDelete, onNew, onOpen })
1736
1754
  flexDirection: "column",
1737
1755
  children: [
1738
1756
  /* @__PURE__ */ jsx(Text, { children: "Sessions" }),
1739
- /* @__PURE__ */ jsx(SelectPromptHint, { message: view === "delete" ? "Delete session" : "Select session" }),
1757
+ /* @__PURE__ */ jsx(SelectPromptHint, { message: view === "delete" ? "Delete session" : view === "open" ? "Open session" : "Select session" }),
1740
1758
  error && /* @__PURE__ */ jsx(Box, {
1741
1759
  marginBottom: 1,
1742
1760
  children: /* @__PURE__ */ jsx(Text, {
package/dist/cli.js CHANGED
@@ -7,18 +7,6 @@ import { Ollama } from "ollama";
7
7
  import { v7 } from "uuid";
8
8
  import { exec } from "node:child_process";
9
9
  import { promisify } from "node:util";
10
- //#region \0rolldown/runtime.js
11
- var __defProp = Object.defineProperty;
12
- var __exportAll = (all, no_symbols) => {
13
- let target = {};
14
- for (var name in all) __defProp(target, name, {
15
- get: all[name],
16
- enumerable: true
17
- });
18
- if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
19
- return target;
20
- };
21
- //#endregion
22
10
  //#region src/constants/command.ts
23
11
  var LIST = [
24
12
  {
@@ -45,7 +33,7 @@ var LIST = [
45
33
  //#endregion
46
34
  //#region package.json
47
35
  var name = "code-ollama";
48
- var version = "0.14.2";
36
+ var version = "0.15.0";
49
37
  //#endregion
50
38
  //#region src/constants/package.ts
51
39
  var NAME = name;
@@ -510,6 +498,33 @@ var WRITE_TOOLS = new Set([
510
498
  RUN_SHELL
511
499
  ]);
512
500
  //#endregion
501
+ //#region src/utils/tools/shell.ts
502
+ var execAsync = promisify(exec);
503
+ var SHELL_EXEC_OPTIONS = {
504
+ timeout: 3e4,
505
+ maxBuffer: 1024 * 1024
506
+ };
507
+ /**
508
+ * Execute shell command with shared options (throws on error)
509
+ */
510
+ function execShell(command) {
511
+ return execAsync(command, SHELL_EXEC_OPTIONS);
512
+ }
513
+ /**
514
+ * Execute shell command
515
+ */
516
+ async function runShell(command) {
517
+ try {
518
+ const { stdout, stderr } = await execShell(command);
519
+ return { content: stdout || stderr };
520
+ } catch (error) {
521
+ return {
522
+ content: "",
523
+ error: `Command failed: ${error instanceof Error ? error.message : String(error)}`
524
+ };
525
+ }
526
+ }
527
+ //#endregion
513
528
  //#region src/utils/tools/filesystem.ts
514
529
  /**
515
530
  * Read file contents
@@ -616,7 +631,6 @@ function listDir(dirPath) {
616
631
  * Search for pattern in files using ripgrep if available, fallback to Node.js
617
632
  */
618
633
  async function grepSearch(pattern, dirPath) {
619
- const { execShell } = await Promise.resolve().then(() => shell_exports);
620
634
  try {
621
635
  const { stdout } = await execShell(`rg --line-number --no-heading --smart-case "${pattern.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}" "${dirPath.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`);
622
636
  // v8 ignore next
@@ -655,37 +669,6 @@ async function grepSearch(pattern, dirPath) {
655
669
  }
656
670
  }
657
671
  //#endregion
658
- //#region src/utils/tools/shell.ts
659
- var shell_exports = /* @__PURE__ */ __exportAll({
660
- execShell: () => execShell,
661
- runShell: () => runShell
662
- });
663
- var execAsync = promisify(exec);
664
- var SHELL_EXEC_OPTIONS = {
665
- timeout: 3e4,
666
- maxBuffer: 1024 * 1024
667
- };
668
- /**
669
- * Execute shell command with shared options (throws on error)
670
- */
671
- function execShell(command) {
672
- return execAsync(command, SHELL_EXEC_OPTIONS);
673
- }
674
- /**
675
- * Execute shell command
676
- */
677
- async function runShell(command) {
678
- try {
679
- const { stdout, stderr } = await execShell(command);
680
- return { content: stdout || stderr };
681
- } catch (error) {
682
- return {
683
- content: "",
684
- error: `Command failed: ${error instanceof Error ? error.message : String(error)}`
685
- };
686
- }
687
- }
688
- //#endregion
689
672
  //#region src/utils/tools/web/fetch.ts
690
673
  var FETCH_TIMEOUT_MS = 1e4;
691
674
  var BASE_HEADERS = { "user-agent": `${NAME}/${VERSION}` };
@@ -948,7 +931,7 @@ async function main(args = process.argv.slice(2)) {
948
931
  else await launchTui();
949
932
  }
950
933
  async function launchTui(sessionId) {
951
- const { renderApp } = await import("./assets/tui-Dse5XVJ_.js");
934
+ const { renderApp } = await import("./assets/tui-DPx5MGHZ.js");
952
935
  reset();
953
936
  renderApp(sessionId);
954
937
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-ollama",
3
- "version": "0.14.2",
3
+ "version": "0.15.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",