omnexx 0.12.0 → 0.13.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.
Files changed (65) hide show
  1. package/README.md +17 -4
  2. package/dist/{chat-context-SP5XSAF7.js → chat-context-P4ZON7M4.js} +7 -7
  3. package/dist/{chat-server-NKLX3WTV.js → chat-server-FMF26CBV.js} +16 -14
  4. package/dist/chat-server-FMF26CBV.js.map +1 -0
  5. package/dist/{chat-settings-K5643AXQ.js → chat-settings-4XUKDH6H.js} +10 -10
  6. package/dist/chunk-23MT7K6X.js +209 -0
  7. package/dist/chunk-23MT7K6X.js.map +1 -0
  8. package/dist/{chunk-UACCTB6B.js → chunk-3OILFLAA.js} +130 -93
  9. package/dist/chunk-3OILFLAA.js.map +1 -0
  10. package/dist/{chunk-P6HRCAYP.js → chunk-ET6OMKAS.js} +4 -2
  11. package/dist/chunk-ET6OMKAS.js.map +1 -0
  12. package/dist/chunk-FSA52KQB.js +569 -0
  13. package/dist/chunk-FSA52KQB.js.map +1 -0
  14. package/dist/{chunk-5XMZIGYS.js → chunk-GBFAEDOD.js} +20 -6
  15. package/dist/chunk-GBFAEDOD.js.map +1 -0
  16. package/dist/chunk-H4XHEBFQ.js +257 -0
  17. package/dist/chunk-H4XHEBFQ.js.map +1 -0
  18. package/dist/{chunk-C2RB5YRZ.js → chunk-KJ5SPE6X.js} +675 -113
  19. package/dist/chunk-KJ5SPE6X.js.map +1 -0
  20. package/dist/{chunk-4C3ZA5OG.js → chunk-L2YBK4AY.js} +14 -5
  21. package/dist/chunk-L2YBK4AY.js.map +1 -0
  22. package/dist/{chunk-MHH66U5Y.js → chunk-MC4NBIIA.js} +6 -6
  23. package/dist/{chunk-HWL2XISD.js → chunk-PRAOJIKH.js} +108 -215
  24. package/dist/chunk-PRAOJIKH.js.map +1 -0
  25. package/dist/{chunk-SFNARMV4.js → chunk-RSQGFSCA.js} +8 -8
  26. package/dist/{chunk-DMJLZWAR.js → chunk-V5RPCSON.js} +25 -10
  27. package/dist/{chunk-DMJLZWAR.js.map → chunk-V5RPCSON.js.map} +1 -1
  28. package/dist/{chunk-RYK3WVH4.js → chunk-XKO2GYOF.js} +1031 -814
  29. package/dist/chunk-XKO2GYOF.js.map +1 -0
  30. package/dist/chunk-XP4J622W.js +35 -0
  31. package/dist/chunk-XP4J622W.js.map +1 -0
  32. package/dist/{chunk-Q2B5FUSA.js → chunk-YJ7BPHUB.js} +7 -7
  33. package/dist/cli.js +41 -27
  34. package/dist/cli.js.map +1 -1
  35. package/dist/{list-TZWF7XUG.js → list-V6A7DKXF.js} +2 -2
  36. package/dist/{model-picker-G6EVIQP7.js → model-picker-IR7QMEWU.js} +8 -8
  37. package/dist/ollama-setup-EJY37RBS.js +31 -0
  38. package/dist/ollama-start-EBZJFMNR.js +72 -0
  39. package/dist/ollama-start-EBZJFMNR.js.map +1 -0
  40. package/dist/{print-HSFNJOYV.js → print-HXC5CFGD.js} +12 -10
  41. package/dist/{print-HSFNJOYV.js.map → print-HXC5CFGD.js.map} +1 -1
  42. package/dist/{session-MNF52NG4.js → session-2YQYN6VU.js} +18 -15
  43. package/dist/session-2YQYN6VU.js.map +1 -0
  44. package/dist/{start-MFBIM4KW.js → start-KMBA2W6F.js} +28 -19
  45. package/dist/start-KMBA2W6F.js.map +1 -0
  46. package/package.json +2 -1
  47. package/dist/chat-server-NKLX3WTV.js.map +0 -1
  48. package/dist/chunk-4C3ZA5OG.js.map +0 -1
  49. package/dist/chunk-5XMZIGYS.js.map +0 -1
  50. package/dist/chunk-C2RB5YRZ.js.map +0 -1
  51. package/dist/chunk-HWL2XISD.js.map +0 -1
  52. package/dist/chunk-P6HRCAYP.js.map +0 -1
  53. package/dist/chunk-RYK3WVH4.js.map +0 -1
  54. package/dist/chunk-UACCTB6B.js.map +0 -1
  55. package/dist/ollama-2BG63S2L.js +0 -72
  56. package/dist/ollama-2BG63S2L.js.map +0 -1
  57. package/dist/start-MFBIM4KW.js.map +0 -1
  58. /package/dist/{chat-context-SP5XSAF7.js.map → chat-context-P4ZON7M4.js.map} +0 -0
  59. /package/dist/{chat-settings-K5643AXQ.js.map → chat-settings-4XUKDH6H.js.map} +0 -0
  60. /package/dist/{chunk-MHH66U5Y.js.map → chunk-MC4NBIIA.js.map} +0 -0
  61. /package/dist/{chunk-SFNARMV4.js.map → chunk-RSQGFSCA.js.map} +0 -0
  62. /package/dist/{chunk-Q2B5FUSA.js.map → chunk-YJ7BPHUB.js.map} +0 -0
  63. /package/dist/{list-TZWF7XUG.js.map → list-V6A7DKXF.js.map} +0 -0
  64. /package/dist/{model-picker-G6EVIQP7.js.map → model-picker-IR7QMEWU.js.map} +0 -0
  65. /package/dist/{session-MNF52NG4.js.map → ollama-setup-EJY37RBS.js.map} +0 -0
