omnexx 0.9.0 → 0.11.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/dist/{chat-context-37IAD72P.js → chat-context-PTZRLJEV.js} +9 -9
- package/dist/{chat-server-RMR3QGFJ.js → chat-server-U3B2GVLU.js} +29 -11
- package/dist/chat-server-U3B2GVLU.js.map +1 -0
- package/dist/{chat-settings-AMSAWVT6.js → chat-settings-X7R4JKI7.js} +90 -7
- package/dist/chat-settings-X7R4JKI7.js.map +1 -0
- package/dist/{chunk-XQTM3SWX.js → chunk-7PNGHZYH.js} +1 -23
- package/dist/chunk-7PNGHZYH.js.map +1 -0
- package/dist/{chunk-IZYY3NPJ.js → chunk-AGALUEDT.js} +581 -668
- package/dist/chunk-AGALUEDT.js.map +1 -0
- package/dist/{chunk-EDB7FXDP.js → chunk-AXEJCZPA.js} +7 -5
- package/dist/{chunk-EDB7FXDP.js.map → chunk-AXEJCZPA.js.map} +1 -1
- package/dist/{chunk-LU3LFPGQ.js → chunk-B4UJJZKS.js} +23 -7
- package/dist/chunk-B4UJJZKS.js.map +1 -0
- package/dist/{chunk-FNHEOL3X.js → chunk-E6JAG5GA.js} +197 -79
- package/dist/chunk-E6JAG5GA.js.map +1 -0
- package/dist/{chunk-STU6YIQJ.js → chunk-E6NF2XSG.js} +9 -5
- package/dist/{chunk-STU6YIQJ.js.map → chunk-E6NF2XSG.js.map} +1 -1
- package/dist/{chunk-NV4LO7BY.js → chunk-LRBHQHO6.js} +85 -16
- package/dist/chunk-LRBHQHO6.js.map +1 -0
- package/dist/{chunk-3S4ULH6B.js → chunk-LZGGM2YZ.js} +8 -6
- package/dist/{chunk-3S4ULH6B.js.map → chunk-LZGGM2YZ.js.map} +1 -1
- package/dist/chunk-Q3MDYD6K.js +27 -0
- package/dist/chunk-Q3MDYD6K.js.map +1 -0
- package/dist/chunk-QS6LKKWO.js +71 -0
- package/dist/chunk-QS6LKKWO.js.map +1 -0
- package/dist/{chunk-NVDO3QO5.js → chunk-UAW5RG53.js} +204 -178
- package/dist/chunk-UAW5RG53.js.map +1 -0
- package/dist/chunk-VDO3EKC4.js +321 -0
- package/dist/chunk-VDO3EKC4.js.map +1 -0
- package/dist/{chunk-IXTUJETQ.js → chunk-VISE5TUX.js} +455 -201
- package/dist/chunk-VISE5TUX.js.map +1 -0
- package/dist/{chunk-TJWLF5MU.js → chunk-YAWRCULP.js} +6 -4
- package/dist/{chunk-TJWLF5MU.js.map → chunk-YAWRCULP.js.map} +1 -1
- package/dist/cli.js +267 -140
- package/dist/cli.js.map +1 -1
- package/dist/list-S2S26L5B.js +14 -0
- package/dist/{model-picker-QX6NHUGJ.js → model-picker-JKB7LVQR.js} +8 -7
- package/dist/{ollama-USDNXHTB.js → ollama-G2MYWBEE.js} +8 -7
- package/dist/{ollama-USDNXHTB.js.map → ollama-G2MYWBEE.js.map} +1 -1
- package/dist/{print-K4HFWHCL.js → print-2Q2GBDVF.js} +10 -7
- package/dist/{print-K4HFWHCL.js.map → print-2Q2GBDVF.js.map} +1 -1
- package/dist/session-FB6CJHQB.js +34 -0
- package/dist/session-FB6CJHQB.js.map +1 -0
- package/dist/{start-NBU4UITZ.js → start-MSL5UICJ.js} +53 -31
- package/dist/start-MSL5UICJ.js.map +1 -0
- package/package.json +1 -1
- package/dist/chat-server-RMR3QGFJ.js.map +0 -1
- package/dist/chat-settings-AMSAWVT6.js.map +0 -1
- package/dist/chunk-FNHEOL3X.js.map +0 -1
- package/dist/chunk-IXTUJETQ.js.map +0 -1
- package/dist/chunk-IZYY3NPJ.js.map +0 -1
- package/dist/chunk-LU3LFPGQ.js.map +0 -1
- package/dist/chunk-NV4LO7BY.js.map +0 -1
- package/dist/chunk-NVDO3QO5.js.map +0 -1
- package/dist/chunk-T2NUPPUG.js +0 -65
- package/dist/chunk-T2NUPPUG.js.map +0 -1
- package/dist/chunk-XQTM3SWX.js.map +0 -1
- package/dist/session-QGVKS2YJ.js +0 -32
- package/dist/start-NBU4UITZ.js.map +0 -1
- /package/dist/{chat-context-37IAD72P.js.map → chat-context-PTZRLJEV.js.map} +0 -0
- /package/dist/{model-picker-QX6NHUGJ.js.map → list-S2S26L5B.js.map} +0 -0
- /package/dist/{session-QGVKS2YJ.js.map → model-picker-JKB7LVQR.js.map} +0 -0
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
repoRoot
|
|
4
|
-
} from "./chunk-T2NUPPUG.js";
|
|
5
2
|
import {
|
|
6
3
|
RunStore,
|
|
7
4
|
listRunIds,
|
|
8
|
-
repoMemoryFile
|
|
9
|
-
|
|
5
|
+
repoMemoryFile,
|
|
6
|
+
repoRoot
|
|
7
|
+
} from "./chunk-LRBHQHO6.js";
|
|
10
8
|
import {
|
|
11
9
|
SECTION_IDS,
|
|
12
10
|
SECTION_INFO,
|
|
@@ -15,12 +13,14 @@ import {
|
|
|
15
13
|
loadConfig,
|
|
16
14
|
readSectionModes,
|
|
17
15
|
sectionsFile
|
|
18
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-UAW5RG53.js";
|
|
19
17
|
import {
|
|
20
|
-
UsageError,
|
|
21
18
|
resolvePaths
|
|
22
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-Q3MDYD6K.js";
|
|
23
20
|
import "./chunk-27GOEUTN.js";
|
|
21
|
+
import {
|
|
22
|
+
UsageError
|
|
23
|
+
} from "./chunk-7PNGHZYH.js";
|
|
24
24
|
import "./chunk-2H7UOFLK.js";
|
|
25
25
|
|
|
26
26
|
// src/cli/chat-context.ts
|
|
@@ -117,4 +117,4 @@ export {
|
|
|
117
117
|
contextFiles,
|
|
118
118
|
setSectionMode
|
|
119
119
|
};
|
|
120
|
-
//# sourceMappingURL=chat-context-
|
|
120
|
+
//# sourceMappingURL=chat-context-PTZRLJEV.js.map
|
|
@@ -3,9 +3,11 @@ import {
|
|
|
3
3
|
println
|
|
4
4
|
} from "./chunk-7PC4SSYS.js";
|
|
5
5
|
import {
|
|
6
|
-
describeError,
|
|
7
6
|
resolvePaths
|
|
8
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-Q3MDYD6K.js";
|
|
8
|
+
import {
|
|
9
|
+
describeError
|
|
10
|
+
} from "./chunk-7PNGHZYH.js";
|
|
9
11
|
import "./chunk-2H7UOFLK.js";
|
|
10
12
|
|
|
11
13
|
// src/cli/chat-server.ts
|
|
@@ -32,7 +34,7 @@ function text(c, key) {
|
|
|
32
34
|
return v;
|
|
33
35
|
}
|
|
34
36
|
async function serveChat(io, runCli, opts) {
|
|
35
|
-
const { Session } = await import("./session-
|
|
37
|
+
const { Session } = await import("./session-FB6CJHQB.js");
|
|
36
38
|
const session = new Session(io, runCli);
|
|
37
39
|
const write = (msg) => {
|
|
38
40
|
println(io.stdout, JSON.stringify(msg));
|
|
@@ -102,7 +104,7 @@ async function serveChat(io, runCli, opts) {
|
|
|
102
104
|
};
|
|
103
105
|
session.onChange(schedule);
|
|
104
106
|
const sendModels = async () => {
|
|
105
|
-
const { loadModelChoices } = await import("./model-picker-
|
|
107
|
+
const { loadModelChoices } = await import("./model-picker-JKB7LVQR.js");
|
|
106
108
|
const { items, unreachable } = await loadModelChoices(io);
|
|
107
109
|
write({
|
|
108
110
|
type: "models",
|
|
@@ -112,11 +114,15 @@ async function serveChat(io, runCli, opts) {
|
|
|
112
114
|
});
|
|
113
115
|
};
|
|
114
116
|
const sendSettings = async () => {
|
|
115
|
-
const { providerSettings } = await import("./chat-settings-
|
|
117
|
+
const { providerSettings } = await import("./chat-settings-X7R4JKI7.js");
|
|
116
118
|
write({ type: "settings", ...await providerSettings(io) });
|
|
117
119
|
};
|
|
120
|
+
const sendBrowser = async () => {
|
|
121
|
+
const { browserSettings } = await import("./chat-settings-X7R4JKI7.js");
|
|
122
|
+
write({ type: "browser", ...await browserSettings(io) });
|
|
123
|
+
};
|
|
118
124
|
const sendContextFiles = async () => {
|
|
119
|
-
const { contextFiles } = await import("./chat-context-
|
|
125
|
+
const { contextFiles } = await import("./chat-context-PTZRLJEV.js");
|
|
120
126
|
write({ type: "contextFiles", ...await contextFiles(io) });
|
|
121
127
|
};
|
|
122
128
|
const sendRoles = async () => {
|
|
@@ -192,7 +198,7 @@ async function serveChat(io, runCli, opts) {
|
|
|
192
198
|
return typeof v === "string" ? v : void 0;
|
|
193
199
|
};
|
|
194
200
|
run(
|
|
195
|
-
import("./chat-settings-
|
|
201
|
+
import("./chat-settings-X7R4JKI7.js").then(async ({ addProvider }) => {
|
|
196
202
|
await providersChanged(
|
|
197
203
|
await addProvider(io, {
|
|
198
204
|
provider: str("provider"),
|
|
@@ -206,7 +212,7 @@ async function serveChat(io, runCli, opts) {
|
|
|
206
212
|
}
|
|
207
213
|
case "testProvider":
|
|
208
214
|
run(
|
|
209
|
-
import("./chat-settings-
|
|
215
|
+
import("./chat-settings-X7R4JKI7.js").then(async ({ testProvider }) => {
|
|
210
216
|
write({ type: "providerTest", ...await testProvider(io, text(c, "name")) });
|
|
211
217
|
})
|
|
212
218
|
);
|
|
@@ -216,12 +222,24 @@ async function serveChat(io, runCli, opts) {
|
|
|
216
222
|
return;
|
|
217
223
|
case "setSectionMode":
|
|
218
224
|
run(
|
|
219
|
-
import("./chat-context-
|
|
225
|
+
import("./chat-context-PTZRLJEV.js").then(async ({ setSectionMode }) => {
|
|
220
226
|
await setSectionMode(io, text(c, "id"), text(c, "mode"));
|
|
221
227
|
await sendContextFiles();
|
|
222
228
|
})
|
|
223
229
|
);
|
|
224
230
|
return;
|
|
231
|
+
case "browser":
|
|
232
|
+
run(sendBrowser());
|
|
233
|
+
return;
|
|
234
|
+
case "setBrowser":
|
|
235
|
+
run(
|
|
236
|
+
import("./chat-settings-X7R4JKI7.js").then(async ({ setBrowserSettings }) => {
|
|
237
|
+
await setBrowserSettings(io, c);
|
|
238
|
+
session.push("system", "browser settings saved; new runs use them");
|
|
239
|
+
await sendBrowser();
|
|
240
|
+
})
|
|
241
|
+
);
|
|
242
|
+
return;
|
|
225
243
|
case "roles":
|
|
226
244
|
run(sendRoles());
|
|
227
245
|
return;
|
|
@@ -236,7 +254,7 @@ async function serveChat(io, runCli, opts) {
|
|
|
236
254
|
return;
|
|
237
255
|
case "removeProvider":
|
|
238
256
|
run(
|
|
239
|
-
import("./chat-settings-
|
|
257
|
+
import("./chat-settings-X7R4JKI7.js").then(async ({ removeProvider }) => {
|
|
240
258
|
await providersChanged(await removeProvider(io, text(c, "name")));
|
|
241
259
|
})
|
|
242
260
|
);
|
|
@@ -281,4 +299,4 @@ async function serveChat(io, runCli, opts) {
|
|
|
281
299
|
export {
|
|
282
300
|
serveChat
|
|
283
301
|
};
|
|
284
|
-
//# sourceMappingURL=chat-server-
|
|
302
|
+
//# sourceMappingURL=chat-server-U3B2GVLU.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} · 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} · browser {engine, profile, sessionName, headless} · 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 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 /** 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\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 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 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 /** 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 '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":[]}
|
|
@@ -2,30 +2,38 @@
|
|
|
2
2
|
import {
|
|
3
3
|
connect,
|
|
4
4
|
describeConnect
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-LZGGM2YZ.js";
|
|
6
6
|
import {
|
|
7
7
|
PROVIDER_TEMPLATES,
|
|
8
8
|
removeEndpointBlock
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-AXEJCZPA.js";
|
|
10
10
|
import "./chunk-7PC4SSYS.js";
|
|
11
|
+
import {
|
|
12
|
+
setTable
|
|
13
|
+
} from "./chunk-QS6LKKWO.js";
|
|
11
14
|
import {
|
|
12
15
|
clearKey,
|
|
13
16
|
findProviderKey,
|
|
14
17
|
maskKey
|
|
15
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-YAWRCULP.js";
|
|
16
19
|
import {
|
|
17
20
|
loadConfig
|
|
18
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-UAW5RG53.js";
|
|
19
22
|
import {
|
|
20
|
-
UsageError,
|
|
21
23
|
resolvePaths,
|
|
22
24
|
userConfigFile
|
|
23
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-Q3MDYD6K.js";
|
|
24
26
|
import "./chunk-27GOEUTN.js";
|
|
27
|
+
import {
|
|
28
|
+
UsageError
|
|
29
|
+
} from "./chunk-7PNGHZYH.js";
|
|
25
30
|
import "./chunk-UX4MF6V4.js";
|
|
26
31
|
import "./chunk-2H7UOFLK.js";
|
|
27
32
|
|
|
28
33
|
// src/cli/chat-settings.ts
|
|
34
|
+
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
35
|
+
import { dirname } from "path";
|
|
36
|
+
import { parse } from "smol-toml";
|
|
29
37
|
var ANTHROPIC = {
|
|
30
38
|
name: "anthropic",
|
|
31
39
|
label: "Anthropic (Claude)",
|
|
@@ -137,11 +145,86 @@ async function testProvider(io, name) {
|
|
|
137
145
|
detail: key || ep.free ? "couldn't reach it or it listed no models" : "no key set"
|
|
138
146
|
};
|
|
139
147
|
}
|
|
148
|
+
var ENGINES = ["chromium", "camoufox"];
|
|
149
|
+
var SESSION_NAME = /^[\w.-]{1,64}$/;
|
|
150
|
+
var hasControl = (text) => Array.from(text).some((ch) => {
|
|
151
|
+
const code = ch.codePointAt(0) ?? 0;
|
|
152
|
+
return code < 32 || code >= 127 && code <= 159;
|
|
153
|
+
});
|
|
154
|
+
async function browserSettings(io) {
|
|
155
|
+
const { config } = await loadConfig({ cwd: io.cwd, env: io.env });
|
|
156
|
+
const b = config.browser;
|
|
157
|
+
return {
|
|
158
|
+
engine: b.engine,
|
|
159
|
+
profile: b.profile ?? null,
|
|
160
|
+
sessionName: b.session_name ?? null,
|
|
161
|
+
headless: b.headless
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function optionalText(raw, label) {
|
|
165
|
+
if (raw === void 0 || raw === null) return void 0;
|
|
166
|
+
if (typeof raw !== "string") throw new UsageError(`${label} must be text`);
|
|
167
|
+
const trimmed = raw.trim();
|
|
168
|
+
if (hasControl(trimmed))
|
|
169
|
+
throw new UsageError(`${label} can't contain newlines or control characters`);
|
|
170
|
+
return trimmed || void 0;
|
|
171
|
+
}
|
|
172
|
+
function parseBrowserSettings(raw) {
|
|
173
|
+
const obj = typeof raw === "object" && raw !== null ? raw : {};
|
|
174
|
+
const engine = obj.engine ?? "chromium";
|
|
175
|
+
if (typeof engine !== "string" || !ENGINES.includes(engine))
|
|
176
|
+
throw new UsageError("the browser engine must be chromium or camoufox");
|
|
177
|
+
const profile = optionalText(obj.profile, "the browser profile");
|
|
178
|
+
const sessionName = optionalText(obj.sessionName, "the session name");
|
|
179
|
+
if (sessionName && !SESSION_NAME.test(sessionName))
|
|
180
|
+
throw new UsageError(
|
|
181
|
+
`"${sessionName}" is not a usable session name`,
|
|
182
|
+
"up to 64 letters, digits, _ . and -"
|
|
183
|
+
);
|
|
184
|
+
if (obj.headless !== void 0 && typeof obj.headless !== "boolean")
|
|
185
|
+
throw new UsageError("headless must be on or off");
|
|
186
|
+
return {
|
|
187
|
+
engine,
|
|
188
|
+
profile: profile ?? null,
|
|
189
|
+
sessionName: sessionName ?? null,
|
|
190
|
+
headless: obj.headless !== false
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
async function readText(file) {
|
|
194
|
+
try {
|
|
195
|
+
return await readFile(file, "utf8");
|
|
196
|
+
} catch (err) {
|
|
197
|
+
if (err.code === "ENOENT") return "";
|
|
198
|
+
throw err;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function existingBrowser(text) {
|
|
202
|
+
const table = parse(text).browser;
|
|
203
|
+
return typeof table === "object" && table !== null ? table : {};
|
|
204
|
+
}
|
|
205
|
+
async function setBrowserSettings(io, raw) {
|
|
206
|
+
const next = parseBrowserSettings(raw);
|
|
207
|
+
const file = userConfigFile(resolvePaths(io.env));
|
|
208
|
+
const text = await readText(file);
|
|
209
|
+
const updated = setTable(text, ["browser"], {
|
|
210
|
+
...existingBrowser(text),
|
|
211
|
+
engine: next.engine,
|
|
212
|
+
profile: next.profile ?? void 0,
|
|
213
|
+
session_name: next.sessionName ?? void 0,
|
|
214
|
+
headless: next.headless
|
|
215
|
+
});
|
|
216
|
+
await mkdir(dirname(file), { recursive: true });
|
|
217
|
+
await writeFile(file, updated, "utf8");
|
|
218
|
+
return next;
|
|
219
|
+
}
|
|
140
220
|
export {
|
|
141
221
|
addProvider,
|
|
222
|
+
browserSettings,
|
|
223
|
+
parseBrowserSettings,
|
|
142
224
|
providerCatalog,
|
|
143
225
|
providerSettings,
|
|
144
226
|
removeProvider,
|
|
227
|
+
setBrowserSettings,
|
|
145
228
|
testProvider
|
|
146
229
|
};
|
|
147
|
-
//# sourceMappingURL=chat-settings-
|
|
230
|
+
//# sourceMappingURL=chat-settings-X7R4JKI7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/chat-settings.ts"],"sourcesContent":["import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { parse } from 'smol-toml';\nimport { clearKey, findProviderKey, maskKey } from '../auth/keys.js';\nimport { loadConfig } from '../config/load.js';\nimport { resolvePaths, userConfigFile } from '../core/paths.js';\nimport { UsageError } from '../errors.js';\nimport { setTable, type TomlValue } from '../integrations/toml-edit.js';\nimport { PROVIDER_TEMPLATES, removeEndpointBlock } from './commands/providers.js';\nimport { connect, describeConnect } from './connect.js';\nimport type { CliIO } from './io.js';\n\n/**\n * Provider settings for editor panels (`omnexx chat-server`): what can be added, what is set up,\n * and adding or removing one. Keys go to the 0600 credentials file and are only ever shown masked.\n */\n\nexport interface CatalogProvider {\n name: string;\n label: string;\n baseUrl: string;\n /** A local server the person runs themselves: no key. */\n local: boolean;\n /** Where to get a key. */\n signup?: string;\n /** How its keys start, for a placeholder. */\n keyPrefix?: string;\n}\n\nexport interface ConnectedProvider {\n name: string;\n label: string;\n baseUrl: string;\n local: boolean;\n free: boolean;\n /** The key, masked (`sk-…wxyz`), or null when none is set. */\n key: string | null;\n /** Where the key comes from: an environment variable or the credentials file. */\n keySource: string | null;\n}\n\nexport interface ProviderSettings {\n catalog: CatalogProvider[];\n connected: ConnectedProvider[];\n}\n\nconst ANTHROPIC: CatalogProvider = {\n name: 'anthropic',\n label: 'Anthropic (Claude)',\n baseUrl: 'https://api.anthropic.com',\n local: false,\n signup: 'https://console.anthropic.com/settings/keys',\n keyPrefix: 'sk-ant-',\n};\n\nconst NAME = /^[a-z][a-z0-9_-]{0,39}$/;\n\nexport function providerCatalog(): CatalogProvider[] {\n const listed = Object.entries(PROVIDER_TEMPLATES)\n .filter(([name]) => name !== 'custom')\n .map(([name, t]) => ({\n name,\n label: t.label ?? name,\n baseUrl: t.baseUrl,\n local: t.local === true,\n ...(t.signup ? { signup: t.signup } : {}),\n ...(t.keyPrefix ? { keyPrefix: t.keyPrefix } : {}),\n }));\n return [ANTHROPIC, ...listed];\n}\n\nexport async function providerSettings(io: CliIO): Promise<ProviderSettings> {\n const paths = resolvePaths(io.env);\n const { config } = await loadConfig({ cwd: io.cwd, env: io.env });\n const catalog = providerCatalog();\n const labelOf = (name: string): string => catalog.find((c) => c.name === name)?.label ?? name;\n const connected: ConnectedProvider[] = [];\n const anthropic = await findProviderKey(paths, io.env, 'anthropic');\n if (anthropic)\n connected.push({\n name: 'anthropic',\n label: ANTHROPIC.label,\n baseUrl: ANTHROPIC.baseUrl,\n local: false,\n free: false,\n key: maskKey(anthropic.key),\n keySource: anthropic.source,\n });\n for (const [name, ep] of Object.entries(config.providers.endpoints)) {\n const found = await findProviderKey(paths, io.env, name, ep.api_key_env);\n connected.push({\n name,\n label: labelOf(name),\n baseUrl: ep.base_url,\n local:\n PROVIDER_TEMPLATES[name]?.local === true ||\n /\\/\\/(localhost|127\\.0\\.0\\.1)[:/]/.test(ep.base_url),\n free: ep.free,\n key: found ? maskKey(found.key) : null,\n keySource: found?.source ?? null,\n });\n }\n return { catalog, connected };\n}\n\nexport interface AddProvider {\n /** A catalog name, or a new name for a custom URL. */\n provider?: string | undefined;\n key?: string | undefined;\n /** For a custom or local OpenAI-compatible server. */\n url?: string | undefined;\n}\n\n/** Connect a provider from the settings form; returns what to tell the person. */\nexport async function addProvider(io: CliIO, a: AddProvider): Promise<string> {\n const url = a.url?.trim();\n const provider = a.provider?.trim().toLowerCase();\n const key = a.key?.trim() ? a.key.trim() : undefined;\n if (url && !/^https?:\\/\\/\\S+$/i.test(url))\n throw new UsageError('the URL must start with http:// or https://');\n if (provider && !NAME.test(provider))\n throw new UsageError(\n `\"${provider}\" is not a usable name`,\n 'lowercase letters, digits, _ and -',\n );\n if (!url && !provider && !key) throw new UsageError('pick a provider or enter a URL');\n // A catalog provider is connected by name; a URL gets the name it was given, if any.\n const target = url ?? provider ?? key ?? '';\n const r = await connect(io, target, url ? key : target === key ? undefined : key, {\n ...(url && provider ? { name: provider } : {}),\n });\n return describeConnect(r);\n}\n\n/** Remove a provider: its endpoint block and its stored key. Environment variables stay. */\nexport async function removeProvider(io: CliIO, name: string): Promise<string> {\n const lower = name.trim().toLowerCase();\n if (!NAME.test(lower)) throw new UsageError(`\"${name}\" is not a provider name`);\n const paths = resolvePaths(io.env);\n const removedBlock =\n lower === 'anthropic' ? false : await removeEndpointBlock(userConfigFile(paths), lower);\n const removedKey = await clearKey(paths, lower);\n if (!removedBlock && !removedKey)\n return `${lower} had nothing to remove (a key from an environment variable stays set)`;\n return `removed ${lower}${removedKey ? ' and its stored key' : ''}`;\n}\n\nexport interface ProviderTest {\n name: string;\n ok: boolean;\n /** How many models the provider listed, when it answered. */\n models: number;\n detail: string;\n}\n\nconst TEST_TIMEOUT_MS = 8_000;\n\n/**\n * Check a provider from the settings page: list its models with the stored key. Anthropic is\n * built in and has no list endpoint here, so it only reports whether a key is set.\n */\nexport async function testProvider(io: CliIO, name: string): Promise<ProviderTest> {\n const lower = name.trim().toLowerCase();\n if (!NAME.test(lower)) throw new UsageError(`\"${name}\" is not a provider name`);\n const paths = resolvePaths(io.env);\n if (lower === 'anthropic') {\n const found = await findProviderKey(paths, io.env, 'anthropic');\n return {\n name: lower,\n ok: found !== undefined,\n models: found ? 3 : 0,\n detail: found ? 'key set (opus, sonnet, haiku)' : 'no key set',\n };\n }\n const { config } = await loadConfig({ cwd: io.cwd, env: io.env });\n const ep = config.providers.endpoints[lower];\n if (!ep) return { name: lower, ok: false, models: 0, detail: 'not set up' };\n const key = (await findProviderKey(paths, io.env, lower, ep.api_key_env))?.key;\n const { discoverModels } = await import('../providers/discovery.js');\n const models = await discoverModels(\n { baseUrl: ep.base_url, ...(key ? { apiKey: key } : {}) },\n { timeoutMs: TEST_TIMEOUT_MS, ...(io.fetch ? { fetch: io.fetch } : {}) },\n );\n if (models.length)\n return { name: lower, ok: true, models: models.length, detail: `${models.length} models` };\n return {\n name: lower,\n ok: false,\n models: 0,\n detail: key || ep.free ? \"couldn't reach it or it listed no models\" : 'no key set',\n };\n}\n\n/** The browser tool's engine, profile and session, as the settings page shows and saves them. */\nexport interface BrowserSettings {\n engine: 'chromium' | 'camoufox';\n /** A folder (or Chrome profile name) whose logins the agent reuses; null when unset. */\n profile: string | null;\n sessionName: string | null;\n headless: boolean;\n}\n\nconst ENGINES = ['chromium', 'camoufox'] as const;\n// Same rule as browser.session_name in src/config/sections/browser.ts.\nconst SESSION_NAME = /^[\\w.-]{1,64}$/;\n/** C0 and C1 control characters, newlines included. */\nconst hasControl = (text: string): boolean =>\n Array.from(text).some((ch) => {\n const code = ch.codePointAt(0) ?? 0;\n return code < 0x20 || (code >= 0x7f && code <= 0x9f);\n });\n\nexport async function browserSettings(io: CliIO): Promise<BrowserSettings> {\n const { config } = await loadConfig({ cwd: io.cwd, env: io.env });\n const b = config.browser;\n return {\n engine: b.engine,\n profile: b.profile ?? null,\n sessionName: b.session_name ?? null,\n headless: b.headless,\n };\n}\n\n/** A trimmed optional text field: empty is unset; newlines and control characters are refused. */\nfunction optionalText(raw: unknown, label: string): string | undefined {\n if (raw === undefined || raw === null) return undefined;\n if (typeof raw !== 'string') throw new UsageError(`${label} must be text`);\n const trimmed = raw.trim();\n if (hasControl(trimmed))\n throw new UsageError(`${label} can't contain newlines or control characters`);\n return trimmed || undefined;\n}\n\n/** Check what the settings form sent; throws a UsageError naming the bad field. */\nexport function parseBrowserSettings(raw: unknown): BrowserSettings {\n const obj = typeof raw === 'object' && raw !== null ? (raw as Record<string, unknown>) : {};\n const engine = obj.engine ?? 'chromium';\n if (typeof engine !== 'string' || !(ENGINES as readonly string[]).includes(engine))\n throw new UsageError('the browser engine must be chromium or camoufox');\n const profile = optionalText(obj.profile, 'the browser profile');\n const sessionName = optionalText(obj.sessionName, 'the session name');\n if (sessionName && !SESSION_NAME.test(sessionName))\n throw new UsageError(\n `\"${sessionName}\" is not a usable session name`,\n 'up to 64 letters, digits, _ . and -',\n );\n if (obj.headless !== undefined && typeof obj.headless !== 'boolean')\n throw new UsageError('headless must be on or off');\n return {\n engine: engine as BrowserSettings['engine'],\n profile: profile ?? null,\n sessionName: sessionName ?? null,\n headless: obj.headless !== false,\n };\n}\n\nasync function readText(file: string): Promise<string> {\n try {\n return await readFile(file, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return '';\n throw err;\n }\n}\n\n/** The [browser] keys already in the user config, kept when the form saves its four. */\nfunction existingBrowser(text: string): Record<string, TomlValue> {\n const table = (parse(text) as Record<string, unknown>).browser;\n return typeof table === 'object' && table !== null ? (table as Record<string, TomlValue>) : {};\n}\n\n/** Save the browser settings to the user's config.toml; other [browser] keys stay as they were. */\nexport async function setBrowserSettings(io: CliIO, raw: unknown): Promise<BrowserSettings> {\n const next = parseBrowserSettings(raw);\n const file = userConfigFile(resolvePaths(io.env));\n const text = await readText(file);\n const updated = setTable(text, ['browser'], {\n ...existingBrowser(text),\n engine: next.engine,\n profile: next.profile ?? undefined,\n session_name: next.sessionName ?? undefined,\n headless: next.headless,\n });\n await mkdir(dirname(file), { recursive: true });\n await writeFile(file, updated, 'utf8');\n return next;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,21 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
// src/core/paths.ts
|
|
4
|
-
import { homedir } from "os";
|
|
5
|
-
import { join } from "path";
|
|
6
|
-
function resolvePaths(env = process.env) {
|
|
7
|
-
const xdg = env.XDG_CONFIG_HOME;
|
|
8
|
-
return {
|
|
9
|
-
home: env.OMNEXX_HOME ?? join(homedir(), ".omnexx"),
|
|
10
|
-
configHome: env.OMNEXX_CONFIG_HOME ?? join(xdg ?? join(homedir(), ".config"), "omnexx")
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
var runsDir = (p) => join(p.home, "runs");
|
|
14
|
-
var runDir = (p, runId) => join(p.home, "runs", runId);
|
|
15
|
-
var worktreesDir = (p) => join(p.home, "worktrees");
|
|
16
|
-
var userConfigFile = (p) => join(p.configHome, "config.toml");
|
|
17
|
-
var credentialsDir = (p) => join(p.configHome, "credentials");
|
|
18
|
-
|
|
19
3
|
// src/errors.ts
|
|
20
4
|
var OmnexxError = class extends Error {
|
|
21
5
|
code;
|
|
@@ -89,12 +73,6 @@ function describeError(err) {
|
|
|
89
73
|
}
|
|
90
74
|
|
|
91
75
|
export {
|
|
92
|
-
resolvePaths,
|
|
93
|
-
runsDir,
|
|
94
|
-
runDir,
|
|
95
|
-
worktreesDir,
|
|
96
|
-
userConfigFile,
|
|
97
|
-
credentialsDir,
|
|
98
76
|
OmnexxError,
|
|
99
77
|
ConfigError,
|
|
100
78
|
NotImplementedError,
|
|
@@ -106,4 +84,4 @@ export {
|
|
|
106
84
|
UsageError,
|
|
107
85
|
describeError
|
|
108
86
|
};
|
|
109
|
-
//# sourceMappingURL=chunk-
|
|
87
|
+
//# sourceMappingURL=chunk-7PNGHZYH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts"],"sourcesContent":["/**\n * Every error Omnexx raises on purpose is an OmnexxError: a stable `code` for scripts and tests,\n * a message that says what went wrong, and a `hint` that says what to do about it.\n */\nexport class OmnexxError extends Error {\n readonly code: string;\n readonly hint: string | undefined;\n\n constructor(code: string, message: string, hint?: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = new.target.name;\n this.code = code;\n this.hint = hint;\n }\n\n /** One line, suitable for a terminal: `error[code]: message (hint)`. */\n oneLine(): string {\n return `error[${this.code}]: ${this.message}${this.hint ? ` (${this.hint})` : ''}`;\n }\n}\n\nexport class ConfigError extends OmnexxError {\n constructor(message: string, hint?: string) {\n super('config', message, hint);\n }\n}\n\nexport class NotImplementedError extends OmnexxError {\n constructor(feature: string, milestone: string) {\n super(\n 'not-implemented',\n `${feature} is not implemented in this version (planned for ${milestone})`,\n 'see README \"What does not work yet\"',\n );\n }\n}\n\nexport class PolicyError extends OmnexxError {\n constructor(message: string, hint?: string) {\n super('policy', message, hint);\n }\n}\n\nexport class GitError extends OmnexxError {\n constructor(message: string, hint?: string, options?: { cause?: unknown }) {\n super('git', message, hint, options);\n }\n}\n\nexport class ProviderError extends OmnexxError {\n readonly retryable: boolean;\n readonly status: number | undefined;\n /** The provider's content filter refused this request; another model may take it. */\n readonly contentFilter: boolean;\n\n constructor(\n message: string,\n opts: {\n retryable: boolean;\n status?: number;\n hint?: string;\n cause?: unknown;\n contentFilter?: boolean;\n },\n ) {\n super('provider', message, opts.hint, { cause: opts.cause });\n this.retryable = opts.retryable;\n this.status = opts.status;\n this.contentFilter = opts.contentFilter ?? false;\n }\n}\n\nexport class LockError extends OmnexxError {\n constructor(message: string, hint?: string) {\n super('lock', message, hint);\n }\n}\n\nexport class StateError extends OmnexxError {\n constructor(message: string, hint?: string) {\n super('state', message, hint);\n }\n}\n\nexport class UsageError extends OmnexxError {\n constructor(message: string, hint?: string) {\n super('usage', message, hint);\n }\n}\n\n/** Render any thrown value as a single line without leaking stack traces to the user. */\nexport function describeError(err: unknown): string {\n if (err instanceof OmnexxError) return err.oneLine();\n if (err instanceof Error) return `error: ${err.message}`;\n return `error: ${String(err)}`;\n}\n"],"mappings":";;;AAIO,IAAM,cAAN,cAA0B,MAAM;AAAA,EAC5B;AAAA,EACA;AAAA,EAET,YAAY,MAAc,SAAiB,MAAe,SAA+B;AACvF,UAAM,SAAS,OAAO;AACtB,SAAK,OAAO,WAAW;AACvB,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AAAA;AAAA,EAGA,UAAkB;AAChB,WAAO,SAAS,KAAK,IAAI,MAAM,KAAK,OAAO,GAAG,KAAK,OAAO,KAAK,KAAK,IAAI,MAAM,EAAE;AAAA,EAClF;AACF;AAEO,IAAM,cAAN,cAA0B,YAAY;AAAA,EAC3C,YAAY,SAAiB,MAAe;AAC1C,UAAM,UAAU,SAAS,IAAI;AAAA,EAC/B;AACF;AAEO,IAAM,sBAAN,cAAkC,YAAY;AAAA,EACnD,YAAY,SAAiB,WAAmB;AAC9C;AAAA,MACE;AAAA,MACA,GAAG,OAAO,oDAAoD,SAAS;AAAA,MACvE;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,cAAN,cAA0B,YAAY;AAAA,EAC3C,YAAY,SAAiB,MAAe;AAC1C,UAAM,UAAU,SAAS,IAAI;AAAA,EAC/B;AACF;AAEO,IAAM,WAAN,cAAuB,YAAY;AAAA,EACxC,YAAY,SAAiB,MAAe,SAA+B;AACzE,UAAM,OAAO,SAAS,MAAM,OAAO;AAAA,EACrC;AACF;AAEO,IAAM,gBAAN,cAA4B,YAAY;AAAA,EACpC;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EAET,YACE,SACA,MAOA;AACA,UAAM,YAAY,SAAS,KAAK,MAAM,EAAE,OAAO,KAAK,MAAM,CAAC;AAC3D,SAAK,YAAY,KAAK;AACtB,SAAK,SAAS,KAAK;AACnB,SAAK,gBAAgB,KAAK,iBAAiB;AAAA,EAC7C;AACF;AAEO,IAAM,YAAN,cAAwB,YAAY;AAAA,EACzC,YAAY,SAAiB,MAAe;AAC1C,UAAM,QAAQ,SAAS,IAAI;AAAA,EAC7B;AACF;AAEO,IAAM,aAAN,cAAyB,YAAY;AAAA,EAC1C,YAAY,SAAiB,MAAe;AAC1C,UAAM,SAAS,SAAS,IAAI;AAAA,EAC9B;AACF;AAEO,IAAM,aAAN,cAAyB,YAAY;AAAA,EAC1C,YAAY,SAAiB,MAAe;AAC1C,UAAM,SAAS,SAAS,IAAI;AAAA,EAC9B;AACF;AAGO,SAAS,cAAc,KAAsB;AAClD,MAAI,eAAe,YAAa,QAAO,IAAI,QAAQ;AACnD,MAAI,eAAe,MAAO,QAAO,UAAU,IAAI,OAAO;AACtD,SAAO,UAAU,OAAO,GAAG,CAAC;AAC9B;","names":[]}
|