package/README.md CHANGED
@@ -121,14 +121,27 @@ Optional: an advisory **fast judge** (Nimble on Ollama, usually on your Mac over
121
121
 
122
122
  ## Free and local with Ollama
123
123
 
124
+ If Ollama is running, `omnexx` (or `omnexx --ollama`, or the VS Code panel) just works. With no
125
+ provider set up, it:
126
+
127
+ - finds Ollama on `localhost:11434` (or `OLLAMA_HOST`) and lists the models you've pulled;
128
+ - keeps only models that can call tools (`/api/show` capabilities), skips `:cloud` models, and
129
+ ranks coding models first (qwen3-coder, devstral, gpt-oss, qwen3.x, qwen2.5-coder, ...), then
130
+ bigger, then longer context;
131
+ - makes a copy with a usable context window (`omnexx-<model>`, `num_ctx` 32k, or 16k under 16 GB
132
+ of RAM, never more than the model supports), since Ollama's default window is too small;
133
+ - saves it as the chat, planner, worker and cheap model, and says so in one line:
134
+ `using Ollama's qwen3-coder:30b (local, free, tools, 32k context) for chat, planning and work`.
135
+
136
+ No usable model yet? It suggests one for your machine (`ollama pull qwen3-coder`, or
137
+ `qwen2.5-coder:7b` under 32 GB) and offers to pull it: `y` in the terminal, **Pull it now** in
138
+ VS Code. Ollama not running? It says how to install (https://ollama.com/download) or start it.
139
+
124
140
  ```bash
125
- ollama pull qwen2.5-coder # or any model you like
126
- npx omnexx --ollama # finds Ollama on localhost:11434, picks a coding model, opens the chat
141
+ npx omnexx --ollama # set up as above, then open the chat
127
142
  npx omnexx --ollama llama3.3 # or name the model
128
143
  ```
129
144
 
130
- No key and no config: with no provider set up, omnexx also connects a running Ollama by itself.
131
-
132
145
  ## From the plain terminal
133
146
 
134
147
  ```bash
@@ -4,7 +4,7 @@ import {
4
4
  listRunIds,
5
5
  repoMemoryFile,
6
6
  repoRoot
7
- } from "./chunk-5XMZIGYS.js";
7
+ } from "./chunk-GBFAEDOD.js";
8
8
  import {
9
9
  SECTION_IDS,
10
10
  SECTION_INFO,
@@ -13,15 +13,15 @@ import {
13
13
  loadConfig,
14
14
  readSectionModes,
15
15
  sectionsFile
16
- } from "./chunk-DMJLZWAR.js";
17
- import "./chunk-27GOEUTN.js";
18
- import {
19
- UsageError
20
- } from "./chunk-7PNGHZYH.js";
16
+ } from "./chunk-V5RPCSON.js";
21
17
  import "./chunk-FR5DUUJ4.js";
22
18
  import {
23
19
  resolvePaths
24
20
  } from "./chunk-Q3MDYD6K.js";
21
+ import "./chunk-27GOEUTN.js";
22
+ import {
23
+ UsageError
24
+ } from "./chunk-7PNGHZYH.js";
25
25
  import "./chunk-2H7UOFLK.js";
26
26
 
27
27
  // src/cli/chat-context.ts
@@ -118,4 +118,4 @@ export {
118
118
  contextFiles,
119
119
  setSectionMode
120
120
  };
121
- //# sourceMappingURL=chat-context-SP5XSAF7.js.map
121
+ //# sourceMappingURL=chat-context-P4ZON7M4.js.map
@@ -2,12 +2,12 @@
2
2
  import {
3
3
  println
4
4
  } from "./chunk-7PC4SSYS.js";
5
- import {
6
- describeError
7
- } from "./chunk-7PNGHZYH.js";
8
5
  import {
9
6
  resolvePaths
10
7
  } from "./chunk-Q3MDYD6K.js";
8
+ import {
9
+ describeError
10
+ } from "./chunk-7PNGHZYH.js";
11
11
  import "./chunk-2H7UOFLK.js";
12
12
 
13
13
  // src/cli/chat-server.ts
@@ -39,7 +39,7 @@ function rawText(c, key) {
39
39
  return v;
40
40
  }
41
41
  async function serveChat(io, runCli, opts) {
42
- const { Session } = await import("./session-MNF52NG4.js");
42
+ const { Session } = await import("./session-2YQYN6VU.js");
43
43
  const session = new Session(io, runCli);
44
44
  const write = (msg) => {
45
45
  println(io.stdout, JSON.stringify(msg));
@@ -77,6 +77,7 @@ async function serveChat(io, runCli, opts) {
77
77
  live: session.live,
78
78
  todos: session.todos,
79
79
  pending: session.pending?.question ?? null,
80
+ pendingLabels: session.pending?.labels ?? null,
80
81
  mode: session.mode,
81
82
  busy: session.busy !== void 0 || session.chatBusy,
82
83
  paused: session.chatPaused,
@@ -95,6 +96,7 @@ async function serveChat(io, runCli, opts) {
95
96
  run: session.runId ? { id: session.runId, alive: session.runAlive, ...session.info } : null,
96
97
  helpers: session.helpers,
97
98
  waiting: session.waiting,
99
+ estimate: session.estimate,
98
100
  browser: session.browserFrame ? {
99
101
  seq: session.browserFrame.seq,
100
102
  url: session.browserFrame.url,
@@ -110,7 +112,7 @@ async function serveChat(io, runCli, opts) {
110
112
  };
111
113
  session.onChange(schedule);
112
114
  const sendModels = async () => {
113
- const { loadModelChoices } = await import("./model-picker-G6EVIQP7.js");
115
+ const { loadModelChoices } = await import("./model-picker-IR7QMEWU.js");
114
116
  const { items, unreachable } = await loadModelChoices(io);
115
117
  write({
116
118
  type: "models",
@@ -120,15 +122,15 @@ async function serveChat(io, runCli, opts) {
120
122
  });
121
123
  };
122
124
  const sendSettings = async () => {
123
- const { providerSettings } = await import("./chat-settings-K5643AXQ.js");
125
+ const { providerSettings } = await import("./chat-settings-4XUKDH6H.js");
124
126
  write({ type: "settings", ...await providerSettings(io) });
125
127
  };
126
128
  const sendBrowser = async () => {
127
- const { browserSettings } = await import("./chat-settings-K5643AXQ.js");
129
+ const { browserSettings } = await import("./chat-settings-4XUKDH6H.js");
128
130
  write({ type: "browser", ...await browserSettings(io) });
129
131
  };
130
132
  const sendContextFiles = async () => {
131
- const { contextFiles } = await import("./chat-context-SP5XSAF7.js");
133
+ const { contextFiles } = await import("./chat-context-P4ZON7M4.js");
132
134
  write({ type: "contextFiles", ...await contextFiles(io) });
133
135
  };
134
136
  const sendContext = () => {
@@ -207,7 +209,7 @@ async function serveChat(io, runCli, opts) {
207
209
  return typeof v === "string" ? v : void 0;
208
210
  };
209
211
  run(
210
- import("./chat-settings-K5643AXQ.js").then(async ({ addProvider }) => {
212
+ import("./chat-settings-4XUKDH6H.js").then(async ({ addProvider }) => {
211
213
  await providersChanged(
212
214
  await addProvider(io, {
213
215
  provider: str("provider"),
@@ -221,7 +223,7 @@ async function serveChat(io, runCli, opts) {
221
223
  }
222
224
  case "testProvider":
223
225
  run(
224
- import("./chat-settings-K5643AXQ.js").then(async ({ testProvider }) => {
226
+ import("./chat-settings-4XUKDH6H.js").then(async ({ testProvider }) => {
225
227
  write({ type: "providerTest", ...await testProvider(io, text(c, "name")) });
226
228
  })
227
229
  );
@@ -231,7 +233,7 @@ async function serveChat(io, runCli, opts) {
231
233
  return;
232
234
  case "setSectionMode":
233
235
  run(
234
- import("./chat-context-SP5XSAF7.js").then(async ({ setSectionMode }) => {
236
+ import("./chat-context-P4ZON7M4.js").then(async ({ setSectionMode }) => {
235
237
  await setSectionMode(io, text(c, "id"), text(c, "mode"));
236
238
  await sendContextFiles();
237
239
  })
@@ -275,7 +277,7 @@ async function serveChat(io, runCli, opts) {
275
277
  return;
276
278
  case "setBrowser":
277
279
  run(
278
- import("./chat-settings-K5643AXQ.js").then(async ({ setBrowserSettings }) => {
280
+ import("./chat-settings-4XUKDH6H.js").then(async ({ setBrowserSettings }) => {
279
281
  await setBrowserSettings(io, c);
280
282
  session.push("system", "browser settings saved; new runs use them");
281
283
  await sendBrowser();
@@ -296,7 +298,7 @@ async function serveChat(io, runCli, opts) {
296
298
  return;
297
299
  case "removeProvider":
298
300
  run(
299
- import("./chat-settings-K5643AXQ.js").then(async ({ removeProvider }) => {
301
+ import("./chat-settings-4XUKDH6H.js").then(async ({ removeProvider }) => {
300
302
  await providersChanged(await removeProvider(io, text(c, "name")));
301
303
  })
302
304
  );
@@ -341,4 +343,4 @@ async function serveChat(io, runCli, opts) {
341
343
  export {
342
344
  serveChat
343
345
  };
344
- //# sourceMappingURL=chat-server-NKLX3WTV.js.map
346
+ //# sourceMappingURL=chat-server-FMF26CBV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/chat-server.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { resolvePaths } from '../core/paths.js';\nimport { readFile } from 'node:fs/promises';\nimport { createInterface } from 'node:readline';\nimport { describeError } from '../errors.js';\nimport type { Telemetry } from '../telemetry/aggregate.js';\nimport type { TodoItem } from '../tools/todo.js';\nimport type { Entry, Helper, Mode, RunCli } from '../tui/session.js';\nimport { println, type CliIO } from './io.js';\n\n/**\n * `omnexx chat-server`: the interactive session behind a JSON-lines protocol on stdin/stdout, for\n * editor panels (the VS Code chat). It drives the same Session as the terminal UI, so slash\n * commands, approvals, model switching and plan mode behave the same way.\n *\n * In (one JSON object per line): send {text} · answer {yes} · stop · pause · resume · mode {mode} ·\n * yolo {on} ·\n * model {ref} · models · connect {value, name?} · undo · clear · compact · sync (resend all) ·\n * settings · addProvider {provider?, key?, url?} · removeProvider {name} · testProvider {name} ·\n * roles · setRoles {roles} · contextFiles · setSectionMode {id, mode} · contextList ·\n * contextUpdate {id, text} · contextDelete {id} · contextReset · chats · resumeChat {id} · browser ·\n * setBrowser {engine, profile?, sessionName?, headless}.\n * Out: ready {version} · state (below; `entries` holds only lines not sent before) · models\n * {items, unreachable, current} · settings {catalog, connected} · providerTest {name, ok, models,\n * detail} · contextItems {items, busy} · chats {chats} · browser {engine, profile, sessionName, headless} ·\n * error {message}.\n */\n\nexport interface ChatUsage {\n /** When the chat's first event happened (epoch ms), for an uptime clock. */\n startedAt: number | null;\n tokens: Telemetry['tokens'];\n usd: number;\n turns: number;\n toolCalls: number;\n toolErrors: number;\n compactions: number;\n}\n\nexport interface ChatState {\n type: 'state';\n entries: Entry[];\n /** The reply as it streams in; empty once it lands in `entries`. */\n live: string;\n todos: TodoItem[];\n /** A question waiting for allow / deny, or null. */\n pending: string | null;\n /** Button names when the question is an offer (Pull it now / Not now) rather than a guard. */\n pendingLabels: { yes: string; no: string } | null;\n mode: Mode;\n busy: boolean;\n paused: boolean;\n autoApprove: boolean;\n model: string | null;\n /** Tokens in use, the compaction limit, and what they are made of. */\n context: {\n used: number;\n limit: number;\n parts?: { system: number; tools: number; conversation: number };\n } | null;\n usage: ChatUsage | null;\n run: { id: string; alive: boolean; phase?: string; done?: number; tasks?: number } | null;\n /** Helpers (subagents) for the current message. */\n helpers: Helper[];\n /** A model request in flight: when it went out and how long it usually takes (null: unknown). */\n waiting: { startedAt: number; estimateMs: number | null } | null;\n /** \"est. ~3 min, ~40k tokens, ~$0.02\" before work, \"~2 min left\" during it, or null. */\n estimate: string | null;\n /** The latest browser frame's number and page; the image comes as a `browserFrame` message. */\n browser: { seq: number; url: string; action: string; at: number } | null;\n}\n\n/** Frames larger than this are skipped rather than pushed through the pipe. */\nconst MAX_FRAME_BYTES = 4 * 1024 * 1024;\n\nconst MODES = new Set<Mode>(['chat', 'plan', 'run']);\n/** Coalesce bursts of changes (a streaming reply fires one per token) into one state line. */\nconst EMIT_EVERY_MS = 40;\n\ntype Command = { type: string } & Record<string, unknown>;\n\nfunction parseCommand(line: string): Command {\n let data: unknown;\n try {\n data = JSON.parse(line);\n } catch {\n throw new Error('expected one JSON object per line');\n }\n if (typeof data !== 'object' || data === null || typeof (data as Command).type !== 'string')\n throw new Error('expected an object with a \"type\"');\n return data as Command;\n}\n\nfunction text(c: Command, key: string): string {\n const v = c[key];\n if (typeof v !== 'string' || !v.trim()) throw new Error(`\"${c.type}\" needs a \"${key}\" string`);\n return v;\n}\n\n/** A string that may be empty (an edit can clear a block's text). */\nfunction rawText(c: Command, key: string): string {\n const v = c[key];\n if (typeof v !== 'string') throw new Error(`\"${c.type}\" needs a \"${key}\" string`);\n return v;\n}\n\nexport async function serveChat(\n io: CliIO,\n runCli: RunCli,\n opts: { version: string },\n): Promise<number> {\n const { Session } = await import('../tui/session.js');\n const session = new Session(io, runCli);\n const write = (msg: object): void => {\n println(io.stdout, JSON.stringify(msg));\n };\n const fail = (err: unknown): void => {\n write({ type: 'error', message: describeError(err) });\n };\n\n let sentUpTo = -1;\n let sentFrame = 0;\n /** Send the browser's latest screenshot once per new frame. */\n const sendFrame = async (): Promise<void> => {\n const f = session.browserFrame;\n if (!f || f.seq === sentFrame) return;\n sentFrame = f.seq;\n const data = await readFile(f.path).catch(() => undefined);\n if (!data || data.length > MAX_FRAME_BYTES) return;\n write({\n type: 'browserFrame',\n seq: f.seq,\n mime: f.mime,\n url: f.url,\n action: f.action,\n data: data.toString('base64'),\n });\n };\n /** The last entry before the latest new chat; a reloaded panel starts after it. */\n let clearedAt = -1;\n let timer: NodeJS.Timeout | undefined;\n const emit = (): void => {\n timer = undefined;\n const fresh = session.entries.filter((e) => e.id > sentUpTo);\n sentUpTo = session.entries.at(-1)?.id ?? sentUpTo;\n const t = session.chatTelemetry;\n const state: ChatState = {\n type: 'state',\n entries: fresh,\n live: session.live,\n todos: session.todos,\n pending: session.pending?.question ?? null,\n pendingLabels: session.pending?.labels ?? null,\n mode: session.mode,\n busy: session.busy !== undefined || session.chatBusy,\n paused: session.chatPaused,\n autoApprove: session.autoApprove,\n model: session.chatModelName ?? null,\n context: session.context ?? null,\n usage: t\n ? {\n startedAt: t.startedAt ?? null,\n tokens: t.tokens,\n usd: t.usd,\n turns: t.turns,\n toolCalls: t.toolCalls,\n toolErrors: t.toolErrors,\n compactions: t.compactions,\n }\n : null,\n run: session.runId ? { id: session.runId, alive: session.runAlive, ...session.info } : null,\n helpers: session.helpers,\n waiting: session.waiting,\n estimate: session.estimate,\n browser: session.browserFrame\n ? {\n seq: session.browserFrame.seq,\n url: session.browserFrame.url,\n action: session.browserFrame.action,\n at: session.browserFrame.at,\n }\n : null,\n };\n write(state);\n void sendFrame();\n };\n const schedule = (): void => {\n timer ??= setTimeout(emit, EMIT_EVERY_MS);\n };\n session.onChange(schedule);\n\n const sendModels = async (): Promise<void> => {\n const { loadModelChoices } = await import('../tui/model-picker.js');\n const { items, unreachable } = await loadModelChoices(io);\n write({\n type: 'models',\n items: items.filter((i) => i.kind === 'model'),\n unreachable,\n current: session.chatModelName ?? null,\n });\n };\n const sendSettings = async (): Promise<void> => {\n const { providerSettings } = await import('./chat-settings.js');\n write({ type: 'settings', ...(await providerSettings(io)) });\n };\n const sendBrowser = async (): Promise<void> => {\n const { browserSettings } = await import('./chat-settings.js');\n write({ type: 'browser', ...(await browserSettings(io)) });\n };\n const sendContextFiles = async (): Promise<void> => {\n const { contextFiles } = await import('./chat-context.js');\n write({ type: 'contextFiles', ...(await contextFiles(io)) });\n };\n /** The context inspector's items: what the next request sends, with token counts. */\n const sendContext = (): void => {\n write({ type: 'contextItems', items: session.contextItems(), busy: session.chatBusy });\n };\n /** Roles as saved, plus which models are out of quota right now (ref → when it ran out). */\n const sendRoles = async (): Promise<void> => {\n const { readRoles } = await import('../config/roles.js');\n const { QuotaLedger } = await import('../providers/quota-ledger.js');\n const paths = resolvePaths(io.env);\n write({\n type: 'roles',\n roles: await readRoles(paths),\n exhausted: new QuotaLedger(join(paths.configHome, 'quota.json')).all(),\n });\n };\n /** After a provider change: say what happened, then refresh the settings page and models. */\n const providersChanged = async (message: string): Promise<void> => {\n session.push('system', message);\n await sendSettings();\n await sendModels();\n };\n\n /** Commands still running, so a closed pipe lets them finish before the process exits. */\n const inflight = new Set<Promise<unknown>>();\n const run = (p: Promise<unknown>): void => {\n const tracked = p.catch(fail).finally(() => {\n inflight.delete(tracked);\n schedule();\n });\n inflight.add(tracked);\n };\n\n const handle = (c: Command): void => {\n switch (c.type) {\n case 'send':\n run(session.submit(text(c, 'text')));\n return;\n case 'answer':\n if (!session.pending) throw new Error('nothing is waiting for an answer');\n run(session.submit(c.yes === true ? 'y' : 'n'));\n return;\n case 'stop':\n case 'pause':\n case 'resume':\n case 'undo':\n case 'compact':\n run(session.command(c.type));\n return;\n case 'clear':\n run(\n session.command('clear').then(() => {\n // A new chat starts the panel over: nothing from before the clear is sent again.\n clearedAt = session.entries.at(-1)?.id ?? clearedAt;\n sentUpTo = clearedAt;\n write({ type: 'ready', version: opts.version });\n emit();\n }),\n );\n return;\n case 'mode': {\n const mode = c.mode as Mode;\n if (!MODES.has(mode)) throw new Error('mode is one of chat, plan, run');\n if (session.mode !== mode) session.setMode(mode);\n return;\n }\n case 'yolo':\n // /yolo toggles; only run it when the state differs from what was asked, and without\n // echoing it as a message.\n if ((c.on === true) !== session.autoApprove) run(session.command('yolo'));\n return;\n case 'model':\n run(session.switchModel(text(c, 'ref')));\n return;\n case 'models':\n run(sendModels());\n return;\n case 'settings':\n run(sendSettings());\n return;\n case 'addProvider': {\n const str = (k: string): string | undefined => {\n const v = c[k];\n return typeof v === 'string' ? v : undefined;\n };\n run(\n import('./chat-settings.js').then(async ({ addProvider }) => {\n await providersChanged(\n await addProvider(io, {\n provider: str('provider'),\n key: str('key'),\n url: str('url'),\n }),\n );\n }),\n );\n return;\n }\n case 'testProvider':\n run(\n import('./chat-settings.js').then(async ({ testProvider }) => {\n write({ type: 'providerTest', ...(await testProvider(io, text(c, 'name'))) });\n }),\n );\n return;\n case 'contextFiles':\n run(sendContextFiles());\n return;\n case 'setSectionMode':\n run(\n import('./chat-context.js').then(async ({ setSectionMode }) => {\n await setSectionMode(io, text(c, 'id'), text(c, 'mode'));\n await sendContextFiles();\n }),\n );\n return;\n case 'chats':\n run(\n session.savedChats().then((chats) => {\n write({ type: 'chats', chats });\n }),\n );\n return;\n case 'resumeChat':\n run(\n (async () => {\n // Mark the panel's start first, so a reload shows only the reopened chat.\n clearedAt = session.entries.at(-1)?.id ?? clearedAt;\n sentUpTo = clearedAt;\n await session.resumeChat(text(c, 'id'));\n write({ type: 'ready', version: opts.version });\n emit();\n })(),\n );\n return;\n case 'contextList':\n sendContext();\n return;\n case 'contextUpdate':\n session.changeContext({ op: 'edit', id: text(c, 'id'), text: rawText(c, 'text') });\n sendContext();\n return;\n case 'contextDelete':\n session.changeContext({ op: 'delete', id: text(c, 'id') });\n sendContext();\n return;\n case 'contextReset':\n session.changeContext({ op: 'reset' });\n sendContext();\n return;\n case 'browser':\n run(sendBrowser());\n return;\n case 'setBrowser':\n run(\n import('./chat-settings.js').then(async ({ setBrowserSettings }) => {\n await setBrowserSettings(io, c);\n session.push('system', 'browser settings saved; new runs use them');\n await sendBrowser();\n }),\n );\n return;\n case 'roles':\n run(sendRoles());\n return;\n case 'setRoles':\n run(\n import('../config/roles.js').then(async ({ parseRoles, writeRoles }) => {\n await writeRoles(resolvePaths(io.env), parseRoles(c.roles));\n session.push('system', 'model roles saved; new chats and runs use them');\n await sendRoles();\n }),\n );\n return;\n case 'removeProvider':\n run(\n import('./chat-settings.js').then(async ({ removeProvider }) => {\n await providersChanged(await removeProvider(io, text(c, 'name')));\n }),\n );\n return;\n case 'connect': {\n const name = typeof c.name === 'string' && c.name.trim() ? ` --name ${c.name.trim()}` : '';\n run(session.submit(`/model ${text(c, 'value')}${name}`));\n return;\n }\n case 'sync':\n // A reloaded panel: start it over with the conversation since the last new chat.\n sentUpTo = clearedAt;\n sentFrame = 0;\n write({ type: 'ready', version: opts.version });\n emit();\n return;\n default:\n throw new Error(`unknown command \"${c.type}\"`);\n }\n };\n\n await session.loadCommands();\n await session.continueChat().catch(fail);\n await session.greet(false).catch(fail);\n write({ type: 'ready', version: opts.version });\n emit();\n\n const lines = createInterface({ input: io.stdin, crlfDelay: Infinity });\n for await (const line of lines) {\n if (!line.trim()) continue;\n try {\n handle(parseCommand(line));\n } catch (err) {\n fail(err);\n }\n }\n // The editor closed the pipe: end any turn in progress, let running commands finish, then\n // flush the last state.\n if (session.chatBusy) await session.command('stop');\n await Promise.allSettled([...inflight]);\n if (timer) {\n clearTimeout(timer);\n emit();\n }\n return 0;\n}\n"],"mappings":"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","names":[]}
@@ -5,30 +5,30 @@ import {
5
5
  import {
6
6
  connect,
7
7
  describeConnect
8
- } from "./chunk-SFNARMV4.js";
8
+ } from "./chunk-RSQGFSCA.js";
9
9
  import {
10
10
  PROVIDER_TEMPLATES,
11
11
  removeEndpointBlock
12
- } from "./chunk-MHH66U5Y.js";
12
+ } from "./chunk-MC4NBIIA.js";
13
13
  import {
14
14
  clearKey,
15
15
  findProviderKey,
16
16
  maskKey
17
- } from "./chunk-4C3ZA5OG.js";
17
+ } from "./chunk-L2YBK4AY.js";
18
18
  import {
19
19
  loadConfig
20
- } from "./chunk-DMJLZWAR.js";
20
+ } from "./chunk-V5RPCSON.js";
21
+ import "./chunk-FR5DUUJ4.js";
21
22
  import "./chunk-7PC4SSYS.js";
23
+ import {
24
+ resolvePaths,
25
+ userConfigFile
26
+ } from "./chunk-Q3MDYD6K.js";
22
27
  import "./chunk-27GOEUTN.js";
23
28
  import {
24
29
  UsageError
25
30
  } from "./chunk-7PNGHZYH.js";
26
31
  import "./chunk-UX4MF6V4.js";
27
- import "./chunk-FR5DUUJ4.js";
28
- import {
29
- resolvePaths,
30
- userConfigFile
31
- } from "./chunk-Q3MDYD6K.js";
32
32
  import "./chunk-2H7UOFLK.js";
33
33
 
34
34
  // src/cli/chat-settings.ts
@@ -228,4 +228,4 @@ export {
228
228
  setBrowserSettings,
229
229
  testProvider
230
230
  };
231
- //# sourceMappingURL=chat-settings-K5643AXQ.js.map
231
+ //# sourceMappingURL=chat-settings-4XUKDH6H.js.map
@@ -0,0 +1,209 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ resolveModelLenient
4
+ } from "./chunk-XP4J622W.js";
5
+ import {
6
+ resolveRunDeps
7
+ } from "./chunk-FSA52KQB.js";
8
+ import {
9
+ connect,
10
+ describeConnect
11
+ } from "./chunk-RSQGFSCA.js";
12
+ import {
13
+ findProviderKey
14
+ } from "./chunk-L2YBK4AY.js";
15
+ import {
16
+ loadConfig
17
+ } from "./chunk-V5RPCSON.js";
18
+ import {
19
+ resolvePaths
20
+ } from "./chunk-Q3MDYD6K.js";
21
+ import {
22
+ describeError
23
+ } from "./chunk-7PNGHZYH.js";
24
+ import {
25
+ discoverModels
26
+ } from "./chunk-UX4MF6V4.js";
27
+
28
+ // src/tui/chat.ts
29
+ var SYSTEM = `You are omnexx's setup assistant, talking to the user in their terminal.
30
+ Your job: help them connect model providers and custom OpenAI-compatible endpoints.
31
+ Use the tools; never invent results. Keys the user pastes reach you as placeholders like
32
+ <key-1>: pass the placeholder as the key argument and omnexx swaps in the real key.
33
+ Never ask the user to paste a key into anything but this chat. Be brief: plain text, no
34
+ markdown headings. When a provider is connected, tell them the model ref to use.`;
35
+ var TOOLS = [
36
+ {
37
+ name: "list_providers",
38
+ description: "Configured providers, their base URLs and whether a key is set.",
39
+ inputSchema: { type: "object", properties: {} }
40
+ },
41
+ {
42
+ name: "connect_provider",
43
+ description: "Add or update a provider. target is a known name (openai, openrouter, groq, deepseek, together, fireworks, mistral, gemini, xai, ollama, lmstudio, vllm, litellm, anthropic) or a base URL of any OpenAI-compatible endpoint. Lists its models to prove it works.",
44
+ inputSchema: {
45
+ type: "object",
46
+ properties: {
47
+ target: { type: "string" },
48
+ key: { type: "string", description: "API key or a <key-N> placeholder" },
49
+ name: { type: "string", description: "name for a URL endpoint (optional)" }
50
+ },
51
+ required: ["target"]
52
+ }
53
+ },
54
+ {
55
+ name: "list_models",
56
+ description: "Models a configured provider serves.",
57
+ inputSchema: {
58
+ type: "object",
59
+ properties: { provider: { type: "string" } },
60
+ required: ["provider"]
61
+ }
62
+ }
63
+ ];
64
+ var KEYISH = /\b(sk-ant-|sk-or-|sk-|gsk_|xai-|AIza|fw_)[A-Za-z0-9_\-.]{16,}/g;
65
+ var Chat = class _Chat {
66
+ constructor(io, ref, provider, route, model) {
67
+ this.io = io;
68
+ this.ref = ref;
69
+ this.provider = provider;
70
+ this.route = route;
71
+ this.model = model;
72
+ }
73
+ io;
74
+ ref;
75
+ provider;
76
+ route;
77
+ model;
78
+ messages = [];
79
+ keys = [];
80
+ static async open(io, ref) {
81
+ const { config, deps } = await resolveRunDeps(io, io.cwd, {
82
+ models: { planner: ref, worker: ref, cheap: ref }
83
+ });
84
+ const m = resolveModelLenient(ref, config);
85
+ return new _Chat(io, ref, deps.provider, m.provider, m.id);
86
+ }
87
+ /** Replace pasted keys with placeholders; the real values stay here. */
88
+ redact(text) {
89
+ return text.replace(KEYISH, (k) => {
90
+ let i = this.keys.indexOf(k);
91
+ if (i === -1) i = this.keys.push(k) - 1;
92
+ return `<key-${i + 1}>`;
93
+ });
94
+ }
95
+ unredact(text) {
96
+ return text?.replace(/<key-(\d+)>/g, (m, n) => this.keys[Number(n) - 1] ?? m);
97
+ }
98
+ /** One user turn: loops through tool calls until the model answers. `say` gets each line. */
99
+ async send(text, say, maxSteps = 8) {
100
+ this.messages.push({ role: "user", content: [{ type: "text", text: this.redact(text) }] });
101
+ for (let step = 0; step < maxSteps; step++) {
102
+ const res = await this.provider.complete({
103
+ model: this.model,
104
+ route: this.route,
105
+ system: [{ text: SYSTEM }],
106
+ tools: TOOLS,
107
+ messages: this.messages,
108
+ maxTokens: 2048,
109
+ messageBreakpoints: []
110
+ });
111
+ this.messages.push({ role: "assistant", content: res.content });
112
+ const said = res.content.filter((b) => b.type === "text").map((b) => b.text).join("").trim();
113
+ if (said) say(said);
114
+ const calls = res.content.filter(
115
+ (b) => b.type === "tool_use"
116
+ );
117
+ if (!calls.length) return;
118
+ const results = [];
119
+ for (const c of calls) {
120
+ say(`\xB7 ${c.name}`);
121
+ try {
122
+ results.push({
123
+ type: "tool_result",
124
+ toolUseId: c.id,
125
+ content: await this.tool(c.name, c.input ?? {})
126
+ });
127
+ } catch (err) {
128
+ results.push({
129
+ type: "tool_result",
130
+ toolUseId: c.id,
131
+ content: describeError(err),
132
+ isError: true
133
+ });
134
+ }
135
+ }
136
+ this.messages.push({ role: "user", content: results });
137
+ }
138
+ say("(stopped after too many tool calls)");
139
+ }
140
+ async tool(name, input) {
141
+ const str = (k) => typeof input[k] === "string" ? input[k] : void 0;
142
+ switch (name) {
143
+ case "list_providers": {
144
+ const { config } = await loadConfig({ cwd: this.io.cwd, env: this.io.env });
145
+ const paths = resolvePaths(this.io.env);
146
+ const rows = [
147
+ `anthropic (built-in) key: ${await findProviderKey(paths, this.io.env, "anthropic") ? "yes" : "no"}`
148
+ ];
149
+ for (const [n, ep] of Object.entries(config.providers.endpoints)) {
150
+ const key = await findProviderKey(paths, this.io.env, n, ep.api_key_env);
151
+ rows.push(`${n} ${ep.base_url} key: ${key ? "yes" : ep.free ? "not needed" : "no"}`);
152
+ }
153
+ return rows.join("\n");
154
+ }
155
+ case "connect_provider": {
156
+ const target = this.unredact(str("target")) ?? "";
157
+ const key = this.unredact(str("key"));
158
+ const nm = str("name");
159
+ const r = await connect(this.io, target, key, nm ? { name: nm } : {});
160
+ return this.redact(describeConnect(r));
161
+ }
162
+ case "list_models": {
163
+ const p = str("provider") ?? "";
164
+ const { config } = await loadConfig({ cwd: this.io.cwd, env: this.io.env });
165
+ const ep = config.providers.endpoints[p];
166
+ if (!ep) return `unknown provider "${p}"`;
167
+ const apiKey = (await findProviderKey(resolvePaths(this.io.env), this.io.env, p, ep.api_key_env))?.key;
168
+ const models = await discoverModels(
169
+ { baseUrl: ep.base_url, ...apiKey ? { apiKey } : {} },
170
+ this.io.fetch ? { fetch: this.io.fetch } : {}
171
+ );
172
+ return models.length ? models.map((m) => m.id).join("\n") : "no models listed";
173
+ }
174
+ default:
175
+ return `unknown tool ${name}`;
176
+ }
177
+ }
178
+ };
179
+ async function defaultChatRef(io) {
180
+ const paths = resolvePaths(io.env);
181
+ if (await findProviderKey(paths, io.env, "anthropic")) return "anthropic:sonnet";
182
+ const { config } = await loadConfig({ cwd: io.cwd, env: io.env });
183
+ for (const [n, ep] of Object.entries(config.providers.endpoints)) {
184
+ const apiKey = (await findProviderKey(paths, io.env, n, ep.api_key_env))?.key;
185
+ if (!apiKey && !ep.free) continue;
186
+ const models = await discoverModels(
187
+ { baseUrl: ep.base_url, ...apiKey ? { apiKey } : {} },
188
+ io.fetch ? { fetch: io.fetch } : {}
189
+ );
190
+ if (models[0]) return `${n}:${models[0].id}`;
191
+ }
192
+ return void 0;
193
+ }
194
+ async function hasProvider(io) {
195
+ const paths = resolvePaths(io.env);
196
+ if (await findProviderKey(paths, io.env, "anthropic")) return true;
197
+ const { config } = await loadConfig({ cwd: io.cwd, env: io.env });
198
+ for (const [n, ep] of Object.entries(config.providers.endpoints)) {
199
+ if (ep.free || await findProviderKey(paths, io.env, n, ep.api_key_env)) return true;
200
+ }
201
+ return false;
202
+ }
203
+
204
+ export {
205
+ Chat,
206
+ defaultChatRef,
207
+ hasProvider
208
+ };
209
+ //# sourceMappingURL=chunk-23MT7K6X.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tui/chat.ts"],"sourcesContent":["import { findProviderKey } from '../auth/keys.js';\nimport { connect, describeConnect } from '../cli/connect.js';\nimport type { CliIO } from '../cli/io.js';\nimport { resolveRunDeps } from '../cli/run-deps.js';\nimport { loadConfig } from '../config/load.js';\nimport { resolvePaths } from '../core/paths.js';\nimport { describeError } from '../errors.js';\nimport { discoverModels } from '../providers/discovery.js';\nimport { resolveModelLenient } from '../providers/profiles.js';\nimport type { ContentBlock, Message, Provider, ToolSpec } from '../providers/types.js';\n\nconst SYSTEM = `You are omnexx's setup assistant, talking to the user in their terminal.\nYour job: help them connect model providers and custom OpenAI-compatible endpoints.\nUse the tools; never invent results. Keys the user pastes reach you as placeholders like\n<key-1>: pass the placeholder as the key argument and omnexx swaps in the real key.\nNever ask the user to paste a key into anything but this chat. Be brief: plain text, no\nmarkdown headings. When a provider is connected, tell them the model ref to use.`;\n\nconst TOOLS: ToolSpec[] = [\n {\n name: 'list_providers',\n description: 'Configured providers, their base URLs and whether a key is set.',\n inputSchema: { type: 'object', properties: {} },\n },\n {\n name: 'connect_provider',\n description:\n 'Add or update a provider. target is a known name (openai, openrouter, groq, deepseek, ' +\n 'together, fireworks, mistral, gemini, xai, ollama, lmstudio, vllm, litellm, anthropic) ' +\n 'or a base URL of any OpenAI-compatible endpoint. Lists its models to prove it works.',\n inputSchema: {\n type: 'object',\n properties: {\n target: { type: 'string' },\n key: { type: 'string', description: 'API key or a <key-N> placeholder' },\n name: { type: 'string', description: 'name for a URL endpoint (optional)' },\n },\n required: ['target'],\n },\n },\n {\n name: 'list_models',\n description: 'Models a configured provider serves.',\n inputSchema: {\n type: 'object',\n properties: { provider: { type: 'string' } },\n required: ['provider'],\n },\n },\n];\n\nconst KEYISH = /\\b(sk-ant-|sk-or-|sk-|gsk_|xai-|AIza|fw_)[A-Za-z0-9_\\-.]{16,}/g;\n\n/**\n * A direct conversation with one model (`/chat openrouter:some-model`). The model can connect\n * further providers through tools; pasted keys never reach it, only `<key-N>` placeholders.\n */\nexport class Chat {\n private messages: Message[] = [];\n private keys: string[] = [];\n\n private constructor(\n private readonly io: CliIO,\n readonly ref: string,\n private readonly provider: Provider,\n private readonly route: string,\n private readonly model: string,\n ) {}\n\n static async open(io: CliIO, ref: string): Promise<Chat> {\n const { config, deps } = await resolveRunDeps(io, io.cwd, {\n models: { planner: ref, worker: ref, cheap: ref },\n });\n const m = resolveModelLenient(ref, config);\n return new Chat(io, ref, deps.provider, m.provider, m.id);\n }\n\n /** Replace pasted keys with placeholders; the real values stay here. */\n redact(text: string): string {\n return text.replace(KEYISH, (k) => {\n let i = this.keys.indexOf(k);\n if (i === -1) i = this.keys.push(k) - 1;\n return `<key-${i + 1}>`;\n });\n }\n\n private unredact(text: string | undefined): string | undefined {\n return text?.replace(/<key-(\\d+)>/g, (m, n: string) => this.keys[Number(n) - 1] ?? m);\n }\n\n /** One user turn: loops through tool calls until the model answers. `say` gets each line. */\n async send(text: string, say: (line: string) => void, maxSteps = 8): Promise<void> {\n this.messages.push({ role: 'user', content: [{ type: 'text', text: this.redact(text) }] });\n for (let step = 0; step < maxSteps; step++) {\n const res = await this.provider.complete({\n model: this.model,\n route: this.route,\n system: [{ text: SYSTEM }],\n tools: TOOLS,\n messages: this.messages,\n maxTokens: 2048,\n messageBreakpoints: [],\n });\n this.messages.push({ role: 'assistant', content: res.content });\n const said = res.content\n .filter((b): b is Extract<ContentBlock, { type: 'text' }> => b.type === 'text')\n .map((b) => b.text)\n .join('')\n .trim();\n if (said) say(said);\n const calls = res.content.filter(\n (b): b is Extract<ContentBlock, { type: 'tool_use' }> => b.type === 'tool_use',\n );\n if (!calls.length) return;\n const results: ContentBlock[] = [];\n for (const c of calls) {\n say(`· ${c.name}`);\n try {\n results.push({\n type: 'tool_result',\n toolUseId: c.id,\n content: await this.tool(c.name, (c.input ?? {}) as Record<string, unknown>),\n });\n } catch (err) {\n results.push({\n type: 'tool_result',\n toolUseId: c.id,\n content: describeError(err),\n isError: true,\n });\n }\n }\n this.messages.push({ role: 'user', content: results });\n }\n say('(stopped after too many tool calls)');\n }\n\n private async tool(name: string, input: Record<string, unknown>): Promise<string> {\n const str = (k: string): string | undefined =>\n typeof input[k] === 'string' ? input[k] : undefined;\n switch (name) {\n case 'list_providers': {\n const { config } = await loadConfig({ cwd: this.io.cwd, env: this.io.env });\n const paths = resolvePaths(this.io.env);\n const rows = [\n `anthropic (built-in) key: ${(await findProviderKey(paths, this.io.env, 'anthropic')) ? 'yes' : 'no'}`,\n ];\n for (const [n, ep] of Object.entries(config.providers.endpoints)) {\n const key = await findProviderKey(paths, this.io.env, n, ep.api_key_env);\n rows.push(`${n} ${ep.base_url} key: ${key ? 'yes' : ep.free ? 'not needed' : 'no'}`);\n }\n return rows.join('\\n');\n }\n case 'connect_provider': {\n const target = this.unredact(str('target')) ?? '';\n const key = this.unredact(str('key'));\n const nm = str('name');\n // A model that passes the key as the target still works.\n const r = await connect(this.io, target, key, nm ? { name: nm } : {});\n return this.redact(describeConnect(r));\n }\n case 'list_models': {\n const p = str('provider') ?? '';\n const { config } = await loadConfig({ cwd: this.io.cwd, env: this.io.env });\n const ep = config.providers.endpoints[p];\n if (!ep) return `unknown provider \"${p}\"`;\n const apiKey = (\n await findProviderKey(resolvePaths(this.io.env), this.io.env, p, ep.api_key_env)\n )?.key;\n const models = await discoverModels(\n { baseUrl: ep.base_url, ...(apiKey ? { apiKey } : {}) },\n this.io.fetch ? { fetch: this.io.fetch } : {},\n );\n return models.length ? models.map((m) => m.id).join('\\n') : 'no models listed';\n }\n default:\n return `unknown tool ${name}`;\n }\n }\n}\n\n/** The model to chat with when `/chat` has no argument: Anthropic if keyed, else any endpoint. */\nexport async function defaultChatRef(io: CliIO): Promise<string | undefined> {\n const paths = resolvePaths(io.env);\n if (await findProviderKey(paths, io.env, 'anthropic')) return 'anthropic:sonnet';\n const { config } = await loadConfig({ cwd: io.cwd, env: io.env });\n for (const [n, ep] of Object.entries(config.providers.endpoints)) {\n const apiKey = (await findProviderKey(paths, io.env, n, ep.api_key_env))?.key;\n if (!apiKey && !ep.free) continue;\n const models = await discoverModels(\n { baseUrl: ep.base_url, ...(apiKey ? { apiKey } : {}) },\n io.fetch ? { fetch: io.fetch } : {},\n );\n if (models[0]) return `${n}:${models[0].id}`;\n }\n return undefined;\n}\n\n/** Whether any provider can be called at all (no network): a key, or a free endpoint. */\nexport async function hasProvider(io: CliIO): Promise<boolean> {\n const paths = resolvePaths(io.env);\n if (await findProviderKey(paths, io.env, 'anthropic')) return true;\n const { config } = await loadConfig({ cwd: io.cwd, env: io.env });\n for (const [n, ep] of Object.entries(config.providers.endpoints)) {\n if (ep.free || (await findProviderKey(paths, io.env, n, ep.api_key_env))) return true;\n }\n return false;\n}\n"],"mappings":"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","names":[]}